vtcode_collaboration_tool_specs/
lib.rs1use serde_json::{Value, json};
4
5#[must_use]
6pub fn spawn_agent_parameters() -> Value {
7 json!({
8 "type": "object",
9 "properties": {
10 "agent_type": {"type": "string", "description": "Subagent type or name to run."},
11 "message": {"type": "string", "description": "Task prompt for the child agent. The child receives the same tools as the parent and may spawn its own child agents."},
12 "items": {
13 "type": "array",
14 "description": "Structured context items for the child agent.",
15 "items": collaboration_input_item_schema()
16 },
17 "fork_context": {"type": "boolean", "description": "Seed the child with the current thread history.", "default": false},
18 "model": {
19 "type": "string",
20 "description": "Optional subagent model override. Omit this field to reuse the parent session model. VT Code only honors this override when the current user turn explicitly asks for that model."
21 },
22 "reasoning_effort": {"type": "string", "description": "Optional subagent reasoning effort override."},
23 "background": {
24 "type": "boolean",
25 "description": "Mark the delegated child thread as background-style work. This still creates a normal child agent thread in the current session; it does not launch the managed background subprocess runtime.",
26 "default": false
27 },
28 "max_turns": {
29 "type": "integer",
30 "description": "Optional turn limit for this child. Values below 2 are promoted to 2 so the child can recover from an initial blocked or denied tool call."
31 }
32 }
33 })
34}
35
36#[must_use]
37pub fn spawn_background_subprocess_parameters() -> Value {
38 json!({
39 "type": "object",
40 "properties": {
41 "agent_type": {"type": "string", "description": "Background-enabled subagent type or name to run."},
42 "message": {"type": "string", "description": "Task prompt for the managed background subprocess. Use this for durable helper work that should be launched once and then managed outside the current foreground turn."},
43 "items": {
44 "type": "array",
45 "description": "Structured context items for the background subprocess.",
46 "items": collaboration_input_item_schema()
47 },
48 "model": {
49 "type": "string",
50 "description": "Optional subagent model override. Omit this field to reuse the parent session model. VT Code only honors this override when the current user turn explicitly asks for that model."
51 },
52 "reasoning_effort": {"type": "string", "description": "Optional subagent reasoning effort override."},
53 "max_turns": {
54 "type": "integer",
55 "description": "Optional turn limit for the launched background subprocess task before it reports readiness. Values below 4 are promoted to 4 for background launches."
56 }
57 }
58 })
59}
60
61#[must_use]
62pub fn send_input_parameters() -> Value {
63 json!({
64 "type": "object",
65 "required": ["target"],
66 "properties": {
67 "target": {"type": "string", "description": "Child agent id to message."},
68 "message": {"type": "string", "description": "Follow-up prompt for the child."},
69 "items": {
70 "type": "array",
71 "description": "Structured follow-up items.",
72 "items": collaboration_input_item_schema()
73 },
74 "interrupt": {"type": "boolean", "description": "When true, abort current child work and restart with this input. When false (default), queue the input; if the child is already running, it starts the child's next turn after the current turn completes.", "default": false}
75 }
76 })
77}
78
79#[must_use]
80pub fn wait_agent_parameters() -> Value {
81 json!({
82 "type": "object",
83 "required": ["targets"],
84 "properties": {
85 "targets": {
86 "type": "array",
87 "items": {"type": "string"},
88 "description": "Child agent ids to wait for. This blocks the current foreground turn until one target reaches a terminal state or the wait times out."
89 },
90 "timeout_ms": {
91 "type": "integer",
92 "description": "Optional wait timeout in milliseconds. Uses the session default timeout when omitted."
93 }
94 }
95 })
96}
97
98#[must_use]
99pub fn resume_agent_parameters() -> Value {
100 json!({
101 "type": "object",
102 "required": ["id"],
103 "properties": {
104 "id": {"type": "string", "description": "Child agent id to resume."}
105 }
106 })
107}
108
109#[must_use]
110pub fn close_agent_parameters() -> Value {
111 json!({
112 "type": "object",
113 "required": ["target"],
114 "properties": {
115 "target": {"type": "string", "description": "Child agent id to close."}
116 }
117 })
118}
119
120#[must_use]
121pub fn request_user_input_description() -> &'static str {
122 "Request user input for one to three short questions and wait for the response. Canonical HITL tool; only available in Plan mode."
123}
124
125#[must_use]
126pub fn request_user_input_parameters() -> Value {
127 json!({
128 "type": "object",
129 "additionalProperties": false,
130 "required": ["questions"],
131 "properties": {
132 "questions": {
133 "type": "array",
134 "description": "Questions to show the user (1-3). Prefer 1 unless multiple independent decisions block progress.",
135 "minItems": 1,
136 "maxItems": 3,
137 "items": {
138 "type": "object",
139 "additionalProperties": false,
140 "required": ["id", "header", "question"],
141 "properties": {
142 "id": {
143 "type": "string",
144 "description": "Stable identifier for mapping answers (snake_case)."
145 },
146 "header": {
147 "type": "string",
148 "description": "Short header label shown in the UI (12 or fewer chars)."
149 },
150 "question": {
151 "type": "string",
152 "description": "Single-sentence prompt shown to the user."
153 },
154 "focus_area": {
155 "type": "string",
156 "description": "Optional short topic hint used to bias auto-suggested choices when options are omitted."
157 },
158 "analysis_hints": {
159 "type": "array",
160 "description": "Optional weakness/risk hints used by the UI to generate suggested options.",
161 "items": {
162 "type": "string"
163 },
164 "maxItems": 8
165 },
166 "options": {
167 "type": "array",
168 "description": "Optional 2-3 mutually exclusive choices. Put the recommended option first and suffix its label with \"(Recommended)\". Do not include an \"Other\" option; the UI provides that automatically. If omitted, the UI auto-suggests options using question text and hints.",
169 "minItems": 2,
170 "maxItems": 3,
171 "items": {
172 "type": "object",
173 "additionalProperties": false,
174 "required": ["label", "description"],
175 "properties": {
176 "label": {
177 "type": "string",
178 "description": "User-facing label (1-5 words)."
179 },
180 "description": {
181 "type": "string",
182 "description": "One short sentence explaining impact/tradeoff if selected."
183 }
184 }
185 }
186 }
187 }
188 }
189 }
190 }
191 })
192}
193
194fn collaboration_input_item_schema() -> Value {
195 json!({
196 "type": "object",
197 "properties": {
198 "type": {"type": "string"},
199 "text": {"type": "string"},
200 "path": {"type": "string"},
201 "name": {"type": "string"},
202 "image_url": {"type": "string"}
203 },
204 "additionalProperties": false
205 })
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use serde_json::json;
212
213 #[test]
214 fn collaboration_schemas_keep_structured_items_consistent() {
215 let spawn_items = &spawn_agent_parameters()["properties"]["items"]["items"];
216 let send_items = &send_input_parameters()["properties"]["items"]["items"];
217
218 assert_eq!(spawn_items, send_items);
219 assert_eq!(spawn_items["additionalProperties"], json!(false));
220 assert_eq!(
221 spawn_items["properties"]["image_url"]["type"],
222 json!("string")
223 );
224 }
225 #[test]
226 fn collaboration_schemas_expose_updated_agent_description_text() {
227 let spawn = spawn_agent_parameters();
228 let spawn_background = spawn_background_subprocess_parameters();
229 let send = send_input_parameters();
230 let wait = wait_agent_parameters();
231
232 assert_eq!(
233 spawn["properties"]["message"]["description"],
234 json!(
235 "Task prompt for the child agent. The child receives the same tools as the parent and may spawn its own child agents."
236 )
237 );
238 assert_eq!(
239 send["properties"]["target"]["description"],
240 json!("Child agent id to message.")
241 );
242 assert_eq!(
243 send["properties"]["interrupt"]["description"],
244 json!(
245 "When true, abort current child work and restart with this input. When false (default), queue the input; if the child is already running, it starts the child's next turn after the current turn completes."
246 )
247 );
248 assert_eq!(
249 spawn["properties"]["background"]["description"],
250 json!(
251 "Mark the delegated child thread as background-style work. This still creates a normal child agent thread in the current session; it does not launch the managed background subprocess runtime."
252 )
253 );
254 assert_eq!(
255 spawn_background["properties"]["message"]["description"],
256 json!(
257 "Task prompt for the managed background subprocess. Use this for durable helper work that should be launched once and then managed outside the current foreground turn."
258 )
259 );
260 assert_eq!(
261 wait["properties"]["targets"]["description"],
262 json!(
263 "Child agent ids to wait for. This blocks the current foreground turn until one target reaches a terminal state or the wait times out."
264 )
265 );
266 assert_eq!(
267 wait["properties"]["timeout_ms"]["description"],
268 json!(
269 "Optional wait timeout in milliseconds. Uses the session default timeout when omitted."
270 )
271 );
272 }
273
274 #[test]
275 fn request_user_input_schema_preserves_description_field_name() {
276 let schema = request_user_input_parameters();
277
278 assert_eq!(schema["required"], json!(["questions"]));
279 assert_eq!(
280 schema["properties"]["questions"]["items"]["properties"]["options"]["items"]["required"],
281 json!(["label", "description"])
282 );
283 assert_eq!(
284 schema["properties"]["questions"]["items"]["properties"]["options"]["items"]["properties"]
285 ["description"]["type"],
286 json!("string")
287 );
288 }
289}