Files
deepseek-harness/packages/session/session-projection
Coder 8719fa84f0
Some checks failed
CI / windows node 24 / wine blocking (push) Has been skipped
CI / node 22.19 (push) Has been skipped
CI / node 26 (push) Has been skipped
CI / python 3.10 / keyless SDK (push) Has been skipped
CI / python runtime / release-shaped Linux x64 (push) Has been skipped
CI / wine apt cache (push) Successful in 7s
CI / serial / linux (push) Has been skipped
Deploy documentation / build (push) Failing after 1m25s
Deploy documentation / deploy (push) Has been skipped
Landlock Run / Matrix (push) Successful in 5s
Release (vendor) / Pack npm tarballs (push) Failing after 2m47s
Release (dsh) / Pack npm tarballs (push) Failing after 1m56s
Sandbox / sandbox e2e (landlock, ubuntu-24.04) (push) Failing after 1m57s
Sandbox / sandbox e2e (bwrap, ubuntu-latest) (push) Failing after 1m19s
Release (vendor) / Publish to npm (push) Has been skipped
Release (dsh) / Publish to npm (push) Has been skipped
CI / serial / windows (self-hosted standby) (push) Has been cancelled
CI / larger-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, typecheck) (push) Has been cancelled
Landlock Run / darwin (no platform package — degradation proof) (push) Has been cancelled
Landlock Run / ${{ matrix.platform }} (push) Has been cancelled
CI / node 24 / static (push) Has been cancelled
CI / node 24 / coverage (push) Has been cancelled
CI / node 24 / snapshots and artifacts (push) Has been cancelled
CI / windows node 24 / native complete (push) Has been cancelled
CI / serial / linux (self-hosted standby) (push) Has been cancelled
CI / serial / macos (push) Has been cancelled
CI / larger-runner-benchmark (16, windows, dsh-windows-2025-16core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (32, windows, dsh-windows-2025-32core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (4, windows, dsh-windows-2025-4core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (64, windows, dsh-windows-2025-64core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (8, windows, dsh-windows-2025-8core, production-site) (push) Has been cancelled
CI / larger-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, typecheck) (push) Has been cancelled
CI / larger-runner-benchmark (96, windows, dsh-windows-2025-96core, production-site) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, linux, dsh-ubuntu-24-04-16core, 16) (push) Has been cancelled
CI / consolidated-runner-benchmark (16, windows, dsh-windows-2025-16core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, linux, dsh-ubuntu-24-04-32core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (32, windows, dsh-windows-2025-32core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, linux, dsh-ubuntu-24-04-4core, 4) (push) Has been cancelled
CI / consolidated-runner-benchmark (4, windows, dsh-windows-2025-4core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, linux, dsh-ubuntu-24-04-64core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (64, windows, dsh-windows-2025-64core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, 8) (push) Has been cancelled
CI / consolidated-runner-benchmark (8, windows, dsh-windows-2025-8core, 2) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, linux, dsh-ubuntu-24-04-96core, 32) (push) Has been cancelled
CI / consolidated-runner-benchmark (96, windows, dsh-windows-2025-96core, 2) (push) Has been cancelled
CI / all checks passed (push) Has been cancelled
Sandbox / sandbox e2e (seatbelt, macos-latest) (push) Has been cancelled
CI / larger-runner-benchmark (8, linux, dsh-ubuntu-24-04-8core, typecheck) (push) Has been cancelled
Sandbox / sandbox e2e (landlock, ubuntu-24.04-arm) (push) Has been cancelled
E2E (real DeepSeek API) / e2e (push) Failing after 1m24s
feat: add economy/maximum presets, tool-lab and subagent-cursor extensions
- new economy and maximum agent presets with three-role pipeline skill
- new packages/extensions/tool-lab (home-lab ComfyUI/Docling/Whishper tools)
- new packages/subagent/subagent-cursor provider
- openrouter balance UI with on-demand refresh
- session projection context-seed boundary fold
- regenerate docs catalogs; keep local searxng benchmark scripts
2026-08-23 22:12:30 +07:00
..
2026-08-17 18:47:02 +08:00

@deepseek-ai/dsh-session-projection

English | 中文

Session-projection Service Definition and drive registry. It owns ctx.sessionProjections, the registry that drives every registered projection unit over committed session events and serves finished whole values to carriers, currently the api-proxy history tail page and session/projection push frame. A domain registers pure mathematics; the framework owns the drive. The session-projection RFC records the design rationale.

Service: SessionProjectionRegistry (ctx key: sessionProjections)

Public API

  • ctx.sessionProjections.register(definition): () => void Register one domain's unit. Duplicate keys and invalid stateVersion throw; the registration is an effect on the calling fiber, so an unloaded domain plugin's key (with its cached cells) disappears from subsequent drives and snapshots — clients read that as capability absence.
  • ctx.sessionProjections.onChanged(listener): () => void Subscribe to the change feed: one call per unit whose state reference changed, per committed event, carrying the schema-validated view and the causing seq. Effect-tied like register.
  • ctx.sessionProjections.snapshot(session): ProjectionSnapshot One consistent synchronous cut over every registered unit — { asOfSeq, values } with asOfSeq = the seq of the last event every value reflects (-1 for an empty log).
  • foldContextOf(header): ProjectionFoldContext Derive the per-session fold context from a session header. Every apply call receives one; a caller folding a detached log (restore) supplies it explicitly.

Key Types

  • SessionProjectionMap — the single merge-extensible type table for the whole chain (host unit, wire block, React hook). Values are wire-JSON whole values; rendering belongs to the slot system, never this layer.
  • ProjectionDefinition<K, S>{ key, schema, init(), apply(state, event, context), view(state), stateVersion }: a state-driven computation unit of three pure synchronous functions plus declarations, never an opaque getter.
  • ProjectionFoldContext — per-session header facts a unit folds against beyond the event stream: seedLength, the durable fork-lineage boundary.

Contract

  • The framework drives, the domain computes. The registry subscribes to session/event once; every committed event passes every unit's apply eagerly. Domains hold no subscriptions. Cells ({state, observedSeq} per unit per session, WeakMap-keyed) build lazily — a unit registered after events flowed, or a read of a session predating the registration, folds init over the in-memory log on first touch.
  • A unit reads session facts through the fold context, never a Session. Every apply call carries ProjectionFoldContext, derived from the session's durable header. Its seedLength is the fork-lineage boundary: events with seq < seedLength were inherited from the forked parent rather than produced by this session. A unit whose value must describe only this session's OWN work (spend, step counts) skips them, so a parent value plus its children's values is a sum rather than a double count; a unit describing the whole conversation (context pressure, the visible transcript) folds them like any other event. A unit needing neither declares two parameters and ignores the third.
  • Same-reference means no work. apply MUST return the same state reference for events that do not concern the unit; the drive gates the change feed on Object.is, so non-matching events cost one call and nothing downstream.
  • Whole-value event rule (load-bearing). A state-carrying log event MUST carry the complete post-change state, never a bare delta — it keeps every transition trivially cheap and every served value self-describing (last-wins for consumers).
  • Synchronous unit discipline. init/apply/view MUST be synchronous; carriers read snapshot() in the same tick as their page slice, which is what makes asOfSeq one consistent cut. An accidentally-async view returns a Promise, which fails the boundary schema.parse loudly.
  • State is plain JSON, stateVersion is its invalidation anchor. The persisted projection cache stores (sessionId, key, ver, seq, val) rows; bump stateVersion whenever the state shape or the fold semantics change so stale rows are discarded instead of forward-applied into garbage.
  • No wire vocabulary here. The registry exposes only the change feed and the snapshot read face; carriers (api-proxy) mint their own frames (session/projection) and blocks from them.
  • Optional capability. Domain plugins register under ctx.inject(['sessionProjections'], …) so headless assemblies without the registry stay unaffected; carriers use ctx.get('sessionProjections') and omit their block/frames entirely when the registry is absent.

Role

This package owns the Service Definition and drive roles of the capability seam: domain host plugins (e.g. dsh-tool-todo) contribute units, carriers (dsh-host-apiproxy) consume the snapshot and change feed, and neither knows the other.

Model Experience

None, as the registry only computes client-facing read models of already-logged session state and touches no prompt, message, schema, stream, or tool result.

KV Cache effect

None; projections never assemble or send provider requests.

Known Limitations and Deferred Work

  • Every tail page carries every registered key — there is no per-key opt-out or lazy-key request shape yet; acceptable while values are UI-scale whole states (a todo list, a goal snapshot), revisit if a domain's value grows large.
  • The unit table is process-wide, so key presence is not a per-session capability signal — a key registered by ANY agent preset appears in every session's snapshot, including sessions whose own composition mounts nothing that produces it. A client must read the VALUE (plan.active, an empty todo list) rather than treat an absent key as absence of the feature; a unit whose empty value is indistinguishable from a real one belongs on the host plane instead, which is why dsh-token-meter sits there.
  • Eager drive touches every unit per event — cheap by construction (whole-value rule, same-reference gate), but a hot path would justify per-unit event-type prefilters, addable without contract change.
  • Registry cells live in memory only — a restart rebuilds by folding the log on first touch; compositions that mount dsh-session-projection-cache seed that fold from persisted rows instead.
  • Synchronous unit discipline is only partially mechanical — the boundary schema.parse rejects a Promise-returning view, but an apply that blocks or reads torn non-session state is a review concern; the invariant companion documents why no runtime check exists.