-
Notifications
You must be signed in to change notification settings - Fork 3.1k
fix(acp-bridge): Disable permission timeout by default #9933
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
Changes from all commits
5697d2f
ecb06d2
6de94b0
07c2342
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Daemon permission-response timeout default | ||
|
|
||
| ## Goal | ||
|
|
||
| Let daemon interactions that require a human response wait indefinitely by default. Operators that require a wall-clock cap continue to use the existing `permissionResponseTimeoutMs` option or `qwen serve --permission-response-timeout-ms` flag. | ||
|
|
||
| ## Current boundary | ||
|
|
||
| `BridgeClient` sends ordinary permissions and ACP tool calls marked with `_meta.qwenInteractionKind = "user_question"` through the same permission mediator. The mediator owns the single per-request timer, so the shared bridge option remains the correct configuration boundary. | ||
|
|
||
| ## Behavior | ||
|
|
||
| - When `permissionResponseTimeoutMs` is omitted or `0`, neither ordinary permissions nor `ask_user_question` requests install a wall-clock timer. | ||
| - A positive `permissionResponseTimeoutMs`, including one supplied by the existing CLI flag, applies to both interaction kinds. | ||
| - No environment variable, wire field, or question-specific option is added. | ||
| - Voter cancellation, session cancellation, prompt cancellation, disconnect cleanup, idle reaping, daemon shutdown, and pending-interaction caps are unchanged. | ||
|
|
||
| ## Non-goals | ||
|
|
||
| This change does not alter permission policy, pending interaction snapshots, daemon restart restoration, or the optional prompt-wide deadline. | ||
|
|
||
| ## Verification | ||
|
|
||
| Focused bridge tests cover both interaction kinds with the default disabled timer and with an explicit finite timeout. Existing CLI tests cover option parsing and validation; package build and type checks cover the shared option wiring. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -203,10 +203,11 @@ Math.max(1, Math.floor(m / 2) + 1); | |
| | 6 | 4 | More than half. | | ||
|
|
||
| For **M = 2**, split votes (A selects X, B selects Y) can only be resolved by | ||
| the per-permission timeout: no option reaches unanimity, so the request waits | ||
| until `permissionResponseTimeoutMs` (default 5 min) and resolves as | ||
| `{cancelled, timeout}`. The vote-advance path logs this "unanimity means split | ||
| votes time out" behavior to stderr for operators. | ||
| voter cancellation, session cancellation, or the optional interaction timeout: | ||
| no option reaches unanimity. `permissionResponseTimeoutMs` is disabled by | ||
| default; when configured, an unresolved split resolves as | ||
| `{cancelled, timeout}` at that deadline. The vote-advance path logs the | ||
| applicable behavior to stderr for operators. | ||
|
Comment on lines
+207
to
+210
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] The timer default this paragraph documents was flipped by this PR, but the same page's unchanged A maintainer modifying Branch the flowchart on the gate that exists in code and fix the rationale sentence (in the Workflow section, lines 107–117): E --> T{"timeoutMs > 0?"}
T -- yes --> F["arm setTimeout(timeoutMs) → resolve {cancelled, timeout}"]
T -- no --> G["no timer — resolves only via voter/session cancellation or forgetSession"]
and state that with the timeout disabled (the default since this PR) entries legitimately carry no timer and the wait is bounded by cancellation paths, not a wall-clock deadline. 中文说明本段描述的计时器默认值已被此 PR 翻转,但同一页面未修改的 修改 建议在 Workflow 小节(107–117 行)将流程图按代码中实际存在的门控分支,并调整理由句说明:超时禁用(本 PR 起为默认)时条目可以合法地不携带计时器,等待由取消路径兜底,而非墙钟截止时间。 — qwen3.8-max via Qwen Code /review (v0.22.0) |
||
|
|
||
| Operators who want first-vote-wins behavior for M = 2 can explicitly set | ||
| `policy.consensusQuorum: 1`. Stricter configurations, such as requiring | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3074,19 +3074,23 @@ The active policy is configured in `settings.json` under `policy.permissionStrat | |||||||||||||||
|
|
||||||||||||||||
| > **F3 (#4175): multi-client permission coordination.** F3 added the four policies above. Pre-F3 daemons hardcoded first-responder; the wire shape stays bit-for-bit unchanged when the configured policy is `first-responder`. New events (`permission_partial_vote`, `permission_forbidden`) are additive — old SDKs see them as `unrecognized_known_event` and gracefully ignore. | ||||||||||||||||
|
|
||||||||||||||||
| > **Permission timeout (default 5 minutes).** A `permission_request` | ||||||||||||||||
| > **Permission timeout (disabled by default).** A `permission_request` | ||||||||||||||||
| > stays pending until: (a) some client votes here, (b) `POST /session/:id/cancel` | ||||||||||||||||
| > fires, (c) the HTTP client driving the prompt disconnects | ||||||||||||||||
| > (mid-prompt cancel resolves outstanding permissions as `cancelled`), | ||||||||||||||||
| > (d) the session is killed, (e) the daemon shuts down, **or | ||||||||||||||||
| > (f) the per-session permission timeout fires** (`DEFAULT_PERMISSION_TIMEOUT_MS`, | ||||||||||||||||
| > 5 minutes). On timeout fire the agent's `requestPermission` resolves | ||||||||||||||||
| > (f) its configured timeout fires**. On timeout fire the agent's | ||||||||||||||||
| > `requestPermission` resolves | ||||||||||||||||
| > as `{outcome: 'cancelled'}`, the audit ring records a | ||||||||||||||||
| > `permission.timeout` entry, daemon stderr emits a one-line | ||||||||||||||||
| > breadcrumb, and the SSE bus fans out the standard | ||||||||||||||||
| > `permission_resolved` cancelled frame so subscribers clean up. The | ||||||||||||||||
| > timeout is configurable via `BridgeOptions.permissionResponseTimeoutMs`; | ||||||||||||||||
| > headless callers running long-form prompts may want to extend it. | ||||||||||||||||
| > shared timeout is configurable via | ||||||||||||||||
| > `BridgeOptions.permissionResponseTimeoutMs` or | ||||||||||||||||
| > `qwen serve --permission-response-timeout-ms`. Its default is `0`, so both | ||||||||||||||||
| > ordinary permissions and `ask_user_question` wait indefinitely for a human | ||||||||||||||||
| > decision. Voter cancellation, session cancellation, disconnect cleanup, and | ||||||||||||||||
| > daemon shutdown still resolve pending interactions as cancelled. | ||||||||||||||||
|
Comment on lines
+3092
to
+3093
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] This sentence (and retained item (c) above) lists "disconnect cleanup" as a resolution path — but no disconnect resolves a pending interaction on the REST/SSE surface this protocol documents: the prompt POST's
Suggested change
中文说明[Suggestion] 这句话(以及上方保留的条目 (c))把 "disconnect cleanup" 列为解决路径——但在本文档所描述的 REST/SSE 表面上,任何断连都不会解决 pending 交互:prompt POST 的 — glm-5.3 via Qwen Code /review (v0.22.0) |
||||||||||||||||
|
|
||||||||||||||||
| Request: | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] The
request()/N1 workflow section ~90 lines above this paragraph still documents unconditional timer arming — the flowchart node at :111 (arm setTimeout(timeoutMs) → resolve {cancelled, timeout}), the Responsibilities bullet at :27, thetimeoutHandlebullet at :94, and the :117 rationale ("Without this … the entry pending with no timeout — the bridge's per-sessionpromptQueuewould hang forever"). At this commitrequest()arms nothing whentimeoutMsis 0, and 0 is what every default-configured daemon forwards — so the documented workflow step never executes by default and this page contradicts itself (:207 says disabled by default; :111 saysrequest()always arms). Worth making the flowchart's arm step conditional and scoping the N1 sentence and bullets to "when a timeout is configured (default0= no timer)" — while editing node F, its F→G order (arm beforepending.set) also doesn't match the code's actual order (pending.setat permissionMediator.ts:446 precedes thesetTimeoutat :509).中文说明
[Suggestion] 本段落上方约 90 行的
request()/N1 工作流小节仍把计时器装配描述为无条件行为——:111 的流程图节点(arm setTimeout(timeoutMs) → resolve {cancelled, timeout})、:27 的 Responsibilities 条目、:94 的timeoutHandle条目,以及 :117 的理由("Without this … the entry pending with no timeout — the bridge's per-sessionpromptQueuewould hang forever")。而在当前提交,timeoutMs为 0 时request()不会装配任何计时器,且每个默认配置的 daemon 转发的正是 0——被文档化的工作流步骤默认情况下从不执行,本页自相矛盾(:207 说默认禁用;:111 说request()总是装配)。建议把流程图的装配步骤改为条件分支,并将 N1 句子和两个条目限定为"配置了超时时(默认0= 无计时器)"——顺便一提,编辑节点 F 时可一并纠正其 F→G 顺序(先装配后pending.set)与代码实际顺序(permissionMediator.ts:446的pending.set先于 :509 的setTimeout)不符的问题。— glm-5.3 via Qwen Code /review (v0.22.0)