Merge origin/master into feat/website-docs
Conflict resolution notes: - package.json/run-gates: both sides' new doc-sync gates kept (master's scoped-events/readme gates + this branch's website-api/website-yaml); js-yaml devDeps deduped (master added them independently). - pnpm-workspace/knip: website AND python/sdk-runtime entries kept. - doc-typecheck/verify-type-equiv: master's condensed headers kept, website glob retained in both scan scopes. - vendor/cordis/src/fiber.ts: master's lifecycle-hardening code taken; this branch's richer FiberState JSDoc reapplied on top. vendor/README.md logs both local modifications (hardening = 6, JSDoc enrichment = 7). - pnpm-lock: regenerated from master's side (pnpm install). Post-merge sync the gates forced (the system working as designed): - verify-website-yaml caught 4 stale plugin names from master's package reorg (dsh-stdio-agent -> dsh-stdio-demo, dsh-acp-agent -> dsh-acp-demo); 8 references fixed across guide/ and develop/. - gen-website-api picked up master's 6 new services automatically (ctx.approval/permission/sandbox/sessionQuery/skills/tasks -> 6 new pages + sidebar); api/index.md hub updated to list them. - AGENTS.md budget ceiling 1370 -> 1400: the website rows (layout line + two command lines) and master's own growth collided with the old ceiling; all three website rows are load-bearing (new top-level dir, new CI command).
This commit is contained in:
@@ -4,13 +4,9 @@
|
||||
|
||||
`CompactService` (abstract seam) — provided by `@deepseek-ai/dsh-compact`.
|
||||
|
||||
Abstract compaction service. Subclass implement the two abstract methods, and load the subclass as a plugin — it registers as `ctx.compact` (one implementation per context; loading a second throws, which is cordis' standard duplicate-service behavior).
|
||||
Both core methods are abstract: the contract states WHAT compaction does, while the entire strategy — token estimation, retention policy, event sequencing, summarization — is a HOW decision owned by the implementation.
|
||||
Implementations MUST honor:
|
||||
- **Surface contract**: a successful compaction shadows the compacted surface nodes with a SINGLE replacement node carrying the summary. Because `SurfaceEventType` is a closed union, that node is a `user/message` with `surfaceOp: { op:'replace', start, end }`; the `compact/*` events are log-only (lock + provenance).
|
||||
- **Blocking**: no compaction begins while another is in progress for the same session. The recommended mechanism is the log-recorded lock — append `compact/start` before the slow work and `compact/end` after (even on failure) — so the lock is visible to replay and crash recovery.
|
||||
Abstract compaction service. Implementations own token estimation, retention, and summarization, but a successful run must replace the selected surface span with one summary node and prevent concurrent compaction of the same session. Load one implementation per context as `ctx.compact`.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/compact/compact/src/index.ts#L65)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/compact/compact/src/index.ts#L36)
|
||||
|
||||
### ctx.compact.compactIfNeeded(agent, fullSystemPrompt, sessionPrefix, signal)
|
||||
|
||||
@@ -18,21 +14,16 @@ Implementations MUST honor:
|
||||
abstract compactIfNeeded( agent: CompactAgentContext, fullSystemPrompt: string, sessionPrefix: readonly Message[], signal: AbortSignal, ): Promise<CompactionResult | null>
|
||||
```
|
||||
|
||||
Check token pressure and compact if the conversation is too large.
|
||||
Estimates the NEXT request's size — the session prefix, the surface-derived history, and the system prompt — and if it exceeds the backend's threshold, compacts an older range via compactRegion, keeping recent context intact. Returns `null` when no compaction is needed.
|
||||
Scope and guarantees a backend MUST honor:
|
||||
- **Compaction acts on surface-derived history only**, but the ESTIMATE counts everything the request carries: the loop composes the session prefix before the pre-step seam fires and hands it here, so the gate sees the prefix this instance will actually send (`EpochHeader.messagePrefix` — request-only, never derived history). Non-surface context injected downstream (into the request `messages` by a later listener) is out of this accounting by construction.
|
||||
- **Head-anchored, best-effort.** Auto-compaction consolidates from the surface HEAD up to a balanced tool-pairing cutoff, so a prior head checkpoint is re-summarized into one fresh checkpoint (the surface holds at most one auto-generated checkpoint, always at the head). It is best-effort over CLOSED steps: when the only compactable content left is an un-splittable open tail step, it declines (`null`) and retries once that step closes.
|
||||
- **Single-unit overflow is out of scope.** If a single retained unit (one closed step, or a large free node such as a pasted `user/message`) ALONE exceeds the budget, compaction cannot help and the call may go out over-budget. Bounding an individual unit's size is a separate concern — as is a session prefix that alone approaches the window (a configuration error no compactor fixes: compaction cannot shrink the prefix).
|
||||
Check token pressure and compact if the conversation is too large. Estimate the next request, including its session prefix, derived history, and system prompt. Above threshold, compact a head-anchored range ending at a balanced tool boundary and reconsolidate any prior automatic checkpoint. Return `null` when no compaction is needed or an open tail leaves no safe cutoff. A single oversized retained unit or prefix cannot be repaired here.
|
||||
|
||||
- `agent` — agent context owning the session surface and model options.
|
||||
- `fullSystemPrompt` — assembled system prompt, counted toward the estimate.
|
||||
- `sessionPrefix` — the instance's composed session prefix, counted toward the estimate.
|
||||
- `signal` — cancellation signal. A backend summarizing via `ctx.llm.stream()` MUST forward this into the call's `GenerateOptions.signal` so an abort/dispose tears down the in-flight summarization rather than leaving an orphaned model call running past the cancellation.
|
||||
- `signal` — cancellation signal; model-backed implementations must forward it.
|
||||
|
||||
**Returns** the compaction result, or `null` if no compaction was needed.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/compact/compact/src/index.ts#L111)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/compact/compact/src/index.ts#L56)
|
||||
|
||||
### ctx.compact.compactRegion(session, start, end, agent, signal?)
|
||||
|
||||
@@ -40,16 +31,14 @@ Scope and guarantees a backend MUST honor:
|
||||
abstract compactRegion( session: Session, start: number, end: number, agent: CompactAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>
|
||||
```
|
||||
|
||||
Forcibly compact a range of surface nodes into a single summary node.
|
||||
`start` and `end` are inclusive seqs of surface nodes to shadow; the backend summarizes their content and appends a replacement surface node. Used by the (future) `/compact` tool and internally by compactIfNeeded.
|
||||
The region MUST NOT split a step's `assistant/message` tool-calls from their `tool/result`s, leaving the rehydrated transcript with a dangling tool-call or an orphaned tool-result that every provider rejects. A region is safe iff both its edges are balanced cuts on the surface: the cut before `start` and the cut after `end` each have no unanswered tool-call before them. A node that belongs to no step (a pre-step user message, inter-step steering, or an injection context message) is a balanced (free) boundary; an `end` inside an open (unclosed) tail step is invalid — its tool-calls have no results yet. `dsh-session` exports `isToolPairingBalanced` for this check.
|
||||
Forcibly compact a range of surface nodes into a single summary node. `start` and `end` name an inclusive span by surface position, not numeric seq order; replacements can make visible seqs non-monotonic. Both edges must be balanced so assistant tool calls remain paired with their results. A model- backed implementation forwards cancellation and rejects active, missing, reversed, or unbalanced ranges.
|
||||
|
||||
- `session` — the session whose surface is mutated.
|
||||
- `start` — inclusive seq of the first surface node to compact.
|
||||
- `end` — inclusive seq of the last surface node to compact.
|
||||
- `agent` — agent context used by router-aware summarizers.
|
||||
- `signal` — optional cancellation signal. A backend that summarizes via `ctx.llm.stream()` MUST forward this into the call's `GenerateOptions.signal` so an abort/dispose tears down the in-flight summarization rather than leaving an orphaned model call running past the cancellation.
|
||||
- `session` — session to mutate.
|
||||
- `start` — first surface seq, inclusive.
|
||||
- `end` — last surface seq, inclusive.
|
||||
- `agent` — summarizer context.
|
||||
- `signal` — optional cancellation; model-backed implementations must forward it.
|
||||
|
||||
**Returns** what the compaction did (the replaced range and its summary node).
|
||||
**Returns** the replaced range and summary.
|
||||
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/compact/compact/src/index.ts#L151)
|
||||
[Source](https://github.com/deepseek-harness/deepseek-harness/blob/master/packages/compact/compact/src/index.ts#L79)
|
||||
|
||||
Reference in New Issue
Block a user