///|
pub struct ToolResultBudget {
  max_visible_count : Int
  max_pending_ack_count : Int
  max_missing_ack_count : Int
  max_artifact_ref_count : Int
} derive(Debug, Eq)

///|
pub struct ToolResultPlan {
  total_count : Int
  visible_count : Int
  hidden_count : Int
  visible_items : Array[ToolResultCard]
  artifact_ref_count : Int
  pending_ack_count : Int
  missing_ack_count : Int
  running_count : Int
  failed_count : Int
  diagnostics : Array[String]
  summary : String
} derive(Debug, Eq)

///|
pub fn tool_result_budget(
  max_visible_count? : Int = 32,
  max_pending_ack_count? : Int = 16,
  max_missing_ack_count? : Int = 0,
  max_artifact_ref_count? : Int = 32,
) -> ToolResultBudget {
  {
    max_visible_count,
    max_pending_ack_count,
    max_missing_ack_count,
    max_artifact_ref_count,
  }
}

///|
pub fn default_tool_result_budget() -> ToolResultBudget {
  tool_result_budget()
}

///|
pub fn plan_tool_result_cards(cards : Array[ToolResultCard]) -> ToolResultPlan {
  plan_tool_result_cards_with_budget(cards, default_tool_result_budget())
}

///|
pub fn plan_tool_result_cards_with_budget(
  cards : Array[ToolResultCard],
  budget : ToolResultBudget,
) -> ToolResultPlan {
  let visible_count = clamp_tool_result_visible_count(
    cards.length(),
    budget.max_visible_count,
  )
  let visible_items : Array[ToolResultCard] = []
  for i in 0..