refactor: narrow synchronous extension contracts

This commit is contained in:
Tianyi Cui
2026-07-13 11:58:55 +08:00
parent f7b9cea733
commit f32cfafa1a
33 changed files with 148 additions and 126 deletions
@@ -12,8 +12,8 @@ Pure Cordis event taxonomy. The loop's extension seams are typed events with del
- **waterfall** (around-middleware) where plugins transform, veto, or wrap: `agent/prompt-submit`, `agent/request`, `agent/step-result`, `agent/turn-continuation`, `tools/pre-execute`, `tools/execute`, `tools/post-execute`, `llm/stream`, `system-prompt/assemble`.
- **serial** (awaited in listener order; a bail value stops later listeners) for ordered checkpoints: every `agent/pre-step` listener runs when all abstain, while the first stop returned from `agent/turn-stop` makes the terminal decision final.
- **parallel** (awaited fan-out) where every listener must get an independent chance: the `session/flush` durability checkpoint and the immutable observe-only `tools/result` notification.
- **emit** (synchronous fire-and-forget) for notifications: turn/step boundaries, stream chunks, lifecycle, and errors.
- **parallel** (awaited fan-out) where every listener must get an independent chance: the `session/flush` durability checkpoint.
- **emit** (synchronous fire-and-forget) for notifications: turn/step boundaries, stream chunks, lifecycle, errors, and the contained immutable `tools/result` observation.
The event vocabulary lives in interface packages (dsh-agent declares the agent/* events); `@deepseek-ai/dsh-agent-loop` is the only concrete loop plugin and is itself swappable — nothing outside it may depend on it.
@@ -135,12 +135,6 @@ flowchart TB
detach --> revoke["Dispose the agent scope"]
```
### Subagent controls are an independent feature
In-process subagents consume agent scope by installing their local composition during unpublished setup. Their optional persona, live global-tool filter, and absolute depth cap are not intrinsic scope semantics; the [subagent composition-controls RFC](../feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) defines those controls, provider capability checks, and dynamic tool behavior.
`inheritsParentContext` describes conversation-history seeding only. It says nothing about Cordis scope, injected services, tools, or authority.
## Security and authority are non-goals
Agent scopes compose trusted same-process registrations. They do not sandbox plugins, define a parent-to-child authority lattice, freeze grants at creation, or guarantee that a child can do no more than its parent.
@@ -218,7 +218,7 @@ A fresh registry-assigned Symbol provides collision-free execution identity with
Arguments are materialized once where model/tool JSON enters the pipeline. Pre-, around-, and post-execute listeners operate on the typed execution and decisions. Call ID correlation, approval, monotonic guards, and Code Mode nesting remain explicit relational checks.
After the last post-execute listener, the registry materializes and freezes the accepted final result once. Every `tools/result` observer receives that exact committed object, and observer failures are awaited and contained individually. An outer pipeline failure is normalized into a committed error result, so observers can discard staged work against the same authoritative boundary.
After the last post-execute listener, the registry materializes and freezes the accepted final result once. Every synchronous `tools/result` observer receives that exact committed object, and observer failures are contained individually. An outer pipeline failure is normalized into a committed error result, so observers can discard staged work against the same authoritative boundary.
### Contribution-owned finality protects only named invariants