dsh-context-compression-improved 0.2.1 → 0.3.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/.gitattributes +1 -1
- package/.github/workflows/ci.yml +1 -7
- package/CHANGELOG.ja.md +18 -21
- package/CHANGELOG.ko.md +17 -21
- package/CHANGELOG.md +16 -17
- package/CHANGELOG.zh.md +15 -18
- package/CONTRIBUTING.md +1 -1
- package/README.ja.md +1 -20
- package/README.ko.md +12 -30
- package/README.md +1 -19
- package/README.zh.md +5 -21
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/docs/compat-0.1.5-report.md +77 -0
- package/docs/installation.ja.md +6 -4
- package/docs/installation.ko.md +9 -7
- package/docs/installation.md +3 -1
- package/docs/installation.zh.md +3 -2
- package/docs/repair-log.md +54 -33
- package/eslint.config.js +2 -2
- package/package.json +56 -36
- package/packages/selector/README.md +7 -12
- package/packages/selector/README.zh.md +6 -13
- package/packages/selector/THIRD_PARTY_NOTICES.md +2 -8
- package/packages/selector/cordis.patch.yml +7 -5
- package/packages/selector/dsh.plugin.json +2 -2
- package/packages/selector/lib/client.d.ts +31 -5
- package/packages/selector/lib/client.js +100 -82
- package/packages/selector/lib/index.d.ts +8 -20
- package/packages/selector/lib/index.js +9 -14
- package/packages/selector/lib/invariant.js +4 -4
- package/packages/selector/lib/pruner.d.ts +13 -4
- package/packages/selector/lib/pruner.js +91 -46
- package/packages/selector/lib/tail-trim.js +13 -4
- package/packages/selector/package.json +23 -23
- package/packages/selector/screenshots.json +1 -4
- package/packages/selector/src/client/CompressionProfileControls.tsx +5 -8
- package/packages/selector/src/client/CompressionProfileSelector.tsx +9 -5
- package/packages/selector/src/client/EstimatorControls.tsx +28 -32
- package/packages/selector/src/client/index.ts +101 -63
- package/packages/selector/src/client/locales.ts +0 -2
- package/packages/selector/src/client/preset-options.ts +49 -35
- package/packages/selector/src/client/settings-section.tsx +4 -6
- package/packages/selector/src/deepseek-v4-tokenizer.ts +0 -5
- package/packages/selector/src/index.ts +41 -46
- package/packages/selector/src/invariant.ts +5 -5
- package/packages/selector/src/pruner.ts +67 -36
- package/packages/selector/src/runtime/measurement.ts +6 -2
- package/packages/selector/src/runtime/session-events.ts +14 -1
- package/packages/selector/src/runtime/tail-trim.ts +4 -4
- package/packages/selector/src/runtime/tokenpilot/estimator.ts +34 -3
- package/packages/selector/src/runtime/types.ts +1 -1
- package/packages/selector/tests/auto-compact.client.spec.tsx +0 -13
- package/packages/selector/tests/built/client-artifact.spec.ts +5 -1
- package/packages/selector/tests/code-skeleton.client.spec.ts +2 -1
- package/packages/selector/tests/custom-contract.client.spec.ts +2 -1
- package/packages/selector/tests/estimator-channel.client.spec.tsx +16 -11
- package/packages/selector/tests/estimator-route-registration.host.spec.ts +12 -0
- package/packages/selector/tests/host-preset-overlay.host.spec.ts +6 -4
- package/packages/selector/tests/preset-options-write.client.spec.ts +87 -79
- package/packages/selector/tests/preset-overlay-loader.e2e.host.spec.ts +17 -12
- package/packages/selector/tests/preset-overlay.host.spec.ts +5 -2
- package/packages/selector/tests/profiles.client.spec.tsx +3 -3
- package/packages/selector/tests/public/package-contract.client.spec.ts +27 -3
- package/packages/selector/tests/runtime/public/public-runtime.spec.ts +103 -81
- package/packages/selector/tests/runtime/session-events.spec.ts +1 -1
- package/packages/selector/tests/settings-seat.client.spec.ts +86 -0
- package/packages/selector/tests/standing-generation.host.spec.ts +88 -71
- package/packages/selector/tests/subagent-cache-reuse.host.spec.ts +24 -21
- package/pnpm-workspace.yaml +52 -5
- package/scripts/capture-profile-baseline.mjs +42 -0
- package/scripts/generate-tokenizer-fixtures.py +5 -5
- package/scripts/generate-vision-fixtures.py +2 -2
- package/scripts/{packed-components-smoke.ts → packed-components-smoke.mjs} +116 -119
- package/scripts/{packed-install-e2e.ts → packed-install-e2e.mjs} +188 -160
- package/scripts/{verify-release.ts → verify-release.mjs} +70 -94
- package/tests/TEST_INVENTORY.md +6 -7
- package/scripts/capture-profile-baseline.ts +0 -80
- package/tsconfig.scripts.json +0 -13
- /package/{packages/selector/assets/screenshots → docs/assets}/context-compression-selector-profiles.jpg +0 -0
- /package/{packages/selector/assets/screenshots → docs/assets}/context-compression-selector-settings.png +0 -0
|
@@ -15,11 +15,11 @@ import CommandRuntime from '@deepseek-ai/dsh-commands'
|
|
|
15
15
|
import LlmRuntime from '@deepseek-ai/dsh-llm'
|
|
16
16
|
import SessionStore from '@deepseek-ai/dsh-session'
|
|
17
17
|
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
|
18
|
+
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
|
|
18
19
|
import TokenMeter from '@deepseek-ai/dsh-token-meter'
|
|
19
20
|
import ToolRuntime from '@deepseek-ai/dsh-tools'
|
|
20
21
|
import {
|
|
21
22
|
SettingsProvider,
|
|
22
|
-
settingsNamespace,
|
|
23
23
|
type SettingsNamespace,
|
|
24
24
|
} from '@deepseek-ai/dsh-settings'
|
|
25
25
|
import { pathToFileURL } from 'node:url'
|
|
@@ -37,6 +37,9 @@ import type {
|
|
|
37
37
|
PresetOverlayMetadataIo,
|
|
38
38
|
} from '../src/preset-overlay.ts'
|
|
39
39
|
|
|
40
|
+
// 0.1.5 removed the settingsNamespace() wrapper; namespaces are validated at runtime.
|
|
41
|
+
const nsBrand = (value: string): SettingsNamespace => value as unknown as SettingsNamespace
|
|
42
|
+
|
|
40
43
|
let root: string | undefined
|
|
41
44
|
let ctx: Context | undefined
|
|
42
45
|
|
|
@@ -176,22 +179,24 @@ async function assertStandingSwitch(
|
|
|
176
179
|
sourceRoot = rootPath
|
|
177
180
|
ctx = new Context()
|
|
178
181
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
179
|
-
await ctx.plugin(Loader)
|
|
182
|
+
await ctx.plugin(Loader).await()
|
|
180
183
|
ctx.loader.builtins.include = Include
|
|
181
184
|
ctx.loader.builtins.group = Group
|
|
182
|
-
await ctx.plugin(LlmRuntime)
|
|
183
|
-
await ctx.plugin(SessionStore)
|
|
184
|
-
await ctx.plugin(SystemPrompt
|
|
185
|
-
await ctx.plugin(ToolRuntime)
|
|
186
|
-
await ctx.plugin(AgentRegistry)
|
|
187
|
-
await ctx.plugin(AgentLoop
|
|
188
|
-
await ctx.plugin(CommandRuntime)
|
|
189
|
-
await ctx.plugin(
|
|
185
|
+
await ctx.plugin(LlmRuntime).await()
|
|
186
|
+
await ctx.plugin(SessionStore).await()
|
|
187
|
+
await ctx.plugin(SystemPrompt).await()
|
|
188
|
+
await ctx.plugin(ToolRuntime).await()
|
|
189
|
+
await ctx.plugin(AgentRegistry).await()
|
|
190
|
+
await ctx.plugin(AgentLoop).await()
|
|
191
|
+
await ctx.plugin(CommandRuntime).await()
|
|
192
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
193
|
+
await ctx.plugin(TokenMeter).await()
|
|
190
194
|
await ctx.plugin(MemorySettings).await()
|
|
191
195
|
await ctx.plugin({ apply }).await()
|
|
192
196
|
await ctx.plugin(AgentPresets, {
|
|
193
197
|
default: 'standard',
|
|
194
198
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
199
|
+
includeShippedRoot: false,
|
|
195
200
|
includeUserRoot: false,
|
|
196
201
|
}).await()
|
|
197
202
|
const act = await arrange()
|
|
@@ -263,20 +268,22 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
263
268
|
|
|
264
269
|
ctx = new Context()
|
|
265
270
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
266
|
-
await ctx.plugin(Loader)
|
|
271
|
+
await ctx.plugin(Loader).await()
|
|
267
272
|
ctx.loader.builtins.include = Include
|
|
268
273
|
ctx.loader.builtins.group = Group
|
|
269
|
-
await ctx.plugin(LlmRuntime)
|
|
270
|
-
await ctx.plugin(SessionStore)
|
|
271
|
-
await ctx.plugin(SystemPrompt
|
|
272
|
-
await ctx.plugin(ToolRuntime)
|
|
273
|
-
await ctx.plugin(AgentRegistry)
|
|
274
|
-
await ctx.plugin(AgentLoop
|
|
275
|
-
await ctx.plugin(CommandRuntime)
|
|
276
|
-
await ctx.plugin(
|
|
274
|
+
await ctx.plugin(LlmRuntime).await()
|
|
275
|
+
await ctx.plugin(SessionStore).await()
|
|
276
|
+
await ctx.plugin(SystemPrompt).await()
|
|
277
|
+
await ctx.plugin(ToolRuntime).await()
|
|
278
|
+
await ctx.plugin(AgentRegistry).await()
|
|
279
|
+
await ctx.plugin(AgentLoop).await()
|
|
280
|
+
await ctx.plugin(CommandRuntime).await()
|
|
281
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
282
|
+
await ctx.plugin(TokenMeter).await()
|
|
277
283
|
await ctx.plugin(AgentPresets, {
|
|
278
284
|
default: 'standard',
|
|
279
285
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
286
|
+
includeShippedRoot: false,
|
|
280
287
|
includeUserRoot: false,
|
|
281
288
|
}).await()
|
|
282
289
|
|
|
@@ -333,25 +340,27 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
333
340
|
sourceRoot = rootPath
|
|
334
341
|
ctx = new Context()
|
|
335
342
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
336
|
-
await ctx.plugin(Loader)
|
|
343
|
+
await ctx.plugin(Loader).await()
|
|
337
344
|
ctx.loader.builtins.include = Include
|
|
338
345
|
ctx.loader.builtins.group = Group
|
|
339
|
-
await ctx.plugin(LlmRuntime)
|
|
340
|
-
await ctx.plugin(SessionStore)
|
|
341
|
-
await ctx.plugin(SystemPrompt
|
|
342
|
-
await ctx.plugin(ToolRuntime)
|
|
343
|
-
await ctx.plugin(AgentRegistry)
|
|
344
|
-
await ctx.plugin(AgentLoop
|
|
345
|
-
await ctx.plugin(CommandRuntime)
|
|
346
|
-
await ctx.plugin(
|
|
346
|
+
await ctx.plugin(LlmRuntime).await()
|
|
347
|
+
await ctx.plugin(SessionStore).await()
|
|
348
|
+
await ctx.plugin(SystemPrompt).await()
|
|
349
|
+
await ctx.plugin(ToolRuntime).await()
|
|
350
|
+
await ctx.plugin(AgentRegistry).await()
|
|
351
|
+
await ctx.plugin(AgentLoop).await()
|
|
352
|
+
await ctx.plugin(CommandRuntime).await()
|
|
353
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
354
|
+
await ctx.plugin(TokenMeter).await()
|
|
347
355
|
await ctx.plugin(MemorySettings).await()
|
|
348
356
|
await ctx.plugin({ apply }).await()
|
|
349
357
|
await ctx.plugin(AgentPresets, {
|
|
350
358
|
default: 'standard',
|
|
351
359
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
360
|
+
includeShippedRoot: false,
|
|
352
361
|
includeUserRoot: false,
|
|
353
362
|
}).await()
|
|
354
|
-
const namespace =
|
|
363
|
+
const namespace = nsBrand('context-compression')
|
|
355
364
|
await ctx.settings.update(namespace, { autoCompact: { thresholdPercent: 80 } })
|
|
356
365
|
const bundle = ctx.plugin({ apply: (child) => {
|
|
357
366
|
apply(child, { presetOverlay: true })
|
|
@@ -388,25 +397,27 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
388
397
|
const rootPath = await presetsRoot()
|
|
389
398
|
ctx = new Context()
|
|
390
399
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
391
|
-
await ctx.plugin(Loader)
|
|
400
|
+
await ctx.plugin(Loader).await()
|
|
392
401
|
ctx.loader.builtins.include = Include
|
|
393
402
|
ctx.loader.builtins.group = Group
|
|
394
|
-
await ctx.plugin(LlmRuntime)
|
|
395
|
-
await ctx.plugin(SessionStore)
|
|
396
|
-
await ctx.plugin(SystemPrompt
|
|
397
|
-
await ctx.plugin(ToolRuntime)
|
|
398
|
-
await ctx.plugin(AgentRegistry)
|
|
399
|
-
await ctx.plugin(AgentLoop
|
|
400
|
-
await ctx.plugin(CommandRuntime)
|
|
401
|
-
await ctx.plugin(
|
|
403
|
+
await ctx.plugin(LlmRuntime).await()
|
|
404
|
+
await ctx.plugin(SessionStore).await()
|
|
405
|
+
await ctx.plugin(SystemPrompt).await()
|
|
406
|
+
await ctx.plugin(ToolRuntime).await()
|
|
407
|
+
await ctx.plugin(AgentRegistry).await()
|
|
408
|
+
await ctx.plugin(AgentLoop).await()
|
|
409
|
+
await ctx.plugin(CommandRuntime).await()
|
|
410
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
411
|
+
await ctx.plugin(TokenMeter).await()
|
|
402
412
|
await ctx.plugin(MemorySettings).await()
|
|
403
413
|
await ctx.plugin({ apply }).await()
|
|
404
414
|
await ctx.plugin(AgentPresets, {
|
|
405
415
|
default: 'standard',
|
|
406
416
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
417
|
+
includeShippedRoot: false,
|
|
407
418
|
includeUserRoot: false,
|
|
408
419
|
}).await()
|
|
409
|
-
const namespace =
|
|
420
|
+
const namespace = nsBrand('context-compression')
|
|
410
421
|
await ctx.settings.update(namespace, { autoCompact: { thresholdPercent: 73 } })
|
|
411
422
|
const bundle = ctx.plugin({ apply: (child) => {
|
|
412
423
|
apply(child, { presetOverlay: true })
|
|
@@ -451,7 +462,7 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
451
462
|
|
|
452
463
|
it('switches the standing generation for an equal-length threshold change', async () => {
|
|
453
464
|
await assertStandingSwitch(async () => {
|
|
454
|
-
const namespace =
|
|
465
|
+
const namespace = nsBrand('context-compression')
|
|
455
466
|
await ctx!.settings.update(namespace, { autoCompact: { thresholdPercent: 70 } })
|
|
456
467
|
return async () => ctx!.settings.update(namespace, { autoCompact: { thresholdPercent: 80 } })
|
|
457
468
|
})
|
|
@@ -459,7 +470,7 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
459
470
|
|
|
460
471
|
it('switches the standing generation for an equal-length source change at a fixed threshold', async () => {
|
|
461
472
|
await assertStandingSwitch(async () => {
|
|
462
|
-
const namespace =
|
|
473
|
+
const namespace = nsBrand('context-compression')
|
|
463
474
|
await ctx!.settings.update(namespace, { autoCompact: { thresholdPercent: 80 } })
|
|
464
475
|
return async () => {
|
|
465
476
|
await rewriteSourceMarker('marker-bbbbbbbbbb.mjs')
|
|
@@ -472,25 +483,27 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
472
483
|
sourceRoot = rootPath
|
|
473
484
|
ctx = new Context()
|
|
474
485
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
475
|
-
await ctx.plugin(Loader)
|
|
486
|
+
await ctx.plugin(Loader).await()
|
|
476
487
|
ctx.loader.builtins.include = Include
|
|
477
488
|
ctx.loader.builtins.group = Group
|
|
478
|
-
await ctx.plugin(LlmRuntime)
|
|
479
|
-
await ctx.plugin(SessionStore)
|
|
480
|
-
await ctx.plugin(SystemPrompt
|
|
481
|
-
await ctx.plugin(ToolRuntime)
|
|
482
|
-
await ctx.plugin(AgentRegistry)
|
|
483
|
-
await ctx.plugin(AgentLoop
|
|
484
|
-
await ctx.plugin(CommandRuntime)
|
|
485
|
-
await ctx.plugin(
|
|
489
|
+
await ctx.plugin(LlmRuntime).await()
|
|
490
|
+
await ctx.plugin(SessionStore).await()
|
|
491
|
+
await ctx.plugin(SystemPrompt).await()
|
|
492
|
+
await ctx.plugin(ToolRuntime).await()
|
|
493
|
+
await ctx.plugin(AgentRegistry).await()
|
|
494
|
+
await ctx.plugin(AgentLoop).await()
|
|
495
|
+
await ctx.plugin(CommandRuntime).await()
|
|
496
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
497
|
+
await ctx.plugin(TokenMeter).await()
|
|
486
498
|
await ctx.plugin(MemorySettings).await()
|
|
487
499
|
await ctx.plugin({ apply }).await()
|
|
488
500
|
await ctx.plugin(AgentPresets, {
|
|
489
501
|
default: 'standard',
|
|
490
502
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
503
|
+
includeShippedRoot: false,
|
|
491
504
|
includeUserRoot: false,
|
|
492
505
|
}).await()
|
|
493
|
-
const namespace =
|
|
506
|
+
const namespace = nsBrand('context-compression')
|
|
494
507
|
await ctx.settings.update(namespace, { autoCompact: { thresholdPercent: 80 } })
|
|
495
508
|
|
|
496
509
|
const presets = ctx.agentPresets as unknown as OverlayableAgentPresets
|
|
@@ -536,25 +549,27 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
536
549
|
const rootPath = await presetsRoot()
|
|
537
550
|
ctx = new Context()
|
|
538
551
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
539
|
-
await ctx.plugin(Loader)
|
|
552
|
+
await ctx.plugin(Loader).await()
|
|
540
553
|
ctx.loader.builtins.include = Include
|
|
541
554
|
ctx.loader.builtins.group = Group
|
|
542
|
-
await ctx.plugin(LlmRuntime)
|
|
543
|
-
await ctx.plugin(SessionStore)
|
|
544
|
-
await ctx.plugin(SystemPrompt
|
|
545
|
-
await ctx.plugin(ToolRuntime)
|
|
546
|
-
await ctx.plugin(AgentRegistry)
|
|
547
|
-
await ctx.plugin(AgentLoop
|
|
548
|
-
await ctx.plugin(CommandRuntime)
|
|
549
|
-
await ctx.plugin(
|
|
555
|
+
await ctx.plugin(LlmRuntime).await()
|
|
556
|
+
await ctx.plugin(SessionStore).await()
|
|
557
|
+
await ctx.plugin(SystemPrompt).await()
|
|
558
|
+
await ctx.plugin(ToolRuntime).await()
|
|
559
|
+
await ctx.plugin(AgentRegistry).await()
|
|
560
|
+
await ctx.plugin(AgentLoop).await()
|
|
561
|
+
await ctx.plugin(CommandRuntime).await()
|
|
562
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
563
|
+
await ctx.plugin(TokenMeter).await()
|
|
550
564
|
await ctx.plugin(MemorySettings).await()
|
|
551
565
|
await ctx.plugin({ apply }).await()
|
|
552
566
|
await ctx.plugin(AgentPresets, {
|
|
553
567
|
default: 'standard',
|
|
554
568
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
569
|
+
includeShippedRoot: false,
|
|
555
570
|
includeUserRoot: false,
|
|
556
571
|
}).await()
|
|
557
|
-
const namespace =
|
|
572
|
+
const namespace = nsBrand('context-compression')
|
|
558
573
|
await ctx.settings.update(namespace, { autoCompact: { thresholdPercent: 73 } })
|
|
559
574
|
const bundle = ctx.plugin({ apply: (child) => {
|
|
560
575
|
apply(child, { presetOverlay: true })
|
|
@@ -581,25 +596,27 @@ describe('real AgentPresets standing generations with the overlay threshold', ()
|
|
|
581
596
|
const rootPath = await presetsRoot()
|
|
582
597
|
ctx = new Context()
|
|
583
598
|
ctx.baseUrl = `${pathToFileURL(rootPath).href}/`
|
|
584
|
-
await ctx.plugin(Loader)
|
|
599
|
+
await ctx.plugin(Loader).await()
|
|
585
600
|
ctx.loader.builtins.include = Include
|
|
586
601
|
ctx.loader.builtins.group = Group
|
|
587
|
-
await ctx.plugin(LlmRuntime)
|
|
588
|
-
await ctx.plugin(SessionStore)
|
|
589
|
-
await ctx.plugin(SystemPrompt
|
|
590
|
-
await ctx.plugin(ToolRuntime)
|
|
591
|
-
await ctx.plugin(AgentRegistry)
|
|
592
|
-
await ctx.plugin(AgentLoop
|
|
593
|
-
await ctx.plugin(CommandRuntime)
|
|
594
|
-
await ctx.plugin(
|
|
602
|
+
await ctx.plugin(LlmRuntime).await()
|
|
603
|
+
await ctx.plugin(SessionStore).await()
|
|
604
|
+
await ctx.plugin(SystemPrompt).await()
|
|
605
|
+
await ctx.plugin(ToolRuntime).await()
|
|
606
|
+
await ctx.plugin(AgentRegistry).await()
|
|
607
|
+
await ctx.plugin(AgentLoop).await()
|
|
608
|
+
await ctx.plugin(CommandRuntime).await()
|
|
609
|
+
await ctx.plugin(SessionProjectionRegistry).await()
|
|
610
|
+
await ctx.plugin(TokenMeter).await()
|
|
595
611
|
await ctx.plugin(MemorySettings).await()
|
|
596
612
|
await ctx.plugin({ apply }).await()
|
|
597
613
|
await ctx.plugin(AgentPresets, {
|
|
598
614
|
default: 'standard',
|
|
599
615
|
roots: [{ path: rootPath, trust: 'system' }],
|
|
616
|
+
includeShippedRoot: false,
|
|
600
617
|
includeUserRoot: false,
|
|
601
618
|
}).await()
|
|
602
|
-
const namespace =
|
|
619
|
+
const namespace = nsBrand('context-compression')
|
|
603
620
|
await ctx.settings.update(namespace, { autoCompact: { thresholdPercent: 70 } })
|
|
604
621
|
const bundle = ctx.plugin({ apply: (child) => {
|
|
605
622
|
apply(child, { presetOverlay: true })
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sessionEvents } from '../src/runtime/session-events.ts'
|
|
1
2
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
2
3
|
import { Context } from '@deepseek-ai/cordis'
|
|
3
4
|
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
|
|
@@ -8,6 +9,7 @@ import { SessionId } from '@deepseek-ai/dsh-session'
|
|
|
8
9
|
import SubagentRuntime from '@deepseek-ai/dsh-subagent'
|
|
9
10
|
import * as Fork from '@deepseek-ai/dsh-subagent-fork-in-process'
|
|
10
11
|
import * as Spawn from '@deepseek-ai/dsh-subagent-spawn-in-process'
|
|
12
|
+
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
|
|
11
13
|
import TokenMeter from '@deepseek-ai/dsh-token-meter'
|
|
12
14
|
import { PublicMockAdapter, publicTextResponse } from './support/mock-adapter.ts'
|
|
13
15
|
import {
|
|
@@ -47,13 +49,14 @@ const envelope = (options: GenerateOptions, messageCount = options.messages.leng
|
|
|
47
49
|
|
|
48
50
|
async function liveHarness(requests: Map<string, GenerateOptions[]>): Promise<Context> {
|
|
49
51
|
const created = new Context()
|
|
50
|
-
await mountAgentLoopTestDependencies(created, { systemPrompt: {
|
|
51
|
-
await created.plugin(
|
|
52
|
-
await created.plugin(
|
|
53
|
-
await created.plugin(
|
|
54
|
-
await created.plugin(
|
|
55
|
-
await created.plugin(
|
|
56
|
-
await created.plugin(
|
|
52
|
+
await mountAgentLoopTestDependencies(created, { systemPrompt: { personaPrefix: SYSTEM } })
|
|
53
|
+
await created.plugin(SessionProjectionRegistry).await()
|
|
54
|
+
await created.plugin(TokenMeter).await()
|
|
55
|
+
await created.plugin(AgentLoop).await()
|
|
56
|
+
await created.plugin(SubagentRuntime).await()
|
|
57
|
+
await created.plugin(Fork).await()
|
|
58
|
+
await created.plugin(Spawn).await()
|
|
59
|
+
await created.plugin(LlmDeepSeek).await()
|
|
57
60
|
created.on('llm/stream', (options, next) => {
|
|
58
61
|
const sessionId = String(options.sessionId)
|
|
59
62
|
requests.set(sessionId, [...(requests.get(sessionId) ?? []), options])
|
|
@@ -64,11 +67,11 @@ async function liveHarness(requests: Map<string, GenerateOptions[]>): Promise<Co
|
|
|
64
67
|
|
|
65
68
|
async function keylessHarness(requests: Map<string, GenerateOptions[]>): Promise<Context> {
|
|
66
69
|
const created = new Context()
|
|
67
|
-
await mountAgentLoopTestDependencies(created, { systemPrompt: {
|
|
68
|
-
await created.plugin(AgentLoop
|
|
69
|
-
await created.plugin(SubagentRuntime)
|
|
70
|
-
await created.plugin(Fork
|
|
71
|
-
await created.plugin(Spawn
|
|
70
|
+
await mountAgentLoopTestDependencies(created, { systemPrompt: { personaPrefix: SYSTEM } })
|
|
71
|
+
await created.plugin(AgentLoop).await()
|
|
72
|
+
await created.plugin(SubagentRuntime).await()
|
|
73
|
+
await created.plugin(Fork).await()
|
|
74
|
+
await created.plugin(Spawn).await()
|
|
72
75
|
created.llm.registerAdapter(['mock'], new PublicMockAdapter([
|
|
73
76
|
publicTextResponse('cobalt-heron-42'),
|
|
74
77
|
publicTextResponse('cobalt-heron-42'),
|
|
@@ -86,7 +89,7 @@ describe('parent/child prefix behavior (keyless full-loop E2E)', () => {
|
|
|
86
89
|
it('runs parent, fork, and spawn through the real loop and session providers', async () => {
|
|
87
90
|
const requests = new Map<string, GenerateOptions[]>()
|
|
88
91
|
ctx = await keylessHarness(requests)
|
|
89
|
-
const parent = ctx.agentLoop.create(SessionId('cache-parent-keyless-e2e'), {
|
|
92
|
+
const parent = await ctx.agentLoop.create(SessionId('cache-parent-keyless-e2e'), {
|
|
90
93
|
provider: 'mock',
|
|
91
94
|
model: 'mock',
|
|
92
95
|
})
|
|
@@ -95,7 +98,7 @@ describe('parent/child prefix behavior (keyless full-loop E2E)', () => {
|
|
|
95
98
|
source: { kind: 'user' },
|
|
96
99
|
}))
|
|
97
100
|
await parent.whenIdle()
|
|
98
|
-
const parentEvents = parent.session.
|
|
101
|
+
const parentEvents = sessionEvents(parent.session).slice()
|
|
99
102
|
const parentRequest = requests.get(String(parent.id))?.at(-1)
|
|
100
103
|
expect(parentRequest).toBeDefined()
|
|
101
104
|
|
|
@@ -112,8 +115,8 @@ describe('parent/child prefix behavior (keyless full-loop E2E)', () => {
|
|
|
112
115
|
if (forkChild === undefined || forkRequest === undefined || parentRequest === undefined) {
|
|
113
116
|
throw new Error('keyless fork did not publish its complete evidence')
|
|
114
117
|
}
|
|
115
|
-
expect(forkChild.session.
|
|
116
|
-
expect(forkChild.session.
|
|
118
|
+
expect(forkChild.session.firstLiveSeq).toBe(parentEvents.length)
|
|
119
|
+
expect(sessionEvents(forkChild.session).slice(0, parentEvents.length)).toEqual(parentEvents)
|
|
117
120
|
const parentStable = envelope(parentRequest)
|
|
118
121
|
const forkStablePrefix = envelope(forkRequest, parentRequest.messages.length)
|
|
119
122
|
expect(fingerprintStablePrefix(forkStablePrefix)).toBe(fingerprintStablePrefix(parentStable))
|
|
@@ -127,7 +130,7 @@ describe('parent/child prefix behavior (keyless full-loop E2E)', () => {
|
|
|
127
130
|
await spawnRun.result
|
|
128
131
|
const spawnChild = spawnRun.localAgent
|
|
129
132
|
const spawnRequest = requests.get(String(spawnRun.id))?.at(-1)
|
|
130
|
-
expect(spawnChild?.session.
|
|
133
|
+
expect(spawnChild?.session.firstLiveSeq).toBe(0)
|
|
131
134
|
expect(spawnRequest).toBeDefined()
|
|
132
135
|
expect(JSON.stringify(spawnRequest?.messages)).not.toContain(PARENT_TEXT)
|
|
133
136
|
expect(assessReusablePrefix({
|
|
@@ -158,7 +161,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('parent/child natural cache-prefi
|
|
|
158
161
|
it('preserves the fork prefix, separates spawn, and records only official usage evidence', async () => {
|
|
159
162
|
const requests = new Map<string, GenerateOptions[]>()
|
|
160
163
|
ctx = await liveHarness(requests)
|
|
161
|
-
const parent = ctx.agentLoop.create(SessionId('cache-parent-e2e'), {
|
|
164
|
+
const parent = await ctx.agentLoop.create(SessionId('cache-parent-e2e'), {
|
|
162
165
|
provider: 'deepseek-official',
|
|
163
166
|
model: 'deepseek-v4-flash',
|
|
164
167
|
})
|
|
@@ -167,7 +170,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('parent/child natural cache-prefi
|
|
|
167
170
|
source: { kind: 'user' },
|
|
168
171
|
}))
|
|
169
172
|
await parent.whenIdle()
|
|
170
|
-
const parentEvents = parent.session.
|
|
173
|
+
const parentEvents = sessionEvents(parent.session).slice()
|
|
171
174
|
const parentRequest = requests.get(String(parent.id))?.at(-1)
|
|
172
175
|
expect(parentRequest).toBeDefined()
|
|
173
176
|
|
|
@@ -186,7 +189,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('parent/child natural cache-prefi
|
|
|
186
189
|
parentSession: parent.session.header.id,
|
|
187
190
|
seedLength: parentEvents.length,
|
|
188
191
|
})
|
|
189
|
-
expect(forkChild.session.
|
|
192
|
+
expect(sessionEvents(forkChild.session).slice(0, parentEvents.length)).toEqual(parentEvents)
|
|
190
193
|
|
|
191
194
|
const parentStable = envelope(parentRequest!)
|
|
192
195
|
const forkStablePrefix = envelope(forkRequest!, parentRequest!.messages.length)
|
|
@@ -234,7 +237,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('parent/child natural cache-prefi
|
|
|
234
237
|
if (spawnChild === undefined) throw new Error('spawn did not publish a local agent')
|
|
235
238
|
const spawnRequest = requests.get(String(spawnRun.id))?.at(-1)
|
|
236
239
|
expect(spawnChild.session.header.parentSession).toBe(parent.session.header.id)
|
|
237
|
-
expect(spawnChild.session.
|
|
240
|
+
expect(spawnChild.session.firstLiveSeq).toBe(0)
|
|
238
241
|
expect(spawnRequest).toBeDefined()
|
|
239
242
|
expect(JSON.stringify(spawnRequest!.messages)).not.toContain(PARENT_TEXT)
|
|
240
243
|
expect(assessReusablePrefix({
|
package/pnpm-workspace.yaml
CHANGED
|
@@ -11,9 +11,56 @@ allowBuilds:
|
|
|
11
11
|
esbuild: true
|
|
12
12
|
"@huggingface/tokenizers": true
|
|
13
13
|
|
|
14
|
-
# GHSA-2883-xcg3-v3hh - js-yaml < 4.3.2 does not bound CPU use for empty merge
|
|
15
|
-
# sources. @deepseek-ai/cordis-plugin-include and @deepseek-ai/dsh-agent-presets
|
|
16
|
-
# both declare ranges that already allow the patch, yet keep resolving 4.3.1, so
|
|
17
|
-
# the floor is pinned here instead of waiting on their next release.
|
|
18
14
|
overrides:
|
|
19
|
-
|
|
15
|
+
'@deepseek-ai/cordis': '4.0.1'
|
|
16
|
+
'@deepseek-ai/cordis-plugin-group': '1.0.1'
|
|
17
|
+
'@deepseek-ai/cordis-plugin-include': '1.0.6'
|
|
18
|
+
'@deepseek-ai/cordis-plugin-loader': '1.0.2'
|
|
19
|
+
'@deepseek-ai/dsh-agent': '0.1.5-rc.2'
|
|
20
|
+
'@deepseek-ai/dsh-agent-loop': '0.1.5-rc.2'
|
|
21
|
+
'@deepseek-ai/dsh-agent-loop-testkit': '0.1.5-rc.2'
|
|
22
|
+
'@deepseek-ai/dsh-agent-presets': '0.1.5-rc.2'
|
|
23
|
+
'@deepseek-ai/dsh-client-locale': '0.1.5-rc.2'
|
|
24
|
+
'@deepseek-ai/dsh-client-ui-primitives': '0.1.5-rc.2'
|
|
25
|
+
'@deepseek-ai/dsh-client-ui-settings': '0.1.5-rc.2'
|
|
26
|
+
'@deepseek-ai/dsh-client-ui-slots': '0.1.5-rc.2'
|
|
27
|
+
'@deepseek-ai/dsh-client-store': '0.1.5-rc.2'
|
|
28
|
+
'@deepseek-ai/dsh-client-ui-workspace': '0.1.5-rc.2'
|
|
29
|
+
'@deepseek-ai/dsh-command-compact': '0.1.5-rc.2'
|
|
30
|
+
'@deepseek-ai/dsh-commands': '0.1.5-rc.2'
|
|
31
|
+
'@deepseek-ai/dsh-compaction': '0.1.5-rc.2'
|
|
32
|
+
'@deepseek-ai/dsh-compaction-basic': '0.1.5-rc.2'
|
|
33
|
+
'@deepseek-ai/dsh-invariants': '0.1.5-rc.2'
|
|
34
|
+
'@deepseek-ai/dsh-llm': '0.1.5-rc.2'
|
|
35
|
+
'@deepseek-ai/dsh-llm-deepseek': '0.1.5-rc.2'
|
|
36
|
+
'@deepseek-ai/dsh-scope': '0.1.5-rc.2'
|
|
37
|
+
'@deepseek-ai/dsh-session': '0.1.5-rc.2'
|
|
38
|
+
'@deepseek-ai/dsh-settings': '0.1.5-rc.2'
|
|
39
|
+
'@deepseek-ai/dsh-subagent': '0.1.5-rc.2'
|
|
40
|
+
'@deepseek-ai/dsh-subagent-fork-in-process': '0.1.5-rc.2'
|
|
41
|
+
'@deepseek-ai/dsh-subagent-spawn-in-process': '0.1.5-rc.2'
|
|
42
|
+
'@deepseek-ai/dsh-system-prompt': '0.1.5-rc.2'
|
|
43
|
+
'@deepseek-ai/dsh-token-meter': '0.1.5-rc.2'
|
|
44
|
+
'@deepseek-ai/dsh-tools': '0.1.5-rc.2'
|
|
45
|
+
'@deepseek-ai/dsh-anonymous-user-id': '0.1.5-rc.2'
|
|
46
|
+
'@deepseek-ai/dsh-atomic-write': '0.1.5-rc.2'
|
|
47
|
+
'@deepseek-ai/dsh-attachment': '0.1.5-rc.2'
|
|
48
|
+
'@deepseek-ai/dsh-code-runtime': '0.1.5-rc.2'
|
|
49
|
+
'@deepseek-ai/dsh-credentials': '0.1.5-rc.2'
|
|
50
|
+
'@deepseek-ai/dsh-home-paths': '0.1.5-rc.2'
|
|
51
|
+
'@deepseek-ai/dsh-launch-environment': '0.1.5-rc.2'
|
|
52
|
+
'@deepseek-ai/dsh-llm-retry': '0.1.5-rc.2'
|
|
53
|
+
'@deepseek-ai/dsh-sandbox': '0.1.5-rc.2'
|
|
54
|
+
'@deepseek-ai/dsh-session-persistence': '0.1.5-rc.2'
|
|
55
|
+
'@deepseek-ai/dsh-session-projection': '0.1.5-rc.2'
|
|
56
|
+
'@deepseek-ai/dsh-subagent-in-process-driver': '0.1.5-rc.2'
|
|
57
|
+
'@deepseek-ai/dsh-user-approval': '0.1.5-rc.2'
|
|
58
|
+
'@deepseek-ai/schemastery': '3.18.2'
|
|
59
|
+
'@deepseek-ai/dsh-client-ui-session': '0.1.5-rc.2'
|
|
60
|
+
'@deepseek-ai/dsh-api-session-controller': '0.1.5-rc.2'
|
|
61
|
+
# Scoped, not global: @deepseek-ai/cordis-plugin-include (^4.1.0) and
|
|
62
|
+
# @deepseek-ai/dsh-agent-presets resolve js-yaml 4.3.1 from ranges that already
|
|
63
|
+
# allow the patched release, so pin the vulnerable ones without waiting on their
|
|
64
|
+
# next release. GHSA-2883-xcg3-v3hh: js-yaml < 4.3.2 does not bound CPU use for
|
|
65
|
+
# empty merge sources.
|
|
66
|
+
'js-yaml@<4.3.2': '^4.3.2'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-off baseline capture: freeze the resolvePolicy output for the pre-existing
|
|
3
|
+
* profiles (before 'tokenpilot-inspired' is added) into a JSON fixture used by
|
|
4
|
+
* tests/tokenpilot/profile-baseline.spec.ts as the backward-compat golden.
|
|
5
|
+
*
|
|
6
|
+
* Usage: node scripts/capture-profile-baseline.mjs [baseline-file]
|
|
7
|
+
*/
|
|
8
|
+
import { writeFileSync } from 'node:fs'
|
|
9
|
+
import { createRequire } from 'node:module'
|
|
10
|
+
|
|
11
|
+
const require = createRequire(import.meta.url)
|
|
12
|
+
const runtime = require('../packages/runtime/lib/index.js')
|
|
13
|
+
|
|
14
|
+
const OLD_PROFILES = ['off', 'native', 'balanced', 'cache-strict', 'savings', 'adaptive', 'custom']
|
|
15
|
+
const baseConfig = runtime.resolveConfig({})
|
|
16
|
+
const OPTION_CASES = [
|
|
17
|
+
{ label: 'defaults', options: {} },
|
|
18
|
+
{ label: 'linkage', options: { contextWindowTokens: 128_000, autoCompactThresholdPercent: 80 } },
|
|
19
|
+
]
|
|
20
|
+
const CUSTOM_DOCS = [
|
|
21
|
+
{ label: 'default-custom', custom: undefined },
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const snapshot = { capturedAt: 'pre-tokenpilot-inspired', profiles: {} }
|
|
25
|
+
for (const profile of OLD_PROFILES) {
|
|
26
|
+
snapshot.profiles[profile] = {}
|
|
27
|
+
for (const optionCase of OPTION_CASES) {
|
|
28
|
+
for (const customCase of CUSTOM_DOCS) {
|
|
29
|
+
const key = `${optionCase.label}${customCase.label === 'default-custom' ? '' : `/${customCase.label}`}`
|
|
30
|
+
snapshot.profiles[profile][key] = runtime.resolvePolicy(
|
|
31
|
+
baseConfig,
|
|
32
|
+
profile,
|
|
33
|
+
customCase.custom,
|
|
34
|
+
optionCase.options,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const out = process.argv[2] ?? 'packages/runtime/tests/fixtures/profile-baseline.json'
|
|
41
|
+
writeFileSync(out, `${JSON.stringify(snapshot, null, 2)}\n`)
|
|
42
|
+
console.log(`baseline written: ${out}`)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Regenerate the tokenizer golden fixture for the Node loader equivalence tests.
|
|
3
3
|
|
|
4
|
-
Loads each pinned ``tokenizer.json`` shipped in ``packages/
|
|
4
|
+
Loads each pinned ``tokenizer.json`` shipped in ``packages/runtime/assets`` with
|
|
5
5
|
the official Hugging Face ``tokenizers`` Python library (the same Rust core the
|
|
6
6
|
``transformers`` tokenizer for these repositories uses) and records the token
|
|
7
7
|
counts the Node runtime must reproduce exactly.
|
|
@@ -10,7 +10,7 @@ Usage:
|
|
|
10
10
|
python3 scripts/generate-tokenizer-fixtures.py
|
|
11
11
|
|
|
12
12
|
Requires: pip install tokenizers
|
|
13
|
-
Output: packages/
|
|
13
|
+
Output: packages/runtime/tests/fixtures/tokenizer-golden.json
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
import json
|
|
@@ -19,11 +19,11 @@ import platform
|
|
|
19
19
|
|
|
20
20
|
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
21
21
|
ASSETS = {
|
|
22
|
-
"deepseek-ai/DeepSeek-V4-Pro": REPO_ROOT / "packages/
|
|
22
|
+
"deepseek-ai/DeepSeek-V4-Pro": REPO_ROOT / "packages/runtime/assets/deepseek-v4",
|
|
23
23
|
"deepseek-ai/DeepSeek-V4-Flash-Vision-Exp": REPO_ROOT
|
|
24
|
-
/ "packages/
|
|
24
|
+
/ "packages/runtime/assets/deepseek-v4-vision-exp",
|
|
25
25
|
}
|
|
26
|
-
OUTPUT = REPO_ROOT / "packages/
|
|
26
|
+
OUTPUT = REPO_ROOT / "packages/runtime/tests/fixtures/tokenizer-golden.json"
|
|
27
27
|
|
|
28
28
|
CASES = [
|
|
29
29
|
("english prose", "The quick brown fox jumps over the lazy dog."),
|
|
@@ -13,7 +13,7 @@ Usage:
|
|
|
13
13
|
python3 scripts/generate-vision-fixtures.py [--workdir DIR]
|
|
14
14
|
|
|
15
15
|
Requires: pip install torch pillow
|
|
16
|
-
Output: packages/
|
|
16
|
+
Output: packages/runtime/tests/fixtures/vision-golden.json
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
import argparse
|
|
@@ -26,7 +26,7 @@ import types
|
|
|
26
26
|
import urllib.request
|
|
27
27
|
|
|
28
28
|
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
29
|
-
OUTPUT = REPO_ROOT / "packages/
|
|
29
|
+
OUTPUT = REPO_ROOT / "packages/runtime/tests/fixtures/vision-golden.json"
|
|
30
30
|
REVISION = "6821d6ad3681a4b137b066b76094fa82ebd0a380"
|
|
31
31
|
BASE = f"https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-Vision-Exp/resolve/{REVISION}"
|
|
32
32
|
|