Repository navigation
feat: add hybrid code mode #11854
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add hybrid code mode #11854
Changes from 1 commit
6ab42db
fda09c0
9a0cd57
30b2a6c
6c919b7
02afce8
2ecf53e
4a38632
3239c68
f35beb1
28df8ee
a7315eb
3c69762
34711cf
ce7e57d
fa457bd
ae35809
4c53574
22a9a40
779d689
b1561b7
e6fbdcd
6edd151
f746b88
ed2e58c
4a72ef8
cad9407
1df2386
71ab2c9
68ceea7
f669bd7
f183ce0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| # CodeModeOnly MVP | ||
|
|
||
| [English](code-mode-only.md) | [简体中文](code-mode-only.zh-CN.md) | ||
|
|
||
| ## 状态 | ||
|
|
||
| 已为 [#10377](https://github.com/QwenLM/qwen-code/issues/10377) 实现。 | ||
| 该功能为可选功能,默认关闭。 | ||
|
Comment on lines
+9
to
+10
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R1-3: The new ZH version's 状态 section omits the English Status paragraph at docs/design/code-mode-only.md:12-16 ("Partly superseded by Lazy Code Mode: The ZH reader never learns that Witness: Suggested fix: Translate the EN Status paragraph into 状态 (adding the The fix must not violate this existing fact: docs/design/code-mode-only.md:12-16 is the source text the translation must carry, and docs/design/README.md ("Keep section order and heading levels aligned") requires it land in the existing 状态 section rather than as a new heading. Acceptance criterion: N/A (documentation text; no guard, branch, or behavior to pin). Please prove it by removing the fix and confirming that test goes red. 中文说明新增中文版的「状态」小节漏掉了英文 Status 段落(docs/design/code-mode-only.md:12-16)中"Partly superseded by Lazy Code Mode"这一段,导致中英两版结构不同步,违反 AGENTS.md 对双语文档"完整且同步"的要求。 — qwen3.8-max via Qwen Code /review (v0.25.0) |
||
|
|
||
| ## 目标 | ||
|
|
||
| 新增 `tools.mode: "code_mode_only"` 设置,用一个 `exec` JavaScript 工具和少量 | ||
| 必须保留为直接调用的控制面工具,取代面向模型的普通工具面。`exec` 中的代码可通过 | ||
| `tools.<name>(args)` 调用普通工具,同时不会绕过 Qwen Code 的校验、权限、审批、 | ||
| hook、遥测、取消、并发或输出预算。 | ||
|
|
||
| 直接模式是兼容性边界:当 `tools.mode` 为 `direct` 时,工具注册、延迟工具行为、 | ||
| provider 请求和执行均保持不变。 | ||
|
|
||
| ## 非目标 | ||
|
|
||
| - 混合暴露直接调用和代码调用。 | ||
| - 在多次 `exec` 调用间持久化 cell、全局变量或值。 | ||
| - 后台任务、`wait`、`yield`、`store` 或 `load`。 | ||
| - 原始/freeform provider 调用。 | ||
| - 在 code mode 中提供 `tool_search` 或 `tool_call` bridge。 | ||
| - 提供兼容 Node.js 的 sandbox。 | ||
|
|
||
| ## 配置 | ||
|
|
||
| ```json | ||
| { | ||
| "tools": { | ||
| "mode": "code_mode_only" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 该设置会解析一次,得到有效的 `ToolMode` 值;`ToolRegistry` 和各执行面使用这一 | ||
| 模式。只有启用某个 code mode 时才注册 `exec`,因此选择 `direct` 也会将它从 | ||
| 诊断信息和 registry 列表中移除。 | ||
|
|
||
| ## 暴露策略 | ||
|
|
||
| registry 仍是事实来源。暴露只是注册工具之上的视图,而不是第二套 registry。 | ||
|
|
||
| | 类别 | 模型顶层调用 | `exec` 内的 `tools.*` | | ||
| | ----------------------------------------- | --------------- | --------------------- | | ||
| | `exec` | 仅 CodeModeOnly | 否 | | ||
| | 直接控制工具 | 是 | 否 | | ||
| | 已注册的普通工具 | 否 | 是 | | ||
| | 隐藏 bridge(`tool_search`、`tool_call`) | 否 | 否 | | ||
|
|
||
| 直接控制 allowlist 集中维护且刻意保持精简。它覆盖用户交互 | ||
| (`ask_user_question`)、委派(`agent`)、终止输出约定、 | ||
| plan/goal/task/team/worktree/session 控制,以及生命周期无法安全隐藏在解释执行程序 | ||
| 后的 ACP host 控制。新工具默认可在 code mode 中调用;增加仅直接调用或隐藏工具时, | ||
| 必须显式修改策略。 | ||
|
|
||
| 延迟工具保持注册状态和延迟 registry 状态,并可从 `exec` 调用。生成的 `exec` | ||
| 描述仍会携带这些工具的完整 schema,以及它们在 `ALL_TOOLS` 中的名称和描述: | ||
| CodeModeOnly 会隐藏 `tool_search`,嵌套调用也不会以 `functionCall` 出现在历史记录 | ||
| 中,因此后续 reveal 无法补充描述里遗漏的 schema。CodeModeOnly 会跳过延迟预加载 | ||
| 和 ToolSearch 提醒,因为二者都不属于它面向模型的协议。 | ||
|
|
||
| ## 确定性的 JavaScript 接口 | ||
|
|
||
| 每次向 provider 同步工具前,都会从当前 registry 生成 `exec` 描述。工具按规范 | ||
| 名称排序。名称会通过替换无效标识符字符来规范化为 JavaScript 属性;如果名称以 | ||
| 数字开头,还会添加前缀。如果两个规范名称映射到同一个属性,则字典序靠前的名称 | ||
| 胜出,并用一条 warning 指出被省略的冲突项。 | ||
|
|
||
| 描述会定义: | ||
|
|
||
| - 全新的异步 JavaScript 执行环境; | ||
| - 用于嵌套调用的 `tools.<normalizedName>(args)`; | ||
| - 包含规范名称和 JavaScript 名称的 `ALL_TOOLS`; | ||
| - `text(value)`、`image(value)`、`audio(value)` 和 `exit()`; | ||
| - 从 JSON Schema 确定性生成的类 TypeScript 签名; | ||
| - 不提供 Node.js、import、网络 API、timer 和持久状态。 | ||
|
DragonnZhang marked this conversation as resolved.
Outdated
|
||
|
|
||
| 嵌套调用返回一个 JSON-safe 对象,其中包含真实 call id、工具名、状态、输出和 | ||
| structured content。调用失败或取消时,guest promise 会使用 scheduler/ACP 错误 | ||
| reject。 | ||
|
|
||
| ## Sandbox 与传输 | ||
|
|
||
| `exec` 在独立子进程中运行编译为 WebAssembly 的 QuickJS。每次调用都会创建全新 | ||
| 的 QuickJS runtime 和 context。子进程通过 stdio 接收精简的 framed JSON 协议; | ||
| 其中不包含工具实现或 Qwen 配置。父进程把 JavaScript 名称映射回规范 registry | ||
| 名称,并分派每次调用。 | ||
|
|
||
| guest 不提供 Node 全局变量、`require`、`process`、文件系统、socket、模块加载器、 | ||
| `console`、timer、`Atomics`、`SharedArrayBuffer` 或 `WebAssembly`。由于没有安装 | ||
| 模块加载器,动态和静态 import 都会失败。runtime 的内存和 stack 限制固定。 | ||
| QuickJS 的 interrupt hook 会限制 guest CPU 预算。当 guest 挂起等待已注册的 host | ||
| 工具时,该预算和父进程的兜底 watchdog 会暂停;在 guest job 再次运行前恢复。 | ||
| 因此,长时间 build 可以继续使用工具声明的 timeout,同时 guest CPU 死循环无法 | ||
| 逃逸固定预算。源码、协议 frame、helper 输出和最终结果都有上限。 | ||
|
|
||
| 取消操作会中止所有嵌套调用并终止子进程。顶层 promise settled 后,也会在 teardown | ||
| 前取消未 await 的嵌套调用。子进程、timer、promise handle 或 guest 全局变量都不 | ||
| 会在调用结束后存活。 | ||
|
|
||
| 子进程只接收最小化且经过清理的环境,guest 无法检查该环境。独立进程为解释器故障 | ||
| 提供纵深防御;QuickJS/WASM 是 guest 的 capability 边界。 | ||
|
|
||
| ## 重入式分派 | ||
|
|
||
| `CoreToolScheduler.schedule()` 无法递归调用:子调用会排在仍在运行的父调用之后, | ||
| 从而形成死锁。因此,scheduler 会在 invocation 边界绑定 async-local | ||
| `ToolCallRuntime` context,`exec` 只与该 context 通信。 | ||
|
|
||
| scheduler runtime 会将同一 event-loop turn 中收到的嵌套调用合并为一批,并通过 | ||
| 使用相同 `Config` 和 observer 配置的 sibling scheduler 执行。这样无需直接调用 | ||
| `tool.execute()`,仍能沿用现有的构建/校验、权限、确认、hook、执行、截断、遥测和 | ||
| 并发链路。guest 的连续 await 会生成连续 batch;`Promise.all` 调用会进入同一个 | ||
| batch,由现有的只读并发分类器处理。嵌套 request id 包含父 id,并携带 | ||
|
Comment on lines
+123
to
+124
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R1-2: The new Chinese translation states the opposite of the English original (docs/design/code-mode-only.md:144-148) on Code Mode shell concurrency: EN says "Code Mode Bash calls bypass the read-only command classifier, with the model responsible for keeping dependent calls sequential. Other tools retain their existing concurrency classification"; ZH says the batch is "由现有的只读并发分类器处理" and drops the Bash carve-out entirely. A reader working from the ZH design concludes that shell calls submitted together inside one Witness: Suggested fix: Translate the two missing EN sentences into the ZH paragraph, e.g. replace "… The fix must not violate this existing fact: Acceptance criterion: N/A (documentation text; no guard, branch, or behavior to pin). Please prove it by removing the fix and confirming that test goes red. 中文说明新增中文翻译在 Code Mode shell 并发这一点上与英文原文相反:英文说 "Code Mode Bash calls bypass the read-only command classifier",中文写成"由现有的只读并发分类器处理",恰好把豁免说成了适用。同仓库的 code-mode-concurrency.zh-CN.md:21 与英文一致,可证这是翻译错误。实测 — qwen3.8-max via Qwen Code /review (v0.25.0) |
||
| `source: code_mode` 和 `parentCallId`。 | ||
|
|
||
| 嵌套 scheduler 更新会合并到所属 scheduler 的可见调用中,嵌套 id 的确认响应也会 | ||
| 委派给它。外层模型仍只接收完整的 `exec` 响应。 | ||
|
|
||
| ACP 沿用其独立审计过的执行链。它的 invocation 边界会绑定相同的 runtime 接口, | ||
| 嵌套分派通过 `Session.runTool` 重入。因此,ACP 顶层和嵌套调用使用相同的 ACP 权限、 | ||
| 审批、hook、遥测、持久化和取消机制,而不是借用 CLI scheduler 状态或直接执行工具。 | ||
| ACP 会串行执行普通嵌套调用,与现有直接工具顺序一致;Core scheduler 则保留现有的 | ||
| 安全只读并行 batch。 | ||
|
|
||
| ## Provider 行为 | ||
|
|
||
| 所有 provider 继续使用 `ToolRegistry` 提供的 `FunctionDeclaration[]`。在 Direct | ||
| 模式下,该数组与现有视图逐字节一致。在 CodeModeOnly 中,它是暴露策略生成的视图, | ||
| 因此 Gemini/Qwen、OpenAI-compatible 和 Anthropic adapter 都会收到结构化的 | ||
| `exec` declaration,不需要 provider 专用 prompt。 | ||
|
|
||
| 经过过滤的子智能体 declaration 使用相同策略。对于只读 teammate 或带执行 | ||
| allowlist 的 fork,`exec` 是经过审计的 gateway,而允许的确切嵌套名称会随 invocation | ||
| context 传递。同一集合既用于生成描述,也会在 Core 分派前再次校验,因此显式 | ||
| allowlist 可以收窄 code-mode-callable 嵌套工具,而不会变成仅 prompt 策略、暴露 | ||
| 隐藏 bridge 或使 `exec` 能够递归。对于 cache-compatible fork,继承的 `exec` | ||
| declaration 代表其普通 binding:省略 `fork_tools` 时继承这些 binding,显式列表则 | ||
| 用请求的子集替换它们。 | ||
|
|
||
| ## 失败与回滚 | ||
|
|
||
| 未知、冲突、隐藏、仅直接调用和递归请求的工具都会在调度前 fail closed。无效参数 | ||
| 继续在正常执行链中失败。sandbox 启动、协议、timeout、内存或 teardown 失败会转为 | ||
| `exec` 工具错误。 | ||
|
|
||
| 回滚方式是将 `tools.mode` 设为 `direct`。无需迁移 session 或清理 registry, | ||
| 因为 code mode 没有持久状态,且普通 registry 从未被替换。 | ||
|
|
||
| ## 验证 | ||
|
|
||
| 单元和集成测试必须覆盖: | ||
|
|
||
| - Direct 和 CodeModeOnly 暴露、延迟保留、冲突处理、确定性描述和显式子智能体过滤。 | ||
| - 有效/无效 JavaScript、异步顺序、`Promise.all`、helper 输出、throw error、CPU | ||
| 死循环、内存限制、import、不可用全局变量、隔离、输出限制、取消、未 await 工作和 | ||
| 递归调用。 | ||
| - 嵌套权限、确认、Pre/Post hook、失败、输出预算、真实名称遥测/UI 更新、MCP 工具 | ||
| 和 scheduler 死锁回归。 | ||
| - Gemini/Qwen、OpenAI-compatible、Anthropic、headless、interactive、subagent | ||
| 和 ACP 调用面。 | ||
|
|
||
| 只有通过相关 package 测试、build、typecheck、E2E probe 和两轮干净的完整 diff | ||
| 自审,才算实现完成。 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # Code Mode | ||
|
|
||
| [English](code-mode.md) | [简体中文](code-mode.zh-CN.md) | ||
|
|
||
| ## Status | ||
|
|
||
| Implemented. The feature is experimental and opt-in. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R1-6: The new hybrid design doc claims full implementation but records nowhere that the Issue #10377 defines hybrid as Witness: Suggested fix: Add a Non-goals (or Scope) section to The fix must not violate this existing fact: AGENTS.md, General workflow §1: "Provide both an English Acceptance criterion: N/A (docs-only; no guard, branch or behaviour to pin). Please prove it by removing the fix and confirming that test goes red. 中文说明新增的 hybrid 设计文档声称"Implemented",却没有任何地方记录所关联 issue 中 hybrid 模式的 — qwen3.8-max via Qwen Code /review (v0.25.0)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R1-6: The new hybrid design doc claims full implementation but records nowhere that the Issue #10377 defines hybrid as Witness: Suggested fix: Add a Non-goals (or Scope) section to The fix must not violate this existing fact: AGENTS.md, General workflow §1: "Provide both an English Acceptance criterion: N/A (docs-only; no guard, branch or behaviour to pin). Please prove it by removing the fix and confirming that test goes red. 中文说明新增的 hybrid 设计文档声称"Implemented",却没有任何地方记录所关联 issue 中 hybrid 模式的 — qwen3.8-max via Qwen Code /review (v0.25.0) |
||
|
|
||
| ## Problem | ||
|
|
||
| Qwen Code currently supports direct tool calls and `CodeModeOnly`. The latter | ||
| replaces ordinary top-level tools with `exec`, which is useful for orchestration | ||
| but prevents a model from choosing direct calls when they are clearer or more | ||
| efficient. Codex models this as three tool modes: direct, hybrid Code Mode, and | ||
| CodeModeOnly. | ||
|
|
||
| ## Goal | ||
|
|
||
| Add a hybrid `CodeMode` option without changing the existing default or | ||
| `CodeModeOnly` behavior. | ||
|
|
||
| ## Configuration | ||
|
|
||
| ```json | ||
| { | ||
| "tools": { | ||
| "mode": "code_mode" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The effective modes are: | ||
|
|
||
| | `tools.mode` value | Effective mode | | ||
| | ------------------ | ---------------- | | ||
| | omitted / `direct` | `direct` | | ||
| | `code_mode` | `code_mode` | | ||
| | `code_mode_only` | `code_mode_only` | | ||
|
|
||
| This follows Codex's `ToolMode` serialized values. Safe mode and bare mode | ||
| force `direct`. | ||
|
|
||
| ## Exposure policy | ||
|
|
||
| | Surface | `direct` | `code_mode` | `code_mode_only` | | ||
| | -------------------- | ------------------------ | ------------------------------- | ---------------- | | ||
| | Ordinary eager tools | Direct | Direct and nested | Nested only | | ||
| | Deferred tools | `tool_search` | `tool_search` and nested | Nested only | | ||
| | Direct-control tools | Direct | Direct only | Direct only | | ||
| | `exec` | Hidden | Direct | Direct | | ||
| | Hidden bridge tools | Existing direct behavior | Direct where already applicable | Hidden | | ||
|
|
||
| In `code_mode`, ordinary visible tool descriptions gain an `exec` declaration | ||
| for that tool. The `exec` description keeps the complete `ALL_TOOLS` metadata | ||
| but does not duplicate every schema. Deferred tools gain their declaration when | ||
| their normal top-level declaration is revealed. In `code_mode_only`, the | ||
| existing behavior remains: all nested declarations live in the `exec` | ||
| description because no later top-level reveal is possible. | ||
|
|
||
| Filtered subagent declarations preserve the same mode and narrow both direct | ||
|
DragonnZhang marked this conversation as resolved.
Outdated
|
||
| and nested calls to the subagent's allowed tool set. | ||
|
|
||
| ## Constraints and risks | ||
|
|
||
| - Normal direct declarations must remain byte-for-byte unchanged in `direct`. | ||
| - Nested calls continue through the existing scheduler or ACP execution path; | ||
| the mode must not bypass validation, permissions, hooks, cancellation, or | ||
| telemetry. | ||
| - Duplicating every schema in hybrid mode would increase prompt size, so only | ||
| the per-tool nested declaration is appended there. | ||
|
|
||
| ## Validation | ||
|
|
||
| - Verify mode resolution and safe/bare-mode fallback. | ||
| - Verify direct, hybrid, and CodeModeOnly declaration surfaces. | ||
| - Verify filtered subagent declarations and nested allowlists. | ||
| - Run focused Core and CLI tests, then build and typecheck. | ||
|
|
||
| ## Acceptance criteria | ||
|
|
||
| - `tools.mode: "code_mode"` registers `exec` while retaining ordinary direct | ||
| tools and deferred discovery. | ||
| - Ordinary visible tools advertise their nested JavaScript signature. | ||
| - `tools.mode: "code_mode_only"` selects the stricter behavior. | ||
| - The default, safe-mode, and bare-mode surfaces remain direct-only. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # Code Mode | ||
|
|
||
| [English](code-mode.md) | [简体中文](code-mode.zh-CN.md) | ||
|
|
||
| ## 状态 | ||
|
|
||
| 已实现。该功能为实验性功能,默认关闭。 | ||
|
|
||
| ## 问题 | ||
|
|
||
| Qwen Code 目前支持直接工具调用和 `CodeModeOnly`。后者会用 `exec` 替换普通 | ||
| 顶层工具,适合编排调用,但模型无法在直接调用更清晰或更高效时选择直接调用。 | ||
| Codex 将这套能力建模为三种工具模式:直接模式、混合 Code Mode 和 | ||
| CodeModeOnly。 | ||
|
|
||
| ## 目标 | ||
|
|
||
| 新增混合 `CodeMode`,同时保持现有默认模式和 `CodeModeOnly` 行为不变。 | ||
|
|
||
| ## 配置 | ||
|
|
||
| ```json | ||
| { | ||
| "tools": { | ||
| "mode": "code_mode" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 有效模式如下: | ||
|
|
||
| | `tools.mode` 值 | 有效模式 | | ||
| | ---------------- | ---------------- | | ||
| | 省略 / `direct` | `direct` | | ||
| | `code_mode` | `code_mode` | | ||
| | `code_mode_only` | `code_mode_only` | | ||
|
|
||
| 这些值与 Codex 的 `ToolMode` 序列化值一致。安全模式和 bare 模式会强制使用 | ||
| `direct`。 | ||
|
|
||
| ## 暴露策略 | ||
|
|
||
| | 调用面 | `direct` | `code_mode` | `code_mode_only` | | ||
| | ------------ | -------------------- | ------------------------ | ---------------- | | ||
| | 普通即时工具 | 直接调用 | 直接调用和嵌套调用 | 仅嵌套调用 | | ||
| | 延迟工具 | `tool_search` | `tool_search` 和嵌套调用 | 仅嵌套调用 | | ||
| | 直接控制工具 | 直接调用 | 仅直接调用 | 仅直接调用 | | ||
| | `exec` | 隐藏 | 直接调用 | 直接调用 | | ||
| | 隐藏桥接工具 | 保持现有直接模式行为 | 在原本适用时直接调用 | 隐藏 | | ||
|
|
||
| 在 `code_mode` 中,普通可见工具的描述会附加该工具的 `exec` 调用声明。 | ||
| `exec` 描述保留完整的 `ALL_TOOLS` 元数据,但不重复所有 schema。延迟工具在 | ||
| 按正常流程暴露顶层声明时获得对应声明。在 `code_mode_only` 中保持现有行为: | ||
| 由于后续无法暴露顶层声明,所有嵌套声明都集中在 `exec` 描述中。 | ||
|
|
||
| 经过过滤的子智能体声明沿用相同模式,并将直接调用和嵌套调用都限制在该子智能体 | ||
| 允许的工具集合内。 | ||
|
|
||
| ## 约束与风险 | ||
|
|
||
| - `direct` 模式下的普通工具声明必须保持完全不变。 | ||
| - 嵌套调用继续经过现有 scheduler 或 ACP 执行链,不能绕过校验、权限、hook、 | ||
| 取消和遥测。 | ||
| - 混合模式若重复全部 schema 会增大提示词,因此只在各顶层工具描述中附加对应的 | ||
| 嵌套声明。 | ||
|
|
||
| ## 验证 | ||
|
|
||
| - 验证模式解析以及安全模式/bare 模式回退。 | ||
| - 验证直接、混合和 CodeModeOnly 三种声明面。 | ||
| - 验证子智能体过滤后的声明和嵌套 allowlist。 | ||
| - 运行 Core 和 CLI 的相关测试,然后执行构建和类型检查。 | ||
|
|
||
| ## 验收标准 | ||
|
|
||
| - `tools.mode: "code_mode"` 注册 `exec`,同时保留普通直接工具和延迟发现。 | ||
| - 普通可见工具会声明其嵌套 JavaScript 调用签名。 | ||
| - `tools.mode: "code_mode_only"` 选择严格模式。 | ||
| - 默认模式、安全模式和 bare 模式仍然只使用直接调用。 |
Uh oh!
There was an error while loading. Please reload this page.