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."},
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": "Run the child as a background task. Prefer this for long-lived helper work instead of blocking the current foreground turn with `wait_agent`.",
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 send_input_parameters() -> Value {
38 json!({
39 "type": "object",
40 "required": ["target"],
41 "properties": {
42 "target": {"type": "string", "description": "Delegated child agent id."},
43 "message": {"type": "string", "description": "Follow-up prompt for the child."},
44 "items": {
45 "type": "array",
46 "description": "Structured follow-up items.",
47 "items": collaboration_input_item_schema()
48 },
49 "interrupt": {"type": "boolean", "description": "Abort current child work and restart with this message.", "default": false}
50 }
51 })
52}
53
54#[must_use]
55pub fn wait_agent_parameters() -> Value {
56 json!({
57 "type": "object",
58 "required": ["targets"],
59 "properties": {
60 "targets": {
61 "type": "array",
62 "items": {"type": "string"},
63 "description": "Child agent ids to wait for. This blocks the current foreground turn until completion or timeout."
64 },
65 "timeout_ms": {
66 "type": "integer",
67 "description": "Optional wait timeout in milliseconds. Prefer short waits in interactive sessions; managed background subprocesses are controlled through `/subprocesses`, not `wait_agent`."
68 }
69 }
70 })
71}
72
73#[must_use]
74pub fn resume_agent_parameters() -> Value {
75 json!({
76 "type": "object",
77 "required": ["id"],
78 "properties": {
79 "id": {"type": "string", "description": "Child agent id to resume."}
80 }
81 })
82}
83
84#[must_use]
85pub fn close_agent_parameters() -> Value {
86 json!({
87 "type": "object",
88 "required": ["target"],
89 "properties": {
90 "target": {"type": "string", "description": "Child agent id to close."}
91 }
92 })
93}
94
95#[must_use]
96pub fn request_user_input_description() -> &'static str {
97 "Request user input for one to three short questions and wait for the response. Canonical HITL tool; only available in Plan mode."
98}
99
100#[must_use]
101pub fn request_user_input_parameters() -> Value {
102 json!({
103 "type": "object",
104 "additionalProperties": false,
105 "required": ["questions"],
106 "properties": {
107 "questions": {
108 "type": "array",
109 "description": "Questions to show the user (1-3). Prefer 1 unless multiple independent decisions block progress.",
110 "minItems": 1,
111 "maxItems": 3,
112 "items": {
113 "type": "object",
114 "additionalProperties": false,
115 "required": ["id", "header", "question"],
116 "properties": {
117 "id": {
118 "type": "string",
119 "description": "Stable identifier for mapping answers (snake_case)."
120 },
121 "header": {
122 "type": "string",
123 "description": "Short header label shown in the UI (12 or fewer chars)."
124 },
125 "question": {
126 "type": "string",
127 "description": "Single-sentence prompt shown to the user."
128 },
129 "focus_area": {
130 "type": "string",
131 "description": "Optional short topic hint used to bias auto-suggested choices when options are omitted."
132 },
133 "analysis_hints": {
134 "type": "array",
135 "description": "Optional weakness/risk hints used by the UI to generate suggested options.",
136 "items": {
137 "type": "string"
138 },
139 "maxItems": 8
140 },
141 "options": {
142 "type": "array",
143 "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.",
144 "minItems": 2,
145 "maxItems": 3,
146 "items": {
147 "type": "object",
148 "additionalProperties": false,
149 "required": ["label", "description"],
150 "properties": {
151 "label": {
152 "type": "string",
153 "description": "User-facing label (1-5 words)."
154 },
155 "description": {
156 "type": "string",
157 "description": "One short sentence explaining impact/tradeoff if selected."
158 }
159 }
160 }
161 }
162 }
163 }
164 }
165 }
166 })
167}
168
169fn collaboration_input_item_schema() -> Value {
170 json!({
171 "type": "object",
172 "properties": {
173 "type": {"type": "string"},
174 "text": {"type": "string"},
175 "path": {"type": "string"},
176 "name": {"type": "string"},
177 "image_url": {"type": "string"}
178 },
179 "additionalProperties": false
180 })
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186 use serde_json::json;
187
188 #[test]
189 fn collaboration_schemas_keep_structured_items_consistent() {
190 let spawn_items = &spawn_agent_parameters()["properties"]["items"]["items"];
191 let send_items = &send_input_parameters()["properties"]["items"]["items"];
192
193 assert_eq!(spawn_items, send_items);
194 assert_eq!(spawn_items["additionalProperties"], json!(false));
195 assert_eq!(
196 spawn_items["properties"]["image_url"]["type"],
197 json!("string")
198 );
199 }
200
201 #[test]
202 fn request_user_input_schema_preserves_description_field_name() {
203 let schema = request_user_input_parameters();
204
205 assert_eq!(schema["required"], json!(["questions"]));
206 assert_eq!(
207 schema["properties"]["questions"]["items"]["properties"]["options"]["items"]["required"],
208 json!(["label", "description"])
209 );
210 assert_eq!(
211 schema["properties"]["questions"]["items"]["properties"]["options"]["items"]["properties"]
212 ["description"]["type"],
213 json!("string")
214 );
215 }
216}