dsh-context-compression-improved 0.5.0 → 0.5.2

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 (50) hide show
  1. package/CHANGELOG.ja.md +51 -0
  2. package/CHANGELOG.ko.md +51 -0
  3. package/CHANGELOG.md +55 -0
  4. package/CHANGELOG.zh.md +45 -0
  5. package/package.json +1 -1
  6. package/packages/selector/lib/advisor-state.js +4 -231
  7. package/packages/selector/lib/client.d.ts +0 -24
  8. package/packages/selector/lib/client.js +6 -501
  9. package/packages/selector/lib/index.d.ts +4 -10
  10. package/packages/selector/lib/index.js +65 -235
  11. package/packages/selector/lib/pruner.d.ts +13 -248
  12. package/packages/selector/lib/pruner.js +148 -552
  13. package/packages/selector/src/client/EstimatorControls.tsx +277 -378
  14. package/packages/selector/src/client/index.ts +0 -17
  15. package/packages/selector/src/client/locales.ts +196 -234
  16. package/packages/selector/src/client/preset-options.ts +3 -2
  17. package/packages/selector/src/client/settings-section.tsx +8 -17
  18. package/packages/selector/src/index.ts +463 -710
  19. package/packages/selector/src/preset-overlay.ts +60 -1
  20. package/packages/selector/src/profiles.ts +4 -27
  21. package/packages/selector/src/pruner/state.ts +50 -73
  22. package/packages/selector/src/pruner.ts +2402 -2730
  23. package/packages/selector/src/runtime/audit.ts +27 -21
  24. package/packages/selector/src/runtime/config.ts +6 -32
  25. package/packages/selector/src/runtime/tokenpilot/advisor-state.ts +16 -0
  26. package/packages/selector/src/runtime/tokenpilot/benefit.ts +200 -0
  27. package/packages/selector/src/runtime/types.ts +0 -17
  28. package/packages/selector/tests/built/client-artifact.spec.ts +9 -5
  29. package/packages/selector/tests/preset-options-write.client.spec.ts +7 -23
  30. package/packages/selector/tests/runtime/advice-never-withholds.host.spec.ts +232 -0
  31. package/packages/selector/tests/runtime/audit.spec.ts +35 -21
  32. package/packages/selector/tests/runtime/deprecated-preset-options.spec.ts +96 -0
  33. package/packages/selector/tests/runtime/tokenpilot/benefit.spec.ts +217 -0
  34. package/packages/selector/tests/runtime/tokenpilot/profile-baseline.spec.ts +4 -5
  35. package/packages/selector/tests/settings-seat.client.spec.ts +16 -10
  36. package/packages/selector/tests/standing-generation.host.spec.ts +54 -5
  37. package/scripts/packed-components-smoke.mjs +30 -8
  38. package/scripts/packed-install-e2e.mjs +69 -15
  39. package/packages/selector/src/client/ReviewOverlay.tsx +0 -320
  40. package/packages/selector/src/client/review-scope.ts +0 -16
  41. package/packages/selector/src/runtime/tokenpilot/proposal.ts +0 -267
  42. package/packages/selector/src/runtime/tokenpilot/review-queue.ts +0 -231
  43. package/packages/selector/src/runtime/tokenpilot/review-registry.ts +0 -117
  44. package/packages/selector/src/runtime/tokenpilot/review-storage.ts +0 -122
  45. package/packages/selector/tests/review-overlay.client.spec.tsx +0 -118
  46. package/packages/selector/tests/review-routes-registry.host.spec.ts +0 -142
  47. package/packages/selector/tests/review-routes.host.spec.ts +0 -290
  48. package/packages/selector/tests/runtime/tokenpilot/proposal.spec.ts +0 -393
  49. package/packages/selector/tests/runtime/tokenpilot/pruner-review.spec.ts +0 -382
  50. package/packages/selector/tests/runtime/tokenpilot/review-queue.spec.ts +0 -168
@@ -116,6 +116,16 @@ export function standingStampMs(identity: string): number {
116
116
  return standingStampMsAtWindow(identity, 0)
117
117
  }
118
118
 
119
+ /**
120
+ * True for the filesystem errors a concurrent publish can raise on Windows:
121
+ * `MoveFileEx` reports a lost race — or a reader holding the destination open —
122
+ * as EPERM/EBUSY/EACCES, where POSIX `rename` simply replaces the destination.
123
+ */
124
+ function isPublishRace(error: unknown): boolean {
125
+ const code = (error as { code?: unknown } | null)?.code
126
+ return code === 'EPERM' || code === 'EBUSY' || code === 'EACCES' || code === 'EEXIST'
127
+ }
128
+
119
129
  const COMPRESSION_IDS = new Set([
120
130
  'compaction',
121
131
  'compaction-basic',
@@ -224,7 +234,7 @@ class PresetOverlayStore {
224
234
  // still private. No reader can observe a colliding {mtimeMs,size}
225
235
  // between rename and a later corrective utimes call.
226
236
  await this.disambiguateStamp(staging, identity)
227
- await rename(staging, path)
237
+ await this.publish(staging, path)
228
238
  } catch (error) {
229
239
  // A failed publish must not leak its staging file into the store; the
230
240
  // cleanup must never mask the original failure either.
@@ -238,6 +248,55 @@ class PresetOverlayStore {
238
248
  return { ...preset, path }
239
249
  }
240
250
 
251
+ /** In-flight publish chains, one per destination path. */
252
+ private readonly publishChains = new Map<string, Promise<void>>()
253
+
254
+ /**
255
+ * Publish one stamped staging file to its final path, serialized per path.
256
+ *
257
+ * POSIX `rename` replaces an existing destination atomically, so concurrent
258
+ * composers of one identity are naturally idempotent there. Windows
259
+ * `MoveFileEx` instead fails the loser of that race with EPERM/EBUSY, which
260
+ * surfaced as `standingKeyFor()` throwing during concurrent composition.
261
+ * Every composer of one identity writes identical bytes and re-derives the
262
+ * same deterministic identity stamp, so a destination that already observes
263
+ * this staging file's {mtimeMs, size} key IS the intended end state: confirm
264
+ * it and treat the lost race as success. Every other outcome still throws, so
265
+ * a silently reused generation stays forbidden, and the caller still removes
266
+ * the staging file when this rejects.
267
+ */
268
+ private publish(staging: string, path: string): Promise<void> {
269
+ const previous = this.publishChains.get(path) ?? Promise.resolve()
270
+ const queued = previous.catch(() => undefined).then(async () => {
271
+ try {
272
+ await rename(staging, path)
273
+ return
274
+ } catch (error) {
275
+ if (!isPublishRace(error)) throw error
276
+ try {
277
+ const intended = await this.metadataIo.read(staging)
278
+ const published = await this.metadataIo.read(path)
279
+ // Sub-second precision survives a wrapped seconds field, but NTFS
280
+ // rounds it to 100ns, so compare the standing key within that
281
+ // rounding rather than by exact float equality.
282
+ if (published.size === intended.size
283
+ && Math.abs(published.mtimeMs - intended.mtimeMs) < 2) {
284
+ await rm(staging, { force: true })
285
+ return
286
+ }
287
+ } catch {
288
+ // The destination is unreadable: report the original publish failure.
289
+ }
290
+ throw error
291
+ }
292
+ })
293
+ const tracked = queued.finally(() => {
294
+ if (this.publishChains.get(path) === tracked) this.publishChains.delete(path)
295
+ })
296
+ this.publishChains.set(path, tracked)
297
+ return tracked
298
+ }
299
+
241
300
  /** Observed {mtimeMs,size} keys published by this store, per identity. */
242
301
  private readonly standingKeys = new Map<string, string>()
243
302
 
@@ -135,11 +135,6 @@ export interface PresetOptionsSettings {
135
135
  readonly estimatorBaseUrl?: string
136
136
  readonly estimatorApiKey?: string
137
137
  readonly estimatorTimeoutMs?: number
138
- /** Review-mode overrides (beta); mirrors the runtime PresetOptions.reviewMode. */
139
- readonly reviewMode?: boolean
140
- readonly reviewTimeoutTurns?: number
141
- readonly cacheHitDiscountAlpha?: number
142
- readonly reviewHighImpactTokens?: number
143
138
  /** Advisory advisor channel; `''` (the default) keeps the advisor off. */
144
139
  readonly advisorMode?: '' | 'host' | 'direct'
145
140
  readonly advisorTimeoutMs?: number
@@ -160,12 +155,15 @@ export function decodePresetOptionsSettings(value: unknown): PresetOptionsSettin
160
155
  const allowed = new Set([
161
156
  'dedupeToolResults', 'summaryLocator', 'prefixStabilizer', 'readState', 'estimatorMode',
162
157
  'estimatorProvider', 'estimatorModel', 'estimatorBaseUrl', 'estimatorApiKey', 'estimatorTimeoutMs',
158
+ // Legacy keys of the retired review gate: still ACCEPTED so an existing
159
+ // settings document keeps decoding (rejecting them would report the whole
160
+ // card unreadable), and ignored — nothing reads them any more.
163
161
  'reviewMode', 'reviewTimeoutTurns', 'cacheHitDiscountAlpha', 'reviewHighImpactTokens',
164
162
  'advisorMode', 'advisorTimeoutMs', 'advisorRefreshTurns', 'advisorScoreThreshold', 'advisorSampleLimit',
165
163
  'advisorMinTokens',
166
164
  ])
167
165
  if (Object.keys(value).some(key => !allowed.has(key))) return undefined
168
- for (const key of ['dedupeToolResults', 'summaryLocator', 'prefixStabilizer', 'readState', 'reviewMode'] as const) {
166
+ for (const key of ['dedupeToolResults', 'summaryLocator', 'prefixStabilizer', 'readState'] as const) {
169
167
  const entry = value[key]
170
168
  if (entry !== undefined && typeof entry !== 'boolean') return undefined
171
169
  }
@@ -187,23 +185,6 @@ export function decodePresetOptionsSettings(value: unknown): PresetOptionsSettin
187
185
  || estimatorTimeoutMs < 100 || estimatorTimeoutMs > 60_000)) {
188
186
  return undefined
189
187
  }
190
- const reviewTimeoutTurns = value.reviewTimeoutTurns
191
- if (reviewTimeoutTurns !== undefined
192
- && (typeof reviewTimeoutTurns !== 'number' || !Number.isSafeInteger(reviewTimeoutTurns) || reviewTimeoutTurns < 1)) {
193
- return undefined
194
- }
195
- const cacheHitDiscountAlpha = value.cacheHitDiscountAlpha
196
- if (cacheHitDiscountAlpha !== undefined
197
- && (typeof cacheHitDiscountAlpha !== 'number' || !Number.isFinite(cacheHitDiscountAlpha)
198
- || cacheHitDiscountAlpha <= 0 || cacheHitDiscountAlpha >= 1)) {
199
- return undefined
200
- }
201
- const reviewHighImpactTokens = value.reviewHighImpactTokens
202
- if (reviewHighImpactTokens !== undefined
203
- && (typeof reviewHighImpactTokens !== 'number' || !Number.isSafeInteger(reviewHighImpactTokens)
204
- || reviewHighImpactTokens < 0)) {
205
- return undefined
206
- }
207
188
  const advisorTimeoutMs = value.advisorTimeoutMs
208
189
  if (advisorTimeoutMs !== undefined
209
190
  && (typeof advisorTimeoutMs !== 'number' || !Number.isSafeInteger(advisorTimeoutMs)
@@ -246,10 +227,6 @@ export function decodePresetOptionsSettings(value: unknown): PresetOptionsSettin
246
227
  if (value.estimatorBaseUrl !== undefined) decoded.estimatorBaseUrl = value.estimatorBaseUrl as string
247
228
  if (value.estimatorApiKey !== undefined) decoded.estimatorApiKey = value.estimatorApiKey as string
248
229
  if (estimatorTimeoutMs !== undefined) decoded.estimatorTimeoutMs = estimatorTimeoutMs as number
249
- if (value.reviewMode !== undefined) decoded.reviewMode = value.reviewMode as boolean
250
- if (reviewTimeoutTurns !== undefined) decoded.reviewTimeoutTurns = reviewTimeoutTurns as number
251
- if (cacheHitDiscountAlpha !== undefined) decoded.cacheHitDiscountAlpha = cacheHitDiscountAlpha as number
252
- if (reviewHighImpactTokens !== undefined) decoded.reviewHighImpactTokens = reviewHighImpactTokens as number
253
230
  if (advisorMode !== undefined) decoded.advisorMode = advisorMode as '' | 'host' | 'direct'
254
231
  if (advisorTimeoutMs !== undefined) decoded.advisorTimeoutMs = advisorTimeoutMs as number
255
232
  if (advisorRefreshTurns !== undefined) decoded.advisorRefreshTurns = advisorRefreshTurns as number
@@ -1,73 +1,50 @@
1
- /**
2
- * Consolidated per-session mutable state for {@link ToolResultPruner}.
3
- *
4
- * Every field is a WeakMap keyed by Session, keeping the service
5
- * stateless across sessions and safe under GC.
6
- */
7
-
8
- import type { Session } from '@deepseek-ai/dsh-session'
9
- import type { DedupeTable } from '../runtime/tokenpilot/dedup.ts'
10
- import type { EstimatorFailures } from '../runtime/tokenpilot/estimator.ts'
11
- import type { ReviewQueue, ReviewQueueStore } from '../runtime/tokenpilot/review-queue.ts'
12
- import type { SideChannel } from '../runtime/tokenpilot/sidechannel.ts'
13
- import type {
14
- ContextCompressionSettings,
15
- ResolvedConfig,
16
- } from '../runtime/types.ts'
17
-
18
- /** Four-state per-session outcome counters behind the floating-window summary row. */
19
- export interface ReviewSessionSummary {
20
- /** Rewrites that landed through the automatic path while review mode served this session. */
21
- autoApplied: number
22
- /** Approved proposals whose merged batch executed with an applied receipt. */
23
- reviewApplied: number
24
- /** Pending proposals that expired unhandled at a turn boundary. */
25
- expired: number
26
- /** Approved proposals voided at the apply point (digest mismatch et al). */
27
- voided: number
28
- }
29
-
30
- /** Mutable per-session state bag used inside {@link ToolResultPruner}. */
31
- export interface PrunerState {
32
- /** Resolved immutable deployment configuration. */
33
- readonly config: ResolvedConfig
34
-
35
- /** Complete canonical setting document frozen when each Session first reaches this root service. */
36
- readonly sessionSettings: WeakMap<Session, ContextCompressionSettings>
37
- /** Original result seqs whose first-exposure KEEP/REDUCE decision has committed. */
38
- readonly firstExposure: WeakMap<Session, Set<number>>
39
- /** Result seqs permanently exempt from further reduction (recovery outputs and registered equivalents). */
40
- readonly recoveryExemptions: WeakMap<Session, Set<number>>
41
- /** Per-session canonical-content hash index backing tokenpilot-inspired dedupe. */
42
- readonly dedupeTables: WeakMap<Session, DedupeTable>
43
- /** Advisory estimator verdicts consumed by the read-state classification. */
44
- readonly estimatorVerdicts: WeakMap<Session, Map<number, boolean>>
45
- /** Per-session estimator failure backoff state. */
46
- readonly estimatorFailures: WeakMap<Session, EstimatorFailures>
47
- /** Runtime prerequisite warnings deduplicated per Session and failure key. */
48
- readonly warnedFailures: WeakMap<Session, Set<string>>
49
- /** Last Adaptive postflight attempt emitted per Session; keeps diagnostics bounded and independent. */
50
- readonly postflightDiagnostics: WeakMap<Session, string>
51
- /** Current pre-step chain identity, shared by this producer and downstream compaction-basic. */
52
- readonly activeRequestBoundaries: WeakMap<Session, object>
53
- /** Boundary identity that already attempted one fully preflighted TailTrim publication. */
54
- readonly tailTrimBoundaryAttempts: WeakMap<Session, object>
55
- /** Last effective policy audit key emitted for each Session. */
56
- readonly policyResolutionAudits: WeakMap<Session, string>
57
- /**
58
- * TokenPilot-inspired R4: shared review-queue store. Starts as the in-memory
59
- * fail-open fallback; swapped to the storageDomain-backed adapter when (and
60
- * if) that seam opens successfully.
61
- */
62
- reviewStore: ReviewQueueStore
63
- /** Per-session review queue carrying the frozen timeout policy. */
64
- readonly reviewQueues: WeakMap<Session, ReviewQueue>
65
- /** Last observed turn index per Session: the monotonic clock for review expiries. */
66
- readonly reviewClocks: WeakMap<Session, number>
67
- /** Estimator-reported remaining turns Ŝ per Session; advisory only. */
68
- readonly estimatorRemainingTurns: WeakMap<Session, number>
69
- /** Per-session advisor side channel, constructed once with the advisor overrides. */
70
- readonly advisorChannels: WeakMap<Session, SideChannel>
71
- /** Four-state outcome counters per Session (floating-window summary row). */
72
- readonly reviewSummaries: WeakMap<Session, ReviewSessionSummary>
73
- }
1
+ /**
2
+ * Consolidated per-session mutable state for {@link ToolResultPruner}.
3
+ *
4
+ * Every field is a WeakMap keyed by Session, keeping the service
5
+ * stateless across sessions and safe under GC.
6
+ */
7
+
8
+ import type { Session } from '@deepseek-ai/dsh-session'
9
+ import type { DedupeTable } from '../runtime/tokenpilot/dedup.ts'
10
+ import type { EstimatorFailures } from '../runtime/tokenpilot/estimator.ts'
11
+ import type { SideChannel } from '../runtime/tokenpilot/sidechannel.ts'
12
+ import type {
13
+ ContextCompressionSettings,
14
+ ResolvedConfig,
15
+ } from '../runtime/types.ts'
16
+
17
+ /** Mutable per-session state bag used inside {@link ToolResultPruner}. */
18
+ export interface PrunerState {
19
+ /** Resolved immutable deployment configuration. */
20
+ readonly config: ResolvedConfig
21
+
22
+ /** Complete canonical setting document frozen when each Session first reaches this root service. */
23
+ readonly sessionSettings: WeakMap<Session, ContextCompressionSettings>
24
+ /** Original result seqs whose first-exposure KEEP/REDUCE decision has committed. */
25
+ readonly firstExposure: WeakMap<Session, Set<number>>
26
+ /** Result seqs permanently exempt from further reduction (recovery outputs and registered equivalents). */
27
+ readonly recoveryExemptions: WeakMap<Session, Set<number>>
28
+ /** Per-session canonical-content hash index backing tokenpilot-inspired dedupe. */
29
+ readonly dedupeTables: WeakMap<Session, DedupeTable>
30
+ /** Advisory estimator verdicts consumed by the read-state classification. */
31
+ readonly estimatorVerdicts: WeakMap<Session, Map<number, boolean>>
32
+ /** Per-session estimator failure backoff state. */
33
+ readonly estimatorFailures: WeakMap<Session, EstimatorFailures>
34
+ /** Runtime prerequisite warnings deduplicated per Session and failure key. */
35
+ readonly warnedFailures: WeakMap<Session, Set<string>>
36
+ /** Last Adaptive postflight attempt emitted per Session; keeps diagnostics bounded and independent. */
37
+ readonly postflightDiagnostics: WeakMap<Session, string>
38
+ /** Current pre-step chain identity, shared by this producer and downstream compaction-basic. */
39
+ readonly activeRequestBoundaries: WeakMap<Session, object>
40
+ /** Boundary identity that already attempted one fully preflighted TailTrim publication. */
41
+ readonly tailTrimBoundaryAttempts: WeakMap<Session, object>
42
+ /** Last effective policy audit key emitted for each Session. */
43
+ readonly policyResolutionAudits: WeakMap<Session, string>
44
+ /** Last observed turn index per Session: the monotonic clock for advisory records. */
45
+ readonly turnClocks: WeakMap<Session, number>
46
+ /** Estimator-reported remaining turns Ŝ per Session; advisory only. */
47
+ readonly estimatorRemainingTurns: WeakMap<Session, number>
48
+ /** Per-session advisor side channel, constructed once with the advisor overrides. */
49
+ readonly advisorChannels: WeakMap<Session, SideChannel>
50
+ }