refactor(session-projection): remove the host state map

This commit is contained in:
_Kerman committed 2026-10-15 21:01:00 +08:00
1 parent e152f17bb2
commit ff731c72de
61 files changed
+193 -335

No files matched your search

@@ -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
@@ -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<K extends keyof SessionProjectionStateMap, S> {
export interface ProjectionDefinition<K extends string, S> {
key: K
stateSchema: ZodType<S>
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<K, S>` 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).
@@ -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<K extends keyof SessionProjectionStateMap, S> {
export interface ProjectionDefinition<K extends string, S> {
key: K
stateSchema: ZodType<S>
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<K, S>` 携带各单元的宿主状态类型;`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)。
+4 -4
View File
@@ -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. */
+4 -4
View File
@@ -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. */
@@ -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,
@@ -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,
+7 -7
View File
@@ -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`) | - |
+7 -7
View File
@@ -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`) | - |
+16 -16
View File
@@ -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
+8 -8
View File
@@ -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 |
|---|---|---|
+8 -8
View File
@@ -187,7 +187,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
}
```
来源:[`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<T extends SessionEventType = SessionEventType> = {
'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<T extends SessionEventType = SessionEventType> = {
'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)
| 属性 | 存在性 | 类型 |
|---|---|---|
+5 -5
View File
@@ -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"
]
},
{
+2 -2
View File
@@ -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
+5 -8
View File
@@ -28,7 +28,7 @@ interface ProjectionHandle<S> {
## 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<K, S>` carries each unit's host state type locally; registration infers `S` from `stateSchema` and returns `ProjectionHandle<S>`. 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<S> {
* 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<K extends string, S> {
/** The projection key this unit owns. */
key: K
/** Validates persisted state before it seeds a fold. */
stateSchema: ZodType<S>
@@ -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<ProjectionDefinition<K, S>, 'wire'> & { wire: NonNullable<ProjectionDefinition<K, S>['wire']> }, ): Promise<ProjectionHandle<S>>
register<K extends keyof SessionProjectionMap, S>( definition: Omit<ProjectionDefinition<K, S>, 'wire'> & { wire: NonNullable<ProjectionDefinition<K, S>['wire']> }, ): Promise<ProjectionHandle<S>>
/**
* 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<keyof SessionProjectionStateMap, keyof SessionProjectionMap>, S extends SessionProjectionStateMap[K], >( definition: Omit<ProjectionDefinition<K, S>, 'wire'>, ): Promise<ProjectionHandle<S>>
register<K extends string, S>( definition: ProjectionDefinition<K, S> & { key: Exclude<K, keyof SessionProjectionMap> }, ): Promise<ProjectionHandle<S>>
/**
* Subscribe to the change feed. The registration is an effect on the
+5 -8
View File
@@ -28,7 +28,7 @@ interface ProjectionHandle<S> {
## 投影单元
`SessionProjectionStateMap` 是 host 侧折叠状态的 merge-extensible 类型表,`SessionProjectionMap` 则继续表示客户端可见的全量值。领域为每个状态 key 贡献一个 `ProjectionDefinition`;`wire` 块使该 key 对客户端可见,渲染归 slot 体系管,永远不归本层:
`ProjectionDefinition<K, S>` 在各单元内部携带宿主状态类型;注册从 `stateSchema` 推导 `S`,并返回 `ProjectionHandle<S>`。只有客户端可见的 key 合并到 `SessionProjectionMap`,由它约束对应的全量值。`wire` 块使单元对客户端可见,渲染归 slot 体系管,永远不归本层:
```ts type-equiv
/**
@@ -39,11 +39,8 @@ interface ProjectionHandle<S> {
* 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<K extends string, S> {
/** The projection key this unit owns. */
key: K
/** Validates persisted state before it seeds a fold. */
stateSchema: ZodType<S>
@@ -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<ProjectionDefinition<K, S>, 'wire'> & { wire: NonNullable<ProjectionDefinition<K, S>['wire']> }, ): Promise<ProjectionHandle<S>>
register<K extends keyof SessionProjectionMap, S>( definition: Omit<ProjectionDefinition<K, S>, 'wire'> & { wire: NonNullable<ProjectionDefinition<K, S>['wire']> }, ): Promise<ProjectionHandle<S>>
/**
* 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<keyof SessionProjectionStateMap, keyof SessionProjectionMap>, S extends SessionProjectionStateMap[K], >( definition: Omit<ProjectionDefinition<K, S>, 'wire'>, ): Promise<ProjectionHandle<S>>
register<K extends string, S>( definition: ProjectionDefinition<K, S> & { key: Exclude<K, keyof SessionProjectionMap> }, ): Promise<ProjectionHandle<S>>
/**
* Subscribe to the change feed. The registration is an effect on the
@@ -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
@@ -8,14 +8,14 @@ English | [中文](guide.zh.md)
## Change
`@deepseek-ai/dsh-session-projection` changes `SessionProjectionRegistry.register(definition)` from a synchronous disposer to `Promise<ProjectionHandle<S>>`. 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<ProjectionHandle<S>>`. Registry-level `stateOf(session, key)` and `SessionProjectionStateMap` are removed. Host state types stay local to `ProjectionDefinition<K, S>` 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<K, S>` 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<void>`, 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.
@@ -8,14 +8,14 @@ description: "Session 投影注册改为异步,并返回保留读取能力的
## 变更
`@deepseek-ai/dsh-session-projection` 的 `SessionProjectionRegistry.register(definition)` 从同步释放函数改为返回 `Promise<ProjectionHandle<S>>`。注册表级 `stateOf(session, key)` 已移除,注册错误现在使返回的 Promise 拒绝。最后一次注册释放后,该投影单元不再参与快照、检查点和实时通知,但保留的句柄仍可按需折叠 Session 事件。
`@deepseek-ai/dsh-session-projection` 的 `SessionProjectionRegistry.register(definition)` 从同步释放函数改为返回 `Promise<ProjectionHandle<S>>`。注册表级 `stateOf(session, key)` 与 `SessionProjectionStateMap` 已移除。宿主状态类型保留在各自的 `ProjectionDefinition<K, S>` 中,注册时从 `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<K, S>` 的第二个类型参数。保留 `SessionProjectionMap` 中的客户端值声明。对插件自己的定义,在异步 `apply()` 或 `[Service.init]()` 中等待 `ctx.sessionProjections.register(definition)`,并在提供依赖操作前于内部保存句柄。保留现有函数插件命名空间导出。
3. 将 `registry.stateOf(session, key)` 替换为其他领域的业务服务方法,或所有者内部的 `handle.stateOf(session)`。将保存的取消注册回调替换为始终返回 `Promise<void>` 的 `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 释放。已释放的读取句柄仍可使用,而投影单元在最后一次注册解除后会从新快照中消失。
@@ -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
@@ -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
}
@@ -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<typeof legacyPromptSchema>
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)
@@ -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<typeof timeContextStateSchema>
/** The agent registry that owns pre-step processing. */
export const inject = ['agents', 'sessionProjections']
@@ -208,15 +208,6 @@ const tmuxContextStateSchema = zod.object({
time: zod.number(),
}).nullable()
type TmuxContextState = zod.infer<typeof tmuxContextStateSchema>
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.
-7
View File
@@ -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<SessionSeq>)
const turnBoundaryProjectionSchema: zod.ZodType<TurnBoundaryProjection> = zod.object({
-4
View File
@@ -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
@@ -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),
@@ -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<ProjectionDefinition<K, S>, \'wire\'> & { wire: NonNullable<ProjectionDefinition<K, S>[\'wire\']> }, ): Promise<ProjectionHandle<S>>',
signature: 'register<K extends keyof SessionProjectionMap, S>( definition: Omit<ProjectionDefinition<K, S>, \'wire\'> & { wire: NonNullable<ProjectionDefinition<K, S>[\'wire\']> }, ): Promise<ProjectionHandle<S>>',
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<keyof SessionProjectionStateMap, keyof SessionProjectionMap>, S extends SessionProjectionStateMap[K], >( definition: Omit<ProjectionDefinition<K, S>, \'wire\'>, ): Promise<ProjectionHandle<S>>',
signature: 'register<K extends string, S>( definition: ProjectionDefinition<K, S> & { key: Exclude<K, keyof SessionProjectionMap> }, ): Promise<ProjectionHandle<S>>',
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<K extends keyof SessionProjectionStateMap, S extends SessionProjectionStateMap[K] = SessionProjectionStateMap[K]> {\n key: K;\n stateSchema: ZodType<S>;\n init(header: SessionHeader, inheritedEventCount: SessionLogOffset): NoInfer<S>;\n apply(state: NoInfer<S>, event: SessionEvent): NoInfer<S>;\n wire?: K extends keyof SessionProjectionMap ? {\n viewSchema: ZodType<SessionProjectionMap[K]>;\n view(state: NoInfer<S>): SessionProjectionMap[K];\n } : never;\n stateVersion: number;\n}',
declaration: 'export interface ProjectionDefinition<K extends string, S> {\n key: K;\n stateSchema: ZodType<S>;\n init(header: SessionHeader, inheritedEventCount: SessionLogOffset): NoInfer<S>;\n apply(state: NoInfer<S>, event: SessionEvent): NoInfer<S>;\n wire?: K extends keyof SessionProjectionMap ? {\n viewSchema: ZodType<SessionProjectionMap[K]>;\n view(state: NoInfer<S>): 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;',
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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` 推送帧提供客户端值。
### 驱动生命周期
-4
View File
@@ -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'
-3
View File
@@ -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
@@ -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 {
/**
@@ -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
}
}
-6
View File
@@ -107,12 +107,6 @@ const llmRetryStateSchema: zod.ZodType<LlmRetryState> = zod.record(zod.string(),
retry: zod.number().int().nonnegative(),
retryId: zod.string(),
})) as unknown as zod.ZodType<LlmRetryState>
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.
@@ -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)
+2 -7
View File
@@ -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<Session, ReplayState>()
private contextPressureProjectionHandle!: ProjectionHandle<SessionProjectionStateMap['contextPressure']>
private contextPressureProjectionHandle!: ProjectionHandle<ContextPressureState>
constructor(ctx: Context, config: TokenMeterConfig = {}) {
super(ctx, 'tokenMeter')
@@ -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<typeof contextPressureStateSchema>
/** Host fold state for provider pressure and surface adjustments. */
export type ContextPressureState = z.infer<typeof contextPressureStateSchema>
/**
* Token-meter's session projection unit.
-4
View File
@@ -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
@@ -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
@@ -93,14 +93,6 @@ const sandboxModeStateSchema = zod.union([
zod.literal('danger-full-access'),
]).nullable()
type SandboxModeState = zod.infer<typeof sandboxModeStateSchema>
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
@@ -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<string, string>
'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[] }
@@ -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
}
@@ -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
@@ -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<void>`. 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<void>`. 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
@@ -55,7 +55,7 @@ const definition = {
### 注册与读取
`await register(definition)` 安装单元,返回提供同步 `stateOf(session)` 读取和 `dispose(): Promise<void>` 的 handle。等待 `dispose()` 完成即可释放注册;重复调用是安全的。具有相同 key 和 `stateVersion` 的注册方共享 cell;版本不兼容或非法时注册会拒绝。注册归调用方 fiber 所有。最后一个注册方注销后,单元退出全局事件驱动、快照、检查点和变更通知。已有 handle 仍可读取:它保留原有单元,按需折叠新增的 Session 事件,即使同一 key 后来注册了其他版本也不受影响。读取 handle 不会初始化无关单元,也不会重新注册。载体用 `snapshot(session)` 读取一致的客户端视图切面,用 `onChanged(listener)` 订阅已注册单元的变更。
`await register(definition)` 从 `stateSchema` 推导宿主状态类型,安装单元,并返回提供同步 `stateOf(session)` 读取和 `dispose(): Promise<void>` 的 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` 类型表 |
### 驱动与检查点流程
@@ -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<S> {
@@ -61,11 +61,8 @@ export interface ProjectionHandle<S> {
* 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<K extends string, S> {
/** The projection key this unit owns. */
key: K
/** Validates persisted state before it seeds a fold. */
stateSchema: ZodType<S>
@@ -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<K extends keyof SessionProjectionMap, S>(
definition: Omit<ProjectionDefinition<K, S>, 'wire'> & {
wire: NonNullable<ProjectionDefinition<K, S>['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<keyof SessionProjectionStateMap, keyof SessionProjectionMap>,
S extends SessionProjectionStateMap[K],
>(
definition: Omit<ProjectionDefinition<K, S>, 'wire'>,
register<K extends string, S>(
definition: ProjectionDefinition<K, S> & { key: Exclude<K, keyof SessionProjectionMap> },
): Promise<ProjectionHandle<S>>
async register<K extends keyof SessionProjectionStateMap, S extends SessionProjectionStateMap[K]>(
async register<K extends string, S>(
definition: ProjectionDefinition<K, S>,
): Promise<ProjectionHandle<S>> {
const wire = definition.wire as {
@@ -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 {}
@@ -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
}
@@ -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<void> {
const host = await registry.register(counter)
expectTypeOf(host).toEqualTypeOf<ProjectionHandle<number>>()
expectTypeOf(host.stateOf(session)).toEqualTypeOf<number>()
const nullable = await registry.register({
key: 'type-test/nullable',
stateSchema: z.string().nullable(),
stateVersion: 1,
init: () => null,
apply: (state) => {
expectTypeOf(state).toEqualTypeOf<string | null>()
return state
},
})
expectTypeOf(nullable.stateOf(session)).toEqualTypeOf<string | null>()
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<number>()
// @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)
}
@@ -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[] }
@@ -63,12 +63,6 @@ interface SessionStatsState extends SessionStatsTotals {
pendingCalls: Record<string, number>
}
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(),
@@ -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`
@@ -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[]
@@ -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. */
@@ -97,12 +97,6 @@ const stateSchema: z.ZodType<SubagentCatalogState> = 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.
@@ -50,13 +50,6 @@ const timingStateSchema: z.ZodType<TimingState> = 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.
*
@@ -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<AllowedModelRoute[] | null> = zod.array(zod.object({
provider: zod.string().min(1),
model: zod.string().min(1),
-3
View File
@@ -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),
-1
View File
@@ -825,7 +825,6 @@ export const LINK_MAP: Readonly<Record<string, string>> = {
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',