dsh-context-compression-improved 0.5.1 → 0.5.3

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.
Files changed (57) hide show
  1. package/.gitattributes +1 -0
  2. package/CHANGELOG.ja.md +144 -83
  3. package/CHANGELOG.ko.md +143 -82
  4. package/CHANGELOG.md +278 -212
  5. package/CHANGELOG.zh.md +131 -77
  6. package/docs/installation.md +103 -103
  7. package/docs/installation.zh.md +100 -100
  8. package/package.json +1 -1
  9. package/packages/selector/cordis.patch.yml +5 -6
  10. package/packages/selector/lib/advisor-state.js +4 -231
  11. package/packages/selector/lib/client.d.ts +0 -24
  12. package/packages/selector/lib/client.js +6 -501
  13. package/packages/selector/lib/index.d.ts +4 -10
  14. package/packages/selector/lib/index.js +16 -234
  15. package/packages/selector/lib/pruner.d.ts +13 -248
  16. package/packages/selector/lib/pruner.js +148 -552
  17. package/packages/selector/src/client/EstimatorControls.tsx +0 -101
  18. package/packages/selector/src/client/index.ts +0 -17
  19. package/packages/selector/src/client/locales.ts +0 -38
  20. package/packages/selector/src/client/preset-options.ts +3 -2
  21. package/packages/selector/src/client/settings-section.tsx +8 -17
  22. package/packages/selector/src/index.ts +24 -271
  23. package/packages/selector/src/profiles.ts +4 -27
  24. package/packages/selector/src/pruner/state.ts +2 -25
  25. package/packages/selector/src/pruner.ts +75 -403
  26. package/packages/selector/src/runtime/audit.ts +27 -21
  27. package/packages/selector/src/runtime/config.ts +6 -32
  28. package/packages/selector/src/runtime/tokenpilot/advisor-prompt.ts +188 -188
  29. package/packages/selector/src/runtime/tokenpilot/advisor-state.ts +149 -133
  30. package/packages/selector/src/runtime/tokenpilot/advisor.ts +419 -419
  31. package/packages/selector/src/runtime/tokenpilot/benefit.ts +200 -0
  32. package/packages/selector/src/runtime/types.ts +0 -17
  33. package/packages/selector/tests/advisor-report.host.spec.ts +223 -223
  34. package/packages/selector/tests/preset-options-write.client.spec.ts +7 -23
  35. package/packages/selector/tests/public/package-contract.client.spec.ts +20 -0
  36. package/packages/selector/tests/runtime/advice-never-withholds.host.spec.ts +232 -0
  37. package/packages/selector/tests/runtime/advisor-invariant.spec.ts +272 -272
  38. package/packages/selector/tests/runtime/advisor.spec.ts +226 -226
  39. package/packages/selector/tests/runtime/audit.spec.ts +35 -21
  40. package/packages/selector/tests/runtime/char-basis.spec.ts +30 -30
  41. package/packages/selector/tests/runtime/deprecated-preset-options.spec.ts +96 -0
  42. package/packages/selector/tests/runtime/tokenpilot/benefit.spec.ts +217 -0
  43. package/packages/selector/tests/runtime/tokenpilot/profile-baseline.spec.ts +4 -5
  44. package/packages/selector/tests/settings-seat.client.spec.ts +45 -14
  45. package/scripts/toolclass-corpus-replay.mjs +281 -281
  46. package/packages/selector/src/client/ReviewOverlay.tsx +0 -320
  47. package/packages/selector/src/client/review-scope.ts +0 -16
  48. package/packages/selector/src/runtime/tokenpilot/proposal.ts +0 -267
  49. package/packages/selector/src/runtime/tokenpilot/review-queue.ts +0 -231
  50. package/packages/selector/src/runtime/tokenpilot/review-registry.ts +0 -117
  51. package/packages/selector/src/runtime/tokenpilot/review-storage.ts +0 -122
  52. package/packages/selector/tests/review-overlay.client.spec.tsx +0 -118
  53. package/packages/selector/tests/review-routes-registry.host.spec.ts +0 -142
  54. package/packages/selector/tests/review-routes.host.spec.ts +0 -290
  55. package/packages/selector/tests/runtime/tokenpilot/proposal.spec.ts +0 -393
  56. package/packages/selector/tests/runtime/tokenpilot/pruner-review.spec.ts +0 -382
  57. package/packages/selector/tests/runtime/tokenpilot/review-queue.spec.ts +0 -168
@@ -1,142 +0,0 @@
1
- /**
2
- * Production-shaped guard for the review routes' pruner resolution.
3
- *
4
- * The older suite provided `toolResultPruner` at the TOP LEVEL, which is a shape
5
- * production never has: `canonicalCompressionRows()` mounts every pruner inside
6
- * an agent preset's isolated group, so a top-level `ctx.get('toolResultPruner')`
7
- * resolves nothing and the queue route answered 503 "review pipeline
8
- * unavailable" for every request while the pipeline itself ran normally.
9
- *
10
- * These cases mount NO top-level service and publish through the review registry
11
- * from a CHILD fiber instead — the path the fix relies on.
12
- */
13
-
14
- import { Context } from '@deepseek-ai/cordis'
15
- import { afterEach, describe, expect, it } from 'vitest'
16
- import { apply } from '../src/index.ts'
17
- import { registerReviewPruner, type ReviewPrunerFace } from '../src/runtime/tokenpilot/review-registry.ts'
18
-
19
- const QUEUE_ROUTE = '/api/dsh-context-compression-improved/review-queue'
20
-
21
- interface RegisteredRoute {
22
- kind: string
23
- path: string
24
- handler: (req: unknown, res: unknown) => unknown
25
- }
26
-
27
- let ctx: Context | undefined
28
-
29
- afterEach(async () => {
30
- await ctx?.fiber.dispose()
31
- ctx = undefined
32
- })
33
-
34
- const settle = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 20))
35
-
36
- /** A pruner face carrying one pending proposal for session `s1`. */
37
- const SAMPLE = {
38
- id: 'abc123def456',
39
- kind: 'read-state',
40
- items: [{ seq: 6, kind: 'read-state', component: 'history', tokensBefore: 2401, tokensAfter: 134 }],
41
- benefit: { recoveredTokens: 400, penaltyTokens: 900, paybackTurns: 2.25 },
42
- enqueuedTurn: 3,
43
- lastTurnIndex: 3,
44
- } as const
45
-
46
- function samplePruner(): ReviewPrunerFace {
47
- return {
48
- listReviewProposals: (session: unknown) => ((session as { id?: string }).id === 's1' ? [SAMPLE] : []),
49
- listAllReviewProposals: () => [{ sessionId: 's1', proposals: [SAMPLE] }],
50
- reviewSummary: () => ({ autoApplied: 2, reviewApplied: 1, expired: 3, voided: 0 }),
51
- decideReviewProposal: (_session: unknown, proposalId: string) => (proposalId === SAMPLE.id
52
- ? { ok: true }
53
- : { ok: false, reason: 'unknown-proposal' }),
54
- }
55
- }
56
-
57
- /** Mount the fake web server the routes register against. */
58
- async function mountWebServer(runtime: Context, routes: RegisteredRoute[]): Promise<void> {
59
- await runtime.plugin({
60
- name: 'fake-webserver',
61
- apply(webCtx) {
62
- webCtx.provide('webServer', {
63
- tables: { exact: new Map<string, RegisteredRoute>() },
64
- register(this: { tables: { exact: Map<string, RegisteredRoute> } }, route: RegisteredRoute) {
65
- const table = this.tables.exact
66
- if (table.has(route.path)) throw new Error(`webserver: duplicate ${route.path}`)
67
- table.set(route.path, route)
68
- routes.push(route)
69
- return () => {}
70
- },
71
- })
72
- },
73
- })
74
- }
75
-
76
- /** Boot the host plugin with both routes opted in, as the Bundle row does. */
77
- async function bootWithRoutes(): Promise<RegisteredRoute[]> {
78
- const routes: RegisteredRoute[] = []
79
- ctx = new Context()
80
- await mountWebServer(ctx, routes)
81
- apply(ctx, { estimatorCatalogRoute: true, reviewQueueRoute: true })
82
- await settle()
83
- return routes
84
- }
85
-
86
- async function readQueue(routes: RegisteredRoute[]): Promise<{ status: number, body: string }> {
87
- const route = routes.find(candidate => candidate.path === QUEUE_ROUTE)
88
- expect(route, `route ${QUEUE_ROUTE} must be registered`).toBeDefined()
89
- // `exactOptionalPropertyTypes` forbids assigning an explicit `undefined` to an
90
- // optional property, so the widened type must spell it out.
91
- const captured: { status?: number, body?: string | undefined } = {}
92
- const res = {
93
- writeHead(code: number) { captured.status = code },
94
- end(body?: string) { captured.body = body },
95
- }
96
- await route!.handler({ url: QUEUE_ROUTE }, res)
97
- return { status: captured.status ?? 0, body: captured.body ?? '' }
98
- }
99
-
100
- describe('review routes resolve a preset-scoped pruner', () => {
101
- it('answers 503 while no pruner has been published', async () => {
102
- const routes = await bootWithRoutes()
103
- const { status, body } = await readQueue(routes)
104
- expect(status).toBe(503)
105
- expect(body).toContain('review pipeline unavailable')
106
- })
107
-
108
- it('reaches a pruner published from a CHILD fiber with no top-level service', async () => {
109
- const routes = await bootWithRoutes()
110
- // Production shape: the pruner is mounted in a preset's isolated group.
111
- await ctx!.plugin({
112
- name: 'preset-scoped-pruner',
113
- apply(childCtx) {
114
- childCtx.effect(() => registerReviewPruner(samplePruner()), 'test-preset-pruner')
115
- },
116
- })
117
- await settle()
118
-
119
- const { status, body } = await readQueue(routes)
120
- expect(status).toBe(200)
121
- const parsed = JSON.parse(body) as { ok: boolean, total: number, pending: readonly { id: string }[] }
122
- expect(parsed.ok).toBe(true)
123
- expect(parsed.total).toBe(1)
124
- expect(parsed.pending[0]?.id).toBe(SAMPLE.id)
125
- })
126
-
127
- it('drops back to 503 once the publishing fiber disposes', async () => {
128
- const routes = await bootWithRoutes()
129
- const fork = await ctx!.plugin({
130
- name: 'preset-scoped-pruner',
131
- apply(childCtx) {
132
- childCtx.effect(() => registerReviewPruner(samplePruner()), 'test-preset-pruner')
133
- },
134
- })
135
- await settle()
136
- expect((await readQueue(routes)).status).toBe(200)
137
-
138
- await fork.dispose()
139
- await settle()
140
- expect((await readQueue(routes)).status).toBe(503)
141
- })
142
- })
@@ -1,290 +0,0 @@
1
- /**
2
- * Host-side guard for the review pipeline's HTTP transport (R4).
3
- *
4
- * Pins the client↔runtime contract: the two routes (queue read, decide write)
5
- * register under both prefixes, the happy path answers a sanitized payload
6
- * (ids/seqs/counts, never digests or content), and every error path answers a
7
- * precise status — 400 for malformed input, 404 for unknown session/proposal,
8
- * 503 when the review pipeline is not serving the session.
9
- */
10
-
11
- import { Context } from '@deepseek-ai/cordis'
12
- import { afterEach, describe, expect, it } from 'vitest'
13
- import { apply } from '../src/index.ts'
14
-
15
- const QUEUE_ROUTE = '/api/dsh-context-compression-improved/review-queue'
16
- const DECIDE_ROUTE = '/api/dsh-context-compression-improved/review-decide'
17
- const LEGACY_QUEUE_ROUTE = '/endpoint/dsh-context-compression-improved/review-queue'
18
- const LEGACY_DECIDE_ROUTE = '/endpoint/dsh-context-compression-improved/review-decide'
19
-
20
- interface RegisteredRoute {
21
- kind: string
22
- path: string
23
- handler: (req: unknown, res: unknown) => unknown
24
- }
25
-
26
- interface FakeResponse {
27
- status?: number
28
- body?: string
29
- }
30
-
31
- let ctx: Context | undefined
32
-
33
- afterEach(async () => {
34
- await ctx?.fiber.dispose()
35
- ctx = undefined
36
- })
37
-
38
- const settle = (): Promise<void> => new Promise(resolve => setTimeout(resolve, 20))
39
-
40
- async function mountWebServer(runtime: Context, routes: RegisteredRoute[]): Promise<void> {
41
- await runtime.plugin({
42
- name: 'fake-webserver',
43
- apply(webCtx) {
44
- webCtx.provide('webServer', {
45
- tables: { exact: new Map<string, RegisteredRoute>() },
46
- register(this: { tables: { exact: Map<string, RegisteredRoute> } }, route: RegisteredRoute) {
47
- const table = this.tables.exact
48
- if (table.has(route.path)) {
49
- throw new Error(`webserver: duplicate ${route.kind} route "${route.path}"`)
50
- }
51
- table.set(route.path, route)
52
- routes.push(route)
53
- return () => {}
54
- },
55
- })
56
- },
57
- })
58
- }
59
-
60
- interface PrunerBehavior {
61
- readonly reviewOn: boolean
62
- decideOutcome?: { ok: true } | { ok: false, reason: string } | undefined
63
- }
64
-
65
- function mountReviewServices(runtime: Context, behavior: PrunerBehavior): void {
66
- void runtime.plugin({
67
- name: 'fake-review-services',
68
- apply(serviceCtx) {
69
- serviceCtx.provide('agents', {
70
- get: (id: unknown) => (id === 's1' ? { session: { id: 's1' } } : undefined),
71
- })
72
- const sampleProposal = {
73
- id: 'abc123def456',
74
- kind: 'read-state',
75
- status: 'pending',
76
- items: [{
77
- seq: 6, kind: 'read-state', component: 'history', tokensBefore: 2401, tokensAfter: 134,
78
- digest: 'dd'.repeat(32),
79
- }],
80
- benefit: { recoveredTokens: 400, penaltyTokens: 900, paybackTurns: 2.25 },
81
- enqueuedTurn: 3,
82
- lastTurnIndex: 3,
83
- }
84
- serviceCtx.provide('toolResultPruner', {
85
- listReviewProposals: (session: unknown) => {
86
- const id = (session as { id?: string }).id
87
- return id === 's1' && behavior.reviewOn ? [sampleProposal] : []
88
- },
89
- listAllReviewProposals: () => (behavior.reviewOn
90
- ? [{ sessionId: 's1', proposals: [sampleProposal] }]
91
- : []),
92
- reviewSummary: () => ({ autoApplied: 2, reviewApplied: 1, expired: 3, voided: 0 }),
93
- decideReviewProposal: (_session: unknown, proposalId: string) => {
94
- if (behavior.reviewOn === false) return undefined
95
- if (proposalId !== 'abc123def456') return { ok: false, reason: 'unknown-proposal' }
96
- return behavior.decideOutcome ?? { ok: true }
97
- },
98
- })
99
- },
100
- })
101
- }
102
-
103
- async function invoke(route: RegisteredRoute, req?: unknown): Promise<FakeResponse> {
104
- const captured: FakeResponse = {}
105
- const res = {
106
- writeHead(code: number) { captured.status = code },
107
- end(body?: string) { if (body !== undefined) captured.body = body },
108
- }
109
- await route.handler(req ?? { method: 'GET' }, res)
110
- await settle()
111
- return captured
112
- }
113
-
114
- describe('review queue route registration', () => {
115
- it('registers both route prefixes only when the row opts in', async () => {
116
- const routes: RegisteredRoute[] = []
117
- const runtime = new Context()
118
- ctx = runtime
119
- await mountWebServer(runtime, routes)
120
-
121
- apply(runtime, { reviewQueueRoute: true })
122
- await settle()
123
-
124
- expect(routes.map(route => route.path)).toEqual([
125
- LEGACY_QUEUE_ROUTE, QUEUE_ROUTE, LEGACY_DECIDE_ROUTE, DECIDE_ROUTE,
126
- ])
127
-
128
- const routesAfterOptOut: RegisteredRoute[] = []
129
- const plain = new Context()
130
- ctx = plain
131
- await mountWebServer(plain, routesAfterOptOut)
132
- apply(plain, { presetOverlay: false })
133
- await settle()
134
- expect(routesAfterOptOut).toHaveLength(0)
135
- })
136
-
137
- it('answers the queue read with a sanitized payload', async () => {
138
- const routes: RegisteredRoute[] = []
139
- const runtime = new Context()
140
- ctx = runtime
141
- await mountWebServer(runtime, routes)
142
- mountReviewServices(runtime, { reviewOn: true })
143
- apply(runtime, { reviewQueueRoute: true })
144
- await settle()
145
-
146
- const route = routes.find(candidate => candidate.path === QUEUE_ROUTE)
147
- const response = await invoke(route as RegisteredRoute, { url: `${QUEUE_ROUTE}?sessionId=s1` })
148
-
149
- expect(response.status).toBe(200)
150
- const body = JSON.parse(String(response.body)) as {
151
- ok: boolean
152
- summary?: Record<string, number>
153
- pending: readonly { id: string, items: readonly Record<string, unknown>[] }[]
154
- }
155
- expect(body.ok).toBe(true)
156
- expect(body.pending).toHaveLength(1)
157
- expect(body.pending[0]!.id).toBe('abc123def456')
158
- expect(body.summary).toEqual({ autoApplied: 2, reviewApplied: 1, expired: 3, voided: 0 })
159
- // Digests never leave the runtime: the client only needs ids and counts.
160
- expect(String(response.body)).not.toContain('digest')
161
- expect(String(response.body)).not.toContain('"content"')
162
- })
163
-
164
- it('aggregates every live session when the read carries no sessionId', async () => {
165
- const routes: RegisteredRoute[] = []
166
- const runtime = new Context()
167
- ctx = runtime
168
- await mountWebServer(runtime, routes)
169
- mountReviewServices(runtime, { reviewOn: true })
170
- apply(runtime, { reviewQueueRoute: true })
171
- await settle()
172
-
173
- const route = routes.find(candidate => candidate.path === QUEUE_ROUTE) as RegisteredRoute
174
- const response = await invoke(route, { url: QUEUE_ROUTE })
175
-
176
- expect(response.status).toBe(200)
177
- const body = JSON.parse(String(response.body)) as {
178
- ok: boolean
179
- total: number
180
- pending: readonly { sessionId: string, id: string }[]
181
- }
182
- expect(body).toMatchObject({ ok: true, total: 1 })
183
- expect(body.pending[0]).toMatchObject({ sessionId: 's1', id: 'abc123def456' })
184
- })
185
-
186
- it('rejects a queue read for an unknown session', async () => {
187
- const routes: RegisteredRoute[] = []
188
- const runtime = new Context()
189
- ctx = runtime
190
- await mountWebServer(runtime, routes)
191
- mountReviewServices(runtime, { reviewOn: true })
192
- apply(runtime, { reviewQueueRoute: true })
193
- await settle()
194
- const route = routes.find(candidate => candidate.path === QUEUE_ROUTE) as RegisteredRoute
195
-
196
- const unknown = await invoke(route, { url: `${QUEUE_ROUTE}?sessionId=nope` })
197
- expect(unknown.status).toBe(404)
198
- })
199
-
200
- it('answers 503 when the pruner is not serving review proposals', async () => {
201
- const routes: RegisteredRoute[] = []
202
- const runtime = new Context()
203
- ctx = runtime
204
- await mountWebServer(runtime, routes)
205
- apply(runtime, { reviewQueueRoute: true })
206
- await settle()
207
-
208
- const route = routes.find(candidate => candidate.path === QUEUE_ROUTE) as RegisteredRoute
209
- const response = await invoke(route, { url: `${QUEUE_ROUTE}?sessionId=s1` })
210
- expect(response.status).toBe(503)
211
- })
212
-
213
- it('rejects malformed decide bodies with 400', async () => {
214
- const routes: RegisteredRoute[] = []
215
- const runtime = new Context()
216
- ctx = runtime
217
- await mountWebServer(runtime, routes)
218
- mountReviewServices(runtime, { reviewOn: true })
219
- apply(runtime, { reviewQueueRoute: true })
220
- await settle()
221
- const route = routes.find(candidate => candidate.path === DECIDE_ROUTE) as RegisteredRoute
222
-
223
- const notJson = await invoke(route, { on: (event: string, listener: (chunk?: Buffer) => void) => {
224
- if (event === 'end') listener()
225
- } })
226
- expect(notJson.status).toBe(400)
227
-
228
- const missingDecision = await invoke(route, { on: (event: string, listener: (chunk?: Buffer) => void) => {
229
- if (event === 'data') listener(Buffer.from(JSON.stringify({ sessionId: 's1', proposalId: 'abc123def456' })))
230
- if (event === 'end') listener()
231
- } })
232
- expect(missingDecision.status).toBe(400)
233
-
234
- const badDecision = await invoke(route, { on: (event: string, listener: (chunk?: Buffer) => void) => {
235
- if (event === 'data') listener(Buffer.from(JSON.stringify({ sessionId: 's1', proposalId: 'abc123def456', decision: 'maybe' })))
236
- if (event === 'end') listener()
237
- } })
238
- expect(badDecision.status).toBe(400)
239
- })
240
-
241
- it('maps decide outcomes to 200, 404, and 503', async () => {
242
- const routes: RegisteredRoute[] = []
243
- const runtime = new Context()
244
- ctx = runtime
245
- await mountWebServer(runtime, routes)
246
- mountReviewServices(runtime, { reviewOn: true })
247
- apply(runtime, { reviewQueueRoute: true })
248
- await settle()
249
- const route = routes.find(candidate => candidate.path === DECIDE_ROUTE) as RegisteredRoute
250
-
251
- const post = (body: unknown): unknown => ({
252
- on: (event: string, listener: (chunk?: Buffer) => void) => {
253
- if (event === 'data') listener(Buffer.from(JSON.stringify(body)))
254
- if (event === 'end') listener()
255
- },
256
- })
257
-
258
- const ok = await invoke(route, post({ sessionId: 's1', proposalId: 'abc123def456', decision: 'approved' }))
259
- expect(ok.status).toBe(200)
260
- expect(JSON.parse(String(ok.body))).toMatchObject({ ok: true, decision: 'approved' })
261
-
262
- const unknownProposal = await invoke(route, post({ sessionId: 's1', proposalId: 'nope', decision: 'approved' }))
263
- expect(unknownProposal.status).toBe(404)
264
-
265
- const unknownSession = await invoke(route, post({ sessionId: 'nope', proposalId: 'abc123def456', decision: 'approved' }))
266
- expect(unknownSession.status).toBe(404)
267
- })
268
-
269
- it('answers 503 when review mode is off for the session', async () => {
270
- const routes: RegisteredRoute[] = []
271
- const runtime = new Context()
272
- ctx = runtime
273
- await mountWebServer(runtime, routes)
274
- mountReviewServices(runtime, { reviewOn: false })
275
- apply(runtime, { reviewQueueRoute: true })
276
- await settle()
277
-
278
- const queueRoute = routes.find(candidate => candidate.path === QUEUE_ROUTE) as RegisteredRoute
279
- expect((await invoke(queueRoute, { url: `${QUEUE_ROUTE}?sessionId=s1` })).status).toBe(200)
280
-
281
- const decideRoute = routes.find(candidate => candidate.path === DECIDE_ROUTE) as RegisteredRoute
282
- const response = await invoke(decideRoute, {
283
- on: (event: string, listener: (chunk?: Buffer) => void) => {
284
- if (event === 'data') listener(Buffer.from(JSON.stringify({ sessionId: 's1', proposalId: 'abc123def456', decision: 'approved' })))
285
- if (event === 'end') listener()
286
- },
287
- })
288
- expect(response.status).toBe(503)
289
- })
290
- })