mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
perf(session-controller): exclude the shared image limits from session summaries
`imageLimits` is a boot constant every Session shares: the unit stores no per-Session state (`stateSchema: z.null()`, `apply: state => state`) and its view returns `ctx.attachments.imageLimits`. A list row therefore repeated one host-wide capability fact on every row. It now carries the summary mark like the three log-derived units, so a summary read skips it while an opened Session still receives it through `session/follow`, the control baseline, and `session.projections`. No other logic changes: the registration, its schema, its constant view, and the host-side prompt validation keep reading `ctx.attachments` directly.
This commit is contained in:
1 parent
ef446fc85f
commit
8e2dd67de8
13 files changed
+44
-37
No files matched your search
+2
-2
@@ -9,8 +9,8 @@
|
||||
en: f5ca718ca5e618c6
|
||||
zh: cbea7f94a2a293b0
|
||||
/agent-note-serve-session-list-rows-from-a-summary-key-set/decision:
|
||||
en: 3477aee912d7e7d9
|
||||
zh: c83280b5a79edac4
|
||||
en: 031d752b8069ef0c
|
||||
zh: 96cc33d309837dec
|
||||
/agent-note-serve-session-list-rows-from-a-summary-key-set/alternatives-considered:
|
||||
en: ce8320f1032018ed
|
||||
zh: 4c5fad5e605bf524
|
||||
|
||||
+2
-2
@@ -13,13 +13,13 @@ A Session-list row carries every registered client view. Three of those views ar
|
||||
The Session summary is every registered client view except the keys whose `SessionProjectionMap` entry carries the summary-exclusion mark.
|
||||
|
||||
- [`packages/session/session-projection/src/types.ts`](../../../../packages/session/session-projection/src/types.ts) declares the type-only mark `SessionProjectionSummaryExcluded<T>` over a unique symbol that is never exported and never present at runtime. `SessionProjectionViewValue<T>` strips it distributively, so a nullable entry keeps its `null`; `SessionProjectionSummaryExcludedKey` tests the non-nullish part; `SessionProjectionSummaryValues` is every view value minus those keys.
|
||||
- Each owning package wraps only its own map entry: `turnOutline` (session-turn-outline), `sessionStats` (session-stats), and `todos` (tool-todo). The todo entry is `SessionProjectionSummaryExcluded<TodoItem[]> | null`, because an intersection with `null` would absorb the null member.
|
||||
- Each owning package wraps only its own map entry: `turnOutline` (session-turn-outline), `sessionStats` (session-stats), `todos` (tool-todo), and `imageLimits` (session-controller's boot-constant attachment limits, which every Session shares). The todo entry is `SessionProjectionSummaryExcluded<TodoItem[]> | null`, because an intersection with `null` would absorb the null member.
|
||||
- Registration is an interlock: `ProjectionDefinition.wire` requires `summary: false` exactly when the key's map entry carries the mark, and accepts only `summary?: never` otherwise. The single runtime erasure of the mark is the wire erasure in `SessionProjectionRegistry.register`, which stores whether the unit belongs to summaries.
|
||||
- [`packages/session/session-projection/src/index.ts`](../../../../packages/session/session-projection/src/index.ts) exposes `summaryKeys(): ReadonlySet<key>`, derived from the live registrations and rebuilt only when a new key registers or a key's last registrant disposes. `cachedSnapshot`, `viewCheckpoint`, and `snapshot` accept `ProjectionKeySelection` (`readonly Key[] | ReadonlySet<Key>`) and use a passed set as-is.
|
||||
- [`packages/session/session-projection-cache/src/index.ts`](../../../../packages/session/session-projection-cache/src/index.ts) forwards that selection unchanged, and [`packages/api/session-controller/src/list.ts`](../../../../packages/api/session-controller/src/list.ts) passes `summaryKeys()` to the live and cold cached faces. `cachedPredecessorTitle` keeps its title-only read.
|
||||
- Client types only: `SessionSummary.projectionValues` narrows to `Partial<SessionProjectionSummaryValues>`, while `SessionProjectionSnapshot.values` keeps every view value. No wire field, function, or UI name changes, and an opened Session still receives every key through `session/follow`, the control baseline, and `session.projections`.
|
||||
|
||||
Estimated effect: with logs whose outlines dominate the projection payload, the three keys are estimated at roughly 60% of a Session-list response for a few hundred Sessions — the outline alone near 57% and the figures and todo list near 5% together — and at roughly 85% of the same response after transport compression, where the outline's unique text barely compresses while the remaining keys do.
|
||||
Estimated effect: with logs whose outlines dominate the projection payload, the four keys are estimated at roughly two thirds of a Session-list response for a few hundred Sessions — the outline alone near 57%, the figures and todo list near 5% together, and the shared image limits near 5% — and at roughly 85% of the same response after transport compression, where the outline's unique text barely compresses while the remaining keys do.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
+2
-2
@@ -13,13 +13,13 @@ Session 列表行携带每个已注册的客户端视图。其中三个视图从
|
||||
Session 摘要就是每个已注册客户端视图,减去 `SessionProjectionMap` 条目带摘要排除标记的键。
|
||||
|
||||
- [`packages/session/session-projection/src/types.ts`](../../../../packages/session/session-projection/src/types.ts) 声明类型层标记 `SessionProjectionSummaryExcluded<T>`,它基于一个从不导出、运行时从不存在的 unique symbol。`SessionProjectionViewValue<T>` 以分发方式去掉标记,可空条目因此保留 `null`;`SessionProjectionSummaryExcludedKey` 取非空部分判断;`SessionProjectionSummaryValues` 是全部视图值减去这些键。
|
||||
- 每个 owning package 只包装自己的 map 条目:`turnOutline`(session-turn-outline)、`sessionStats`(session-stats)、`todos`(tool-todo)。todo 条目写作 `SessionProjectionSummaryExcluded<TodoItem[]> | null`,因为与 `null` 求交会吞掉 null 成员。
|
||||
- 每个 owning package 只包装自己的 map 条目:`turnOutline`(session-turn-outline)、`sessionStats`(session-stats)、`todos`(tool-todo),以及 `imageLimits`(session-controller 的启动常量附件上限,每个 Session 共享)。todo 条目写作 `SessionProjectionSummaryExcluded<TodoItem[]> | null`,因为与 `null` 求交会吞掉 null 成员。
|
||||
- 注册是一道互锁:`ProjectionDefinition.wire` 恰好在该键的 map 条目带标记时要求 `summary: false`,其余情况只接受 `summary?: never`。标记唯一的运行时擦除发生在 `SessionProjectionRegistry.register` 的 wire 擦除处,由它记录该单元是否属于摘要。
|
||||
- [`packages/session/session-projection/src/index.ts`](../../../../packages/session/session-projection/src/index.ts) 提供 `summaryKeys(): ReadonlySet<key>`,从实时注册派生,只有新键注册或某键最后一个注册者注销时才重建。`cachedSnapshot`、`viewCheckpoint`、`snapshot` 接受 `ProjectionKeySelection`(`readonly Key[] | ReadonlySet<Key>`),传入 Set 时直接使用。
|
||||
- [`packages/session/session-projection-cache/src/index.ts`](../../../../packages/session/session-projection-cache/src/index.ts) 原样转发该选择,[`packages/api/session-controller/src/list.ts`](../../../../packages/api/session-controller/src/list.ts) 把 `summaryKeys()` 传给 live 与 cold 两个缓存读取面。`cachedPredecessorTitle` 保持只读 title。
|
||||
- 客户端只有类型变化:`SessionSummary.projectionValues` 收窄为 `Partial<SessionProjectionSummaryValues>`,而 `SessionProjectionSnapshot.values` 保留全部视图值。wire 字段、函数名与 UI 名称均不变;打开的 Session 仍通过 `session/follow`、控制基线与 `session.projections` 收到每个键。
|
||||
|
||||
估算效果:当 outline 在投影负载中占主导时,三个键估计占几百个 Session 时列表响应的约 60% —— outline 单项约 57%,统计与 todo 合计约 5% —— 占传输压缩后同一响应的约 85%,因为 outline 的唯一文本几乎无法压缩,而其余键可以。
|
||||
估算效果:当 outline 在投影负载中占主导时,四个键估计占几百个 Session 时列表响应的约三分之二 —— outline 单项约 57%,统计与 todo 合计约 5%,共享的图片上限约 5% —— 占传输压缩后同一响应的约 85%,因为 outline 的唯一文本几乎无法压缩,而其余键可以。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -141,8 +141,8 @@
|
||||
en: 9edf4ef31e60e880
|
||||
zh: 9edf4ef31e60e880
|
||||
/session-persistence-event-catalog/events/model/model-selection-log-only:
|
||||
en: 0d9e20c2357ae7ac
|
||||
zh: 23401d59e97d6011
|
||||
en: 5332aa18683a642f
|
||||
zh: 025aa9bd6c4e022f
|
||||
/session-persistence-event-catalog/events/permission:
|
||||
en: 19917bc5438e60af
|
||||
zh: 19917bc5438e60af
|
||||
@@ -1146,8 +1146,8 @@
|
||||
en: 3b677f021d7dd4d3
|
||||
zh: 2a875742b22879a2
|
||||
/session-persistence-event-catalog/resolved-persistence-types/modelselection:
|
||||
en: 6d66ffc1b393f2f2
|
||||
zh: ef6cb30b71f287e7
|
||||
en: e93aa07ba5b5c4a7
|
||||
zh: d6b13c93675d3d0e
|
||||
/session-persistence-event-catalog/resolved-persistence-types/oneshotscheduledispatchchange:
|
||||
en: a3300babe57b6b67
|
||||
zh: 4aaf06a149b399c3
|
||||
@@ -1347,8 +1347,8 @@
|
||||
en: 2786fef560851bb4
|
||||
zh: 5d787475356b2606
|
||||
/session-persistence-event-catalog/resolved-persistence-types/string:
|
||||
en: 009c7ecb8c7d3bb5
|
||||
zh: 7f56d672f376b22f
|
||||
en: c0dbca0eaef2b953
|
||||
zh: 2a8410c6368cb974
|
||||
/session-persistence-event-catalog/resolved-persistence-types/string~2:
|
||||
en: 0089620bf4638263
|
||||
zh: 1922bef1713094bb
|
||||
@@ -1833,8 +1833,8 @@
|
||||
en: 809a23c25ded8497
|
||||
zh: e9cd23e281f8d31f
|
||||
/session-persistence-event-catalog/resolved-persistence-types/kind-user:
|
||||
en: 9b6318ab4d7eba12
|
||||
zh: f475439ef40b2681
|
||||
en: 59ba32e3350c1b79
|
||||
zh: 3121b41aab435bda
|
||||
/session-persistence-event-catalog/resolved-persistence-types/kind-user-approval:
|
||||
en: a52d2dfbaf844127
|
||||
zh: 4c5306ca40f20873
|
||||
|
||||
@@ -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:45`](../packages/api/session-controller/src/types.ts)
|
||||
|
||||
### `permission/*`
|
||||
|
||||
@@ -4337,7 +4337,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:105`](../packages/api/session-controller/src/types.ts)
|
||||
|
||||
| Property | Presence | Type |
|
||||
|---|---|---|
|
||||
@@ -5583,7 +5583,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:413`](../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`
|
||||
|
||||
@@ -7554,7 +7554,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:422`](../packages/api/session-controller/src/types.ts)
|
||||
|
||||
| Property | Presence | Type |
|
||||
|---|---|---|
|
||||
|
||||
@@ -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:45`](../packages/api/session-controller/src/types.ts)
|
||||
|
||||
### `permission/*`
|
||||
|
||||
@@ -4339,7 +4339,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:105`](../packages/api/session-controller/src/types.ts)
|
||||
|
||||
| 属性 | 存在性 | 类型 |
|
||||
|---|---|---|
|
||||
@@ -5585,7 +5585,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:413`](../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`
|
||||
|
||||
@@ -7556,7 +7556,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:422`](../packages/api/session-controller/src/types.ts)
|
||||
|
||||
| 属性 | 存在性 | 类型 |
|
||||
|---|---|---|
|
||||
|
||||
Generated
+3
-3
@@ -23574,7 +23574,7 @@
|
||||
"packages/workflow/workflow/src/types.ts#WorkflowRunId"
|
||||
],
|
||||
"sources": [
|
||||
"packages/api/session-controller/src/types.ts:409",
|
||||
"packages/api/session-controller/src/types.ts:413",
|
||||
"packages/attachment/attachment/src/brand.ts:6",
|
||||
"packages/compaction/compaction/src/brand.ts:4",
|
||||
"packages/core/session/src/types.ts:21",
|
||||
@@ -24096,7 +24096,7 @@
|
||||
"digest": "6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def",
|
||||
"names": [],
|
||||
"sources": [
|
||||
"packages/api/session-controller/src/types.ts:418"
|
||||
"packages/api/session-controller/src/types.ts:422"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -25916,7 +25916,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:105"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -98,6 +98,7 @@ export class ApiSessionList {
|
||||
wire: {
|
||||
viewSchema: imageLimitsSchema,
|
||||
view: () => attachmentCtx.attachments.imageLimits,
|
||||
summary: false,
|
||||
},
|
||||
stateVersion: 1,
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { Branded } from '@deepseek-ai/dsh-brand'
|
||||
import type { LlmAttemptId, MessageId } from '@deepseek-ai/dsh-llm/brand'
|
||||
import type { TextBlock } from '@deepseek-ai/dsh-llm'
|
||||
import type { SessionId, SessionSeqCursor } from '@deepseek-ai/dsh-session/types'
|
||||
import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types'
|
||||
import type { SessionProjectionMap, SessionProjectionSummaryExcluded } from '@deepseek-ai/dsh-session-projection/types'
|
||||
import type { Principal } from '@deepseek-ai/dsh-typert-protocol'
|
||||
import type { JsonValue } from '@deepseek-ai/dsh-util-values'
|
||||
import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types'
|
||||
@@ -25,8 +25,12 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
|
||||
interface SessionProjectionMap {
|
||||
/** Persisted facts used to summarize a Session without activating it. */
|
||||
sessionListMetadata: SessionListMetadata
|
||||
/** Image-intake limits enforced by the Session prompt endpoint. */
|
||||
imageLimits: ImageAttachmentLimits
|
||||
/**
|
||||
* Image-intake limits enforced by the Session prompt endpoint. Boot
|
||||
* constant, excluded from Session summary payloads: every Session shares
|
||||
* it, so a list row would repeat one host-wide fact.
|
||||
*/
|
||||
imageLimits: SessionProjectionSummaryExcluded<ImageAttachmentLimits>
|
||||
/** Durable model selection already used and selected for the next request. */
|
||||
modelSelection: ModelSelectionProjection
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Session-list summary payloads: a `session.list` row carries every registered
|
||||
* wire projection except the three units that declare `summary: false`
|
||||
* (`turnOutline`, `sessionStats`, `todos`), while an opened Session's
|
||||
* wire projection except the units that declare `summary: false`
|
||||
* (`turnOutline`, `sessionStats`, `todos`, `imageLimits`), while an opened Session's
|
||||
* `session/follow` opening snapshot keeps serving them.
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
} from '@deepseek-ai/dsh-tool-todo'
|
||||
import { createSessionTestRemote } from './test-remote.ts'
|
||||
|
||||
const SUMMARY_EXCLUDED_KEYS = ['turnOutline', 'sessionStats', 'todos'] as const
|
||||
const SUMMARY_EXCLUDED_KEYS = ['turnOutline', 'sessionStats', 'todos', 'imageLimits'] as const
|
||||
|
||||
const ownedContexts = new Set<Context>()
|
||||
afterEach(async () => {
|
||||
@@ -112,7 +112,7 @@ describe('session.list summary payload', () => {
|
||||
expect(row?.projections?.values.sessionListMetadata).toMatchObject({ blank: false })
|
||||
})
|
||||
|
||||
it('keeps the three units on an opened Session\'s follow snapshot', async () => {
|
||||
it('keeps the excluded units on an opened Session\'s follow snapshot', async () => {
|
||||
const { ctx } = await harness()
|
||||
const { id } = seedSession(ctx)
|
||||
const session = ctx.sessions.get(id)
|
||||
@@ -126,9 +126,10 @@ describe('session.list summary payload', () => {
|
||||
.toEqual(everyValue[key as keyof typeof everyValue])
|
||||
}
|
||||
expect(snapshot.projections.values.todos).toEqual([{ content: 'ship it', status: 'in_progress' }])
|
||||
expect(snapshot.projections.values.imageLimits).toEqual(ctx.attachments.imageLimits)
|
||||
})
|
||||
|
||||
it('drops the three units from the list while a Session is still attached', async () => {
|
||||
it('drops the excluded units from the list while a Session is still attached', async () => {
|
||||
const { ctx } = await harness()
|
||||
const { id } = seedSession(ctx)
|
||||
// Two consecutive pulls: a refresh must not reintroduce a dropped unit.
|
||||
@@ -139,6 +140,7 @@ describe('session.list summary payload', () => {
|
||||
expect(row?.projections?.values, `attempt ${String(attempt)}`).not.toHaveProperty('turnOutline')
|
||||
expect(row?.projections?.values, `attempt ${String(attempt)}`).not.toHaveProperty('sessionStats')
|
||||
expect(row?.projections?.values, `attempt ${String(attempt)}`).not.toHaveProperty('todos')
|
||||
expect(row?.projections?.values, `attempt ${String(attempt)}`).not.toHaveProperty('imageLimits')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -30,8 +30,8 @@
|
||||
en: 3bbc61a438aeabd0
|
||||
zh: bd1824f4da278764
|
||||
/deepseek-ai-dsh-session-projection/use-this-package/session-summaries:
|
||||
en: f025ff71f632c377
|
||||
zh: fcaef391a951b919
|
||||
en: 4a9e068f1d672b61
|
||||
zh: 373ace99986e7627
|
||||
/deepseek-ai-dsh-session-projection/understand-the-implementation:
|
||||
en: 3397f58d6f49bfda
|
||||
zh: efb85d382e25574d
|
||||
|
||||
@@ -72,7 +72,7 @@ Every unit's state is checkpointed — client-visible and host-only alike — th
|
||||
|
||||
A Session summary is every registered client view except the keys whose non-nullish `SessionProjectionMap` entry carries the `SessionProjectionSummaryExcluded<T>` mark. `summaryKeys()` returns that set, derived from the live registrations and stable — the same instance — until a registration or its disposal changes the key table. A summary consumer passes it to the existing key-taking reads — `cachedSnapshot(session, keys)` for live cells, `viewCheckpoint(rows, keys)` for checkpoint rows, and `cachedSnapshot(header, keys)` through the persisted cache — which treat a set as already selected, so there is no summary-specific read face, no copy per read, and no second definition of the set. Because the registry derives it, a consumer cannot request an excluded key and cannot drift from the marks the owning units declare.
|
||||
|
||||
The mark and the registration are one interlock: a key whose map entry carries the mark must declare `wire.summary: false`, and a key without the mark cannot declare it. A nullable entry keeps `null` outside the wrapper (`SessionProjectionSummaryExcluded<TodoItem[]> | null`) so the pre-first-write value stays expressible. The keys currently marked are `turnOutline`, `sessionStats`, and `todos`: an outline grows with the whole log, and no list row renders the stats or todo list.
|
||||
The mark and the registration are one interlock: a key whose map entry carries the mark must declare `wire.summary: false`, and a key without the mark cannot declare it. A nullable entry keeps `null` outside the wrapper (`SessionProjectionSummaryExcluded<TodoItem[]> | null`) so the pre-first-write value stays expressible. The keys currently marked are `turnOutline`, `sessionStats`, `todos`, and `imageLimits`: an outline grows with the whole log, no list row renders the stats or todo list, and the image limits are one host-wide boot constant every Session shares.
|
||||
|
||||
Summaries serve the Session list rows, which list Sessions without opening them. The `@` reference lists Sessions the same way but reads only its `title` and `subagent` label keys through the key-taking `snapshot(session, keys)` and `cachedSnapshot(header, keys)` faces. `snapshot`, `cachedSnapshot`, and `viewCheckpoint` still serve every wire key when called without a key subset, so an opened Session receives every projected value.
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ const { asOfSeq, values } = ctx.sessionProjections.snapshot(session)
|
||||
|
||||
Session 摘要包含每个已注册客户端视图,但排除 `SessionProjectionMap` 条目(非空值)带 `SessionProjectionSummaryExcluded<T>` 标记的 key。`summaryKeys()` 返回该集合,从实时注册派生;在注册或注销改变 key 表之前,它保持同一实例。摘要消费方把它传给既有的带 key 读取面 —— 实时 cell 用 `cachedSnapshot(session, keys)`,checkpoint 行用 `viewCheckpoint(rows, keys)`,持久化缓存用 `cachedSnapshot(header, keys)` —— 这些读取面把 Set 视为已选好的集合,因此不存在摘要专用读取面、每次读取无需复制,集合也只有一处定义。由于集合由注册表派生,消费方既无法请求被排除的 key,也不会与各 owning unit 声明的标记漂移。
|
||||
|
||||
标记与注册是一道互锁:map 条目带标记的 key 必须声明 `wire.summary: false`,没有标记的 key 不能声明。可空条目把 `null` 放在包装之外(`SessionProjectionSummaryExcluded<TodoItem[]> | null`),以便首次写入前的值仍可表达。当前被标记的 key 是 `turnOutline`、`sessionStats` 和 `todos`:outline 随整份日志增长,而列表行不渲染统计或 todo 清单。
|
||||
标记与注册是一道互锁:map 条目带标记的 key 必须声明 `wire.summary: false`,没有标记的 key 不能声明。可空条目把 `null` 放在包装之外(`SessionProjectionSummaryExcluded<TodoItem[]> | null`),以便首次写入前的值仍可表达。当前被标记的 key 是 `turnOutline`、`sessionStats`、`todos` 和 `imageLimits`:outline 随整份日志增长,列表行不渲染统计或 todo 清单,而图片上限是每个 Session 共享的同一个宿主级启动常量。
|
||||
|
||||
摘要服务于 Session 列表行,列表无需打开 Session。`@` 引用同样以列表方式枚举 Session,但只通过带 key 的 `snapshot(session, keys)` 与 `cachedSnapshot(header, keys)` 读取其 `title` 和 `subagent` 标签 key。`snapshot`、`cachedSnapshot` 和 `viewCheckpoint` 在不传 key 子集时仍返回每个 wire key,因此打开的 Session 仍会收到全部投影值。
|
||||
|
||||
|
||||
Reference in new issue
Block a user