Repository navigation
Feature request: optional System One Decision Gate (von-install + /superfast) #12589
Description
Problem
Every user turn wakes the full System Two LLM to make decisions that do not need a large generative model: is this a chat message or does it need a tool? can it be answered from context already in the conversation? how urgent is it? These are cheap classification decisions, but today they ride on the same expensive, slow, autoregressive call as the real work. On local models the cost is felt twice: latency and tokens spent on routing that a tiny model could answer in a single forward pass.
Proposed feature: a System One "Decision Gate"
A small, non-autoregressive System One decision model sits at the front door of the agent loop. It reads the pending turn and returns typed, calibrated answers (choice / noul / score) in one forward pass, without generating text. The harness can use those answers to skip expensive work on obvious requests.
This is the "Decision Gate" concept documented (CC BY 4.0, author Andrea Bruno) at harness-superfast. The idea is deliberately not patented and given to the community; attribution is the only condition.
Why this fits the existing architecture (architectural coherence)
The gate is designed to look and behave like features Qwen Code already ships, so it is a natural extension rather than a foreign object:
- Install-the-backend-via-a-command. Like
qwen sandboxinspects/proves its confinement backend, a newvon-installsubcommand provisions the decision backend out-of-band. The fork never bundles the model. - A specialized decision model already exists here. The AUTO approval-mode classifier (
packages/core/src/permissions/classifier.ts) is a two-stage, schema-typed, fail-closed decision model. The Decision Gate is the same pattern applied at the front door. - Off by default, behind a flag + a slash command.
/superfast on|off|status, persisted insettings.jsonunder a newsuperfastsection. Users who never run it see no change. - Fails open. Any error, timeout, non-2xx, or low confidence returns "no opinion" and the harness behaves exactly as if the feature were off. The gate can only make things faster, never change behavior when unsure.
- No new runtime dependencies. The gate talks to a local
/v1/systemoneendpoint over plainfetch.
Backend: Von
Von (wfzyx/von, Apache-2.0) is chosen because it is small (~1.5 GB) and runs on CPU, CUDA, ROCm, Apple Metal, and Intel iGPU — so the option is accessible on essentially any machine, including laptops with no discrete GPU. It is protocol-compatible with the Jev /v1/systemone spec, so any compatible server can be swapped in.
Scope of the first increment
The first PR ships the gate infrastructure running in shadow mode: when enabled, it classifies each turn and logs the recommendation, but does not yet change routing. This is the safe way to validate the model's accuracy against real traffic before acting on the decision. Acting on the route (skipping work) is a clearly-scoped follow-up once validated.
Alternatives considered
- Doing nothing (status quo): every turn pays full LLM cost for routing.
- A larger always-on gate: rejected as too invasive and unsafe without a validation phase.
Credits & License
The Decision Gate concept and architecture are by Andrea Bruno.
- Original white paper and license: https://github.com/Andrea-Bruno/harness-superfast
- Released under CC BY 4.0, intentionally not patented — given to the community; attribution is the only condition.
- The decision model (Von,
wfzyx/von) is third-party, Apache-2.0.
Please keep the attribution to Andrea Bruno and a link to the harness-superfast project in any reuse of this concept.
Activity
doudouOUC commentedon Sep 24, 2026
感谢这份详尽的 feature request。我逐条对照了 main (b7cd42e) 的源码,核实每一项 architectural-coherence 声明,以下是基于源码的独立评估。
1. AUTO approval-mode classifier 作为先例 — 确认
packages/core/src/permissions/classifier.ts确实存在于 main HEAD。文件头注释(第 1-17 行)明确描述:STAGE1_SCHEMA(line ~128) 和STAGE2_SCHEMA(line ~136) 用 JSON Schema 约束输出结构,additionalProperties: false,required字段精确声明。failUnavailable()函数在 Stage 1 构建失败、API 调用失败时均会触发。报告者称其为 "a two-stage, schema-typed, fail-closed decision model" — 完全准确。将同一模式推广到 front-door 决策门在架构风格上是连贯的。
2.
qwen sandboxsubcommand 作为von-install先例 — 确认packages/cli/src/commands/sandbox.ts存在,注册为 yargsCommandModule:提供
--verify(验证内核边界)、无参数 (报告当前执行策略)、-- <cmd>(在沙箱中运行单条命令) 三种模式。handler 内部动态 import sandboxConfig / execution-sandbox-settings,不做模型推理。这确实是
von-install可以遵循的先例:一个新的 yargs subcommand,out-of-band 配置后端,不 bundle 模型本身。模式可行。3. Slash command 注册模式 — 确认
SlashCommand接口定义于packages/cli/src/ui/commands/types.ts(line 379),包含name、description、kind: CommandKind、action()函数、可选subCommands。BuiltinCommandLoader.ts(line ~60+) 逐个 import 并注册所有内置 slash command(如contextCommand、compressCommand、settingsCommand等数十个)。CommandService.ts用 loader 模式并行加载、去重、解决命名冲突。commands.ts的parseSlashCommand()实现了多级 path 解析 (/config set theme dark等),支持 subCommands 递归匹配。/superfast on|off|status可以作为一个SlashCommand注册,on/off/status作为 subCommands 或 action 参数解析。config 持久化到settings.json的模式在该文件中已有先例(settingsCommand等)。注册路径清晰可行。4. 核心:front-door / chokepoint 声明 — 需要坦诚讨论的张力
这是本提案最关键的架构问题。我追踪了完整的 agent loop:
调用链:
client.ts:sendMessageStream()(line 3054) →Turn.run()(turn.ts:704) →LlmChat.sendMessageStream()(llm-chat.ts:2965) → 流式返回GenerateContentResponsechunksTool-use 路由的决策方式: turn.ts 第 805 行:
模型在自己的 autoregressive 输出中生成
functionCallparts — 工具调用决策是 LLM 响应的一部分,而非 harness 层的 pre-classifier 步骤。Turn.handlePendingFunctionCall()(turn.ts:893) 从模型输出的FunctionCall构造ToolCallRequestInfo。Agent loop 继续: client.ts 在多处检查
turn.pendingToolCalls.length(line 4581, 4592, 4630, 4894, 4912) — 当模型输出了 functionCall,loop 将 tool result 作为下一次sendMessageStream的输入,驱动下一轮 LLM 调用。张力所在: 报告者提出 gate 可以 "skip expensive work on obvious requests"。但:
coreToolScheduler,不发起下一轮),它需要拦截 LLM 已经做出的 functionCall——此时 LLM 调用的成本已经产生了,gate 只省了 tool execution + next-turn LLM call,不是"front door"的节省。换言之:当前架构中不存在一个 harness 层的 pre-routing chokepoint 来决定"这个 turn 需不需要工具"——这个决策是 LLM 输出的一部分。
classifier.ts的先例是在 tool execution 之前(post-LLM-call)做安全分类,不是在 LLM 调用之前做路由分类。二者的位置不同。5. Shadow-mode-first 评估
Shadow mode(分类 + 日志记录,不改变路由)是安全的——它不触及上述张力,只是旁路观测。作为第一个 increment 是合理的:
/v1/systemoneendpoint、von-install、/superfastflag、settings 持久化都可以在此阶段交付和验证。但从 shadow 到 active 的路径需要重新审视: active gating 要节省 LLM 调用本身,需要 gate 做的不只是"分类"而是"替代"——即对于 gate 判定为"可从上下文回答"的 turn,直接用 System One 模型的输出回答用户。这是一个完全不同的架构(dual-model serving),而非"在现有 agent loop 前加一个 pre-classifier"。报告者应该考虑将 active 阶段的 scope 明确为:
建议
hasPendingToolCallguard 和 context 注入逻辑),引导 LLM 在明显不需要工具的 turn 中直接回答——这不改变架构,只是 prompt-level 优化,更符合 "fails open" 的承诺。Andrea-Bruno commentedon Sep 24, 2026
Thank you for such a careful, source-grounded review. Your point 4 is correct and I want to be honest about it. In the current architecture the decision to use a tool lives inside the model's own output, not in a harness step before the model, so a gate placed before the model cannot skip the call that makes that decision. You are right that the classifier.ts precedent sits after the model call, before tool execution, and that a front-door routing gate is a different position.
This PR is deliberately only the shadow phase. It classifies each turn and writes the recommendation to the debug log as a fire-and-forget call. It never awaits the result, never blocks the turn, and never changes routing, so it does not touch the tension you described. With the feature off, which is the default, the code path is a no-op. The goal of this phase is exactly what you suggest, to collect the real distribution of turns, how many are plain chat, how many need a tool, and how many could be answered from what is already in the conversation, before we decide whether active gating is worth the cost.
For the active phase I agree with your framing. The honest near-term win is the conservative one, where the gate skips the tool execution and the follow-up turn only when it is confident the answer is already in context, which saves less than the headline claim. Your middle suggestion is the one I find most promising and most consistent with fails open. Instead of skipping the model call, use the gate signal to add a short prompt-level hint that nudges the model to answer directly on turns that clearly need no tool. That keeps the architecture intact and only changes guidance, so a wrong gate decision degrades to the normal path rather than to a wrong answer. The aggressive path, where the small model answers the user directly and replaces the first model call, is a real dual-model serving design with its own questions about conversation consistency and history format, and we are not claiming it in this PR.
So the plan matches your recommendation. Ship the safe shadow infrastructure now, and write the active design only after the shadow data is in, with an explicit answer to which decision the gate replaces and how consistency is held. Thanks again for taking the time to check the source line by line.
IRONICBo commentedon Sep 24, 2026
One thing I would add to the shadow phase: version the question and ordered choices, then label the prediction against what the main turn actually did—not just whether it emitted a tool call. A no-tool turn can still be wrong or incomplete, so the useful metric is work avoided without changing task success.
We use that boundary in Jev Social: route-level accuracy, fallback rate, and final evidence coverage are evaluated together. I maintain the project; Codex helped me verify this note.
Andrea-Bruno commentedon Sep 25, 2026
Thanks, that is a sharp point and I agree with it. Measuring only whether the main turn emitted a tool call is too coarse, because a turn with no tool call can still be wrong or incomplete. The metric that actually matters is work avoided without any change to task success. We will version the question and the ordered choices, then label each prediction against what the main turn really did, so the shadow phase reports avoided work only when the outcome stayed correct. That keeps the gate honest and matches the fails-open contract, and it is a better boundary than a plain tool-call check.