From 30b2a04b69cb755a202ac3e718dfedfe6c2b7302 Mon Sep 17 00:00:00 2001 From: Turtle Date: Wed, 12 Aug 2026 19:52:04 +0800 Subject: [PATCH] docs: correct the turn-flow event order and dispatch modes turn/start precedes the first claim and pre-step, a rejected or empty first claim closes a zero-step turn, llm/stream and tools/* are their own domains, and agent/turn-stopping is serial. Regenerates the lifecycle diagram from the same facts and names --patch overlays exactly. --- docs/agent-lifecycle.i18n.yaml | 4 ++-- docs/agent-lifecycle.md | 6 +++--- docs/agent-lifecycle.zh.md | 6 +++--- docs/architecture.i18n.yaml | 4 ++-- docs/architecture.md | 20 +++++++++++--------- docs/architecture.zh.md | 20 +++++++++++--------- docs/subsystems/llm-streaming.i18n.yaml | 2 +- scripts/gen-doc-graphs.ts | 6 +++--- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/docs/agent-lifecycle.i18n.yaml b/docs/agent-lifecycle.i18n.yaml index 7402e60690..23edeff80d 100644 --- a/docs/agent-lifecycle.i18n.yaml +++ b/docs/agent-lifecycle.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/agent-lifecycle.md -agent-lifecycle.md: 8bdf54b0345e539ca415eec108fd58ace70ba72c -agent-lifecycle.zh.md: ad6f2ec1f9e7d2e336b79a10e85736d096b784fb +agent-lifecycle.md: 84e235563d05d8105c55f9dc40ac0d791bd05dce +agent-lifecycle.zh.md: df6fe19385f16477d60da260d72477a19526e686 diff --git a/docs/agent-lifecycle.md b/docs/agent-lifecycle.md index 8bdf54b034..84e235563d 100644 --- a/docs/agent-lifecycle.md +++ b/docs/agent-lifecycle.md @@ -21,15 +21,15 @@ sequenceDiagram Agent-->>SDK: agent/inbox/inserted { message } Agent->>Driver: queued work wakes driver Driver-->>SDK: agent/status running + Driver->>Session: turn/start Note over Agent,Driver: claim pending next-step input plus one queued prompt Driver-->>SDK: agent/inbox/spliced pure deletion Driver-->>SDK: agent/inbox/claimed { message, turn } per message Driver->>Hooks: agent/pre-step waterfall Hooks-->>Driver: authoritative reject or enter(messages) alt proposed step rejected or pre-step failed - Driver-->>Driver: claimed batch stays removed, no turn opens + Driver-->>Driver: claimed batch stays removed, the open turn spends no step else enter proposed step - Driver->>Session: turn/start Driver->>Session: step/start Driver->>Session: user/message per entered message Driver->>Prompt: system-prompt/assemble waterfall @@ -66,8 +66,8 @@ sequenceDiagram Hooks-->>Driver: authoritative reject or enter(messages) end end - Driver->>Session: turn/end end + Driver->>Session: turn/end Driver-->>SDK: agent/status idle ``` diff --git a/docs/agent-lifecycle.zh.md b/docs/agent-lifecycle.zh.md index ad6f2ec1f9..df6fe19385 100644 --- a/docs/agent-lifecycle.zh.md +++ b/docs/agent-lifecycle.zh.md @@ -23,15 +23,15 @@ sequenceDiagram Agent-->>SDK: agent/inbox/inserted { message } Agent->>Driver: queued work wakes driver Driver-->>SDK: agent/status running + Driver->>Session: turn/start Note over Agent,Driver: claim pending next-step input plus one queued prompt Driver-->>SDK: agent/inbox/spliced pure deletion Driver-->>SDK: agent/inbox/claimed { message, turn } per message Driver->>Hooks: agent/pre-step waterfall Hooks-->>Driver: authoritative reject or enter(messages) alt proposed step rejected or pre-step failed - Driver-->>Driver: claimed batch stays removed, no turn opens + Driver-->>Driver: claimed batch stays removed, the open turn spends no step else enter proposed step - Driver->>Session: turn/start Driver->>Session: step/start Driver->>Session: user/message per entered message Driver->>Prompt: system-prompt/assemble waterfall @@ -68,8 +68,8 @@ sequenceDiagram Hooks-->>Driver: authoritative reject or enter(messages) end end - Driver->>Session: turn/end end + Driver->>Session: turn/end Driver-->>SDK: agent/status idle ``` diff --git a/docs/architecture.i18n.yaml b/docs/architecture.i18n.yaml index 13545de428..d348645119 100644 --- a/docs/architecture.i18n.yaml +++ b/docs/architecture.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/architecture.md -architecture.md: b88bae1c35ae4c286ac1b591c7857012ab065cd7 -architecture.zh.md: 63e39a4ea02d4794dd13d5a599ae6d1b563ecd95 +architecture.md: e0909c7924fcb9a8b29b3a3426c847e9ca7f4dfb +architecture.zh.md: b35088aa2a00623eacb2d53b19c86d9c192cd1d0 diff --git a/docs/architecture.md b/docs/architecture.md index b88bae1c35..e0909c7924 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -24,7 +24,7 @@ Each declares itself in its own `package.json` under a `dsh` field: `dsh.profile [`dsh-base`](../packages/bundle/base/README.md) is the first layer of every profile: model adapters, tools, persistence, sandbox and approval policy, settings, credentials, telemetry. [`dsh-web-app`](../packages/bundle/web-app/README.md) adds the browser application; [`dsh-headless`](../packages/bundle/headless/README.md) adds a one-shot runner with no server at all. -Layers apply to an empty entry list in this order: each bundle in the profile's listed order, then the profile's `cordis.patch.yml`, then the home-level one, then any app overlay. A patch targets a row by id and replaces its whole config, or inserts new rows. +Layers apply to an empty entry list in this order: each bundle in the profile's listed order, then the profile's `cordis.patch.yml`, then the home-level one, then any `--patch` overlay. A patch targets a row by id and replaces its whole config, or inserts new rows. To see the tree your machine actually boots: @@ -62,28 +62,30 @@ The [event map](event-producer-consumer.md) lists every event's producers and co ## Turn flow -A **step** is one model request plus the tools it calls. A **turn** is one or more steps, opened from queued input and closed once nothing is owed. +A **step** is one model request plus the tools it calls. A **turn** is zero or more steps: it opens before its first input is claimed and closes once nothing is owed. ```text -claim next-step input plus one queued message - -> agent/pre-step reject | enter(messages) - -> turn/start +turn/start + claim next-step input plus one queued message + assemble prompt sections + tool schemas + -> agent/pre-step reject | enter(messages) + reject, or a first enter rewritten empty -> close the turn with no step step/start append entered messages as user/message - assemble prompt sections + tool schemas, derive history from the log + derive model history from the log agent/request -> llm/stream -> assistant/chunk* -> assistant/message tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result* step/end tools owe another request, or next-step input arrived -> claim -> next step -> agent/turn-stopping - -> turn/end +turn/end ``` -`turn/*`, `step/*`, `user/message`, `assistant/*`, and `tool/*` are durable session events; the rest are live `agent/*` waterfalls, whose listeners must call `next()` to delegate. +`turn/*`, `step/*`, `user/message`, `assistant/*`, and `tool/*` are durable session events; the rest are live extension points across three domains. `agent/pre-step`, `agent/request`, `llm/stream`, and the three `tools/*` events are waterfalls, whose listeners must call `next()` to delegate; `agent/turn-stopping` is serial and has no `next()`. Input reaches the driver through one inbox. Some messages wake it immediately; injected context waits in the inbox until another message does. -`agent/pre-step` decides what the model sees. Listeners may rewrite the claimed messages or reject them outright, and a rejected attempt still opens and closes a durable turn, so the log records it. Each step then assembles what the model reads from the prompt sections and tool schemas that plugins registered. +`agent/pre-step` decides what the model sees. Listeners may rewrite the claimed messages or reject them outright; a rejected or empty first claim still closes a durable turn that spent no step, so the log records the attempt. Each step reads the prompt sections and tool schemas that plugins registered. Details: the [sequence diagram](agent-lifecycle.md), the [tool pipeline](tool-execution-pipeline.md), and [cancellation and error recovery](subsystems/core.md#the-agent-handle). diff --git a/docs/architecture.zh.md b/docs/architecture.zh.md index 604028354e..b35088aa2a 100644 --- a/docs/architecture.zh.md +++ b/docs/architecture.zh.md @@ -24,7 +24,7 @@ [`dsh-base`](../packages/bundle/base/README.md) 是每个 profile 的第一层:模型适配器、工具、持久化、沙箱与审批策略、设置、凭据、遥测。[`dsh-web-app`](../packages/bundle/web-app/README.md) 增加浏览器应用;[`dsh-headless`](../packages/bundle/headless/README.md) 增加一次性运行器,且完全不带服务器。 -各层按此顺序应用在空条目列表之上:先按 profile 列出的顺序应用每个组合包,然后是 profile 的 `cordis.patch.yml`,然后是 home 级的那份,最后是任意应用 overlay。一条 patch 按 id 定位某个条目并替换其整个 config,或插入新条目。 +各层按此顺序应用在空条目列表之上:先按 profile 列出的顺序应用每个组合包,然后是 profile 的 `cordis.patch.yml`,然后是 home 级的那份,最后是任意 `--patch` overlay。一条 patch 按 id 定位某个条目并替换其整个 config,或插入新条目。 要查看你的机器实际启动的配置树: @@ -62,28 +62,30 @@ dsh --profile web --dump-config ## 轮次流程 -一个**步骤**是一次模型请求加上它调用的工具。一个**轮次**包含一个或多个步骤,由已排队的输入打开,并在不再欠下任何工作时关闭。 +一个**步骤**是一次模型请求加上它调用的工具。一个**轮次**包含零个或多个步骤:它在领取首条输入之前打开,并在不再欠下任何工作时关闭。 ```text -claim next-step input plus one queued message - -> agent/pre-step reject | enter(messages) - -> turn/start +turn/start + claim next-step input plus one queued message + assemble prompt sections + tool schemas + -> agent/pre-step reject | enter(messages) + reject, or a first enter rewritten empty -> close the turn with no step step/start append entered messages as user/message - assemble prompt sections + tool schemas, derive history from the log + derive model history from the log agent/request -> llm/stream -> assistant/chunk* -> assistant/message tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result* step/end tools owe another request, or next-step input arrived -> claim -> next step -> agent/turn-stopping - -> turn/end +turn/end ``` -`turn/*`、`step/*`、`user/message`、`assistant/*` 和 `tool/*` 是持久会话事件;其余是实时的 `agent/*` waterfall(瀑布式事件),其监听器必须调用 `next()` 才能委托下去。 +`turn/*`、`step/*`、`user/message`、`assistant/*` 和 `tool/*` 是持久会话事件;其余是分属三个事件域的实时扩展点。`agent/pre-step`、`agent/request`、`llm/stream` 和三个 `tools/*` 事件是 waterfall(瀑布式事件),其监听器必须调用 `next()` 才能委托下去;`agent/turn-stopping` 是 serial 事件,没有 `next()`。 输入通过同一个 inbox 到达驱动器。有些消息会立即唤醒它;注入的上下文会留在 inbox 中,直到另一条消息将其唤醒。 -`agent/pre-step` 决定模型看到什么。监听器可以改写已领取的消息,也可以直接拒绝它们,而被拒绝的尝试仍会打开并关闭一个持久轮次,因此日志会记录它。随后每个步骤都会用插件注册的提示词片段和工具 schema 组装模型读到的内容。 +`agent/pre-step` 决定模型看到什么。监听器可以改写已领取的消息,也可以直接拒绝它们;首次领取被拒绝或被改写为空时,仍会关闭一个不含步骤的持久轮次,因此日志会记录这次尝试。每个步骤读取插件注册的提示词片段和工具 schema。 详情见[时序图](agent-lifecycle.md)、[工具流水线](tool-execution-pipeline.md)和[取消与错误恢复](subsystems/core.md#the-agent-handle)。 diff --git a/docs/subsystems/llm-streaming.i18n.yaml b/docs/subsystems/llm-streaming.i18n.yaml index 7912667da5..7e45417c0a 100644 --- a/docs/subsystems/llm-streaming.i18n.yaml +++ b/docs/subsystems/llm-streaming.i18n.yaml @@ -3,4 +3,4 @@ # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/llm-streaming.md llm-streaming.md: 6b3b539fd874857f2b5e94cc05ee68ac4a1d0fb7 -llm-streaming.zh.md: d42699a27057d96b828bb902b02d10e6df9da3e3 +llm-streaming.zh.md: d5bf02c20ead8a574075d996540efba427fe75ce diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index a12b3918b3..5fc19b07de 100644 --- a/scripts/gen-doc-graphs.ts +++ b/scripts/gen-doc-graphs.ts @@ -1213,15 +1213,15 @@ function renderLifecycle(): string { ` Agent-->>SDK: ${mermaidCode('agent/inbox/inserted')} { message }`, ' Agent->>Driver: queued work wakes driver', ` Driver-->>SDK: ${mermaidCode('agent/status')} running`, + ` Driver->>Session: ${mermaidCode('turn/start')}`, ' Note over Agent,Driver: claim pending next-step input plus one queued prompt', ` Driver-->>SDK: ${mermaidCode('agent/inbox/spliced')} pure deletion`, ` Driver-->>SDK: ${mermaidCode('agent/inbox/claimed')} { message, turn } per message`, ` Driver->>Hooks: ${mermaidCode('agent/pre-step')} waterfall`, ' Hooks-->>Driver: authoritative reject or enter(messages)', ' alt proposed step rejected or pre-step failed', - ' Driver-->>Driver: claimed batch stays removed, no turn opens', + ' Driver-->>Driver: claimed batch stays removed, the open turn spends no step', ' else enter proposed step', - ` Driver->>Session: ${mermaidCode('turn/start')}`, ` Driver->>Session: ${mermaidCode('step/start')}`, ` Driver->>Session: ${mermaidCode('user/message')} per entered message`, ` Driver->>Prompt: ${mermaidCode('system-prompt/assemble')} waterfall`, @@ -1258,8 +1258,8 @@ function renderLifecycle(): string { ' Hooks-->>Driver: authoritative reject or enter(messages)', ' end', ' end', - ` Driver->>Session: ${mermaidCode('turn/end')}`, ' end', + ` Driver->>Session: ${mermaidCode('turn/end')}`, ` Driver-->>SDK: ${mermaidCode('agent/status')} idle`, '```', '',