feat(approval): the approval seam — one-shot permission decisions over a waterfall of answerers
ctx.approval (dsh-approval): request() dispatches the approval/request waterfall and always resolves a closed outcome — allowed-once / rejected / cancelled / unavailable — never rejects; zero listeners fall through to fail-closed unavailable; abort settles cancelled and discards late answers; throwing or rogue answerers are contained as unavailable; every ask lands the log-only approval/asked / approval/decided audit pair. dsh-tools routes a pre-execute ask through the seam opportunistically (ctx.get) with three distinct deny reasons, keeping the historical ask→deny degrade when the seam is absent. The per-session policy tier, the ACP bridge answerer, and the sandbox escalation asker are staged follow-ups of the approval-seam RFC.
This commit is contained in:
@@ -11,7 +11,8 @@ flowchart TD
|
||||
toolCall["Session event: <code>tool/call</code><br/>logged before execution"]
|
||||
presentCall["UI pending card<br/>presentCall(args)"]
|
||||
pre["<code>tools/pre-execute</code> waterfall<br/>hooks, permission, sandbox"]
|
||||
denied["deny or ask<br/>tool body skipped"]
|
||||
denied["denied<br/>tool body skipped"]
|
||||
approval["<code>ctx.approval</code> one-shot prompt<br/>absent or unanswerable: deny"]
|
||||
around["<code>tools/execute</code> waterfall<br/>timeout, retry, metrics (around dispatch)"]
|
||||
toolBody["Registered tool execute() body"]
|
||||
fsGate["<code>fs/write-intent</code> or <code>fs/edit-intent</code><br/>tool-fs mutations only"]
|
||||
@@ -25,7 +26,10 @@ flowchart TD
|
||||
toolCall --> pre
|
||||
pre -->|allow| around
|
||||
around --> toolBody
|
||||
pre -->|deny or ask| denied
|
||||
pre -->|deny| denied
|
||||
pre -->|ask| approval
|
||||
approval -->|allowed-once| around
|
||||
approval -->|rejected, cancelled, unavailable| denied
|
||||
denied --> post
|
||||
toolBody --> fsGate
|
||||
fsGate --> toolBody
|
||||
@@ -37,6 +41,6 @@ flowchart TD
|
||||
toolResult --> presentResult
|
||||
```
|
||||
|
||||
Filesystem read-before-edit checks live below `tool-fs` on the `fs/*` event gate; hook bridges and future permission prompts live on the generic pre/post tool waterfalls; and around-dispatch concerns like the tool-call timeout policy (`@deepseek-ai/dsh-timeout-policy`) wrap core dispatch on `tools/execute`. That split lets the same hooks observe bash, fs, web, todo, and subagent calls without coupling those tools to one policy service. Code Mode rides the same pipeline twice over: `run_code` is itself a registered tool body, and each tool call its program makes re-enters `ctx.tools.execute()` through BOTH waterfalls — serialized one at a time, logged as a `tool/code-dispatch` session event, with a deny surfacing to the program as a binding rejection (a sub-call's `additionalContext` is deliberately dropped — no safe outlet mid-run preserves call/result adjacency).
|
||||
Filesystem read-before-edit checks live below `tool-fs` on the `fs/*` event gate; hook bridges and the approval seam's permission prompts live on the generic pre/post tool waterfalls; and around-dispatch concerns like the tool-call timeout policy (`@deepseek-ai/dsh-timeout-policy`) wrap core dispatch on `tools/execute`. That split lets the same hooks observe bash, fs, web, todo, and subagent calls without coupling those tools to one policy service.
|
||||
|
||||
Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.
|
||||
|
||||
Reference in New Issue
Block a user