From ff731c72dee9e7a23a1b9bb67cee6ce520ce5405 Mon Sep 17 00:00:00 2001 From: _Kerman Date: Thu, 15 Oct 2026 21:01:00 +0800 Subject: [PATCH] refactor(session-projection): remove the host state map --- ...ssion-projection-and-command-log.i18n.yaml | 8 +-- ...7-27-session-projection-and-command-log.md | 11 ++- ...7-session-projection-and-command-log.zh.md | 11 ++- docs/config-catalog.md | 8 +-- docs/config-catalog.zh.md | 8 +-- .../conversation-and-session.md | 2 +- .../conversation-and-session.zh.md | 2 +- docs/event-producer-consumer.md | 14 ++-- docs/event-producer-consumer.zh.md | 14 ++-- docs/persistence-catalog.i18n.yaml | 32 ++++----- docs/persistence-catalog.md | 16 ++--- docs/persistence-catalog.zh.md | 16 ++--- docs/persistence-schema.json | 10 +-- docs/subsystems/session-projection.i18n.yaml | 4 +- docs/subsystems/session-projection.md | 13 ++-- docs/subsystems/session-projection.zh.md | 13 ++-- .../guide.i18n.yaml | 8 +-- .../session-projection-handles/guide.md | 4 +- .../session-projection-handles/guide.zh.md | 4 +- packages/api/session-controller/src/types.ts | 8 --- .../tests/session-projections.host.spec.ts | 5 -- .../context/harness-dev-context/src/index.ts | 7 -- packages/context/time-context/src/index.ts | 10 --- packages/context/tmux-context/src/index.ts | 9 --- packages/core/agent/src/projection.ts | 7 -- packages/core/agent/src/types.ts | 4 -- .../experimental/agent-team/src/projection.ts | 6 -- .../extensions/tool-cordis/src/api-catalog.ts | 10 +-- packages/goal/goal/README.i18n.yaml | 4 +- packages/goal/goal/README.md | 2 +- packages/goal/goal/README.zh.md | 2 +- packages/goal/goal/src/index.ts | 4 -- packages/goal/goal/src/types.ts | 3 - .../permission-presets/src/index.ts | 7 -- .../user-questions/src/projection.ts | 6 -- packages/llm/llm-retry/src/index.ts | 6 -- .../token-meter/src/breakdown-projection.ts | 8 +-- packages/llm/token-meter/src/index.ts | 9 +-- .../llm/token-meter/src/usage-projection.ts | 10 +-- packages/plan/plan-mode/src/types.ts | 4 -- .../preset/agent-preset-registry/src/types.ts | 3 - packages/sandbox/sandbox-policy/src/index.ts | 8 --- .../tests/cache.spec.ts | 9 --- .../tests/fixtures.spec.ts | 3 - .../session-projection/README.i18n.yaml | 8 +-- packages/session/session-projection/README.md | 4 +- .../session/session-projection/README.zh.md | 4 +- .../session/session-projection/src/index.ts | 29 +++----- .../session/session-projection/src/types.ts | 7 -- .../tests/registration-reader.spec.ts | 4 -- .../tests/registration.type-test.ts | 68 +++++++++++++++++++ .../session-projection/tests/registry.spec.ts | 7 -- .../session/session-stats/src/projection.ts | 6 -- packages/session/session-title/src/types.ts | 6 -- .../session/session-turn-outline/src/types.ts | 4 -- .../session/working-directory/src/index.ts | 5 -- packages/subagent/subagent/src/catalog.ts | 6 -- packages/subagent/subagent/src/projection.ts | 7 -- .../src/model-selection-state.ts | 7 -- packages/todo/tool-todo/src/types.ts | 3 - scripts/gen-cordis-catalog.ts | 1 - 61 files changed, 193 insertions(+), 335 deletions(-) create mode 100644 packages/session/session-projection/tests/registration.type-test.ts diff --git a/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.i18n.yaml b/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.i18n.yaml index 59a262d59e..e0639785f1 100644 --- a/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.i18n.yaml +++ b/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.i18n.yaml @@ -15,8 +15,8 @@ en: e6c93d89a25f0d03 zh: 65e1f5842bc74008 /agent-note-session-projections-and-command-lifecycle-logging/proposal/host-projection-registry-dsh-session-projection-new-package: - en: a0f86a588c9dff31 - zh: 421803bc8b0dddb5 + en: bb52ae77e0302d2d + zh: 75e6a76ce7d02342 /agent-note-session-projections-and-command-lifecycle-logging/proposal/shipped-consumer-the-subagent-identity-unit: en: 10093535660c3cae zh: a7f4ff9e71ee6751 @@ -39,8 +39,8 @@ en: 64ad8d08a8ab44e0 zh: fb0a0f7369d0bd23 /agent-note-session-projections-and-command-lifecycle-logging/alternatives-considered: - en: e945e84e8360e0c4 - zh: becdeb100a4c5b6b + en: 4776bd01e7ec14f0 + zh: 9b1c2db96e1120f6 /agent-note-session-projections-and-command-lifecycle-logging/acceptance-criteria: en: 9dfcca30fffda225 zh: 0beddb81d32e0ca7 diff --git a/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md b/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md index 4e2e02482e..f907f77959 100644 --- a/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md +++ b/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.md @@ -24,15 +24,14 @@ A state-carrying log event MUST carry the complete post-change state, never a ba ### Host projection registry (`dsh-session-projection`, new package) -A light Service Definition package: merge-extensible host-state and client-view type maps, the registry service, and zod validation for persisted state and client values. Capability-seam roles: domain host plugins provide projection units, carriers consume them, and neither knows the other. +A light Service Definition package: local host-state definitions, a merge-extensible client-view type map, the registry service, and zod validation for persisted state and client values. Capability-seam roles: domain host plugins provide projection units, carriers consume them, and neither knows the other. What a domain registers is a **state-driven computation unit** — a pure fold plus declarations and an optional client view — never an opaque getter. The framework owns driving it (subscription, watermark, caching, and later checkpointing); the domain owns only the computation. Projections serve every business domain (session title, plan, goal, permission, todos); commands are merely one trigger path and hold no special position in this contract. ```ts ignore-check -export interface SessionProjectionStateMap {} // host fold states -export interface SessionProjectionMap {} // client-visible whole values +export interface SessionProjectionMap {} // client-visible whole values -export interface ProjectionDefinition { +export interface ProjectionDefinition { key: K stateSchema: ZodType persist?: boolean // host-only units opt in; client-visible units always persist @@ -54,7 +53,7 @@ declare module 'cordis' { } ``` -- `SessionProjectionStateMap` types host fold states; `SessionProjectionMap` remains the one client DTO table shared by the wire block and React hook via `import type`. A unit may remain host-only by omitting `wire`. How a client value is *rendered* is the slot system's business, never the projection layer's. The state/view split is specified by the [implemented state and client-view note](../../archived/architecture/2026-08-19-session-projection-state-and-client-views.md). +- `ProjectionDefinition` carries each unit's host state type; `SessionProjectionMap` remains the one client DTO table shared by the wire block and React hook via `import type`. A unit may remain host-only by omitting `wire`. How a client value is *rendered* is the slot system's business, never the projection layer's. The state/view split is specified by the [implemented state and client-view note](../../archived/architecture/2026-08-19-session-projection-state-and-client-views.md). - **The host is the only place a projection is computed.** The framework drives every registered unit forward eagerly: each committed session event passes through `apply`; a unit uninterested in an event returns the same state reference, and an unchanged reference (`Object.is`) produces no downstream work. Clients never fold domain events — they receive finished values (baseline block + push frame below). This removes the double-implementation trap (plan's two-event fold written once, on the host) and any client-side domain code. - **State is always computed, never logged.** The log holds events only; the unit's state lives in the framework's per-session watermark cache (`{state, observedSeq}` per unit) and, in a later phase, in a **persisted projection cache** on the domain-KV storage seam: rows of `(sessionId, key, ver, seq, val)` (`ver` = the unit's `stateVersion`, `seq` = the watermark, `val` = the state JSON). A row is never wrong, only possibly stale — its `seq` says exactly how stale. The one read recipe, cold and live alike: take the cached state (or `init()`), forward-apply only the events past its watermark, `view` the result. Cold listings (every session's title across all workspaces) become an index read plus, at worst, a short tail replay; the session-persistence seam grows a read-from-seq primitive for that tail in the same later phase. Write policy: throttled (count/interval, configurable) plus two mandatory points — `turn/end` and detach (the live-to-cold moment). A crash between writes costs a longer tail replay, never a wrong value. - A domain's input event set is its own choice: todos folds `todo/write` alone; plan folds `plan/mode` plus its own `/plan` `command/run` records (see the plan section); goal folds `goal/change` metadata; session title folds its title events (retiring the bespoke `session/title` frame and the client's title-snapshot map — the fourth hand-rolled projection this seam absorbs). @@ -161,7 +160,7 @@ Infrastructure first; the three in-flight PRs are left untouched and re-target a **Hanging the registry off `ctx.apiProxy`** — rejected: session projections are not web-specific (TUI, ACP, headless are future consumers), and domain packages must not depend on the apiproxy package. The independent seam also deletes #587's type-only import edge from api-proxy into the plan package. -**A second client DTO table** — rejected: `SessionProjectionMap` remains the single client vocabulary shared by wire and UI. `SessionProjectionStateMap` is not another client view table; it types host fold state so internal state may differ from the value sent to clients. +**A second client DTO table** — rejected: `SessionProjectionMap` remains the single client vocabulary shared by wire and UI. Each unit types its host fold state locally, independently of the value sent to clients. **Event-broadcast collection instead of a registry walk** — rejected: async listeners cannot yield the single synchronous cut that makes `asOfSeq` one consistent snapshot across all keys; registries are this repo's shape for contributions (`ctx.tools`, prompt sections, slots). diff --git a/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.zh.md b/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.zh.md index f226acfc83..e3f23ec975 100644 --- a/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.zh.md +++ b/.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.zh.md @@ -24,15 +24,14 @@ Status: proposed ### host 侧投影注册表(`dsh-session-projection`,新包) -一个轻量的 Service Definition 包:merge-extensible 的 host 状态与客户端视图类型表、注册表服务,以及针对持久状态和客户端值的 zod 校验。能力 seam 的角色如下:领域 host 插件提供投影单元,载体消费这些单元,两侧互不相识。 +一个轻量的 Service Definition 包:局部 host 状态定义、merge-extensible 的客户端视图类型表、注册表服务,以及针对持久状态和客户端值的 zod 校验。能力 seam 的角色如下:领域 host 插件提供投影单元,载体消费这些单元,两侧互不相识。 领域注册的是一个**状态驱动计算单元(state-driven computation unit)**——纯折叠、若干声明及可选客户端视图——绝不是一个不透明的 getter。驱动它是框架的职责(订阅、水位线(watermark)、缓存,以及后续的检查点机制),领域只负责计算。投影服务于所有业务领域(会话标题、plan、goal、权限、todos);命令只是其中一条触发路径,在本约定中没有任何特殊地位。 ```ts ignore-check -export interface SessionProjectionStateMap {} // host fold states -export interface SessionProjectionMap {} // client-visible whole values +export interface SessionProjectionMap {} // client-visible whole values -export interface ProjectionDefinition { +export interface ProjectionDefinition { key: K stateSchema: ZodType persist?: boolean // host-only units opt in; client-visible units always persist @@ -54,7 +53,7 @@ declare module 'cordis' { } ``` -- `SessionProjectionStateMap` 描述 host 折叠状态;`SessionProjectionMap` 继续作为协议块和 React 钩子经 `import type` 共享的唯一客户端 DTO 表。单元省略 `wire` 即保持 host-only。客户端值如何*渲染*是 slot 体系的事,永远不归投影层管。状态/视图拆分见[已实现的状态与客户端视图记录](../../archived/architecture/2026-08-19-session-projection-state-and-client-views.md)。 +- `ProjectionDefinition` 携带各单元的宿主状态类型;`SessionProjectionMap` 继续作为协议块和 React 钩子经 `import type` 共享的唯一客户端 DTO 表。单元省略 `wire` 即保持 host-only。客户端值如何*渲染*是 slot 体系的事,永远不归投影层管。状态/视图拆分见[已实现的状态与客户端视图记录](../../archived/architecture/2026-08-19-session-projection-state-and-client-views.md)。 - **host 是投影唯一的计算地点。** 框架主动驱动(eager drive)每个已注册的单元:每个已提交的会话事件都经过 `apply`;对某事件不感兴趣的单元返回同一个状态引用,而引用未变(`Object.is`)就不产生任何下游工作。客户端从不折叠领域事件——它们收到的是成品值(基线块 + 下文的推送帧)。这消除了双重实现陷阱(plan 的双事件折叠只在 host 写一遍),也消除了一切客户端侧领域代码。 - **状态永远靠计算得出,绝不入日志。** 日志只存事件;单元的状态住在框架的按会话水位线缓存里(每单元一份 `{state, observedSeq}`),并在后续阶段进入 domain-KV 存储 seam 上的**持久投影缓存(persisted projection cache)**:形如 `(sessionId, key, ver, seq, val)` 的行(`ver` = 单元的 `stateVersion`,`seq` = 水位线,`val` = 状态 JSON)。一行永远不会是错的,至多是陈旧的——其 `seq` 精确说明陈旧到哪。冷读与活读共用同一套读取配方:取缓存状态(或 `init()`),只对超出其水位线的事件做正向 `apply`,再对结果做 `view`。冷列表(跨全部 workspace 列出每个会话的标题)变成一次索引读,至多外加一小段尾部回放;session-persistence seam 在同一后续阶段为这段尾部补一个按 seq 起读的原语。写入策略:节流(次数/间隔,可配置)外加两个强制点——`turn/end` 与 detach(由活转冷的时刻)。两次写入之间崩溃的代价是尾部回放更长一些,绝不会是值出错。 - 领域的输入事件集由领域自己选择:todos 只折叠 `todo/write`;plan 折叠 `plan/mode` 外加它自己的 `/plan` `command/run` 记录(见 plan 一节);goal 折叠 `goal/change` 元数据;会话标题折叠其标题事件(顺带下线专设的 `session/title` 帧与客户端的标题快照表——这是该 seam 收编的第四个手工投影)。 @@ -161,7 +160,7 @@ host 侧命令执行器(`packages/interaction/commands`)在调用处理器 **把注册表挂到 `ctx.apiProxy` 名下**——不予采纳:会话投影并非 web 专属(TUI、ACP(Agent Client Protocol)、headless 都是未来消费方),且领域包不得依赖 apiproxy 包。独立 seam 还顺带删掉了 #587 从 api-proxy 指向 plan 包的 type-only 导入边。 -**第二张客户端 DTO 类型表**——不予采纳:`SessionProjectionMap` 仍是协议与 UI 共享的唯一客户端词汇。`SessionProjectionStateMap` 不是另一张客户端视图表;它描述 host 折叠状态,使内部状态可以不同于发往客户端的值。 +**第二张客户端 DTO 类型表**——不予采纳:`SessionProjectionMap` 仍是协议与 UI 共享的唯一客户端词汇。各单元在内部声明宿主折叠状态类型,与发往客户端的值相互独立。 **用事件广播收集、替代注册表遍历**——不予采纳:异步监听器给不出那个单一的同步切面,而正是它让 `asOfSeq` 成为横跨所有 key 的一致快照;注册表才是本仓库承接贡献的通行形状(`ctx.tools`、提示词片段、slot)。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index b025f67f9c..326c9d2ac2 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -1418,7 +1418,7 @@ export type Config = LocalConfig ## `@deepseek-ai/dsh-goal` - `inject`: `agents` · `sessionProjections` -- `source`: [`packages/goal/goal/src/index.ts:172`](../packages/goal/goal/src/index.ts) +- `source`: [`packages/goal/goal/src/index.ts:168`](../packages/goal/goal/src/index.ts) ```ts config-catalog /** Deployment defaults for goal creation. */ @@ -2337,7 +2337,7 @@ export interface Config { - `inject`: `shell` · `approval` · `sessions` · `sessionProjections` - `refs`: [`ApprovalPolicy`](subsystems/approval.md) · [`SandboxMode`](subsystems/sandbox.md) · `Volatile` (`@deepseek-ai/cordis`) -- `source`: [`packages/interaction/permission-presets/src/index.ts:159`](../packages/interaction/permission-presets/src/index.ts) +- `source`: [`packages/interaction/permission-presets/src/index.ts:152`](../packages/interaction/permission-presets/src/index.ts) ```ts config-catalog /** The {@link PermissionPresetService} config: preset table and composition default. */ @@ -3636,7 +3636,7 @@ export type ShellDialect = 'bash' | 'pwsh' ## `@deepseek-ai/dsh-time-context` - `inject`: `agents` · `sessionProjections` -- `source`: [`packages/context/time-context/src/index.ts:56`](../packages/context/time-context/src/index.ts) +- `source`: [`packages/context/time-context/src/index.ts:46`](../packages/context/time-context/src/index.ts) ```ts config-catalog /** Request-preparation clock formatting and append scheduling. Invalid values fail plugin load. */ @@ -4515,7 +4515,7 @@ export interface Config { ## `@deepseek-ai/dsh-working-directory` - `inject`: `fs` · `sessionProjections` · `systemPrompt` -- `source`: [`packages/session/working-directory/src/index.ts:56`](../packages/session/working-directory/src/index.ts) +- `source`: [`packages/session/working-directory/src/index.ts:51`](../packages/session/working-directory/src/index.ts) ```ts config-catalog /** Deployment default for Sessions without an original project directory. */ diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index bb92fc0686..5f1378aed0 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -1420,7 +1420,7 @@ export type Config = LocalConfig ## `@deepseek-ai/dsh-goal` - `inject`: `agents` · `sessionProjections` -- `source`: [`packages/goal/goal/src/index.ts:172`](../packages/goal/goal/src/index.ts) +- `source`: [`packages/goal/goal/src/index.ts:168`](../packages/goal/goal/src/index.ts) ```ts config-catalog /** Deployment defaults for goal creation. */ @@ -2339,7 +2339,7 @@ export interface Config { - `inject`: `shell` · `approval` · `sessions` · `sessionProjections` - `refs`: [`ApprovalPolicy`](subsystems/approval.zh.md) · [`SandboxMode`](subsystems/sandbox.zh.md) · `Volatile` (`@deepseek-ai/cordis`) -- `source`: [`packages/interaction/permission-presets/src/index.ts:159`](../packages/interaction/permission-presets/src/index.ts) +- `source`: [`packages/interaction/permission-presets/src/index.ts:152`](../packages/interaction/permission-presets/src/index.ts) ```ts config-catalog /** The {@link PermissionPresetService} config: preset table and composition default. */ @@ -3638,7 +3638,7 @@ export type ShellDialect = 'bash' | 'pwsh' ## `@deepseek-ai/dsh-time-context` - `inject`: `agents` · `sessionProjections` -- `source`: [`packages/context/time-context/src/index.ts:56`](../packages/context/time-context/src/index.ts) +- `source`: [`packages/context/time-context/src/index.ts:46`](../packages/context/time-context/src/index.ts) ```ts config-catalog /** Request-preparation clock formatting and append scheduling. Invalid values fail plugin load. */ @@ -4517,7 +4517,7 @@ export interface Config { ## `@deepseek-ai/dsh-working-directory` - `inject`: `fs` · `sessionProjections` · `systemPrompt` -- `source`: [`packages/session/working-directory/src/index.ts:56`](../packages/session/working-directory/src/index.ts) +- `source`: [`packages/session/working-directory/src/index.ts:51`](../packages/session/working-directory/src/index.ts) ```ts config-catalog /** Deployment default for Sessions without an original project directory. */ diff --git a/docs/defensive-patterns/conversation-and-session.md b/docs/defensive-patterns/conversation-and-session.md index 7b91d6a676..f2f610ebe4 100644 --- a/docs/defensive-patterns/conversation-and-session.md +++ b/docs/defensive-patterns/conversation-and-session.md @@ -24,7 +24,7 @@ function PlanChip({ useProjection }: PlanChipProps) { } // The computation is a registered unit; the registry drives it and publishes changes. -const planDefinition: ProjectionDefinition<'plan'> = { +const planDefinition: ProjectionDefinition<'plan', typeof emptyPlan> = { key: 'plan', stateVersion: 1, init: () => emptyPlan, diff --git a/docs/defensive-patterns/conversation-and-session.zh.md b/docs/defensive-patterns/conversation-and-session.zh.md index 855fdd876f..448ce061ec 100644 --- a/docs/defensive-patterns/conversation-and-session.zh.md +++ b/docs/defensive-patterns/conversation-and-session.zh.md @@ -24,7 +24,7 @@ function PlanChip({ useProjection }: PlanChipProps) { } // The computation is a registered unit; the registry drives it and publishes changes. -const planDefinition: ProjectionDefinition<'plan'> = { +const planDefinition: ProjectionDefinition<'plan', typeof emptyPlan> = { key: 'plan', stateVersion: 1, init: () => emptyPlan, diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 90c4d87f8d..d695116cb7 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -9,7 +9,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | Event | Mode | Declared in | Dispatchers | Listeners | | --- | --- | --- | --- | --- | | `agent-loop/config-start-failed` | `emit` | [`packages/core/agent-loop/src/index.ts:196`](../packages/core/agent-loop/src/index.ts) | [`agent-loop`](../packages/core/agent-loop) (`events.dispatch`) | - | -| `agent-preset/selected` | `emit` | [`packages/preset/agent-preset-registry/src/types.ts:69`](../packages/preset/agent-preset-registry/src/types.ts) | [`agent-preset-registry`](../packages/preset/agent-preset-registry) (`emit`) | `remotes` | +| `agent-preset/selected` | `emit` | [`packages/preset/agent-preset-registry/src/types.ts:66`](../packages/preset/agent-preset-registry/src/types.ts) | [`agent-preset-registry`](../packages/preset/agent-preset-registry) (`emit`) | `remotes` | | `agent/assistant-stream` | `emit` | [`packages/core/agent/src/runtime-types.ts:363`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`headless`](../packages/bundle/headless), `session-controller` | | `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:261`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | `agent-team`, `browser-use-runtime`, `claude-code-mods`, [`file-reference-local`](../packages/context/file-reference-local), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`loader-smoke`](../packages/test-support/loader-smoke), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/disposed` | `emit` | [`packages/core/agent/src/runtime-types.ts:270`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `claude-code-mods`, [`file-reference-local`](../packages/context/file-reference-local), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`subagent`](../packages/subagent/subagent), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | @@ -22,11 +22,11 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:353`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm-retry`](../packages/llm/llm-retry) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:280`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), `server`, `session-controller` | | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:381`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:629`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:609`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:636`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:615`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:622`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:621`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:601`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:628`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:607`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:614`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | | `app-boot/config-reload` | `emit` | [`packages/boot/app-boot/src/index.ts:54`](../packages/boot/app-boot/src/index.ts) | [`app-boot`](../packages/boot/app-boot) (`emit`) | [`settings`](../packages/settings/settings) | | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:87`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes` | | `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | - | @@ -49,7 +49,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:67`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy), [`workspace-changes`](../packages/deliverables/workspace-changes) | | `fs/observed` | `emit` | [`packages/fs/fs/src/index.ts:77`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`emit`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`emit`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy), [`skill-filesystem`](../packages/skill/skill-filesystem), `workspace-files` | | `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:59`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `goal/activation-changed` | `emit` | [`packages/goal/goal/src/types.ts:150`](../packages/goal/goal/src/types.ts) | [`goal`](../packages/goal/goal) (`emit`) | `remotes` | +| `goal/activation-changed` | `emit` | [`packages/goal/goal/src/types.ts:147`](../packages/goal/goal/src/types.ts) | [`goal`](../packages/goal/goal) (`emit`) | `remotes` | | `goal/changed` | `emit` | [`packages/goal/goal/src/domain.ts:114`](../packages/goal/goal/src/domain.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver) | | `hmr/change` | `emit` | [`packages/boot/hmr/src/index.ts:35`](../packages/boot/hmr/src/index.ts) | [`hmr`](../packages/boot/hmr) (`emit`) | - | | `hmr/reload` | `emit` | [`packages/boot/hmr/src/index.ts:40`](../packages/boot/hmr/src/index.ts) | [`hmr`](../packages/boot/hmr) (`emit`) | - | diff --git a/docs/event-producer-consumer.zh.md b/docs/event-producer-consumer.zh.md index e34342c21d..318b933db3 100644 --- a/docs/event-producer-consumer.zh.md +++ b/docs/event-producer-consumer.zh.md @@ -11,7 +11,7 @@ | Event | Mode | Declared in | Dispatchers | Listeners | | --- | --- | --- | --- | --- | | `agent-loop/config-start-failed` | `emit` | [`packages/core/agent-loop/src/index.ts:196`](../packages/core/agent-loop/src/index.ts) | [`agent-loop`](../packages/core/agent-loop) (`events.dispatch`) | - | -| `agent-preset/selected` | `emit` | [`packages/preset/agent-preset-registry/src/types.ts:69`](../packages/preset/agent-preset-registry/src/types.ts) | [`agent-preset-registry`](../packages/preset/agent-preset-registry) (`emit`) | `remotes` | +| `agent-preset/selected` | `emit` | [`packages/preset/agent-preset-registry/src/types.ts:66`](../packages/preset/agent-preset-registry/src/types.ts) | [`agent-preset-registry`](../packages/preset/agent-preset-registry) (`emit`) | `remotes` | | `agent/assistant-stream` | `emit` | [`packages/core/agent/src/runtime-types.ts:363`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`headless`](../packages/bundle/headless), `session-controller` | | `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:261`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | `agent-team`, `browser-use-runtime`, `claude-code-mods`, [`file-reference-local`](../packages/context/file-reference-local), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`loader-smoke`](../packages/test-support/loader-smoke), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/disposed` | `emit` | [`packages/core/agent/src/runtime-types.ts:270`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `claude-code-mods`, [`file-reference-local`](../packages/context/file-reference-local), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`subagent`](../packages/subagent/subagent), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | @@ -24,11 +24,11 @@ | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:353`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm-retry`](../packages/llm/llm-retry) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:280`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), `server`, `session-controller` | | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:381`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:629`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:609`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:636`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:615`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:622`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:621`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:601`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:628`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:607`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:614`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | | `app-boot/config-reload` | `emit` | [`packages/boot/app-boot/src/index.ts:54`](../packages/boot/app-boot/src/index.ts) | [`app-boot`](../packages/boot/app-boot) (`emit`) | [`settings`](../packages/settings/settings) | | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:87`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes` | | `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | - | @@ -51,7 +51,7 @@ | `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:67`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy), [`workspace-changes`](../packages/deliverables/workspace-changes) | | `fs/observed` | `emit` | [`packages/fs/fs/src/index.ts:77`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`emit`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`emit`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy), [`skill-filesystem`](../packages/skill/skill-filesystem), `workspace-files` | | `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:59`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `goal/activation-changed` | `emit` | [`packages/goal/goal/src/types.ts:150`](../packages/goal/goal/src/types.ts) | [`goal`](../packages/goal/goal) (`emit`) | `remotes` | +| `goal/activation-changed` | `emit` | [`packages/goal/goal/src/types.ts:147`](../packages/goal/goal/src/types.ts) | [`goal`](../packages/goal/goal) (`emit`) | `remotes` | | `goal/changed` | `emit` | [`packages/goal/goal/src/domain.ts:114`](../packages/goal/goal/src/domain.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver) | | `hmr/change` | `emit` | [`packages/boot/hmr/src/index.ts:35`](../packages/boot/hmr/src/index.ts) | [`hmr`](../packages/boot/hmr) (`emit`) | - | | `hmr/reload` | `emit` | [`packages/boot/hmr/src/index.ts:40`](../packages/boot/hmr/src/index.ts) | [`hmr`](../packages/boot/hmr) (`emit`) | - | diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index b6a310d21e..b7eb3300cb 100644 --- a/docs/persistence-catalog.i18n.yaml +++ b/docs/persistence-catalog.i18n.yaml @@ -21,8 +21,8 @@ en: 9188862058c6986b zh: 9188862058c6986b /session-persistence-event-catalog/events/agent/agent-inbox-spliced-log-only: - en: 269a193ddd48917f - zh: 63ef1beb457dbdd9 + en: 8309b4babad90744 + zh: b344ac640d79947e /session-persistence-event-catalog/events/agent-preset: en: 49891ca9be5ac123 zh: 49891ca9be5ac123 @@ -141,14 +141,14 @@ en: 9edf4ef31e60e880 zh: 9edf4ef31e60e880 /session-persistence-event-catalog/events/model/model-selection-log-only: - en: 0d9e20c2357ae7ac - zh: 23401d59e97d6011 + en: 778af1e2e58810b8 + zh: df0fbae320d404a2 /session-persistence-event-catalog/events/permission: en: 19917bc5438e60af zh: 19917bc5438e60af /session-persistence-event-catalog/events/permission/permission-preset-log-only: - en: 41de5f6e1dad8620 - zh: 92cb5d5e87a23405 + en: 54423cb464a0a495 + zh: 8b3a9595255184f0 /session-persistence-event-catalog/events/plan: en: 4294f78d26ed985b zh: 4294f78d26ed985b @@ -1143,8 +1143,8 @@ en: 3b677f021d7dd4d3 zh: 2a875742b22879a2 /session-persistence-event-catalog/resolved-persistence-types/modelselection: - en: 6d66ffc1b393f2f2 - zh: ef6cb30b71f287e7 + en: e50c44f077599608 + zh: 7491723e289b1b3b /session-persistence-event-catalog/resolved-persistence-types/oneshotscheduledispatchchange: en: a3300babe57b6b67 zh: 4aaf06a149b399c3 @@ -1344,8 +1344,8 @@ en: 2786fef560851bb4 zh: 5d787475356b2606 /session-persistence-event-catalog/resolved-persistence-types/string: - en: 009c7ecb8c7d3bb5 - zh: 7f56d672f376b22f + en: 86bef22439bace14 + zh: 9350d592cb64e8f2 /session-persistence-event-catalog/resolved-persistence-types/string~2: en: 0089620bf4638263 zh: 1922bef1713094bb @@ -1521,8 +1521,8 @@ en: 8a9199b1784c70f5 zh: 76c98bc74686fda0 /session-persistence-event-catalog/resolved-persistence-types/inserted-outcome-removedcount-start: - en: fb9bed95931d510b - zh: dcaccd4254b4475c + en: 452ff7ab39ffb3a9 + zh: 33af56489f0a45bc /session-persistence-event-catalog/resolved-persistence-types/interrupted-message-step-stream: en: ec10cd8e9c202a81 zh: e08f859bcb13f0d4 @@ -1830,8 +1830,8 @@ en: 809a23c25ded8497 zh: e9cd23e281f8d31f /session-persistence-event-catalog/resolved-persistence-types/kind-user: - en: 9b6318ab4d7eba12 - zh: f475439ef40b2681 + en: 9a36cd81095ac333 + zh: fbcc74bbcac8eb5d /session-persistence-event-catalog/resolved-persistence-types/kind-user-approval: en: a52d2dfbaf844127 zh: 4c5306ca40f20873 @@ -1884,8 +1884,8 @@ en: 00f1d435f82d2753 zh: c2ab108ad2748a6c /session-persistence-event-catalog/resolved-persistence-types/preset: - en: f60ecbd156c6f063 - zh: c9149679bbacff21 + en: 26cf71c850765c59 + zh: 7a436be430e04898 /session-persistence-event-catalog/resolved-persistence-types/reason-turn: en: a4ba4d0ee1396381 zh: b6f595f8a696d512 diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index fb90826391..af9fedf418 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -185,7 +185,7 @@ Sources: [`packages/core/session/src/types.ts:432`](../packages/core/session/src } ``` -Source: [`packages/core/agent/src/types.ts:88`](../packages/core/agent/src/types.ts) +Source: [`packages/core/agent/src/types.ts:84`](../packages/core/agent/src/types.ts) ### `agent-preset/*` @@ -700,7 +700,7 @@ Source: [`packages/llm/llm-retry/src/types.ts:11`](../packages/llm/llm-retry/src 'model/selection': ModelSelection ``` -Source: [`packages/api/session-controller/src/types.ts:41`](../packages/api/session-controller/src/types.ts) +Source: [`packages/api/session-controller/src/types.ts:33`](../packages/api/session-controller/src/types.ts) ### `permission/*` @@ -718,7 +718,7 @@ Source: [`packages/api/session-controller/src/types.ts:41`](../packages/api/sess 'permission/preset': { preset: string } ``` -Source: [`packages/interaction/permission-presets/src/index.ts:59`](../packages/interaction/permission-presets/src/index.ts) +Source: [`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) ### `plan/*` @@ -4329,7 +4329,7 @@ Sources: [`packages/llm/llm/src/message.ts:24`](../packages/llm/llm/src/message. SHA-256: `f09e5e7acf5ff5ccd193ff2eeec015fa2ff7c29d98bc465f8c3302058d47e29b` -Sources: [`packages/api/session-controller/src/types.ts:101`](../packages/api/session-controller/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:93`](../packages/api/session-controller/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -5575,7 +5575,7 @@ Array of `number`. SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -Sources: [`packages/api/session-controller/src/types.ts:409`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:401`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` @@ -6369,7 +6369,7 @@ Sources: [`packages/core/session/src/types.ts:428`](../packages/core/session/src SHA-256: `fa106c5b33b657e8ef16e8cbf39f3b7d44e5cbcdf4f9303d9db6410f28951e42` -Sources: [`packages/core/agent/src/types.ts:88`](../packages/core/agent/src/types.ts) +Sources: [`packages/core/agent/src/types.ts:84`](../packages/core/agent/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7546,7 +7546,7 @@ Sources: [`packages/core/tools/src/index.ts:35`](../packages/core/tools/src/inde SHA-256: `6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def` -Sources: [`packages/api/session-controller/src/types.ts:418`](../packages/api/session-controller/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:410`](../packages/api/session-controller/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7781,7 +7781,7 @@ Sources: [`packages/interaction/user-approval/src/index.ts:40`](../packages/inte SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` -Sources: [`packages/interaction/permission-presets/src/index.ts:59`](../packages/interaction/permission-presets/src/index.ts) +Sources: [`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) | Property | Presence | Type | |---|---|---| diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index 75a0ade844..6c064bfbcc 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -187,7 +187,7 @@ export type SessionEvent = { } ``` -来源:[`packages/core/agent/src/types.ts:88`](../packages/core/agent/src/types.ts) +来源:[`packages/core/agent/src/types.ts:84`](../packages/core/agent/src/types.ts) ### `agent-preset/*` @@ -702,7 +702,7 @@ export type SessionEvent = { 'model/selection': ModelSelection ``` -来源:[`packages/api/session-controller/src/types.ts:41`](../packages/api/session-controller/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:33`](../packages/api/session-controller/src/types.ts) ### `permission/*` @@ -720,7 +720,7 @@ export type SessionEvent = { 'permission/preset': { preset: string } ``` -来源:[`packages/interaction/permission-presets/src/index.ts:59`](../packages/interaction/permission-presets/src/index.ts) +来源:[`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) ### `plan/*` @@ -4331,7 +4331,7 @@ SHA-256: `719c51f67074f97034a6c94297fe1f4b5d3c8d392c57586dab732aa5398c7a91` SHA-256: `f09e5e7acf5ff5ccd193ff2eeec015fa2ff7c29d98bc465f8c3302058d47e29b` -来源:[`packages/api/session-controller/src/types.ts:101`](../packages/api/session-controller/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:93`](../packages/api/session-controller/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5577,7 +5577,7 @@ SHA-256: `5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78` SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -来源:[`packages/api/session-controller/src/types.ts:409`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:401`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` @@ -6371,7 +6371,7 @@ SHA-256: `17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3` SHA-256: `fa106c5b33b657e8ef16e8cbf39f3b7d44e5cbcdf4f9303d9db6410f28951e42` -来源:[`packages/core/agent/src/types.ts:88`](../packages/core/agent/src/types.ts) +来源:[`packages/core/agent/src/types.ts:84`](../packages/core/agent/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7548,7 +7548,7 @@ SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543` SHA-256: `6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def` -来源:[`packages/api/session-controller/src/types.ts:418`](../packages/api/session-controller/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:410`](../packages/api/session-controller/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7783,7 +7783,7 @@ SHA-256: `11f70b595aa76897fc4e25a352bfa718c659f44b799e5aa14e84e5a38fe72912` SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` -来源:[`packages/interaction/permission-presets/src/index.ts:59`](../packages/interaction/permission-presets/src/index.ts) +来源:[`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) | 属性 | 存在性 | 类型 | |---|---|---| diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json index ec0566a51e..9f52ce31cb 100644 --- a/docs/persistence-schema.json +++ b/docs/persistence-schema.json @@ -23546,7 +23546,7 @@ "packages/workflow/workflow/src/types.ts#WorkflowRunId" ], "sources": [ - "packages/api/session-controller/src/types.ts:409", + "packages/api/session-controller/src/types.ts:401", "packages/attachment/attachment/src/brand.ts:6", "packages/compaction/compaction/src/brand.ts:4", "packages/core/session/src/types.ts:21", @@ -24068,7 +24068,7 @@ "digest": "6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def", "names": [], "sources": [ - "packages/api/session-controller/src/types.ts:418" + "packages/api/session-controller/src/types.ts:410" ] }, { @@ -24490,7 +24490,7 @@ "digest": "8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad", "names": [], "sources": [ - "packages/interaction/permission-presets/src/index.ts:59" + "packages/interaction/permission-presets/src/index.ts:52" ] }, { @@ -25884,7 +25884,7 @@ "packages/api/session-controller/src/types.ts#ModelSelection" ], "sources": [ - "packages/api/session-controller/src/types.ts:101" + "packages/api/session-controller/src/types.ts:93" ] }, { @@ -26047,7 +26047,7 @@ "digest": "fa106c5b33b657e8ef16e8cbf39f3b7d44e5cbcdf4f9303d9db6410f28951e42", "names": [], "sources": [ - "packages/core/agent/src/types.ts:88" + "packages/core/agent/src/types.ts:84" ] }, { diff --git a/docs/subsystems/session-projection.i18n.yaml b/docs/subsystems/session-projection.i18n.yaml index 5f008d2f02..7f4e45e098 100644 --- a/docs/subsystems/session-projection.i18n.yaml +++ b/docs/subsystems/session-projection.i18n.yaml @@ -6,8 +6,8 @@ en: e9330151d3eb579a zh: 53e47acd1d810da9 /session-projections/the-unit: - en: fad897af8b8839ff - zh: 3c68c5256973bc39 + en: d48814d3ab0e997f + zh: d0337d8eba097a63 /session-projections/the-snapshot-and-the-change-feed: en: 630c1041f41f89bf zh: a3361bdead116cd7 diff --git a/docs/subsystems/session-projection.md b/docs/subsystems/session-projection.md index b7d8fb2bad..950ae2d89f 100644 --- a/docs/subsystems/session-projection.md +++ b/docs/subsystems/session-projection.md @@ -28,7 +28,7 @@ interface ProjectionHandle { ## The unit -`SessionProjectionStateMap` is the merge-extensible table of host fold states, while `SessionProjectionMap` retains the client-visible whole values. A domain contributes one `ProjectionDefinition` per state key; a `wire` block makes that key client-visible, and rendering belongs to the slot system, never this layer: +`ProjectionDefinition` carries each unit's host state type locally; registration infers `S` from `stateSchema` and returns `ProjectionHandle`. Only client-visible keys merge into `SessionProjectionMap`, which types their whole values. A `wire` block makes a unit client-visible, and rendering belongs to the slot system, never this layer: ```ts type-equiv /** @@ -39,11 +39,8 @@ interface ProjectionHandle { * synchronous (an async unit would tear the carriers' consistency cut), and * `state` MUST be plain JSON (the persisted-cache precondition). */ -interface ProjectionDefinition< - K extends keyof SessionProjectionStateMap, - S extends SessionProjectionStateMap[K] = SessionProjectionStateMap[K], -> { - /** The projection key this unit owns (its `SessionProjectionStateMap` entry). */ +interface ProjectionDefinition { + /** The projection key this unit owns. */ key: K /** Validates persisted state before it seeds a fold. */ stateSchema: ZodType @@ -235,7 +232,7 @@ Source: [`packages/session/session-projection-cache/src/index.ts`](../../package * @param definition - key, state schema, pure unit functions, and stateVersion. * @returns a ready handle with synchronous state reads and the effect disposer. */ -register< K extends keyof SessionProjectionMap, S extends SessionProjectionStateMap[K], >( definition: Omit, 'wire'> & { wire: NonNullable['wire']> }, ): Promise> +register( definition: Omit, 'wire'> & { wire: NonNullable['wire']> }, ): Promise> /** * Register one host-only unit. Its state is omitted from client snapshots @@ -244,7 +241,7 @@ register< K extends keyof SessionProjectionMap, S extends SessionProjectionState * @param definition - key, state schema, pure unit functions, and stateVersion. * @returns a ready handle with synchronous state reads and the effect disposer. */ -register< K extends Exclude, S extends SessionProjectionStateMap[K], >( definition: Omit, 'wire'>, ): Promise> +register( definition: ProjectionDefinition & { key: Exclude }, ): Promise> /** * Subscribe to the change feed. The registration is an effect on the diff --git a/docs/subsystems/session-projection.zh.md b/docs/subsystems/session-projection.zh.md index 224a5dfdb6..52611c07c7 100644 --- a/docs/subsystems/session-projection.zh.md +++ b/docs/subsystems/session-projection.zh.md @@ -28,7 +28,7 @@ interface ProjectionHandle { ## 投影单元 -`SessionProjectionStateMap` 是 host 侧折叠状态的 merge-extensible 类型表,`SessionProjectionMap` 则继续表示客户端可见的全量值。领域为每个状态 key 贡献一个 `ProjectionDefinition`;`wire` 块使该 key 对客户端可见,渲染归 slot 体系管,永远不归本层: +`ProjectionDefinition` 在各单元内部携带宿主状态类型;注册从 `stateSchema` 推导 `S`,并返回 `ProjectionHandle`。只有客户端可见的 key 合并到 `SessionProjectionMap`,由它约束对应的全量值。`wire` 块使单元对客户端可见,渲染归 slot 体系管,永远不归本层: ```ts type-equiv /** @@ -39,11 +39,8 @@ interface ProjectionHandle { * synchronous (an async unit would tear the carriers' consistency cut), and * `state` MUST be plain JSON (the persisted-cache precondition). */ -interface ProjectionDefinition< - K extends keyof SessionProjectionStateMap, - S extends SessionProjectionStateMap[K] = SessionProjectionStateMap[K], -> { - /** The projection key this unit owns (its `SessionProjectionStateMap` entry). */ +interface ProjectionDefinition { + /** The projection key this unit owns. */ key: K /** Validates persisted state before it seeds a fold. */ stateSchema: ZodType @@ -235,7 +232,7 @@ Source: [`packages/session/session-projection-cache/src/index.ts`](../../package * @param definition - key, state schema, pure unit functions, and stateVersion. * @returns a ready handle with synchronous state reads and the effect disposer. */ -register< K extends keyof SessionProjectionMap, S extends SessionProjectionStateMap[K], >( definition: Omit, 'wire'> & { wire: NonNullable['wire']> }, ): Promise> +register( definition: Omit, 'wire'> & { wire: NonNullable['wire']> }, ): Promise> /** * Register one host-only unit. Its state is omitted from client snapshots @@ -244,7 +241,7 @@ register< K extends keyof SessionProjectionMap, S extends SessionProjectionState * @param definition - key, state schema, pure unit functions, and stateVersion. * @returns a ready handle with synchronous state reads and the effect disposer. */ -register< K extends Exclude, S extends SessionProjectionStateMap[K], >( definition: Omit, 'wire'>, ): Promise> +register( definition: ProjectionDefinition & { key: Exclude }, ): Promise> /** * Subscribe to the change feed. The registration is an effect on the diff --git a/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.i18n.yaml index 16a7f3f11c..6918fdf4c1 100644 --- a/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.i18n.yaml +++ b/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.i18n.yaml @@ -9,8 +9,8 @@ en: 5cf8cb0051860df5 zh: 2578c6c3e77bc1c7 /session-projection-registration-handles/change: - en: d488f71dcb5fcafb - zh: 0133ba0a568993ad + en: 64c2492c43c7a263 + zh: ba5a15b959df496c /session-projection-registration-handles/migration: - en: f268d8ba1d131b0f - zh: 29c3fe01d8b1cd0e + en: bd4310bb946b6f08 + zh: 2086e6e9c11bc4ed diff --git a/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.md b/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.md index 25f76616c2..73734634e3 100644 --- a/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.md +++ b/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.md @@ -8,14 +8,14 @@ English | [中文](guide.zh.md) ## Change -`@deepseek-ai/dsh-session-projection` changes `SessionProjectionRegistry.register(definition)` from a synchronous disposer to `Promise>`. Registry-level `stateOf(session, key)` is removed. Registration errors now reject the returned promise. After the last registration is disposed, the unit leaves snapshots, checkpoints, and live notifications, but retained handles can still fold Session events on demand. +`@deepseek-ai/dsh-session-projection` changes `SessionProjectionRegistry.register(definition)` from a synchronous disposer to `Promise>`. Registry-level `stateOf(session, key)` and `SessionProjectionStateMap` are removed. Host state types stay local to `ProjectionDefinition` and are inferred from `stateSchema` during registration. Registration errors now reject the returned promise. After the last registration is disposed, the unit leaves snapshots, checkpoints, and live notifications, but retained handles can still fold Session events on demand. `@deepseek-ai/dsh-agent` and `@deepseek-ai/dsh-subagent` require `sessionProjections`. AgentRegistry owns turn and step state; consumers use `ctx.agents.turnBoundaryOf(session)` instead of importing `turnBoundaryProjectionDefinition`. Turn-state consumers, including the Claude Code mods bridge, require `agents`. Preset and context-pressure reads use `ctx.agentPresets.presetForSession(session)` and `ctx.tokenMeter.contextPressure(session)`. The API controller and mods bridge no longer register those definitions independently; their optional-service behavior applies when the owning service is absent. `@deepseek-ai/dsh-api-session-controller` also removes `installModelSelectionProjection`. ## Migration 1. Mount `SessionProjectionRegistry` before `AgentRegistry`, `SubagentRuntime`, and other projection owners in custom compositions. Include `@deepseek-ai/dsh-agent` wherever a plugin requires `agents`. Consumers of domain data inject the owning service. -2. For a plugin's own definitions, await `ctx.sessionProjections.register(definition)` in asynchronous `apply()` or `[Service.init]()` and retain the handle privately before publishing dependent operations. Keep existing function-plugin namespace exports. +2. Remove host-state map augmentations and imports; pass the local state type as the second `ProjectionDefinition` argument. Keep client-value declarations in `SessionProjectionMap`. For a plugin's own definitions, await `ctx.sessionProjections.register(definition)` in asynchronous `apply()` or `[Service.init]()` and retain the handle privately before publishing dependent operations. Keep existing function-plugin namespace exports. 3. Replace `registry.stateOf(session, key)` with a business service method for another domain, or `handle.stateOf(session)` inside the owner. Replace stored unregister callbacks with `handle.dispose`, which always returns `Promise`, and await explicit disposal; fiber disposal still releases registrations automatically. Await registration when handling initialization failures. 4. Replace `installModelSelectionProjection(ctx)` with `await ctx.sessionProjections.register(modelSelectionProjection)`, importing the definition from `@deepseek-ai/dsh-api-session-controller/src/model-selection-projection.ts`. 5. Typecheck custom plugins, then verify activation, a Session state read, and owner disposal. A released reader remains usable, while the released unit disappears from new snapshots once its final registration is gone. diff --git a/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.zh.md b/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.zh.md index 7c917af0e4..d79783d036 100644 --- a/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.zh.md +++ b/docs/upgrade-guide/v0.2.1-alpha.3/session-projection-handles/guide.zh.md @@ -8,14 +8,14 @@ description: "Session 投影注册改为异步,并返回保留读取能力的 ## 变更 -`@deepseek-ai/dsh-session-projection` 的 `SessionProjectionRegistry.register(definition)` 从同步释放函数改为返回 `Promise>`。注册表级 `stateOf(session, key)` 已移除,注册错误现在使返回的 Promise 拒绝。最后一次注册释放后,该投影单元不再参与快照、检查点和实时通知,但保留的句柄仍可按需折叠 Session 事件。 +`@deepseek-ai/dsh-session-projection` 的 `SessionProjectionRegistry.register(definition)` 从同步释放函数改为返回 `Promise>`。注册表级 `stateOf(session, key)` 与 `SessionProjectionStateMap` 已移除。宿主状态类型保留在各自的 `ProjectionDefinition` 中,注册时从 `stateSchema` 推导。注册错误现在使返回的 Promise 拒绝。最后一次注册释放后,该投影单元不再参与快照、检查点和实时通知,但保留的句柄仍可按需折叠 Session 事件。 `@deepseek-ai/dsh-agent` 与 `@deepseek-ai/dsh-subagent` 依赖 `sessionProjections`。AgentRegistry 持有轮次和步骤状态;消费方使用 `ctx.agents.turnBoundaryOf(session)`,不再导入 `turnBoundaryProjectionDefinition`。包括 Claude Code mods 桥接在内的轮次状态消费方依赖 `agents`。预设与上下文压力分别通过 `ctx.agentPresets.presetForSession(session)` 和 `ctx.tokenMeter.contextPressure(session)` 读取。API 控制器与 mods 桥接不再独立注册这些定义;所属服务缺席时采用各自的可选服务行为。`@deepseek-ai/dsh-api-session-controller` 同时移除了 `installModelSelectionProjection`。 ## 迁移 1. 在自定义组合中,先挂载 `SessionProjectionRegistry`,再挂载 `AgentRegistry`、`SubagentRuntime` 及其他投影所有者。组合中的插件依赖 `agents` 时,加入 `@deepseek-ai/dsh-agent`。领域数据的消费方注入所属服务。 -2. 对插件自己的定义,在异步 `apply()` 或 `[Service.init]()` 中等待 `ctx.sessionProjections.register(definition)`,并在提供依赖操作前于内部保存句柄。保留现有函数插件命名空间导出。 +2. 删除宿主状态映射的声明合并与导入,将局部状态类型作为 `ProjectionDefinition` 的第二个类型参数。保留 `SessionProjectionMap` 中的客户端值声明。对插件自己的定义,在异步 `apply()` 或 `[Service.init]()` 中等待 `ctx.sessionProjections.register(definition)`,并在提供依赖操作前于内部保存句柄。保留现有函数插件命名空间导出。 3. 将 `registry.stateOf(session, key)` 替换为其他领域的业务服务方法,或所有者内部的 `handle.stateOf(session)`。将保存的取消注册回调替换为始终返回 `Promise` 的 `handle.dispose`,并等待显式释放完成;fiber 释放仍会自动释放注册。处理初始化失败时须等待注册。 4. 将 `installModelSelectionProjection(ctx)` 替换为 `await ctx.sessionProjections.register(modelSelectionProjection)`,从 `@deepseek-ai/dsh-api-session-controller/src/model-selection-projection.ts` 导入该定义。 5. 对自定义插件执行类型检查,再验证激活、Session 状态读取与 owner 释放。已释放的读取句柄仍可使用,而投影单元在最后一次注册解除后会从新快照中消失。 diff --git a/packages/api/session-controller/src/types.ts b/packages/api/session-controller/src/types.ts index c0b2b9a573..0d94a302af 100644 --- a/packages/api/session-controller/src/types.ts +++ b/packages/api/session-controller/src/types.ts @@ -14,14 +14,6 @@ import type { JsonValue } from '@deepseek-ai/dsh-util-values' import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types' declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Host state persisted for cold Session list summaries. */ - sessionListMetadata: SessionListMetadata - /** Host state for the boot-constant image-limit view. */ - imageLimits: null - /** Durable model selection already used by a request and still pending for a later request. */ - modelSelection: ModelSelectionProjectionState - } interface SessionProjectionMap { /** Persisted facts used to summarize a Session without activating it. */ sessionListMetadata: SessionListMetadata diff --git a/packages/api/session-controller/tests/session-projections.host.spec.ts b/packages/api/session-controller/tests/session-projections.host.spec.ts index b8848c2084..14be3e07aa 100644 --- a/packages/api/session-controller/tests/session-projections.host.spec.ts +++ b/packages/api/session-controller/tests/session-projections.host.spec.ts @@ -41,11 +41,6 @@ afterEach(async () => { let nextHarnessSession = 1 declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - 'test/last-user': LastUserState - 'test/internal-count': number - 'test/private-prompt': string | null - } interface SessionProjectionMap { 'test/last-user': { text: string } | null } diff --git a/packages/context/harness-dev-context/src/index.ts b/packages/context/harness-dev-context/src/index.ts index 588bb84b9b..40ae8f38f1 100644 --- a/packages/context/harness-dev-context/src/index.ts +++ b/packages/context/harness-dev-context/src/index.ts @@ -85,13 +85,6 @@ const legacyPromptSchema = zod.object({ source: zod.string().nullable(), web: zo /** Value-bearing paragraphs of the latest nonempty system prompt a Session committed; `null` where it has none. */ type LegacyPrompt = zod.infer -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Value-bearing harness-source and Web-surface paragraphs of the latest nonempty admitted system prompt. */ - harnessDevLegacyPrompt: LegacyPrompt - } -} - /** The complete single-line paragraph between `prefix` and `suffix`, or `null` when the prompt has none. */ function legacyParagraph(prompt: string, { prefix, suffix }: { prefix: string; suffix: string }): string | null { const start = prompt.indexOf(prefix) diff --git a/packages/context/time-context/src/index.ts b/packages/context/time-context/src/index.ts index 25cc4b484d..69eb467fc6 100644 --- a/packages/context/time-context/src/index.ts +++ b/packages/context/time-context/src/index.ts @@ -30,13 +30,6 @@ import { createTimestampFormatter, formatTimestamp } from './timestamp.ts' /** Cordis plugin name used by loader diagnostics. */ export const name = 'time-context' -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Latest time-context readings. */ - timeContext: TimeContextProjection - } -} - const timeContextStateSchema = zod.object({ /** Time of the latest model-visible event (user/assistant message, tool result), or null. */ lastMessageTime: zod.number().nullable(), @@ -46,9 +39,6 @@ const timeContextStateSchema = zod.object({ lastTurnInjectionTime: zod.number().nullable(), }) -/** Folded time-context readings. */ -type TimeContextProjection = zod.infer - /** The agent registry that owns pre-step processing. */ export const inject = ['agents', 'sessionProjections'] diff --git a/packages/context/tmux-context/src/index.ts b/packages/context/tmux-context/src/index.ts index 8a5f9d7ae3..02c756f90f 100644 --- a/packages/context/tmux-context/src/index.ts +++ b/packages/context/tmux-context/src/index.ts @@ -208,15 +208,6 @@ const tmuxContextStateSchema = zod.object({ time: zod.number(), }).nullable() -type TmuxContextState = zod.infer - -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** The stable state block of this plugin's latest durable injection, or null. */ - tmuxContext: TmuxContextState - } -} - /** * Register a prepended pre-step listener for the lifetime of `ctx`. * @param ctx - plugin context; the listener is disposed with it. diff --git a/packages/core/agent/src/projection.ts b/packages/core/agent/src/projection.ts index c4a56449f3..a3414561c5 100644 --- a/packages/core/agent/src/projection.ts +++ b/packages/core/agent/src/projection.ts @@ -5,13 +5,6 @@ import type { SessionSeq } from '@deepseek-ai/dsh-session/types' import { brandNumber } from '@deepseek-ai/dsh-brand' import { z as zod } from 'zod' -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** The agent session's open/last turn and step boundary facts (whole value). */ - turnBoundary: TurnBoundaryProjection - } -} - const sessionSeqSchema = zod.number().int().nonnegative().transform(brandNumber) const turnBoundaryProjectionSchema: zod.ZodType = zod.object({ diff --git a/packages/core/agent/src/types.ts b/packages/core/agent/src/types.ts index 2045e9ca11..dc54eb6737 100644 --- a/packages/core/agent/src/types.ts +++ b/packages/core/agent/src/types.ts @@ -56,10 +56,6 @@ export interface InboxWireState { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Pending agent input reconstructed from durable inbox splices. */ - inbox: InboxState - } interface SessionProjectionMap { /** Pending agent input reconstructed from durable inbox splices. */ inbox: InboxWireState diff --git a/packages/experimental/agent-team/src/projection.ts b/packages/experimental/agent-team/src/projection.ts index bc9239d3d8..dc02db2298 100644 --- a/packages/experimental/agent-team/src/projection.ts +++ b/packages/experimental/agent-team/src/projection.ts @@ -158,12 +158,6 @@ export interface TeamProjectionState extends TeamState { readonly failure?: string } -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - agentTeam: TeamProjectionState - } -} - const teamProjectionEntrySchema = z.object({ id: teamIdSchema, members: z.array(teamMemberSnapshotSchema), diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts index 1c1190b1e0..393b333827 100644 --- a/packages/extensions/tool-cordis/src/api-catalog.ts +++ b/packages/extensions/tool-cordis/src/api-catalog.ts @@ -2320,13 +2320,13 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ description: '`ctx.sessionProjections`: the projection unit table and its drive. The service subscribes to `session/event` once; every committed event passes every registered unit\'s `apply` (eager drive). A changed state reference computes the next client view; the change feed is notified only when its raw result changes by `Object.is`. Cells build lazily — a unit registered after events flowed, or a session older than the registry, folds `init` over the in-memory log on first touch (event or read). Consumers declare `sessionProjections` as a required injection, await registration during activation, and retain its ready handle. Registrants sharing a key share one unit and are counted. The last release removes the unit from live drives, checkpoints, and client snapshots; retained handles still fold new events on demand using the original unit.', methods: [ { - signature: 'register< K extends keyof SessionProjectionMap, S extends SessionProjectionStateMap[K], >( definition: Omit, \'wire\'> & { wire: NonNullable[\'wire\']> }, ): Promise>', + signature: 'register( definition: Omit, \'wire\'> & { wire: NonNullable[\'wire\']> }, ): Promise>', description: 'Register one domain\'s unit on the calling context\'s fiber. Fiber or handle disposal releases one reference; the final release removes live participation. Retained handles remain readable after release. Callers must await registration before publishing consumers; registration may perform asynchronous work.', parameters: [{ name: 'definition', description: 'key, state schema, pure unit functions, and stateVersion.' }], returns: 'a ready handle with synchronous state reads and the effect disposer.', }, { - signature: 'register< K extends Exclude, S extends SessionProjectionStateMap[K], >( definition: Omit, \'wire\'>, ): Promise>', + signature: 'register( definition: ProjectionDefinition & { key: Exclude }, ): Promise>', description: 'Register one host-only unit. Its state is omitted from client snapshots and always checkpointed like every other unit. Callers must await registration before publishing consumers; registration may perform asynchronous work.', parameters: [{ name: 'definition', description: 'key, state schema, pure unit functions, and stateVersion.' }], returns: 'a ready handle with synchronous state reads and the effect disposer.', @@ -6551,7 +6551,7 @@ export const TYPE_API: readonly TypeApiEntry[] = [ }, { name: 'ProjectionDefinition', - declaration: 'export interface ProjectionDefinition {\n key: K;\n stateSchema: ZodType;\n init(header: SessionHeader, inheritedEventCount: SessionLogOffset): NoInfer;\n apply(state: NoInfer, event: SessionEvent): NoInfer;\n wire?: K extends keyof SessionProjectionMap ? {\n viewSchema: ZodType;\n view(state: NoInfer): SessionProjectionMap[K];\n } : never;\n stateVersion: number;\n}', + declaration: 'export interface ProjectionDefinition {\n key: K;\n stateSchema: ZodType;\n init(header: SessionHeader, inheritedEventCount: SessionLogOffset): NoInfer;\n apply(state: NoInfer, event: SessionEvent): NoInfer;\n wire?: K extends keyof SessionProjectionMap ? {\n viewSchema: ZodType;\n view(state: NoInfer): SessionProjectionMap[K];\n } : never;\n stateVersion: number;\n}', }, { name: 'ProjectionHandle', @@ -7357,10 +7357,6 @@ export const TYPE_API: readonly TypeApiEntry[] = [ name: 'SessionProjectionsRequest', declaration: 'export interface SessionProjectionsRequest {\n readonly sessionId: SessionId;\n}', }, - { - name: 'SessionProjectionStateMap', - declaration: 'export interface SessionProjectionStateMap {\n}', - }, { name: 'SessionProjectionsValue', declaration: 'export type SessionProjectionsValue = (SessionProjectionBaseline & {\n readonly kind: \'sequenced\';\n}) | {\n readonly kind: \'migration-required\';\n readonly values: SessionProjectionValues;\n} | null;', diff --git a/packages/goal/goal/README.i18n.yaml b/packages/goal/goal/README.i18n.yaml index d7e3878d2c..4aa0d5c88d 100644 --- a/packages/goal/goal/README.i18n.yaml +++ b/packages/goal/goal/README.i18n.yaml @@ -24,8 +24,8 @@ en: 81d959eecdec4bbd zh: ff47fb2cba8f1e73 /deepseek-ai-dsh-goal/use-this-package/session-projection: - en: 251f84f8959a2072 - zh: c57a4d252e12b128 + en: 67b924c4f6902dc1 + zh: 99ed177a06126895 /deepseek-ai-dsh-goal/use-this-package/drive-the-lifecycle: en: 622890ced87a44e9 zh: 6ba1f3f872400452 diff --git a/packages/goal/goal/README.md b/packages/goal/goal/README.md index c39bc0cbcb..9e0a1ee60d 100644 --- a/packages/goal/goal/README.md +++ b/packages/goal/goal/README.md @@ -49,7 +49,7 @@ Load the package with a composition entry; the only deployment choice is the def ### Session projection -`GoalService` requires `ctx.sessionProjections` ([`@deepseek-ai/dsh-session-projection`](../../session/session-projection/README.md)) and registers the `goal` projection unit at startup; a composition that omits the projection registry cannot activate `ctx.goals`. The unit's version 6 host state retains the latest valid current goal, every previously used goal id, and the first strict replay failure. Its client view exposes the current goal or `null` before the first create and after a clear tombstone. The key merges into both `SessionProjectionStateMap` and `SessionProjectionMap`; carriers serve the client value on the history tail page and the `session/projection` push frame. +`GoalService` requires `ctx.sessionProjections` ([`@deepseek-ai/dsh-session-projection`](../../session/session-projection/README.md)) and registers the `goal` projection unit at startup; a composition that omits the projection registry cannot activate `ctx.goals`. The unit's version 6 host state retains the latest valid current goal, every previously used goal id, and the first strict replay failure. Its client view exposes the current goal or `null` before the first create and after a clear tombstone. The client key merges into `SessionProjectionMap`; carriers serve the client value on the history tail page and the `session/projection` push frame. ### Drive the lifecycle diff --git a/packages/goal/goal/README.zh.md b/packages/goal/goal/README.zh.md index a52fbcfdc2..ac8fd3837b 100644 --- a/packages/goal/goal/README.zh.md +++ b/packages/goal/goal/README.zh.md @@ -49,7 +49,7 @@ goal 适合一个需要跨自动 Goal Round 持续的长期完成目标——例 ### 会话投影 -`GoalService` 要求组合提供 `ctx.sessionProjections`([`@deepseek-ai/dsh-session-projection`](../../session/session-projection/README.zh.md)),并在启动时注册 `goal` 投影单元;未组合投影注册表的组合无法激活 `ctx.goals`。该单元版本为 6,其宿主状态保留最新的有效当前 goal、所有曾使用的 goal id,以及第一次严格回放失败。客户端视图提供当前 goal;首次 create 前与 clear tombstone 后为 `null`。该键同时合并到 `SessionProjectionStateMap` 与 `SessionProjectionMap`;载体通过历史尾页和 `session/projection` 推送帧提供客户端值。 +`GoalService` 要求组合提供 `ctx.sessionProjections`([`@deepseek-ai/dsh-session-projection`](../../session/session-projection/README.zh.md)),并在启动时注册 `goal` 投影单元;未组合投影注册表的组合无法激活 `ctx.goals`。该单元版本为 6,其宿主状态保留最新的有效当前 goal、所有曾使用的 goal id,以及第一次严格回放失败。客户端视图提供当前 goal;首次 create 前与 clear tombstone 后为 `null`。客户端键合并到 `SessionProjectionMap`;载体通过历史尾页和 `session/projection` 推送帧提供客户端值。 ### 驱动生命周期 diff --git a/packages/goal/goal/src/index.ts b/packages/goal/goal/src/index.ts index 275b757eba..3d54ed75d6 100644 --- a/packages/goal/goal/src/index.ts +++ b/packages/goal/goal/src/index.ts @@ -47,10 +47,6 @@ import type { GoalSnapshotChangeMeta, } from './domain.ts' -// The pure payload outlet (./types.ts, ONE home of the `goal` projection-key -// declaration) re-exported onto the package root keeps the module edge in -// the emitted index.d.ts, so aggregate programs consuming the declarations -// still receive the SessionProjectionStateMap merge. export type * from './types.ts' export type * from './domain.ts' export { GOAL_CHANGE_VERSION, GoalError, GoalId } from './runtime.ts' diff --git a/packages/goal/goal/src/types.ts b/packages/goal/goal/src/types.ts index eb7cd602ed..f7078de673 100644 --- a/packages/goal/goal/src/types.ts +++ b/packages/goal/goal/src/types.ts @@ -126,9 +126,6 @@ export interface GoalProjectionState { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - goal: GoalProjectionState - } interface SessionProjectionMap { /** * The session's current goal and admitted-round count, or diff --git a/packages/interaction/permission-presets/src/index.ts b/packages/interaction/permission-presets/src/index.ts index 580443d7c3..935de3d5fa 100644 --- a/packages/interaction/permission-presets/src/index.ts +++ b/packages/interaction/permission-presets/src/index.ts @@ -41,13 +41,6 @@ declare module '@deepseek-ai/cordis' { } } -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Latest logged permission overrides and constructor-seed status. */ - permissions: PermissionProjectionState - } -} - declare module '@deepseek-ai/dsh-session/types' { interface SessionEventMap { /** diff --git a/packages/interaction/user-questions/src/projection.ts b/packages/interaction/user-questions/src/projection.ts index 7453a265a5..0c64c93fa0 100644 --- a/packages/interaction/user-questions/src/projection.ts +++ b/packages/interaction/user-questions/src/projection.ts @@ -329,9 +329,3 @@ export const userQuestionProjectionDefinition = { wire: { viewSchema: projectionViewSchema, view: state => state.questions }, stateVersion: 2, } satisfies ProjectionDefinition<'userQuestions', UserQuestionProjectionState> - -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - userQuestions: UserQuestionProjectionState - } -} diff --git a/packages/llm/llm-retry/src/index.ts b/packages/llm/llm-retry/src/index.ts index 6b7fb6e682..0c181260ce 100644 --- a/packages/llm/llm-retry/src/index.ts +++ b/packages/llm/llm-retry/src/index.ts @@ -107,12 +107,6 @@ const llmRetryStateSchema: zod.ZodType = zod.record(zod.string(), retry: zod.number().int().nonnegative(), retryId: zod.string(), })) as unknown as zod.ZodType -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Retry state for the current step by provider and policy. */ - llmRetry: LlmRetryState - } -} /** * Install provider-routed normal or unbounded request recovery. diff --git a/packages/llm/token-meter/src/breakdown-projection.ts b/packages/llm/token-meter/src/breakdown-projection.ts index 66ea6ae398..43ce1b04f7 100644 --- a/packages/llm/token-meter/src/breakdown-projection.ts +++ b/packages/llm/token-meter/src/breakdown-projection.ts @@ -13,15 +13,9 @@ import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection' // Type-only: the `compaction/*` SessionEventMap merges (shadow-price events). import type {} from '@deepseek-ai/dsh-compaction' import { estimateMessage, estimateToolsTokens } from './estimate.ts' -// Import for the `contextBreakdown` SessionProjectionStateMap key merge. +// Type-only: the client projection key and value declaration. import type {} from './projection.ts' -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - contextBreakdown: ContextBreakdownState - } -} - const tokenCount = z.number().int().nonnegative() const sessionSeq = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).transform(SessionSeq) diff --git a/packages/llm/token-meter/src/index.ts b/packages/llm/token-meter/src/index.ts index 27768fa394..552e5d9620 100644 --- a/packages/llm/token-meter/src/index.ts +++ b/packages/llm/token-meter/src/index.ts @@ -24,7 +24,6 @@ import { SessionSeq, } from '@deepseek-ai/dsh-session' import type { ProjectionHandle } from '@deepseek-ai/dsh-session-projection' -import type { SessionProjectionStateMap } from '@deepseek-ai/dsh-session-projection/types' import type { ContextPressureProjection, TokenMeasurement, @@ -33,17 +32,13 @@ import type { } from './types.ts' import { contextBreakdownProjectionDefinition } from './breakdown-projection.ts' import { contextPressureProjectionDefinition, tokenUsageProjectionDefinition } from './usage-projection.ts' +import type { ContextPressureState } from './usage-projection.ts' import { estimateContent, estimateMessage, estimateToolsTokens, ROLE_OVERHEAD } from './estimate.ts' import { commitSurfaceTokens, planSurfaceTokens } from './surface-fold.ts' import type { MeterSurfaceNode } from './surface-fold.ts' import { priceSurface } from './route-pricing.ts' export type * from './types.ts' -// Module-edge re-export: forces the emitted index.d.ts to import the -// projection-unit modules, so their SessionProjectionStateMap augmentations load -// in aggregate programs that only import the package root. -export type * from './usage-projection.ts' -export type * from './breakdown-projection.ts' /** * Raw anchor facts captured at the latest successful call; the baseline is @@ -107,7 +102,7 @@ export class TokenMeter extends Service { static inject = ['sessionProjections'] private readonly states = new WeakMap() - private contextPressureProjectionHandle!: ProjectionHandle + private contextPressureProjectionHandle!: ProjectionHandle constructor(ctx: Context, config: TokenMeterConfig = {}) { super(ctx, 'tokenMeter') diff --git a/packages/llm/token-meter/src/usage-projection.ts b/packages/llm/token-meter/src/usage-projection.ts index 2238316fab..f07fa676a9 100644 --- a/packages/llm/token-meter/src/usage-projection.ts +++ b/packages/llm/token-meter/src/usage-projection.ts @@ -85,13 +85,6 @@ function usageOf(event: SessionEvent): TokenUsage | undefined { return lastAssistantStreamChunk(event.data.stream, 'usage')?.usage } -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - tokenUsage: TokenUsageState - contextPressure: ContextPressureState - } -} - /** The context-pressure state schema and source of its inferred type. */ const contextPressureStateSchema = z.object({ contextWindow: z.number().int().positive().optional(), @@ -105,7 +98,8 @@ const contextPressureStateSchema = z.object({ }).optional(), }).strict() -type ContextPressureState = z.infer +/** Host fold state for provider pressure and surface adjustments. */ +export type ContextPressureState = z.infer /** * Token-meter's session projection unit. diff --git a/packages/plan/plan-mode/src/types.ts b/packages/plan/plan-mode/src/types.ts index 3325c6b0c4..79fbaa3617 100644 --- a/packages/plan/plan-mode/src/types.ts +++ b/packages/plan/plan-mode/src/types.ts @@ -36,10 +36,6 @@ export interface PlanUnitState { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Host plan-mode fold state. */ - plan: PlanUnitState - } interface SessionProjectionMap { /** Plan collaboration state folded from the plan command lifecycle and `plan/mode` events. */ plan: PlanProjection diff --git a/packages/preset/agent-preset-registry/src/types.ts b/packages/preset/agent-preset-registry/src/types.ts index c30141d621..0875990d11 100644 --- a/packages/preset/agent-preset-registry/src/types.ts +++ b/packages/preset/agent-preset-registry/src/types.ts @@ -48,9 +48,6 @@ declare module '@deepseek-ai/dsh-typert-protocol' { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - agentPreset: string | null - } interface SessionProjectionMap { /** Preset the Session runs, or null when the deployment composes none. */ agentPreset: string | null diff --git a/packages/sandbox/sandbox-policy/src/index.ts b/packages/sandbox/sandbox-policy/src/index.ts index 942838ca36..e1fa052558 100644 --- a/packages/sandbox/sandbox-policy/src/index.ts +++ b/packages/sandbox/sandbox-policy/src/index.ts @@ -93,14 +93,6 @@ const sandboxModeStateSchema = zod.union([ zod.literal('danger-full-access'), ]).nullable() -type SandboxModeState = zod.infer -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Last logged sandbox-mode override, or null before one (deployment default applies at resolve time). */ - sandboxMode: SandboxModeState - } -} - /** * The sandbox-policy service (`ctx.sandboxPolicy`). Owns the deployment * default mode, fallback workspace root, and current request-time policy diff --git a/packages/session/session-projection-cache/tests/cache.spec.ts b/packages/session/session-projection-cache/tests/cache.spec.ts index 77d2f81ab3..bacceed9e9 100644 --- a/packages/session/session-projection-cache/tests/cache.spec.ts +++ b/packages/session/session-projection-cache/tests/cache.spec.ts @@ -38,15 +38,6 @@ import { checkpointRecord, projectionCacheDomainSpec } from '../src/spec.ts' import type { CheckpointRecord } from '../src/spec.ts' declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - 'cache-test/marks': MarksState - 'cache-test/secondary-marks': MarksState - 'cache-test/marks2': Map - 'cache-test/count': number - 'cache-test/secret': string - 'cache-test/marks3': MarksState - title: string | null - } interface SessionProjectionMap { 'cache-test/marks': { marks: string[] } 'cache-test/secondary-marks': { marks: string[] } diff --git a/packages/session/session-projection-cache/tests/fixtures.spec.ts b/packages/session/session-projection-cache/tests/fixtures.spec.ts index 1fd5126eeb..d20b9a8c73 100644 --- a/packages/session/session-projection-cache/tests/fixtures.spec.ts +++ b/packages/session/session-projection-cache/tests/fixtures.spec.ts @@ -37,9 +37,6 @@ import { checkpointRow, projectionCacheDomainSpec } from '../src/spec.ts' // Declarations must match the shipped title unit's exactly (the repo-wide // compile face sees both). declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - title: string | null - } interface SessionProjectionMap { title: string | null } diff --git a/packages/session/session-projection/README.i18n.yaml b/packages/session/session-projection/README.i18n.yaml index 96becd6d49..4cbe0781d9 100644 --- a/packages/session/session-projection/README.i18n.yaml +++ b/packages/session/session-projection/README.i18n.yaml @@ -24,8 +24,8 @@ en: 09758d1475fad86e zh: 473637cb34aebe72 /deepseek-ai-dsh-session-projection/use-this-package/register-and-read: - en: 43af8fda90742877 - zh: 4d03fef88cb0eb54 + en: b75f8f00df2933e1 + zh: c53e64518953110b /deepseek-ai-dsh-session-projection/use-this-package/persisted-checkpoints: en: 45f1c05fb7e08180 zh: f8d62c749899651a @@ -36,8 +36,8 @@ en: 8afa0fdb49898f6d zh: 6b2da34455963935 /deepseek-ai-dsh-session-projection/understand-the-implementation/source-map: - en: b0263d26c5a65d7a - zh: 2e58d3181dde901c + en: 48f170aebd4a630b + zh: 2b249e8fb9bde678 /deepseek-ai-dsh-session-projection/understand-the-implementation/drive-and-checkpoint-flow: en: 00136880bb586403 zh: bd35f645111c068c diff --git a/packages/session/session-projection/README.md b/packages/session/session-projection/README.md index 930de0955d..35db3ed33c 100644 --- a/packages/session/session-projection/README.md +++ b/packages/session/session-projection/README.md @@ -55,7 +55,7 @@ const definition = { ### Register and read -`await register(definition)` installs the unit and returns a handle with synchronous `stateOf(session)` reads and `dispose(): Promise`. Await `dispose()` to release the registration; repeated calls are safe. Registrants with the same key and `stateVersion` share cells; incompatible or invalid versions reject registration. Registration belongs to the calling fiber. The last unregister removes the unit from global event drives, snapshots, checkpoints, and change notifications. Existing handles remain readable: each retains its original unit and folds new Session events on demand, even if another version later registers the same key. Reading a handle does not initialize unrelated units or register it again. Carriers use `snapshot(session)` for a consistent client-view cut and `onChanged(listener)` for changes to registered units. +`await register(definition)` infers the host state type from `stateSchema`, installs the unit, and returns a handle with synchronous `stateOf(session)` reads and `dispose(): Promise`. Await `dispose()` to release the registration; repeated calls are safe. Registrants with the same key and `stateVersion` share cells; incompatible or invalid versions reject registration. Registration belongs to the calling fiber. The last unregister removes the unit from global event drives, snapshots, checkpoints, and change notifications. Existing handles remain readable: each retains its original unit and folds new Session events on demand, even if another version later registers the same key. Reading a handle does not initialize unrelated units or register it again. Carriers use `snapshot(session)` for a consistent client-view cut and `onChanged(listener)` for changes to registered units. ```text const todoProjectionHandle = await ctx.sessionProjections.register(definition) @@ -88,7 +88,7 @@ The package is the Service Definition and drive role of a capability seam: the f | File | Role | |---|---| | [`src/index.ts`](src/index.ts) | Plugin entry: `SessionProjectionRegistry` service, `ProjectionDefinition`, snapshot and checkpoint machinery | -| [`src/types.ts`](src/types.ts) | The merge-extensible `SessionProjectionMap` and `SessionProjectionStateMap` type tables | +| [`src/types.ts`](src/types.ts) | The merge-extensible client `SessionProjectionMap` type table | ### Drive and checkpoint flow diff --git a/packages/session/session-projection/README.zh.md b/packages/session/session-projection/README.zh.md index e0adbadde0..5554c29879 100644 --- a/packages/session/session-projection/README.zh.md +++ b/packages/session/session-projection/README.zh.md @@ -55,7 +55,7 @@ const definition = { ### 注册与读取 -`await register(definition)` 安装单元,返回提供同步 `stateOf(session)` 读取和 `dispose(): Promise` 的 handle。等待 `dispose()` 完成即可释放注册;重复调用是安全的。具有相同 key 和 `stateVersion` 的注册方共享 cell;版本不兼容或非法时注册会拒绝。注册归调用方 fiber 所有。最后一个注册方注销后,单元退出全局事件驱动、快照、检查点和变更通知。已有 handle 仍可读取:它保留原有单元,按需折叠新增的 Session 事件,即使同一 key 后来注册了其他版本也不受影响。读取 handle 不会初始化无关单元,也不会重新注册。载体用 `snapshot(session)` 读取一致的客户端视图切面,用 `onChanged(listener)` 订阅已注册单元的变更。 +`await register(definition)` 从 `stateSchema` 推导宿主状态类型,安装单元,并返回提供同步 `stateOf(session)` 读取和 `dispose(): Promise` 的 handle。等待 `dispose()` 完成即可释放注册;重复调用是安全的。具有相同 key 和 `stateVersion` 的注册方共享 cell;版本不兼容或非法时注册会拒绝。注册归调用方 fiber 所有。最后一个注册方注销后,单元退出全局事件驱动、快照、检查点和变更通知。已有 handle 仍可读取:它保留原有单元,按需折叠新增的 Session 事件,即使同一 key 后来注册了其他版本也不受影响。读取 handle 不会初始化无关单元,也不会重新注册。载体用 `snapshot(session)` 读取一致的客户端视图切面,用 `onChanged(listener)` 订阅已注册单元的变更。 ```text const todoProjectionHandle = await ctx.sessionProjections.register(definition) @@ -88,7 +88,7 @@ const { asOfSeq, values } = ctx.sessionProjections.snapshot(session) | 文件 | 职责 | |---|---| | [`src/index.ts`](src/index.ts) | 插件入口:`SessionProjectionRegistry` 服务、`ProjectionDefinition`、快照与检查点机制 | -| [`src/types.ts`](src/types.ts) | 可合并扩展的 `SessionProjectionMap` 与 `SessionProjectionStateMap` 类型表 | +| [`src/types.ts`](src/types.ts) | 可合并扩展的客户端 `SessionProjectionMap` 类型表 | ### 驱动与检查点流程 diff --git a/packages/session/session-projection/src/index.ts b/packages/session/session-projection/src/index.ts index 1790882394..8f5c62d216 100644 --- a/packages/session/session-projection/src/index.ts +++ b/packages/session/session-projection/src/index.ts @@ -1,6 +1,6 @@ /** - * Service Definition and drive registry for the session-projection capability seam: the merge-extensible state and client-view type - * tables, the `ProjectionDefinition` state-driven computation unit contract, + * Service Definition and drive registry for the session-projection capability seam: the merge-extensible client-view type + * table, the `ProjectionDefinition` state-driven computation unit contract, * and the `ctx.sessionProjections` registry that DRIVES every registered unit * forward eagerly over committed session events. Domain host plugins * contribute pure folds and optional client views; the framework owns the @@ -33,9 +33,9 @@ declare module '@deepseek-ai/cordis' { } } -import type { SessionProjectionMap, SessionProjectionStateMap } from './types.ts' +import type { SessionProjectionMap } from './types.ts' -export type { SessionProjectionMap, SessionProjectionStateMap } from './types.ts' +export type { SessionProjectionMap } from './types.ts' /** An effect-owned registration with a reader retained independently of registration. */ export interface ProjectionHandle { @@ -61,11 +61,8 @@ export interface ProjectionHandle { * synchronous (an async unit would tear the carriers' consistency cut), and * `state` MUST be plain JSON (the persisted-cache precondition). */ -export interface ProjectionDefinition< - K extends keyof SessionProjectionStateMap, - S extends SessionProjectionStateMap[K] = SessionProjectionStateMap[K], -> { - /** The projection key this unit owns (its `SessionProjectionStateMap` entry). */ +export interface ProjectionDefinition { + /** The projection key this unit owns. */ key: K /** Validates persisted state before it seeds a fold. */ stateSchema: ZodType @@ -242,10 +239,7 @@ export class SessionProjectionRegistry extends Service { * @param definition - key, state schema, pure unit functions, and stateVersion. * @returns a ready handle with synchronous state reads and the effect disposer. */ - register< - K extends keyof SessionProjectionMap, - S extends SessionProjectionStateMap[K], - >( + register( definition: Omit, 'wire'> & { wire: NonNullable['wire']> }, @@ -257,13 +251,10 @@ export class SessionProjectionRegistry extends Service { * @param definition - key, state schema, pure unit functions, and stateVersion. * @returns a ready handle with synchronous state reads and the effect disposer. */ - register< - K extends Exclude, - S extends SessionProjectionStateMap[K], - >( - definition: Omit, 'wire'>, + register( + definition: ProjectionDefinition & { key: Exclude }, ): Promise> - async register( + async register( definition: ProjectionDefinition, ): Promise> { const wire = definition.wire as { diff --git a/packages/session/session-projection/src/types.ts b/packages/session/session-projection/src/types.ts index 8373e4677b..0b112ce0db 100644 --- a/packages/session/session-projection/src/types.ts +++ b/packages/session/session-projection/src/types.ts @@ -15,10 +15,3 @@ * system's business, never this layer's. */ export interface SessionProjectionMap {} - -/** - * The merge-extensible host fold-state table. Each client-visible key also - * appears in {@link SessionProjectionMap}; host-only keys appear only here. - * Values must be plain JSON so the projection cache can persist them. - */ -export interface SessionProjectionStateMap {} diff --git a/packages/session/session-projection/tests/registration-reader.spec.ts b/packages/session/session-projection/tests/registration-reader.spec.ts index ab287d6110..6850d1fd86 100644 --- a/packages/session/session-projection/tests/registration-reader.spec.ts +++ b/packages/session/session-projection/tests/registration-reader.spec.ts @@ -7,10 +7,6 @@ import { describe, expect, it, onTestFinished, vi } from 'vitest' import { z } from 'zod' declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - 'test/reader': number - 'test/unrelated-reader': number - } interface SessionProjectionMap { 'test/reader': number } diff --git a/packages/session/session-projection/tests/registration.type-test.ts b/packages/session/session-projection/tests/registration.type-test.ts new file mode 100644 index 0000000000..dc9cadce3b --- /dev/null +++ b/packages/session/session-projection/tests/registration.type-test.ts @@ -0,0 +1,68 @@ +/** Compile-time registration checks for local state inference and client view declarations. */ +import { expectTypeOf } from 'vitest' +import { z } from 'zod' +import type { Session } from '@deepseek-ai/dsh-session' +import type { ProjectionDefinition, ProjectionHandle, SessionProjectionRegistry } from '@deepseek-ai/dsh-session-projection' + +declare module '@deepseek-ai/dsh-session-projection/types' { + interface SessionProjectionMap { + 'type-test/label': { label: string } + } +} + +const counter = { + key: 'type-test/counter', + stateSchema: z.number(), + stateVersion: 1, + init: () => 0, + apply: state => state + 1, +} satisfies ProjectionDefinition<'type-test/counter', number> + +/** + * Check inference and invalid registrations without executing them. + * @param registry - public projection registry. + * @param session - Session used to typecheck retained reads. + * @returns after the typechecked registration calls. + */ +export async function checkProjectionRegistrationTypes(registry: SessionProjectionRegistry, session: Session): Promise { + const host = await registry.register(counter) + expectTypeOf(host).toEqualTypeOf>() + expectTypeOf(host.stateOf(session)).toEqualTypeOf() + + const nullable = await registry.register({ + key: 'type-test/nullable', + stateSchema: z.string().nullable(), + stateVersion: 1, + init: () => null, + apply: (state) => { + expectTypeOf(state).toEqualTypeOf() + return state + }, + }) + expectTypeOf(nullable.stateOf(session)).toEqualTypeOf() + + const visible = { + ...counter, + key: 'type-test/label' as const, + wire: { + viewSchema: z.object({ label: z.string() }), + view: (state: number) => ({ label: String(state) }), + }, + } + const client = await registry.register(visible) + expectTypeOf(client.stateOf(session)).toEqualTypeOf() + + // @ts-expect-error -- initial state must match the state schema. + void registry.register({ ...counter, init: () => 'wrong' }) + // @ts-expect-error -- fold results must match the state schema. + void registry.register({ ...counter, apply: () => 'wrong' }) + // @ts-expect-error -- a declared client key requires its view. + void registry.register({ ...counter, key: 'type-test/label' }) + + const wrongView = { ...visible, wire: { ...visible.wire, view: (state: number) => ({ label: state }) } } + // @ts-expect-error -- the view must match the client key's declared value. + void registry.register(wrongView) + const unknownView = { ...visible, key: 'type-test/undeclared-view' as const } + // @ts-expect-error -- client-visible keys must be declared in the client map. + void registry.register(unknownView) +} diff --git a/packages/session/session-projection/tests/registry.spec.ts b/packages/session/session-projection/tests/registry.spec.ts index 189bcf96f2..589c44fc9f 100644 --- a/packages/session/session-projection/tests/registry.spec.ts +++ b/packages/session/session-projection/tests/registry.spec.ts @@ -22,13 +22,6 @@ import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection' import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection' declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - 'test/marks': MarksState - 'test/count': number - 'test/stable-view': StableViewState - 'test/cut': number - } - interface SessionProjectionMap { 'test/marks': { marks: string[] } 'test/stable-view': { marks: string[] } diff --git a/packages/session/session-stats/src/projection.ts b/packages/session/session-stats/src/projection.ts index e7d3f32377..c3560a8aca 100644 --- a/packages/session/session-stats/src/projection.ts +++ b/packages/session/session-stats/src/projection.ts @@ -63,12 +63,6 @@ interface SessionStatsState extends SessionStatsTotals { pendingCalls: Record } -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - sessionStats: SessionStatsState - } -} - const sessionStatsSchema = z.object({ turns: z.number().int().nonnegative(), steps: z.number().int().nonnegative(), diff --git a/packages/session/session-title/src/types.ts b/packages/session/session-title/src/types.ts index 20855445a5..be3c4aa7db 100644 --- a/packages/session/session-title/src/types.ts +++ b/packages/session/session-title/src/types.ts @@ -77,12 +77,6 @@ export interface TitleInputState { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Latest logged title text, or null. */ - title: string | null - /** Eligible human title input. */ - titleInput: TitleInputState - } interface SessionProjectionMap { /** * The session's current normalized title — the latest `session/title` diff --git a/packages/session/session-turn-outline/src/types.ts b/packages/session/session-turn-outline/src/types.ts index c4ccbcdab3..fac481681b 100644 --- a/packages/session/session-turn-outline/src/types.ts +++ b/packages/session/session-turn-outline/src/types.ts @@ -38,10 +38,6 @@ export interface TurnOutlineState { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Whole-log turn outline fold state (entries plus the open turn's response draft). */ - turnOutline: TurnOutlineState - } interface SessionProjectionMap { /** Every started turn with its `turn/start` seq and bounded previews, strictly increasing by turn; see {@link TurnOutlineEntry}. */ turnOutline: readonly TurnOutlineEntry[] diff --git a/packages/session/working-directory/src/index.ts b/packages/session/working-directory/src/index.ts index 61ca035d70..8664a8aca1 100644 --- a/packages/session/working-directory/src/index.ts +++ b/packages/session/working-directory/src/index.ts @@ -45,11 +45,6 @@ declare module '@deepseek-ai/dsh-session-projection/types' { /** Recorded current directory for Session observations, or null when none is recorded. */ workingDirectory: string | null } - - interface SessionProjectionStateMap { - /** Last committed working directory, or null before an explicit value exists. */ - workingDirectory: string | null - } } /** Deployment default for Sessions without an original project directory. */ diff --git a/packages/subagent/subagent/src/catalog.ts b/packages/subagent/subagent/src/catalog.ts index d640c8f6b8..416625c594 100644 --- a/packages/subagent/subagent/src/catalog.ts +++ b/packages/subagent/subagent/src/catalog.ts @@ -97,12 +97,6 @@ const stateSchema: z.ZodType = z.object({ head: chunkedListSchema(eventDataSchema).optional(), }).strict() -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - subagentCatalog: SubagentCatalogState - } -} - /** * Materialize complete and unknown-mode child identities from parent catalog events. * @param state - parent catalog fold state. diff --git a/packages/subagent/subagent/src/projection.ts b/packages/subagent/subagent/src/projection.ts index 541721f2c1..bc283d911b 100644 --- a/packages/subagent/subagent/src/projection.ts +++ b/packages/subagent/subagent/src/projection.ts @@ -50,13 +50,6 @@ const timingStateSchema: z.ZodType = z.object({ lastTurnCompleted: z.boolean().optional(), }).strict() -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - subagentTiming: TimingState - subagent: IdentityState - } -} - /** * Fold turn boundaries around the child's own durable descriptor. * diff --git a/packages/subagent/tool-subagent/src/model-selection-state.ts b/packages/subagent/tool-subagent/src/model-selection-state.ts index 92cdac56bb..ff09b7248a 100644 --- a/packages/subagent/tool-subagent/src/model-selection-state.ts +++ b/packages/subagent/tool-subagent/src/model-selection-state.ts @@ -21,13 +21,6 @@ declare module '@deepseek-ai/dsh-session/types' { } } -declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - /** Exact routes authorized for child LLM selection, or null when disabled. */ - subagentModelSelectionPolicy: AllowedModelRoute[] | null - } -} - const modelSelectionPolicySchema: zod.ZodType = zod.array(zod.object({ provider: zod.string().min(1), model: zod.string().min(1), diff --git a/packages/todo/tool-todo/src/types.ts b/packages/todo/tool-todo/src/types.ts index 68d5649bb0..efa4d070d3 100644 --- a/packages/todo/tool-todo/src/types.ts +++ b/packages/todo/tool-todo/src/types.ts @@ -33,9 +33,6 @@ declare module '@deepseek-ai/dsh-session/types' { } declare module '@deepseek-ai/dsh-session-projection/types' { - interface SessionProjectionStateMap { - todos: TodoItem[] | null - } interface SessionProjectionMap { /** * The agent's current whole todo list (the latest `todo/write` snapshot), diff --git a/scripts/gen-cordis-catalog.ts b/scripts/gen-cordis-catalog.ts index 4763950a68..8c0ac6f5d0 100644 --- a/scripts/gen-cordis-catalog.ts +++ b/scripts/gen-cordis-catalog.ts @@ -825,7 +825,6 @@ export const LINK_MAP: Readonly> = { ProjectionDefinition: 'session-projection.md', ProjectionHandle: 'session-projection.md', SessionProjectionMap: 'session-projection.md', - SessionProjectionStateMap: 'session-projection.md', ProjectionChangeListener: 'session-projection.md', ProjectionSnapshot: 'session-projection.md', ProjectionCheckpoint: 'session-projection.md',