cosh_tools/subagent/types.rs
1//! Types for the `subagent.call` tool.
2
3use serde::{Deserialize, Serialize};
4
5/// Input for calling a sub-agent.
6///
7/// The same visible tool dispatches to TWO implementations: an external
8/// ACP agent harness when `agent` is provided, or the internal sub-agent
9/// (a nested harness) when `agent` is omitted or empty.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct SubAgentCallInput {
12 /// The agent harness to call (e.g. "gemini").
13 /// Must be one of the supported agents listed in the tool description.
14 ///
15 /// Optional: if omitted (or empty), an internal agent runs the task
16 /// instead — a fresh nested harness with an empty context, in
17 /// auto-approve mode, that persists nothing and returns only its final
18 /// report.
19 pub agent: Option<String>,
20 /// The message to send to the sub-agent.
21 ///
22 /// Optional: if omitted (or empty), the last message sent to a sub-agent
23 /// in this session is reused automatically. If no sub-agent has been
24 /// called yet, an error is returned telling the caller to provide one.
25 pub input: Option<String>,
26 /// Whether this sub-agent task is a CODE REVIEW.
27 ///
28 /// When `true`, the harness appends a contract to the prompt: the
29 /// sub-agent's FINAL REPORT must start with an HTML comment header
30 /// declaring the review outcome — `<!-- severity: green -->`,
31 /// `<!-- severity: yellow -->` (minor issues / bad practice at most) or
32 /// `<!-- severity: red -->` (something critical was found). The header
33 /// is consumed by the client: it is never rendered, it only tints the
34 /// sub-agent box (green/yellow/red). Without the flag (or without a
35 /// header in the report) the box keeps its neutral per-agent color.
36 ///
37 /// Optional; defaults to `false`.
38 #[serde(default)]
39 pub code_review: bool,
40 /// Resume the agent's most recent session, keeping its context (default).
41 ///
42 /// `true` (or omitted): the call resumes the sub-agent's most recent
43 /// ACP session for this agent (tracked per agent name in the calling
44 /// session), keeping its conversation context — the token-efficient
45 /// default for review/iteration loops. `false`: start a brand-new
46 /// session with clean context, for tasks unrelated to the previous
47 /// one (the `--continue`/`-c` CLI convention, inverted to a positive
48 /// flag).
49 ///
50 /// Graceful degradation: a harness without session-resume support, or
51 /// one whose stored session no longer exists (e.g. it restarted and
52 /// lost state), silently falls back to a fresh `session/new`.
53 ///
54 /// Optional; defaults to `true`. Ignored when `agent` is omitted (the
55 /// internal agent never persists state across calls).
56 #[serde(default = "default_true")]
57 pub continue_session: bool,
58 /// Run the sub-agent in the BACKGROUND (default `false`).
59 ///
60 /// `true`: the harness spawns the sub-agent without blocking, returns a
61 /// `task_id` immediately, and the final report is delivered later — as
62 /// an automated completion notification in a subsequent turn. Query
63 /// progress at any time with the `subagent_status` tool (by `task_id`,
64 /// or omit its argument to list all background tasks).
65 ///
66 /// Omitted or `false`: the call blocks until the sub-agent finishes and
67 /// returns its report directly (the default synchronous behavior).
68 #[serde(default)]
69 pub run_in_background: bool,
70}
71
72/// Serde default for [`SubAgentCallInput::continue_session`]: omitted means
73/// RESUME (the token-efficient default), so the flag is opt-out only.
74fn default_true() -> bool {
75 true
76}
77
78/// Output from calling a sub-agent over ACP.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct SubAgentCallOutput {
81 /// The sub-agent's report: its FINAL message — the text written after
82 /// its last tool call (see `subagent::closure::TurnClosure`), not the
83 /// concatenation of every message of the turn.
84 pub output: String,
85 /// Why the prompt turn ended: a snake_case ACP stop reason (e.g.
86 /// `end_turn`, `cancelled` — the spec-mandated answer to a
87 /// `session/cancel`), or the client-side terminal marker `error` when
88 /// the harness failed mid-turn. There is no timeout: the turn runs
89 /// until the agent ends it or the user stops it.
90 pub stop_reason: String,
91}