@qwen-code/qwen-code 0.15.12-preview.2 → 0.16.0-nightly.20260522.48b0a8bfc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +69 -71
  2. package/bundled/qc-helper/docs/features/_meta.ts +2 -0
  3. package/bundled/qc-helper/docs/features/approval-mode.md +119 -2
  4. package/bundled/qc-helper/docs/features/auto-mode.md +263 -0
  5. package/bundled/qc-helper/docs/features/commands.md +11 -10
  6. package/bundled/qc-helper/docs/features/lsp.md +87 -10
  7. package/bundled/qc-helper/docs/features/skills.md +3 -0
  8. package/bundled/qc-helper/docs/features/structured-output.md +309 -0
  9. package/bundled/qc-helper/docs/features/sub-agents.md +47 -5
  10. package/bundled/qc-helper/docs/qwen-serve.md +179 -24
  11. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +11 -11
  12. package/bundled/review/SKILL.md +12 -3
  13. package/bundled/stuck/SKILL.md +124 -0
  14. package/chunks/{agent-UQY6A6OS.js → agent-GRCSD6XI.js} +15 -17
  15. package/chunks/{anthropicContentGenerator-4QE6LTVV.js → anthropicContentGenerator-RQJNXJIY.js} +7 -4
  16. package/chunks/{askUserQuestion-QFSCBTUO.js → askUserQuestion-PQPMPNM3.js} +2 -2
  17. package/chunks/{ca-VQSV6JHA.js → ca-UZ7BANMN.js} +29 -3
  18. package/chunks/{chunk-B7ZL7HUA.js → chunk-4AOCVI6J.js} +2 -1
  19. package/chunks/{chunk-PCL3EJGY.js → chunk-4U3O4VDA.js} +4722 -3823
  20. package/chunks/{chunk-AEJ2DKLP.js → chunk-C6WMLUNB.js} +1 -1
  21. package/chunks/{chunk-FSYKVGER.js → chunk-C7PY32RJ.js} +115 -23
  22. package/chunks/{chunk-JMZQICAL.js → chunk-CAVZVZX6.js} +2 -2
  23. package/chunks/{chunk-CAWKL3UC.js → chunk-CSWBPY3P.js} +2 -2
  24. package/chunks/{chunk-G27O2LD2.js → chunk-D5NTAHYL.js} +1 -1
  25. package/chunks/{chunk-BXNCPI75.js → chunk-DMIMF3CG.js} +2 -2
  26. package/chunks/{chunk-OCC4MZRS.js → chunk-F23NCRJ2.js} +1 -1
  27. package/chunks/{chunk-SOIEFHIK.js → chunk-G7YTSRES.js} +1 -100
  28. package/chunks/{chunk-SQNQIOD5.js → chunk-GGNTZ2NH.js} +92 -21
  29. package/chunks/{chunk-FKVKVE6N.js → chunk-KXZ4TJB4.js} +1 -1
  30. package/chunks/{chunk-CBVB66WY.js → chunk-L5E26RN6.js} +2 -2
  31. package/chunks/{chunk-UXW7MYAW.js → chunk-MAY32HXD.js} +376 -1
  32. package/chunks/{chunk-2WFU3IUH.js → chunk-OZO6R4KI.js} +11796 -4086
  33. package/chunks/{chunk-CM2IESUE.js → chunk-PR4T27R7.js} +1 -1
  34. package/chunks/{chunk-FYMSCRHM.js → chunk-PVVL5Q3W.js} +32 -1
  35. package/chunks/{chunk-MXBWOU2L.js → chunk-TM4RMEYN.js} +17 -349
  36. package/chunks/{chunk-YHEAJFCI.js → chunk-USE2VQ5P.js} +3 -0
  37. package/chunks/chunk-UY2AYRZF.js +19126 -0
  38. package/chunks/{chunk-GJXIKCKL.js → chunk-XP27SJMH.js} +76 -5
  39. package/chunks/chunk-XTYIPAUG.js +379 -0
  40. package/chunks/{chunk-TPGOGCWM.js → chunk-YJLGXDQJ.js} +1 -1
  41. package/chunks/{contextCommand-MQRG6RMG.js → contextCommand-O2OLCMOG.js} +17 -19
  42. package/chunks/{cron-create-WUTD5ZTH.js → cron-create-IGYXQVG4.js} +28 -2
  43. package/chunks/{cron-delete-N3UQYCRA.js → cron-delete-ETKIZCWT.js} +2 -2
  44. package/chunks/{cron-list-Z6RJJ4YH.js → cron-list-BVCUSWRU.js} +2 -2
  45. package/chunks/{de-M2IPQRBS.js → de-V4IE2OOZ.js} +29 -3
  46. package/chunks/{dist-RRYNPBOE.js → dist-4L54HRX2.js} +2 -2
  47. package/chunks/{dist-WP4AH3VK.js → dist-BXDUQ2QY.js} +1 -1
  48. package/chunks/{dist-M6GFCZ7S.js → dist-MN2PDDPR.js} +1 -1
  49. package/chunks/{edit-3KCBTA25.js → edit-NRL5ZYWP.js} +32 -18
  50. package/chunks/{en-N5GMPCVT.js → en-HGJ2SPLM.js} +32 -3
  51. package/chunks/{enter-worktree-VWS5QZTU.js → enter-worktree-TLT6EXVN.js} +41 -17
  52. package/chunks/{exit-worktree-RVXFWAPD.js → exit-worktree-PE7RZMLE.js} +41 -17
  53. package/chunks/{exitPlanMode-UL5DILDG.js → exitPlanMode-JYMKAHYD.js} +15 -17
  54. package/chunks/{fr-BTHRYEXO.js → fr-CJULI7ZX.js} +29 -3
  55. package/chunks/{geminiContentGenerator-O2OPGHJG.js → geminiContentGenerator-GYIOVT4A.js} +3 -3
  56. package/chunks/{glob-57BSREPN.js → glob-T7KIVIWT.js} +15 -17
  57. package/chunks/{grep-XO5JOC7T.js → grep-4KI7ZJR5.js} +15 -17
  58. package/chunks/{ja-D63TAEBO.js → ja-L7CHRQEW.js} +29 -3
  59. package/chunks/{keychain-token-storage-DMFP5IJM.js → keychain-token-storage-335UOLJ6.js} +2 -2
  60. package/chunks/{ls-SUILOZZB.js → ls-7HD6XG3V.js} +3 -3
  61. package/chunks/{lsp-6TQBWVMZ.js → lsp-ZZSFCIWD.js} +2 -2
  62. package/chunks/{monitor-BECPGO3K.js → monitor-L5YPPGVO.js} +45 -26
  63. package/chunks/notebook-edit-HYXLIC3D.js +756 -0
  64. package/chunks/{openaiContentGenerator-KEZQHIRM.js → openaiContentGenerator-XRP5JM6P.js} +12 -11
  65. package/chunks/{pt-XUV7FSKC.js → pt-M6JULLEQ.js} +29 -3
  66. package/chunks/{qwenContentGenerator-RPMRXTNH.js → qwenContentGenerator-EOX3HZXX.js} +17 -19
  67. package/chunks/{qwenOAuth2-JSQ7EPR3.js → qwenOAuth2-EEJGROP7.js} +9 -3
  68. package/chunks/{read-file-LGHEIQNH.js → read-file-3XOYPTIB.js} +7 -8
  69. package/chunks/{ripGrep-6SFSXZ2G.js → ripGrep-5QUURWGU.js} +15 -17
  70. package/chunks/{ru-7KHWMN3A.js → ru-QILM4HBC.js} +29 -3
  71. package/chunks/{send-message-Q2JRAC3J.js → send-message-ULK4MQXJ.js} +23 -2
  72. package/chunks/{serve-27O2AFE3.js → serve-AZ44ZNWF.js} +8864 -1351
  73. package/chunks/{shell-J7K5KYCH.js → shell-O6OTTSIP.js} +15 -17
  74. package/chunks/{skill-2R7P4ATS.js → skill-MUGS3H4M.js} +23 -10
  75. package/chunks/{src-CGEDVW67.js → src-YCQBAYCP.js} +292 -28
  76. package/chunks/{syntheticOutput-S4DRGMQM.js → syntheticOutput-IS2X5OZ2.js} +3 -3
  77. package/chunks/{task-stop-7THHVAQS.js → task-stop-7QSJGSSP.js} +2 -2
  78. package/chunks/{todoWrite-WKUGUTPX.js → todoWrite-7CVACFUX.js} +3 -3
  79. package/chunks/{tool-search-XOH3ZWVS.js → tool-search-UFDQJOXT.js} +7 -8
  80. package/chunks/{web-fetch-OZE6ZQUF.js → web-fetch-ENQ2I5JA.js} +7 -4
  81. package/chunks/{write-file-74NQ27Q2.js → write-file-GBLDDYQT.js} +29 -18
  82. package/chunks/{zh-VGHU6XBB.js → zh-PWL2NKY3.js} +32 -3
  83. package/chunks/{zh-TW-O36Q4V7E.js → zh-TW-S3YGWICZ.js} +32 -3
  84. package/cli.js +61338 -76795
  85. package/locales/ca.js +44 -5
  86. package/locales/de.js +44 -5
  87. package/locales/en.js +49 -5
  88. package/locales/fr.js +45 -5
  89. package/locales/ja.js +43 -5
  90. package/locales/pt.js +43 -5
  91. package/locales/ru.js +43 -5
  92. package/locales/zh-TW.js +46 -4
  93. package/locales/zh.js +46 -4
  94. package/package.json +2 -2
  95. package/chunks/chunk-5P5XGNYH.js +0 -93
  96. package/chunks/chunk-SYCJMSIJ.js +0 -82
  97. package/chunks/chunk-Y6Z2O3WR.js +0 -33
@@ -0,0 +1,309 @@
1
+ # Structured Output (`--json-schema`)
2
+
3
+ Constrain the model's final answer to a JSON Schema you supply. Qwen
4
+ Code registers a synthetic terminal tool the model is required to call,
5
+ parses the call's arguments against your schema, and exposes the
6
+ validated payload on stdout (or in the JSON / stream-json result
7
+ envelope). The first valid call ends the run.
8
+
9
+ Headless only — works with `qwen -p`, a positional prompt, or a prompt
10
+ piped via stdin.
11
+
12
+ ## Quick start
13
+
14
+ ```bash
15
+ qwen --prompt "Summarize the changes in HEAD with risk_level" \
16
+ --json-schema '{
17
+ "type": "object",
18
+ "properties": {
19
+ "summary": { "type": "string" },
20
+ "risk_level": { "type": "string", "enum": ["low", "medium", "high"] }
21
+ },
22
+ "required": ["summary", "risk_level"],
23
+ "additionalProperties": false
24
+ }'
25
+ ```
26
+
27
+ Output on stdout (default `--output-format text`):
28
+
29
+ ```json
30
+ { "summary": "…", "risk_level": "low" }
31
+ ```
32
+
33
+ The line is exactly the JSON-stringified payload + newline — no
34
+ envelope, no event log. Pipe it straight into `jq` or another consumer.
35
+
36
+ In **text** mode, stdout is reserved for the JSON payload on success
37
+ and is empty on failure; error messages and log lines go to stderr.
38
+ That makes `$(qwen --json-schema …) || exit 1` capture patterns safe
39
+ under text mode — failures land in stderr, not mixed into the captured
40
+ variable. The model's incidental prose during planning is **not**
41
+ mirrored to stderr either — text mode discards it; reach for
42
+ `--output-format json` or `stream-json` if you need to see it.
43
+
44
+ In `--output-format json` and `stream-json`, the failure result
45
+ message is emitted on **stdout** alongside the success path (as the
46
+ final element of the JSON array, or the terminating `result` line on
47
+ the JSONL stream). Not all failure modes emit a result to stdout —
48
+ max-session-turns (exit 53) and signal interrupts (exit 130) exit with
49
+ stderr output only. Check the exit code first; `is_error` on the
50
+ result object disambiguates within the subset of failures that do
51
+ produce a result event.
52
+
53
+ > **Empty schema:** Passing `{}` produces `{}` (an empty JSON object)
54
+ > on stdout. The model calls `structured_output` with no arguments;
55
+ > the upstream argument-normalisation path turns the empty function
56
+ > call into an empty-object payload, which passes validation against
57
+ > the empty schema and is emitted verbatim.
58
+
59
+ ## Supplying the schema
60
+
61
+ Two equivalent forms:
62
+
63
+ ```bash
64
+ # Inline JSON literal
65
+ qwen -p "…" --json-schema '{"type":"object", "properties":{…}}'
66
+
67
+ # Read from a file
68
+ qwen -p "…" --json-schema @./schemas/summary.json
69
+ ```
70
+
71
+ The `@path` form expands `~`, normalizes the path, and reads the file
72
+ with `utf8` encoding.
73
+
74
+ > **Latency note:** Successful runs incur a shutdown holdback **capped
75
+ > at ~500 ms** while in-flight background agents flush their final
76
+ > notifications before the result is emitted. The holdback exits early
77
+ > if no background tasks are pending, so simple runs barely notice it;
78
+ > batch pipelines that fan out hundreds of `--json-schema` invocations
79
+ > against busy agents should account for this upper bound.
80
+
81
+ > **Security note:** Schemas may contain user-supplied regular
82
+ > expressions in `pattern` keywords. Ajv compiles these with the
83
+ > ECMAScript regex engine, which is vulnerable to catastrophic
84
+ > backtracking. Because tool arguments are always objects, the
85
+ > `pattern` keyword only fires inside string properties — a malicious
86
+ > schema like
87
+ > `{"type":"object","properties":{"value":{"type":"string","pattern":"(a+)+b"}}}`
88
+ > can hang the CLI when the model supplies a moderately long
89
+ > matching value. Only run `--json-schema` with schemas from sources
90
+ > you trust.
91
+
92
+ Validation at parse time:
93
+
94
+ - The file must be a regular file (no FIFOs, character devices, or
95
+ directories).
96
+ - File size is capped at 4 MiB. Real-world JSON schemas are well under
97
+ this; multi-MiB files almost always indicate a wrong-path mistake.
98
+ - The schema must be valid JSON. For `@path` input, the parse error is
99
+ generic ("content of `<path>` is not valid JSON") rather than echoing
100
+ the SyntaxError detail, so a wrapping process that surfaces stderr
101
+ can't read a prefix of the file's contents back from the error.
102
+ - The schema must compile under the strict Ajv configuration —
103
+ typos like `propertees` are surfaced, but spec-valid patterns
104
+ (e.g. `required` without listing every key in `properties`) are
105
+ accepted.
106
+ - The schema root must accept object-typed values. Function-calling
107
+ APIs (Gemini, OpenAI, Anthropic) all require tool arguments to be
108
+ JSON objects, so a non-object root would register an unusable tool.
109
+
110
+ The root-acceptance check walks `type`, `const`, `enum`, `anyOf`,
111
+ `oneOf`, `allOf`, `not`, and `if`/`then`/`else` (best-effort for the
112
+ decidable cases). When in doubt it defers to Ajv at runtime.
113
+
114
+ > **Root `$ref` is rejected** by the parse-time check. If your schema
115
+ > reuses a definition via `$ref`, wrap it in `allOf`:
116
+ >
117
+ > ```jsonc
118
+ > // Rejected:
119
+ > { "$ref": "#/$defs/MyObj", "$defs": { "MyObj": { "type": "object", "properties": { "name": { "type": "string" } } } } }
120
+ >
121
+ > // Accepted (root accepts objects via the allOf branch):
122
+ > { "allOf": [{ "$ref": "#/$defs/MyObj" }], "$defs": { "MyObj": { "type": "object", "properties": { "name": { "type": "string" } } } } }
123
+ > ```
124
+ >
125
+ > `$ref` inside `anyOf` / `oneOf` / `allOf` is deferred to Ajv at
126
+ > runtime, so the wrapped form passes the root-acceptance check.
127
+
128
+ ## Output shape per format
129
+
130
+ | `--output-format` | What goes to stdout |
131
+ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
132
+ | `text` (default) | `JSON.stringify(payload) + "\n"` — one line, the validated object. |
133
+ | `json` | A single JSON **array** of message objects (the full event log). The final element is the `type: "result"` message, which carries both `result` (`JSON.stringify(payload)`) and `structured_result` (the raw object). |
134
+ | `stream-json` | Each event on its own line as JSONL. The terminating `result` line carries `result` (stringified) and `structured_result` (raw object). |
135
+
136
+ In both JSON formats, prefer reading `structured_result` over `result`
137
+ when you want the object; `result` is the stringified form provided for
138
+ consumers that always expect a string in that field. For `--output-format
139
+ json`, read the last element of the array and pull `structured_result`
140
+ from there (e.g. `jq '.[-1].structured_result'`); for `stream-json`,
141
+ read the final `type: "result"` line on the stream.
142
+
143
+ ## Restrictions
144
+
145
+ | Combination | Behavior |
146
+ | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
+ | `--json-schema` + `-i` / `--prompt-interactive` | Rejected at parse time. The synthetic tool's "session ends now" message has no terminator in the TUI loop. |
148
+ | `--json-schema` + `--input-format stream-json` | Rejected at parse time. The single-shot terminal contract is incompatible with the long-lived stream-json input protocol. |
149
+ | `--json-schema` + `--acp` / `--experimental-acp` | Rejected at parse time. ACP runs its own turn loop that doesn't honor the synthetic-tool terminal contract. |
150
+ | `--json-schema` with no prompt and no piped stdin | Rejected at parse time. Headless mode needs a prompt — pass `-p`, a positional argument, or pipe one in. |
151
+ | `--bare` + `--json-schema` | Supported. The synthetic tool is registered alongside the bare three (`read_file`, `edit`, `run_shell_command`). |
152
+ | `--json-schema` inside a subagent | Tool is NOT registered. Only the main / drain turns of the top-level run honor the terminal contract; a subagent calling the tool would receive "session ends now" and then keep running because its loop has no terminator. |
153
+
154
+ ## Retry and failure modes
155
+
156
+ > **Cost note.** Two things multiply token spend in a `--json-schema`
157
+ > run, both worth designing for:
158
+ >
159
+ > - **Schema embedded in every turn.** The schema ships as the
160
+ > `structured_output` function declaration's `parameters` block on
161
+ > every model request, not just the first. Large schemas (up to the
162
+ > 4 MiB parse cap) proportionally increase per-turn input tokens
163
+ > for the entire run.
164
+ > - **Each validation retry is a full model turn.** A schema the
165
+ > model misses repeatedly is multiplied per failure (request +
166
+ > inference + response). Keep schemas constrained enough to guide
167
+ > the model and simple enough to nail on the first try; raise
168
+ > `--max-session-turns` when retries are expected.
169
+
170
+ The session ends on the first valid call. Until then:
171
+
172
+ - **Args fail validation.** `structured_output` returns a tool-result
173
+ error with Ajv's message, the model sees it on the next turn, and
174
+ may correct the arguments and call again.
175
+ - **Model calls a side-effecting tool in the same turn as
176
+ `structured_output`.** The pre-scan suppresses the sibling — it
177
+ never runs, regardless of whether the structured call ultimately
178
+ validates. The two paths split on what the model sees next:
179
+ - **Validation succeeds:** the run ends immediately, and the model
180
+ never gets another turn — the suppressed sibling is silently
181
+ discarded.
182
+ - **Validation fails:** the model gets another turn and sees a
183
+ synthesised "Skipped:" `tool_result` for the suppressed call,
184
+ so it can re-issue that call in a **separate turn** (one that
185
+ does not include `structured_output`).
186
+ - **Model emits plain text instead of calling
187
+ `structured_output`.** Exit code `1`. The error message includes
188
+ the turn count and a truncated preview of the model's output so
189
+ you can see what it actually said.
190
+ - **Run reaches `maxSessionTurns`.** Exit code `53`. Standard
191
+ "Reached max session turns" exit, plus a `--json-schema`-specific
192
+ hint that points at the three common stuck-run causes: model never
193
+ called the tool, `structured_output` is denied by permission rules,
194
+ or the schema is unsatisfiable.
195
+ - **Run is interrupted (SIGINT / Ctrl-C).** Exit code `130`. The
196
+ structured result is normally not emitted, but the shutdown
197
+ holdback loop does not poll the abort signal, so a SIGINT that
198
+ arrives after a successful call has been captured but before the
199
+ result reaches stdout may still land on stdout. Treat the exit
200
+ code as the source of truth.
201
+
202
+ ## Privacy
203
+
204
+ The args you submit through `structured_output` ARE the structured
205
+ payload — already emitted on stdout. To avoid persisting the same
206
+ payload a second time into on-device surfaces that may be exported off
207
+ the machine, args are redacted with the placeholder
208
+ `{ __redacted: 'structured_output payload (see stdout result)' }` on:
209
+
210
+ - The `ToolCallEvent` telemetry path (OTLP exports, QwenLogger,
211
+ ui-telemetry stream, chat-recording UI event mirror).
212
+ - The on-disk chat-recording JSONL at
213
+ `~/.qwen/projects/<sanitized-cwd>/chats/<sessionId>.jsonl` (re-fed
214
+ into model context on `--continue` / `--resume`), including every
215
+ validation-failure retry.
216
+
217
+ Tool-call metrics (duration, success, decision) and surrounding event
218
+ metadata are preserved.
219
+
220
+ > **Schema is sent to the model provider.** Redaction covers the
221
+ > _call arguments_ on local surfaces only. The schema itself rides
222
+ > on every model request as the `structured_output` function
223
+ > declaration's `parameters` block — so any literal values you put
224
+ > inside it (`enum`, `const`, `default`, `examples`, `description`,
225
+ > `$comment`, etc.) reach the provider in cleartext just like prompt
226
+ > text. Schemas should describe shape and constraints; treat them as
227
+ > public toward the provider and keep secrets, customer records, and
228
+ > other sensitive payloads out of the schema body.
229
+
230
+ > **Hooks see raw args.** The redaction described above only applies
231
+ > to telemetry and chat-recording. `PreToolUse`, `PostToolUse`, and
232
+ > `PostToolUseFailure` hooks (including HTTP hooks that can forward
233
+ > payloads off-device) receive the unredacted `tool_input` for
234
+ > `structured_output`, since the hook contract is "see what the tool
235
+ > sees." If you operate audit-style catch-all hooks, either disable
236
+ > them for `structured_output` (filter on `tool_name`) or add
237
+ > hook-side redaction before running `--json-schema` against
238
+ > sensitive data.
239
+
240
+ ## Session resumption (`--continue` / `--resume`)
241
+
242
+ `--json-schema` is a per-run flag, not a per-session property. The
243
+ synthetic tool is registered when the CLI parses its arguments, so:
244
+
245
+ - Re-pass `--json-schema` on every `--continue` / `--resume` you want
246
+ the terminal contract to apply to. The same schema as the original
247
+ run is the safe default — a mid-session schema swap is allowed but
248
+ changes the contract the model is being held to.
249
+ - If you `--continue` without `--json-schema`, the resumed run is an
250
+ ordinary headless session: `structured_output` simply doesn't
251
+ exist as a tool, and the model will respond in free-form text.
252
+ - The `__redacted` placeholder in the resumed chat-recording does
253
+ not affect resumability in practice. A successful `structured_output`
254
+ call terminates the session immediately, so the only redacted args
255
+ a resumed run could see are from failed attempts. The model still
256
+ has each attempt's Ajv validation error in the recorded `tool_result`
257
+ and the live parameter schema (re-registered from `--json-schema`),
258
+ which is enough to retry.
259
+
260
+ ## Permission gating
261
+
262
+ `structured_output` deliberately bypasses the `--core-tools` allowlist:
263
+ the tool only exists when `--json-schema` is set, so excluding it
264
+ would leave the run with no terminal contract.
265
+
266
+ Explicit `permissions.deny` rules and `--exclude-tools` settings DO
267
+ take effect — both use the same deny mechanism and both prevent
268
+ `structured_output` from being registered, so the model never sees
269
+ the tool declaration. The typical result is that the model answers in
270
+ plain text (exit 1). If the model loops through other tools without
271
+ ever producing text, it will eventually hit `maxSessionTurns`
272
+ (exit 53) and the `--json-schema` hint in the error message tells you
273
+ where to look.
274
+
275
+ > **`--bare` caveat.** Bare mode ignores most settings-derived inputs,
276
+ > including settings-level `permissions.deny` and `tools.exclude`. The
277
+ > synthetic tool stays registered, so a settings-only deny of
278
+ > `structured_output` will silently no-op under `--bare`. Argv-level
279
+ > `--exclude-tools structured_output` still applies in bare mode — use
280
+ > the flag rather than settings if you need to lock down a bare run.
281
+
282
+ ## Conflict with MCP tools
283
+
284
+ If an MCP server registers a tool literally named `structured_output`,
285
+ the tool-registry collision check renames the MCP tool to
286
+ `mcp__<server-name>__structured_output` so the synthetic tool keeps
287
+ the bare name. The user-supplied schema is always the one the model
288
+ sees.
289
+
290
+ ## Example: gating a multi-step run on the structured output
291
+
292
+ ```bash
293
+ RESULT=$(qwen --prompt "Audit this diff and rate its risk." \
294
+ --json-schema @./schemas/audit.json) || exit 1
295
+
296
+ risk=$(jq -r '.risk_level' <<<"$RESULT")
297
+ if [ "$risk" = "high" ]; then
298
+ echo "High-risk diff; pausing pipeline." >&2
299
+ exit 2
300
+ fi
301
+ ```
302
+
303
+ ## See also
304
+
305
+ - [Headless Mode](headless.md) — the `-p`-based flow `--json-schema`
306
+ builds on.
307
+ - [Dual Output](dual-output.md) — records a JSON-event sidecar
308
+ alongside the TUI (a different approach to machine-readable output;
309
+ does not require `--json-schema`).
@@ -134,7 +134,7 @@ Subagents are configured using Markdown files with YAML frontmatter. This format
134
134
  ---
135
135
  name: agent-name
136
136
  description: Brief description of when and how to use this agent
137
- model: inherit # Optional: inherit or model-id
137
+ model: inherit # Optional: inherit, fast, modelId, or authType:modelId
138
138
  approvalMode: auto-edit # Optional: default, plan, auto-edit, yolo
139
139
  tools: # Optional: allowlist of tools
140
140
  - tool1
@@ -151,10 +151,48 @@ Multiple paragraphs are supported.
151
151
 
152
152
  Use the optional `model` frontmatter field to control which model a subagent uses:
153
153
 
154
- - `inherit`: Use the same model as the main conversation
155
- - Omit the field: Same as `inherit`
156
- - `glm-5`: Use that model ID with the main conversation's auth type
157
- - `openai:gpt-4o`: Use a different provider (resolves credentials from env vars)
154
+ - `inherit`: Use the same model as the main conversation.
155
+ - Omit the field: Same as `inherit`.
156
+ - `fast`: Use the configured `fastModel`. If no valid fast model is configured,
157
+ the subagent falls back to `inherit`.
158
+ - `glm-5`: Use that model ID. Qwen Code first checks the main conversation's
159
+ auth type; if the model is not available there, it can resolve the model from
160
+ another configured provider.
161
+ - `openai:gpt-4o`: Use an explicit provider and model ID. This is useful when a
162
+ subagent should run on a model registered under a different auth type from the
163
+ main conversation.
164
+
165
+ For example:
166
+
167
+ ```
168
+ ---
169
+ name: fast-reviewer
170
+ description: Reviews small diffs with the configured fast model
171
+ model: fast
172
+ tools:
173
+ - read_file
174
+ - grep_search
175
+ ---
176
+ ```
177
+
178
+ ```
179
+ ---
180
+ name: openai-researcher
181
+ description: Uses an OpenAI-compatible provider for research tasks
182
+ model: openai:gpt-4o
183
+ tools:
184
+ - read_file
185
+ - grep_search
186
+ - glob
187
+ ---
188
+ ```
189
+
190
+ The `fast` selector uses the same `fastModel` setting configured in
191
+ `settings.json` or with `/model --fast`. That setting may itself refer to a
192
+ model under another configured auth type, such as `openai:deepseek-v4-flash`.
193
+ When the selector resolves to another auth type, Qwen Code creates a dedicated
194
+ runtime provider for that subagent request and sends the provider only the bare
195
+ model ID.
158
196
 
159
197
  #### Permission Mode
160
198
 
@@ -620,6 +658,10 @@ Always follow these standards:
620
658
 
621
659
  - **Tool Restrictions**: Use `tools` to limit which tools a subagent can access, or `disallowedTools` to block specific tools while inheriting everything else
622
660
  - **Permission Mode**: Subagents inherit their parent's permission mode by default. Plan-mode sessions cannot escalate to auto-edit through delegated agents. Privileged modes (auto-edit, yolo) are blocked in untrusted folders.
661
+ - **Provider Selection**: A subagent with `model: authType:modelId`, or
662
+ `model: fast` where `fastModel` resolves to another auth type, sends that
663
+ subagent's model requests to the selected provider. Make sure that provider is
664
+ appropriate for the subagent's task and data.
623
665
  - **Sandboxing**: All tool execution follows the same security model as direct tool use
624
666
  - **Audit Trail**: All Subagents actions are logged and visible in real-time
625
667
  - **Access Control**: Project and user-level separation provides appropriate boundaries