Files
deepseek-harness/packages/session/session-projection/README.zh.md
T
pku-xht 84cbec28e9 Merge remote-tracking branch 'origin/master' into codex/localized-chinese-doc-links
# Conflicts:
#	.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.i18n.yaml
#	.agents/notes/implemented/architecture/2026-06-11-content-block-vocabulary.zh.md
#	.agents/notes/implemented/architecture/2026-06-18-shared-persistence-write-coordinator.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md
#	.agents/notes/implemented/bug-fix/2026-07-29-pnpm-setup-runner-isolation.i18n.yaml
#	.agents/notes/implemented/bug-fix/2026-07-29-pnpm-setup-runner-isolation.zh.md
#	.agents/notes/implemented/bug-fix/2026-08-18-request-image-payload-bound.i18n.yaml
#	.agents/notes/implemented/bug-fix/2026-08-18-request-image-payload-bound.zh.md
#	.agents/notes/implemented/feature/2026-07-06-sandbox.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-06-sandbox.zh.md
#	.agents/notes/implemented/feature/2026-07-16-persistent-pty-sessions.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-21-cross-session-references.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-21-cross-session-references.zh.md
#	.agents/notes/implemented/feature/2026-07-22-web-multimodal-image-input-and-durable-attachments.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-22-web-multimodal-image-input-and-durable-attachments.zh.md
#	.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-31-permission-default-for-new-sessions.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-03-web-search-source-scroll.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-03-web-search-source-scroll.zh.md
#	.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md
#	.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md
#	.agents/notes/implemented/feature/2026-08-11-workspace-sidebar-order-and-folding.i18n.yaml
#	.agents/notes/implemented/feature/2026-08-15-product-subagent-noninteractive-permissions.i18n.yaml
#	.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.i18n.yaml
#	.agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.zh.md
#	.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.i18n.yaml
#	.agents/notes/implemented/process/2026-07-22-evidence-based-larger-hosted-runners.zh.md
#	.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.i18n.yaml
#	.agents/notes/implemented/process/2026-07-23-portable-required-pull-request-ci.zh.md
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.i18n.yaml
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.zh.md
#	.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.i18n.yaml
#	.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md
#	.agents/notes/proposed/architecture/2026-07-27-session-projection-and-command-log.i18n.yaml
#	README.i18n.yaml
#	README.zh.md
#	docs/architecture.i18n.yaml
#	docs/architecture.zh.md
#	docs/development.i18n.yaml
#	docs/development.zh.md
#	docs/persistence-catalog.i18n.yaml
#	docs/persistence-catalog.zh.md
#	docs/subsystems/README.i18n.yaml
#	docs/subsystems/README.zh.md
#	docs/subsystems/agent-team.i18n.yaml
#	docs/subsystems/agent-team.zh.md
#	docs/subsystems/client-modules.i18n.yaml
#	docs/subsystems/client-modules.zh.md
#	docs/subsystems/commands.i18n.yaml
#	docs/subsystems/commands.zh.md
#	docs/subsystems/persistence.i18n.yaml
#	docs/subsystems/persistence.zh.md
#	docs/subsystems/session-reference.i18n.yaml
#	docs/tool-catalog.i18n.yaml
#	docs/tool-catalog.zh.md
#	docs/user/guide/providers.i18n.yaml
#	docs/user/guide/providers.zh.md
#	packages/README.i18n.yaml
#	packages/README.zh.md
#	packages/bundle/web-app/README.i18n.yaml
#	packages/bundle/web-app/README.zh.md
#	packages/client/README.i18n.yaml
#	packages/client/README.zh.md
#	packages/client/connection/README.i18n.yaml
#	packages/client/connection/README.zh.md
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.zh.md
#	packages/client/ui-primitives/README.i18n.yaml
#	packages/client/ui-primitives/README.zh.md
#	packages/client/ui-sidebar/README.i18n.yaml
#	packages/client/ui-sidebar/README.zh.md
#	packages/client/ui-workspace/README.i18n.yaml
#	packages/client/ui-workspace/README.zh.md
#	packages/context/README.i18n.yaml
#	packages/context/README.zh.md
#	packages/core/agent-loop/README.i18n.yaml
#	packages/credentials/README.i18n.yaml
#	packages/credentials/README.zh.md
#	packages/experimental/agent-team/README.i18n.yaml
#	packages/experimental/agent-team/README.zh.md
#	packages/experimental/tool-agent-team/README.i18n.yaml
#	packages/experimental/tool-agent-team/README.zh.md
#	packages/host/frontend-static/README.i18n.yaml
#	packages/host/frontend-static/README.zh.md
#	packages/host/webserver/README.i18n.yaml
#	packages/host/webserver/README.zh.md
#	packages/interaction/commands/README.i18n.yaml
#	packages/interaction/commands/README.zh.md
#	packages/plan/plan-mode/README.i18n.yaml
#	packages/plan/plan-mode/README.zh.md
#	packages/sandbox/sandbox-local/README.i18n.yaml
#	packages/sandbox/sandbox-local/README.zh.md
#	packages/session/README.i18n.yaml
#	packages/session/README.zh.md
#	packages/session/session-persistence-sqlite/README.i18n.yaml
#	packages/session/session-persistence-sqlite/README.zh.md
#	packages/session/session-projection-cache/README.i18n.yaml
#	packages/session/session-projection-cache/README.zh.md
#	packages/shell/tool-pwsh/README.i18n.yaml
#	packages/shell/tool-pwsh/README.zh.md
#	packages/subagent/subagent-codex/README.i18n.yaml
#	packages/subagent/subagent-codex/README.zh.md
#	packages/subagent/subagent/README.i18n.yaml
#	packages/subagent/subagent/README.zh.md
#	packages/web/tool-web/README.i18n.yaml
#	packages/web/tool-web/README.zh.md
#	scripts/snapshots/translation-prompt-v4/request-response.expected.json
2026-08-20 19:15:33 +08:00

6.0 KiB
Raw Blame History

@deepseek-ai/dsh-session-projection

English | 中文

会话投影 Service Definition 与驱动注册表。它拥有 ctx.sessionProjections:该注册表在已提交的会话事件上驱动每个已注册的投影单元,并向载体提供完整的最终值,目前包括 api-proxy 历史尾页和 session/projection 推送帧。领域注册的只是纯数学;驱动权归框架。session-projection RFC 记录了设计理由。

服务:SessionProjectionRegistryctx 键:sessionProjections

公开 API

  • ctx.sessionProjections.register(definition): () => void 注册一个领域的单元。key 重复或 stateVersion 非法都会 throw;注册是挂在调用方 fiber 上的 effect,领域插件卸载后其 key(连同缓存的 cell)从后续驱动与快照中消失——客户端将其读作能力缺失。
  • ctx.sessionProjections.onChanged(listener): () => void 订阅变更流:每个已提交事件、每个状态引用发生变化的客户端可见单元各回调一次,携带经 schema 校验的 view 与致因 seq。与 register 一样绑定 effect。
  • ctx.sessionProjections.stateOf(session, key) 读取一个已注册单元的当前 host 状态,不计算无关 view。返回值是活的只读引用;调用方不得修改。
  • ctx.sessionProjections.snapshot(session): ProjectionSnapshot 对全部已注册客户端可见单元做一次一致的同步切面——{ asOfSeq, values },其中 asOfSeq = 所有值共同反映到的最后一个事件的 seq(空日志为 -1)。host-only 状态只能通过 stateOf 读取。

关键类型

  • SessionProjectionMap——协议块与客户端钩子共享的 merge-extensible client view 表。值是协议层 JSON 全量值;渲染归 slot 体系管,永远不归本层。
  • SessionProjectionStateMap——merge-extensible host 折叠状态表。每个 client-visible key 同时出现在两个表中;host-only key 只出现在这里。
  • ProjectionDefinition<K, S>——{ key, stateSchema, init(), apply(state, event), wire?, stateVersion }:同步的状态驱动计算单元。wire 提供 viewSchemaview;省略它即为 host-only 单元。

约定

  • 框架负责驱动,领域负责计算。 注册表只订阅一次 session/event;每个已提交事件都会主动经过每个单元的 apply。领域不持有任何订阅。cell(每会话每单元一份 {state, observedSeq},以 WeakMap 为键)惰性构建——在事件流过之后才注册的单元,或读取一个早于该注册的会话,都在首次触达时从 init 出发在内存日志上折叠。
  • 同引用即无工作。 对与单元无关的事件,apply 必须返回同一个状态引用;驱动以 Object.is 把守变更流,因此不匹配的事件只花一次调用,不产生任何下游工作。
  • 全量值事件规则(承重)。 携带状态的日志事件必须携带变更后的完整状态,绝不携带裸增量——这让每次状态转移始终足够廉价,也让每个被供给的值自描述(对消费方即 last-wins)。
  • 单元的同步纪律。init/apply/wire.view 必须是同步的;载体在切出页面切片的同一 tick 内读取 snapshot()asOfSeq 之所以是一个一致切面正系于此。误写成异步的 view 会返回 Promise,并被 wire.viewSchema.parse 拒绝。
  • 状态是经校验的纯 JSONstateVersion 是其失效锚点。 持久投影缓存存储 (sessionId, key, ver, seq, val) 行,并在使用前以 stateSchema 校验 val;状态字段或折叠语义一旦变化就递增 stateVersion。每个单元的状态都会被检查点化——client-visible 与 host-only 一视同仁。
  • 本层没有协议词汇。 注册表只暴露变更流与快照读取面;载体(api-proxy)据此自铸各自的帧(session/projection)与块。
  • 可选能力。 领域插件在 ctx.inject(['sessionProjections'], …) 下注册,因此不带注册表的 headless 组装完全不受影响;载体使用 ctx.get('sessionProjections'),注册表缺席时完全省略自己的块与帧。

职责

本包承担能力 seam 的 Service Definition 与驱动角色:领域 host 插件(如 dsh-tool-todo)贡献单元,载体(dsh-host-apiproxy)消费快照与变更流,两侧互不相识。

模型体验

无——注册表只对已入日志的会话状态计算面向客户端的读模型,不触碰任何提示词、消息、schema、流或工具结果。

KV Cache 影响

无;投影从不组装或发送提供方请求。

已知限制与暂缓事项

  • 每个尾页携带每个 client-visible key——尚无逐 key 的 opt-out 或惰性 key 请求形状;在值都是 UI 量级的全量状态(一张 todo 清单、一份 goal 快照)时可以接受,若某领域的值变大再重议。
  • 单元表是进程级的,因此 key 是否存在不能当作逐会话的能力信号——只要任何一个 agent preset 注册了某个 key,它就出现在每个会话的快照里,包括自身组装完全不产出该值的会话。客户端必须读plan.active、空的 todo 列表),不能把 key 缺席当作功能缺席;如果某个单元的空值与真实值无法区分,它就该待在宿主平面——dsh-token-meter 正因如此留在那里。
  • 主动驱动(eager drive)逐事件触达每个单元——按构造开销很低(全量值规则、同引用闸门),但若出现热点路径,可加按单元的事件类型预过滤,约定不变。
  • 注册表 cell 只活在内存里——重启后首次触达时靠折叠日志重建;挂载了 dsh-session-projection-cache 的组合改由持久行播种该折叠。
  • 单元同步纪律只有部分可机械把关——wire.viewSchema.parse 能拒绝返回 Promise 的 view,但阻塞的 apply、或读取撕裂的非会话状态的 apply,只能靠评审把关;invariant 配套项记载了为何不存在运行时检查。