dsh-context-mode 0.3.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -124,7 +124,7 @@ node node_modules/dsh-context-mode/scripts/cleanup-injected.mjs --db <path>
124
124
  node node_modules/dsh-context-mode/scripts/cleanup-injected.mjs --db <path> --apply # delete
125
125
  ```
126
126
 
127
- ## Checkpoint archive index
127
+ ## Checkpoint transcript and archive index
128
128
 
129
129
  A checkpoint keeps only a summary of the span it replaces, and the shipped
130
130
  checkpoint format has no section for tool output — a long tool result survives
@@ -132,39 +132,20 @@ only as whatever the summarizing model chose to keep. `precompact` files that
132
132
  same span into the knowledge base beforehand, but nothing told the model so,
133
133
  and a summary that omits a detail reads as if the detail never existed.
134
134
 
135
- This package also exports a compaction engine that closes that gap. It extends
136
- the shipped `BasicCompactionEngine` and overrides only `summarize()`, appending
137
- an `## Archive Index` that names the archived sources:
135
+ Closing that gap is a **separate product**, not part of this package:
138
136
 
139
- ```ts
140
- import DshContextModeCompaction from 'dsh-context-mode/compaction'
137
+ ```sh
138
+ npm install dsh-context-mode-compaction
139
+ npx dsh-context-mode-compaction
141
140
  ```
142
141
 
143
- Mount it in place of the shipped backend, inside the isolate group the shipped
144
- one requires:
145
-
146
- ```yaml
147
- - id: compaction
148
- name: cordis:group
149
- group: true
150
- isolate:
151
- compaction: true
152
- toolResultPruner: true
153
- config:
154
- - id: compaction-basic
155
- name: 'dsh-context-mode/compaction' # was @deepseek-ai/dsh-compaction-basic
156
-
157
- - id: command-compact
158
- name: '@deepseek-ai/dsh-command-compact'
159
- ```
142
+ `dsh-context-mode-compaction` supplies the compaction engine that writes the
143
+ transcript and the index; this package supplies the archiver that stores what
144
+ those pointers name, and the `ctx_search` tool that reads it back. The two are
145
+ independent — install both for the full path.
160
146
 
161
- Trigger policy, retention, the transaction bracket, token metering, and
162
- prefix-cache-aligned replay all stay on the shipped engine only the returned
163
- summary text differs. The index is appended to the summary rather than injected
164
- into the summarization instruction, so the shipped output contract is untouched
165
- and no model has to follow an amended format. Failing to build the index
166
- returns the superseded summary unchanged, and restoring the shipped `name` row
167
- disables the index entirely.
147
+ See [dsh-context-mode-compaction](https://www.npmjs.com/package/dsh-context-mode-compaction)
148
+ for the checkpoint format, the tuning constants, and the preset wiring.
168
149
 
169
150
  ## Development
170
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-context-mode",
3
- "version": "0.3.3",
3
+ "version": "0.5.0",
4
4
  "description": "Expose context-mode MCP tools as native DeepSeek Harness tools",
5
5
  "keywords": [
6
6
  "dsh",
@@ -24,10 +24,6 @@
24
24
  "types": "./lib/types/index.d.ts",
25
25
  "import": "./lib/types/index.js"
26
26
  },
27
- "./compaction": {
28
- "types": "./lib/types/compaction.d.ts",
29
- "import": "./lib/types/compaction.js"
30
- },
31
27
  "./package.json": "./package.json",
32
28
  "./cordis.patch.yml": "./cordis.patch.yml"
33
29
  },
@@ -63,20 +59,13 @@
63
59
  },
64
60
  "peerDependencies": {
65
61
  "@deepseek-ai/cordis": "^4.0.2",
66
- "@deepseek-ai/dsh-compaction-basic": "^0.1.5-rc.2",
67
62
  "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
68
63
  "@deepseek-ai/dsh-system-prompt": "^0.1.5-rc.2",
69
64
  "@deepseek-ai/dsh-tools": "^0.1.5-rc.2"
70
65
  },
71
- "peerDependenciesMeta": {
72
- "@deepseek-ai/dsh-compaction-basic": {
73
- "optional": true
74
- }
75
- },
76
66
  "devDependencies": {
77
67
  "@deepseek-ai/cordis": "^4.0.2",
78
68
  "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
79
- "@deepseek-ai/dsh-compaction-basic": "0.1.5-rc.2",
80
69
  "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
81
70
  "@deepseek-ai/dsh-skill": "^0.1.5-rc.2",
82
71
  "@deepseek-ai/dsh-system-prompt": "^0.1.5-rc.2",
@@ -1,100 +0,0 @@
1
- /**
2
- * Compaction backend that appends an archive index to every checkpoint.
3
- *
4
- * DSH's shipped backend condenses an older span of the conversation into a
5
- * summary and lets the raw events fall out of the derived history. The summary
6
- * is lossy by design: its instruction fixes the sections a checkpoint may
7
- * carry, and tool output has no section of its own, so a long tool result
8
- * survives only as whatever the summarizing model chose to keep.
9
- *
10
- * This plugin's `precompact` listener files the same span into the
11
- * context-mode knowledge base first, so the detail still exists and
12
- * `ctx_search` can reach it. What it cannot do from outside is tell the model
13
- * that — the checkpoint text is written here, inside the engine, and the
14
- * shipped engine has no reason to mention a knowledge base it does not know
15
- * about. That is the gap this subclass closes.
16
- *
17
- * Two deliberate choices keep the risk low:
18
- *
19
- * - Only `summarize()` is overridden. Trigger policy, retention, the
20
- * bracket-first transaction, token metering, and KV-cache-aligned replay
21
- * all stay on the shipped implementation, so this cannot diverge from the
22
- * behavior the rest of DSH expects.
23
- * - The index is appended to the *returned* summary, never injected into the
24
- * summarization instruction. The summarizing model never sees this text,
25
- * so the shipped output contract ("keep every section, in order") stays
26
- * intact and no model has to be trusted to follow an amended format.
27
- *
28
- * Nothing here is allowed to fail a compaction: if the index cannot be built,
29
- * the superseded summary is returned unchanged.
30
- *
31
- * @module dsh-context-mode/compaction
32
- */
33
- import type { ContentBlock } from '@deepseek-ai/dsh-llm';
34
- import { BasicCompactionEngine } from '@deepseek-ai/dsh-compaction-basic';
35
- /**
36
- * The shipped summarization input and result types, derived from the base
37
- * class rather than restated.
38
- *
39
- * The package does not re-export them from its root, and deep-importing its
40
- * private `lib/types/summarizer.js` path would break on any internal move.
41
- * Deriving from the method signature keeps this module aligned with whatever
42
- * the installed version declares, and needs no import of its own.
43
- */
44
- type SummarizeArgs = Parameters<BasicCompactionEngine['summarize']>;
45
- type SummarizedResult = Awaited<ReturnType<BasicCompactionEngine['summarize']>>;
46
- /** Session-event shapes this module reads. */
47
- interface SessionEventLike {
48
- readonly type: string;
49
- readonly seq?: number;
50
- readonly data?: unknown;
51
- }
52
- interface SessionLike {
53
- readonly id?: string;
54
- snapshotEvents(): readonly SessionEventLike[];
55
- }
56
- interface AgentLike {
57
- readonly session?: SessionLike;
58
- }
59
- /**
60
- * A compaction engine that names the session archive in each checkpoint.
61
- *
62
- * Constructed by DSH exactly like the shipped engine it extends, so the row
63
- * that mounts it needs no additional wiring.
64
- */
65
- export declare class DshContextModeCompaction extends BasicCompactionEngine {
66
- /**
67
- * Summarize the replayed region, then append the archive index.
68
- *
69
- * The index is appended after `super.summarize()` resolves, so the shipped
70
- * call — and therefore prefix-cache alignment, token accounting, and the
71
- * returned `SummaryResult` envelope — are unchanged.
72
- */
73
- protected summarize(input: SummarizeArgs[0], agent: SummarizeArgs[1], signal?: SummarizeArgs[2]): Promise<SummarizedResult>;
74
- }
75
- /**
76
- * Build the archive-index block for one agent's session.
77
- *
78
- * The source labels are derivable without waiting on the archiver: the
79
- * `precompact` listener files each layer under `session/<id>/<layer>`, and the
80
- * session id is available here. The index therefore states *where* the detail
81
- * lives rather than claiming anything about what it contains.
82
- *
83
- * @param agent - owner of the session being compacted.
84
- * @returns the markdown block, or an empty string when no session is reachable.
85
- */
86
- export declare function buildArchiveIndex(agent: AgentLike): string;
87
- /**
88
- * Append an index block to the text of a summary.
89
- *
90
- * Only text blocks are touched. A summary may also carry non-text blocks, and
91
- * rewriting or dropping those is the shipped engine's business, not this
92
- * module's; they are copied through untouched.
93
- *
94
- * @param summary - the superseded summary blocks.
95
- * @param index - the block to append.
96
- * @returns new blocks with the index appended to the trailing text.
97
- */
98
- export declare function appendToSummary(summary: readonly ContentBlock[], index: string): ContentBlock[];
99
- export default DshContextModeCompaction;
100
- //# sourceMappingURL=compaction.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AAEzE;;;;;;;;GAQG;AACH,KAAK,aAAa,GAAG,UAAU,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAA;AACnE,KAAK,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;AAQ/E,8CAA8C;AAC9C,UAAU,gBAAgB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,IAAI,SAAS,gBAAgB,EAAE,CAAA;CAC9C;AAED,UAAU,SAAS;IACjB,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;CAC/B;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,qBAAqB;IACjE;;;;;;OAMG;cACsB,SAAS,CAChC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,gBAAgB,CAAC;CAY7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAuB1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,KAAK,EAAE,MAAM,GACZ,YAAY,EAAE,CAUhB;AAED,eAAe,wBAAwB,CAAA"}
@@ -1,94 +0,0 @@
1
- import { BasicCompactionEngine } from '@deepseek-ai/dsh-compaction-basic';
2
- /** Heading of the appended section. Kept short; it costs context on every later request. */
3
- const INDEX_HEADING = '## Archive Index';
4
- /** Upper bound on the appended section, so a checkpoint can never be grown without limit. */
5
- const MAX_INDEX_CHARS = 1_200;
6
- /**
7
- * A compaction engine that names the session archive in each checkpoint.
8
- *
9
- * Constructed by DSH exactly like the shipped engine it extends, so the row
10
- * that mounts it needs no additional wiring.
11
- */
12
- export class DshContextModeCompaction extends BasicCompactionEngine {
13
- /**
14
- * Summarize the replayed region, then append the archive index.
15
- *
16
- * The index is appended after `super.summarize()` resolves, so the shipped
17
- * call — and therefore prefix-cache alignment, token accounting, and the
18
- * returned `SummaryResult` envelope — are unchanged.
19
- */
20
- async summarize(input, agent, signal) {
21
- const result = await super.summarize(input, agent, signal);
22
- try {
23
- const index = buildArchiveIndex(agent);
24
- if (index.length === 0)
25
- return result;
26
- return { ...result, summary: appendToSummary(result.summary, index) };
27
- }
28
- catch {
29
- // An index is an improvement, never a requirement: a failure here must
30
- // not turn into a failed compaction.
31
- return result;
32
- }
33
- }
34
- }
35
- /**
36
- * Build the archive-index block for one agent's session.
37
- *
38
- * The source labels are derivable without waiting on the archiver: the
39
- * `precompact` listener files each layer under `session/<id>/<layer>`, and the
40
- * session id is available here. The index therefore states *where* the detail
41
- * lives rather than claiming anything about what it contains.
42
- *
43
- * @param agent - owner of the session being compacted.
44
- * @returns the markdown block, or an empty string when no session is reachable.
45
- */
46
- export function buildArchiveIndex(agent) {
47
- const session = agent.session;
48
- if (session === undefined)
49
- return '';
50
- const id = session.id;
51
- if (typeof id !== 'string' || id.length === 0)
52
- return '';
53
- const base = `session/${id}`;
54
- const lines = [
55
- INDEX_HEADING,
56
- '',
57
- 'The raw transcript of this span was archived to the context-mode knowledge',
58
- 'base before it was condensed, so detail the summary above omits is still',
59
- 'retrievable with `ctx_search`. Scope each query to one layer by `source`:',
60
- '',
61
- `- \`source: "${base}/constraint"\` — user messages: requirements, decisions, limits`,
62
- `- \`source: "${base}/finding"\` — tool results and stated conclusions`,
63
- `- \`source: "${base}/narrative"\` — assistant reasoning and plans`,
64
- '',
65
- 'Search for a concrete token you expect in the original (a command, an error',
66
- 'string, a path, an identifier) rather than a paraphrase of the question.',
67
- ];
68
- const block = lines.join('\n');
69
- return block.length <= MAX_INDEX_CHARS ? block : `${block.slice(0, MAX_INDEX_CHARS - 1)}…`;
70
- }
71
- /**
72
- * Append an index block to the text of a summary.
73
- *
74
- * Only text blocks are touched. A summary may also carry non-text blocks, and
75
- * rewriting or dropping those is the shipped engine's business, not this
76
- * module's; they are copied through untouched.
77
- *
78
- * @param summary - the superseded summary blocks.
79
- * @param index - the block to append.
80
- * @returns new blocks with the index appended to the trailing text.
81
- */
82
- export function appendToSummary(summary, index) {
83
- const blocks = summary.map(block => ({ ...block }));
84
- for (let position = blocks.length - 1; position >= 0; position -= 1) {
85
- const block = blocks[position];
86
- if (block.type !== 'text' || typeof block.text !== 'string')
87
- continue;
88
- blocks[position] = { ...block, text: `${block.text}\n\n${index}` };
89
- return blocks;
90
- }
91
- // A summary with no text block at all: add one rather than dropping the index.
92
- return [...blocks, { type: 'text', text: index }];
93
- }
94
- export default DshContextModeCompaction;