dsh-context-compression-improved 0.1.1 → 0.2.1
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 -0
- package/.github/workflows/ci.yml +39 -0
- package/CHANGELOG.ja.md +39 -0
- package/CHANGELOG.ko.md +39 -0
- package/CHANGELOG.md +135 -0
- package/CHANGELOG.zh.md +39 -0
- package/CONTRIBUTING.md +22 -0
- package/README.ja.md +104 -0
- package/README.ko.md +103 -0
- package/README.md +89 -12
- package/README.zh.md +87 -12
- package/SECURITY.md +18 -0
- package/THIRD_PARTY_NOTICES.md +7 -31
- package/docs/installation.ja.md +76 -0
- package/docs/installation.ko.md +76 -0
- package/docs/installation.md +76 -0
- package/docs/installation.zh.md +76 -0
- package/docs/repair-log.md +582 -0
- package/eslint.config.js +30 -0
- package/package.json +85 -82
- package/packages/selector/LICENSE +21 -0
- package/packages/selector/README.md +26 -0
- package/packages/selector/README.zh.md +26 -0
- package/packages/selector/THIRD_PARTY_NOTICES.md +38 -0
- package/packages/selector/docs/history-tool-call-working-set-spec.md +112 -0
- package/packages/selector/docs/native-tool-result-selector-spec.md +34 -0
- package/packages/selector/docs/subagent-cache-reuse-spec.md +46 -0
- package/packages/selector/lib/style.css +308 -0
- package/packages/selector/package.json +115 -0
- package/{screenshots.json → packages/selector/screenshots.json} +6 -6
- package/packages/selector/src/client/CompressionProfileControls.tsx +229 -0
- package/packages/selector/src/client/CompressionProfileSelector.module.css +170 -0
- package/packages/selector/src/client/CompressionProfileSelector.tsx +79 -0
- package/packages/selector/src/client/CustomPolicyEditor.tsx +216 -0
- package/packages/selector/src/client/EstimatorControls.tsx +281 -0
- package/packages/selector/src/client/decode.ts +49 -0
- package/packages/selector/src/client/index.ts +111 -0
- package/packages/selector/src/client/locales.ts +198 -0
- package/packages/selector/src/client/preset-options.ts +70 -0
- package/packages/selector/src/client/settings-section.tsx +126 -0
- package/packages/selector/src/css-modules.d.ts +6 -0
- package/packages/selector/src/deepseek-v4-tokenizer.ts +210 -0
- package/packages/selector/src/estimator-catalog.ts +104 -0
- package/packages/selector/src/index.ts +327 -0
- package/packages/selector/src/invariant.ts +113 -0
- package/packages/selector/src/preset-overlay.ts +567 -0
- package/packages/selector/src/profiles.ts +342 -0
- package/packages/selector/src/pruner/content.ts +188 -0
- package/packages/selector/src/pruner/session.ts +94 -0
- package/packages/selector/src/pruner/state.ts +43 -0
- package/packages/selector/src/pruner/tuning.ts +23 -0
- package/packages/selector/src/pruner/types.ts +60 -0
- package/packages/selector/src/pruner.ts +2144 -0
- package/packages/selector/src/runtime/adaptive-cost.ts +194 -0
- package/packages/selector/src/runtime/audit.ts +215 -0
- package/packages/selector/src/runtime/config.ts +613 -0
- package/packages/selector/src/runtime/custom-policy.ts +278 -0
- package/packages/selector/src/runtime/deepseek-official-pricing.ts +298 -0
- package/packages/selector/src/runtime/deepseek-v4-vision-tokens.ts +254 -0
- package/packages/selector/src/runtime/measurement.ts +403 -0
- package/packages/selector/src/runtime/reducers.ts +656 -0
- package/packages/selector/src/runtime/retrieve.ts +457 -0
- package/packages/selector/src/runtime/session-events.ts +17 -0
- package/packages/selector/src/runtime/tail-trim.ts +166 -0
- package/packages/selector/src/runtime/token-count.ts +72 -0
- package/packages/selector/src/runtime/tokenpilot/dedup.ts +81 -0
- package/packages/selector/src/runtime/tokenpilot/estimator.ts +183 -0
- package/packages/selector/src/runtime/tokenpilot/locator.ts +128 -0
- package/packages/selector/src/runtime/tokenpilot/read-state.ts +77 -0
- package/packages/selector/src/runtime/types.ts +309 -0
- package/packages/selector/src/runtime/value.ts +48 -0
- package/packages/selector/tests/auto-compact.client.spec.tsx +226 -0
- package/packages/selector/tests/built/client-artifact.spec.ts +51 -0
- package/packages/selector/tests/cache-prefix-audit.spec.ts +123 -0
- package/packages/selector/tests/code-skeleton.client.spec.ts +88 -0
- package/packages/selector/tests/custom-contract.client.spec.ts +202 -0
- package/packages/selector/tests/estimator-catalog.spec.ts +70 -0
- package/packages/selector/tests/estimator-channel.client.spec.tsx +247 -0
- package/packages/selector/tests/estimator-route-registration.host.spec.ts +176 -0
- package/packages/selector/tests/host-preset-overlay.host.spec.ts +204 -0
- package/packages/selector/tests/preset-options-write.client.spec.ts +181 -0
- package/packages/selector/tests/preset-overlay-loader.e2e.host.spec.ts +196 -0
- package/packages/selector/tests/preset-overlay.host.spec.ts +243 -0
- package/packages/selector/tests/profiles.client.spec.tsx +434 -0
- package/packages/selector/tests/public/package-contract.client.spec.ts +33 -0
- package/packages/selector/tests/runtime/adaptive-cost.spec.ts +167 -0
- package/packages/selector/tests/runtime/audit.spec.ts +129 -0
- package/packages/selector/tests/runtime/auto-compact-config.spec.ts +523 -0
- package/packages/selector/tests/runtime/code-skeleton.spec.ts +141 -0
- package/packages/selector/tests/runtime/deepseek-official-pricing.spec.ts +186 -0
- package/packages/selector/tests/runtime/deepseek-v4-tokenizer.spec.ts +122 -0
- package/packages/selector/tests/runtime/deepseek-v4-vision-tokens.spec.ts +122 -0
- package/packages/selector/tests/runtime/fixtures/profile-baseline.json +273 -0
- package/packages/selector/tests/runtime/fixtures/tokenizer-golden.json +106 -0
- package/packages/selector/tests/runtime/fixtures/vision-golden.json +459 -0
- package/packages/selector/tests/runtime/public/public-runtime.spec.ts +2531 -0
- package/packages/selector/tests/runtime/session-events.spec.ts +27 -0
- package/packages/selector/tests/runtime/tokenizer-golden.spec.ts +53 -0
- package/packages/selector/tests/runtime/tokenpilot/dedup.spec.ts +52 -0
- package/packages/selector/tests/runtime/tokenpilot/estimator.spec.ts +56 -0
- package/packages/selector/tests/runtime/tokenpilot/locator.spec.ts +76 -0
- package/packages/selector/tests/runtime/tokenpilot/profile-baseline.spec.ts +100 -0
- package/packages/selector/tests/runtime/tokenpilot/read-state.spec.ts +58 -0
- package/packages/selector/tests/runtime/value.spec.ts +23 -0
- package/packages/selector/tests/standing-generation.host.spec.ts +631 -0
- package/packages/selector/tests/subagent-cache-reuse.host.spec.ts +250 -0
- package/packages/selector/tests/support/cache-prefix-audit.ts +105 -0
- package/packages/selector/tests/support/mock-adapter.ts +37 -0
- package/packages/selector/tests/support/ui-primitives.tsx +34 -0
- package/packages/selector/tsconfig.json +11 -0
- package/packages/selector/tsdown.client.config.ts +102 -0
- package/packages/selector/tsdown.config.ts +20 -0
- package/pnpm-workspace.yaml +19 -0
- package/scripts/capture-profile-baseline.ts +80 -0
- package/scripts/generate-tokenizer-fixtures.py +81 -0
- package/scripts/generate-vision-fixtures.py +208 -0
- package/scripts/packed-components-smoke.ts +713 -0
- package/scripts/packed-install-e2e.ts +1072 -0
- package/scripts/verify-release.ts +300 -0
- package/tests/TEST_INVENTORY.md +42 -0
- package/tsconfig.base.json +18 -0
- package/tsconfig.json +7 -0
- package/tsconfig.scripts.json +13 -0
- package/tsconfig.tests.json +15 -0
- package/vitest.built.config.ts +9 -0
- package/vitest.config.ts +43 -0
- /package/{assets → packages/selector/assets}/deepseek-v4/LICENSE.DeepSeek-V4-Pro.txt +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4/manifest.json +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4/tokenizer.json +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4/tokenizer_config.json +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4-vision-exp/LICENSE.DeepSeek-V4-Flash-Vision-Exp.txt +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4-vision-exp/manifest.json +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4-vision-exp/tokenizer.json +0 -0
- /package/{assets → packages/selector/assets}/deepseek-v4-vision-exp/tokenizer_config.json +0 -0
- /package/{assets → packages/selector/assets}/screenshots/context-compression-selector-profiles.jpg +0 -0
- /package/{assets → packages/selector/assets}/screenshots/context-compression-selector-settings.png +0 -0
- /package/{cordis.patch.yml → packages/selector/cordis.patch.yml} +0 -0
- /package/{dsh.plugin.json → packages/selector/dsh.plugin.json} +0 -0
- /package/{lib → packages/selector/lib}/client.d.ts +0 -0
- /package/{lib → packages/selector/lib}/client.js +0 -0
- /package/{lib → packages/selector/lib}/config.js +0 -0
- /package/{lib → packages/selector/lib}/index.d.ts +0 -0
- /package/{lib → packages/selector/lib}/index.js +0 -0
- /package/{lib → packages/selector/lib}/invariant.d.ts +0 -0
- /package/{lib → packages/selector/lib}/invariant.js +0 -0
- /package/{lib → packages/selector/lib}/pruner.d.ts +0 -0
- /package/{lib → packages/selector/lib}/pruner.js +0 -0
- /package/{lib → packages/selector/lib}/tail-trim.js +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/** Conservative cost interval used by the Adaptive History gate. */
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
MeasuredTokenSurfaceNode,
|
|
5
|
+
TokenCount,
|
|
6
|
+
} from './measurement.ts'
|
|
7
|
+
import { decimalRateNanoUnits } from './deepseek-official-pricing.ts'
|
|
8
|
+
|
|
9
|
+
/** Inputs that conservatively bound one already-planned Adaptive History batch. */
|
|
10
|
+
export interface AdaptiveTokenBoundsInput {
|
|
11
|
+
/** Exact sum of the planned canonical replacements' net token reduction. */
|
|
12
|
+
readonly exactReclaimedTokens: number
|
|
13
|
+
/** Durable sequence number of the earliest message changed by the plan. */
|
|
14
|
+
readonly earliestChangedSeq: number
|
|
15
|
+
/** Official request-level prompt_tokens from the immediately preceding request. */
|
|
16
|
+
readonly previousPromptTokens: number
|
|
17
|
+
/** Tokenizer artifact revision carried by that request's exact provider key. */
|
|
18
|
+
readonly expectedTokenizerRevision: string
|
|
19
|
+
/** Tokenizer-first measurement of that exact preceding assembled request. */
|
|
20
|
+
readonly previousRequestMeasurement: TokenCount
|
|
21
|
+
/** Same-revision provider-tokenizer counts for the durable surface. */
|
|
22
|
+
readonly measuredNodes: readonly MeasuredTokenSurfaceNode[]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Available lower-benefit and upper-risk bounds for one History batch. */
|
|
26
|
+
export interface AvailableAdaptiveTokenBounds {
|
|
27
|
+
readonly kind: 'available'
|
|
28
|
+
readonly measurementKind: 'exact-tokenizer' | 'tokenizer-estimate'
|
|
29
|
+
/** D: conservative lower bound of input tokens removed by the plan. */
|
|
30
|
+
readonly reclaimedLowerBoundTokens: number
|
|
31
|
+
/** A: conservative upper bound of retained suffix tokens that may lose a hit. */
|
|
32
|
+
readonly affectedRetainedSuffixUpperBoundTokens: number
|
|
33
|
+
/** Known exact canonical prefix before the first changed durable sequence. */
|
|
34
|
+
readonly exactPrefixLowerBoundTokens: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Available conservative bounds or an explicit reason they cannot be derived. */
|
|
38
|
+
export type AdaptiveTokenBounds = AvailableAdaptiveTokenBounds | {
|
|
39
|
+
readonly kind: 'unknown'
|
|
40
|
+
readonly reason: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Bound Adaptive's benefit and cache-loss exposure without attributing the
|
|
45
|
+
* request-level cache split to individual messages. Removed tokens are not
|
|
46
|
+
* charged again as part of the retained suffix.
|
|
47
|
+
* @param input - exact planned reclaim, adjacent request measurement, and same-revision nodes.
|
|
48
|
+
* @returns Conservative removal/cache-risk bounds or an explicit unknown reason.
|
|
49
|
+
*/
|
|
50
|
+
export function deriveAdaptiveTokenBounds(input: AdaptiveTokenBoundsInput): AdaptiveTokenBounds {
|
|
51
|
+
if (!isCount(input.exactReclaimedTokens) || input.exactReclaimedTokens === 0) {
|
|
52
|
+
return unknown('invalid-reclaimed-token-count')
|
|
53
|
+
}
|
|
54
|
+
if (!isCount(input.earliestChangedSeq)) return unknown('invalid-earliest-changed-seq')
|
|
55
|
+
if (!isCount(input.previousPromptTokens)) return unknown('invalid-previous-prompt-tokens')
|
|
56
|
+
if (input.expectedTokenizerRevision.length === 0) {
|
|
57
|
+
return unknown('expected-tokenizer-revision-unavailable')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const request = input.previousRequestMeasurement
|
|
61
|
+
let margin = 0
|
|
62
|
+
let measurementKind: AvailableAdaptiveTokenBounds['measurementKind']
|
|
63
|
+
if (request.kind === 'unavailable') return unknown('request-measurement-unavailable')
|
|
64
|
+
if (request.kind === 'exact-tokenizer') {
|
|
65
|
+
if (!isCount(request.tokens) || request.tokens !== input.previousPromptTokens) {
|
|
66
|
+
return unknown('exact-request-usage-mismatch')
|
|
67
|
+
}
|
|
68
|
+
if (request.tokenizerRevision !== input.expectedTokenizerRevision) {
|
|
69
|
+
return unknown('request-tokenizer-revision-mismatch')
|
|
70
|
+
}
|
|
71
|
+
measurementKind = request.kind
|
|
72
|
+
} else {
|
|
73
|
+
const calibration = request.calibration
|
|
74
|
+
if (calibration === undefined) return unknown('estimate-calibration-unavailable')
|
|
75
|
+
if (!isCount(request.tokens)
|
|
76
|
+
|| !isCount(request.upperBoundTokens)
|
|
77
|
+
|| request.upperBoundTokens < request.tokens
|
|
78
|
+
|| input.previousPromptTokens > request.upperBoundTokens
|
|
79
|
+
|| !isCount(calibration.sampleCount)
|
|
80
|
+
|| !isCount(calibration.conservativeMarginTokens)) {
|
|
81
|
+
return unknown('invalid-estimate-calibration')
|
|
82
|
+
}
|
|
83
|
+
margin = calibration.conservativeMarginTokens
|
|
84
|
+
measurementKind = request.kind
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const reclaimedLowerBoundTokens = Math.max(0, input.exactReclaimedTokens - margin)
|
|
88
|
+
if (reclaimedLowerBoundTokens === 0) return unknown('reclaim-not-positive-after-margin')
|
|
89
|
+
|
|
90
|
+
let identity: { readonly tokenizerId: string; readonly tokenizerRevision: string } | undefined
|
|
91
|
+
let exactPrefixLowerBoundTokens = 0
|
|
92
|
+
const seen = new Set<number>()
|
|
93
|
+
for (const node of input.measuredNodes) {
|
|
94
|
+
if (!isCount(node.seq) || seen.has(node.seq)) return unknown('invalid-measured-node-sequence')
|
|
95
|
+
seen.add(node.seq)
|
|
96
|
+
if (node.seq >= input.earliestChangedSeq || node.count.kind !== 'exact-tokenizer') continue
|
|
97
|
+
if (!isCount(node.count.tokens)) return unknown('invalid-exact-prefix-count')
|
|
98
|
+
if (node.count.tokenizerRevision !== input.expectedTokenizerRevision) {
|
|
99
|
+
return unknown('exact-prefix-tokenizer-revision-mismatch')
|
|
100
|
+
}
|
|
101
|
+
if (identity !== undefined
|
|
102
|
+
&& (identity.tokenizerId !== node.count.tokenizerId
|
|
103
|
+
|| identity.tokenizerRevision !== node.count.tokenizerRevision)) {
|
|
104
|
+
return unknown('exact-prefix-tokenizer-identity-mismatch')
|
|
105
|
+
}
|
|
106
|
+
identity ??= node.count
|
|
107
|
+
exactPrefixLowerBoundTokens += node.count.tokens
|
|
108
|
+
if (!isCount(exactPrefixLowerBoundTokens)) return unknown('exact-prefix-overflow')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const accounted = exactPrefixLowerBoundTokens + reclaimedLowerBoundTokens
|
|
112
|
+
if (!isCount(accounted) || accounted > input.previousPromptTokens) {
|
|
113
|
+
return unknown('adaptive-bounds-exceed-previous-prompt')
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
kind: 'available',
|
|
117
|
+
measurementKind,
|
|
118
|
+
reclaimedLowerBoundTokens,
|
|
119
|
+
affectedRetainedSuffixUpperBoundTokens: input.previousPromptTokens - accounted,
|
|
120
|
+
exactPrefixLowerBoundTokens,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Conservative bounds, capacity authority, and applicable official input prices. */
|
|
125
|
+
export interface ConservativeAdaptiveDecisionInput {
|
|
126
|
+
readonly capacityPressure: boolean
|
|
127
|
+
readonly bounds: AdaptiveTokenBounds
|
|
128
|
+
/** Official price per one million cache-hit input tokens. */
|
|
129
|
+
readonly inputCacheHitRate?: string
|
|
130
|
+
/** Official price per one million cache-miss input tokens. */
|
|
131
|
+
readonly inputCacheMissRate?: string
|
|
132
|
+
/** Request-level hit total; caps, but never attributes, the affected hit exposure. */
|
|
133
|
+
readonly observedCacheReadTokens?: number
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Authorization decision plus fixed-point comparison telemetry when evaluated. */
|
|
137
|
+
export type ConservativeAdaptiveDecision =
|
|
138
|
+
| { readonly allowHistory: true; readonly reason: 'capacity-override' }
|
|
139
|
+
| {
|
|
140
|
+
readonly allowHistory: boolean
|
|
141
|
+
readonly reason: string
|
|
142
|
+
readonly minimumRemovalValue?: string
|
|
143
|
+
readonly maximumCacheLossPenalty?: string
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Allow routine History only when D*P_hit is strictly greater than A*(P_miss-P_hit).
|
|
148
|
+
* @param input - capacity state, token bounds, request hit cap, and official input rates.
|
|
149
|
+
* @returns Capacity override or a strict fixed-point conservative-cost decision.
|
|
150
|
+
*/
|
|
151
|
+
export function decideConservativeAdaptive(
|
|
152
|
+
input: ConservativeAdaptiveDecisionInput,
|
|
153
|
+
): ConservativeAdaptiveDecision {
|
|
154
|
+
if (input.capacityPressure) return { allowHistory: true, reason: 'capacity-override' }
|
|
155
|
+
if (input.bounds.kind === 'unknown') {
|
|
156
|
+
return { allowHistory: false, reason: input.bounds.reason }
|
|
157
|
+
}
|
|
158
|
+
if (input.inputCacheHitRate === undefined || input.inputCacheMissRate === undefined) {
|
|
159
|
+
return { allowHistory: false, reason: 'adaptive-unknown-price' }
|
|
160
|
+
}
|
|
161
|
+
const hit = decimalRateNanoUnits(input.inputCacheHitRate)
|
|
162
|
+
const miss = decimalRateNanoUnits(input.inputCacheMissRate)
|
|
163
|
+
if (hit === undefined || miss === undefined || miss < hit) {
|
|
164
|
+
return { allowHistory: false, reason: 'adaptive-unknown-price' }
|
|
165
|
+
}
|
|
166
|
+
if (input.observedCacheReadTokens !== undefined && !isCount(input.observedCacheReadTokens)) {
|
|
167
|
+
return { allowHistory: false, reason: 'adaptive-invalid-cache-telemetry' }
|
|
168
|
+
}
|
|
169
|
+
const affectedHitUpperBound = input.observedCacheReadTokens === undefined
|
|
170
|
+
? input.bounds.affectedRetainedSuffixUpperBoundTokens
|
|
171
|
+
: Math.min(
|
|
172
|
+
input.bounds.affectedRetainedSuffixUpperBoundTokens,
|
|
173
|
+
input.observedCacheReadTokens,
|
|
174
|
+
)
|
|
175
|
+
const minimumRemovalValue = BigInt(input.bounds.reclaimedLowerBoundTokens) * hit
|
|
176
|
+
const maximumCacheLossPenalty = BigInt(affectedHitUpperBound)
|
|
177
|
+
* (miss - hit)
|
|
178
|
+
return {
|
|
179
|
+
allowHistory: minimumRemovalValue > maximumCacheLossPenalty,
|
|
180
|
+
reason: minimumRemovalValue > maximumCacheLossPenalty
|
|
181
|
+
? 'cost-interval-clearly-favourable'
|
|
182
|
+
: 'cache-risk-not-clearly-paid-back',
|
|
183
|
+
minimumRemovalValue: minimumRemovalValue.toString(),
|
|
184
|
+
maximumCacheLossPenalty: maximumCacheLossPenalty.toString(),
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function unknown(reason: string): AdaptiveTokenBounds {
|
|
189
|
+
return { kind: 'unknown', reason }
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function isCount(value: number): boolean {
|
|
193
|
+
return Number.isSafeInteger(value) && value >= 0
|
|
194
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/** Structured, content-free runtime audit records for context compression. */
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
CompressionPolicy,
|
|
5
|
+
CompressionProfile,
|
|
6
|
+
ContextCompressionSettings,
|
|
7
|
+
HistoryMode,
|
|
8
|
+
ResolvedConfig,
|
|
9
|
+
} from './types.ts'
|
|
10
|
+
|
|
11
|
+
/** Stable prefix used to locate one JSON audit record in Harness runtime logs. */
|
|
12
|
+
export const COMPRESSION_AUDIT_PREFIX = 'context-compression audit '
|
|
13
|
+
|
|
14
|
+
/** Compression primitive that committed one model-free surface rewrite. */
|
|
15
|
+
export type CompressionAuditComponent =
|
|
16
|
+
| 'fresh'
|
|
17
|
+
| 'aggregate'
|
|
18
|
+
| 'history'
|
|
19
|
+
| 'tail-trim'
|
|
20
|
+
| 'native-tool-result'
|
|
21
|
+
| 'dedupe'
|
|
22
|
+
| 'summary-locator'
|
|
23
|
+
|
|
24
|
+
/** Non-mutating outcome of evaluating one component at one runtime boundary. */
|
|
25
|
+
export type CompressionAuditEvaluationStatus = 'disabled' | 'skipped'
|
|
26
|
+
|
|
27
|
+
interface CompressionAuditBase {
|
|
28
|
+
readonly schemaVersion: 1
|
|
29
|
+
readonly sessionId: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Complete settings and deployment config frozen on first runtime observation. */
|
|
33
|
+
export interface CompressionPolicyFrozenAuditRecord extends CompressionAuditBase {
|
|
34
|
+
readonly kind: 'policy-frozen'
|
|
35
|
+
readonly settingsSource: 'host-settings' | 'plugin-config-fallback'
|
|
36
|
+
/** Where the frozen Auto Compact threshold came from. */
|
|
37
|
+
readonly autoCompactThresholdSource?: 'generation-config' | 'host-settings' | 'schema-default'
|
|
38
|
+
/** Present when the stored document was invalid and the session froze losslessly. */
|
|
39
|
+
readonly settingsInvalidFallback?: 'lossless-off'
|
|
40
|
+
readonly settings: ContextCompressionSettings
|
|
41
|
+
readonly deploymentConfig: ResolvedConfig
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Routed request facts captured alongside one policy resolution. */
|
|
45
|
+
export interface CompressionRouteAuditFact {
|
|
46
|
+
readonly provider: string
|
|
47
|
+
readonly model: string
|
|
48
|
+
readonly modality?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Bundled tokenizer identity backing exact counts for one route. */
|
|
52
|
+
export interface CompressionTokenizerAuditFact {
|
|
53
|
+
readonly repository: string
|
|
54
|
+
readonly revision: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** How the resolved History watermarks were derived for one Session. */
|
|
58
|
+
export interface CompressionCoordinationAuditFact {
|
|
59
|
+
/** Frozen Auto Compact threshold percent from the settings snapshot. */
|
|
60
|
+
readonly thresholdPercent: number
|
|
61
|
+
/** `A = floor(C × a)`; undefined when linkage did not resolve. */
|
|
62
|
+
readonly autoCompactTokens?: number
|
|
63
|
+
/** `D = floor(A × 0.875)`; undefined when linkage did not resolve. */
|
|
64
|
+
readonly microDeadlineTokens?: number
|
|
65
|
+
/**
|
|
66
|
+
* Whether History follows the Auto Compact watermark, explicit deployment
|
|
67
|
+
* overrides, a mix of both, Custom manual tokens, or the fixed preset.
|
|
68
|
+
*/
|
|
69
|
+
readonly paramSource: 'auto-compact-linked' | 'deployment-override' | 'mixed' | 'custom-manual' | 'fixed-preset'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** One effective policy resolution, including context-percent capacity when used. */
|
|
73
|
+
export interface CompressionPolicyResolvedAuditRecord extends CompressionAuditBase {
|
|
74
|
+
readonly kind: 'policy-resolved'
|
|
75
|
+
readonly policy: CompressionPolicy
|
|
76
|
+
readonly contextWindowTokens?: number
|
|
77
|
+
readonly coordination?: CompressionCoordinationAuditFact
|
|
78
|
+
readonly route?: CompressionRouteAuditFact
|
|
79
|
+
readonly tokenizer?: CompressionTokenizerAuditFact
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One committed model-free surface rewrite and its exact token accounting. */
|
|
83
|
+
export interface CompressionRewriteAuditRecord extends CompressionAuditBase {
|
|
84
|
+
readonly kind: 'rewrite'
|
|
85
|
+
readonly profile: CompressionProfile
|
|
86
|
+
readonly component: CompressionAuditComponent
|
|
87
|
+
readonly stage: 'fresh' | 'pressure'
|
|
88
|
+
readonly reducer: string
|
|
89
|
+
readonly historyMode?: HistoryMode
|
|
90
|
+
readonly manifestEventType: 'compaction/prune'
|
|
91
|
+
readonly manifestSeq: number
|
|
92
|
+
readonly replacementSeq: number
|
|
93
|
+
readonly sourceSeqs: readonly number[]
|
|
94
|
+
readonly tokensBefore: number
|
|
95
|
+
readonly tokensAfter: number
|
|
96
|
+
readonly tokensRemoved: number
|
|
97
|
+
readonly tokenizerId: string
|
|
98
|
+
readonly tokenizerRevision: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Why an enabled component did not rewrite, or why it was disabled. */
|
|
102
|
+
export interface CompressionComponentEvaluationAuditRecord extends CompressionAuditBase {
|
|
103
|
+
readonly kind: 'component-evaluation'
|
|
104
|
+
readonly profile: CompressionProfile
|
|
105
|
+
readonly component: CompressionAuditComponent
|
|
106
|
+
readonly stage: 'fresh' | 'pressure'
|
|
107
|
+
readonly status: CompressionAuditEvaluationStatus
|
|
108
|
+
readonly reason: string
|
|
109
|
+
readonly historyMode?: HistoryMode
|
|
110
|
+
readonly measurementKind?: 'exact-tokenizer' | 'tokenizer-estimate' | 'unavailable'
|
|
111
|
+
readonly currentTokens?: number
|
|
112
|
+
readonly triggerTokens?: number
|
|
113
|
+
readonly targetTokens?: number
|
|
114
|
+
/** Reclaim the planned batch reached (insufficient-reclaim family only). */
|
|
115
|
+
readonly reclaimTokens?: number
|
|
116
|
+
/** Reclaim the batch required (insufficient-reclaim family only). */
|
|
117
|
+
readonly requiredTokens?: number
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** One fail-open runtime error, without prompt or tool-result content. */
|
|
121
|
+
export interface CompressionFailureAuditRecord extends CompressionAuditBase {
|
|
122
|
+
readonly kind: 'failure'
|
|
123
|
+
readonly stage: 'fresh' | 'pressure'
|
|
124
|
+
readonly operation:
|
|
125
|
+
| 'request-boundary'
|
|
126
|
+
| 'terminal-pass'
|
|
127
|
+
| 'policy-resolution'
|
|
128
|
+
| 'summary-locator'
|
|
129
|
+
| 'publication'
|
|
130
|
+
readonly component?: CompressionAuditComponent
|
|
131
|
+
readonly manifestSeq?: number
|
|
132
|
+
readonly errorName: string
|
|
133
|
+
readonly errorMessage: string
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** One observed core Native auto-compaction summary event. */
|
|
137
|
+
export interface NativeAutoCompactAuditRecord extends CompressionAuditBase {
|
|
138
|
+
readonly kind: 'native-auto-compact'
|
|
139
|
+
readonly manifestEventType: 'compaction/summary'
|
|
140
|
+
readonly manifestSeq: number
|
|
141
|
+
readonly reducer: 'llm-summary'
|
|
142
|
+
readonly provider: string
|
|
143
|
+
readonly model: string
|
|
144
|
+
readonly tokensBefore: number | null
|
|
145
|
+
readonly tokensAfter: null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** One Exact Sources locator block appended to a landed Auto Compact summary. */
|
|
149
|
+
export interface SummaryLocatorAuditRecord extends CompressionAuditBase {
|
|
150
|
+
readonly kind: 'summary-locator'
|
|
151
|
+
readonly profile: CompressionProfile
|
|
152
|
+
readonly checkpointSeq: number
|
|
153
|
+
readonly summarySeq: number
|
|
154
|
+
readonly locatorChars: number
|
|
155
|
+
readonly spillFiles: number
|
|
156
|
+
readonly touchedFiles: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** One background estimator pass. Only numeric metadata — never prompts or keys. */
|
|
160
|
+
export interface EstimatorOutcomeAuditRecord extends CompressionAuditBase {
|
|
161
|
+
readonly kind: 'estimator-outcome'
|
|
162
|
+
readonly profile: CompressionProfile
|
|
163
|
+
readonly channel: 'host' | 'direct'
|
|
164
|
+
readonly sampled: number
|
|
165
|
+
readonly expired: number
|
|
166
|
+
readonly latencyMs: number
|
|
167
|
+
readonly ok: boolean
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Closed version-one context-compression audit vocabulary. */
|
|
171
|
+
export type CompressionAuditRecord =
|
|
172
|
+
| CompressionPolicyFrozenAuditRecord
|
|
173
|
+
| CompressionPolicyResolvedAuditRecord
|
|
174
|
+
| CompressionRewriteAuditRecord
|
|
175
|
+
| CompressionComponentEvaluationAuditRecord
|
|
176
|
+
| CompressionFailureAuditRecord
|
|
177
|
+
| NativeAutoCompactAuditRecord
|
|
178
|
+
| SummaryLocatorAuditRecord
|
|
179
|
+
| EstimatorOutcomeAuditRecord
|
|
180
|
+
|
|
181
|
+
/** Minimal logger method consumed by the audit publisher. */
|
|
182
|
+
export interface CompressionAuditLogger {
|
|
183
|
+
/**
|
|
184
|
+
* Publish one informational message.
|
|
185
|
+
* @param message - complete single-line audit message.
|
|
186
|
+
* @returns logger-specific chaining value, if any.
|
|
187
|
+
*/
|
|
188
|
+
info(message: string): unknown
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Encode one stable single-line audit message.
|
|
193
|
+
* @param record - content-free structured audit record.
|
|
194
|
+
* @returns the fixed prefix followed by one JSON object.
|
|
195
|
+
*/
|
|
196
|
+
export function formatCompressionAudit(record: CompressionAuditRecord): string {
|
|
197
|
+
return `${COMPRESSION_AUDIT_PREFIX}${JSON.stringify(record)}`
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Publish one audit message through the Harness logger.
|
|
202
|
+
* @param logger - current plugin logger.
|
|
203
|
+
* @param record - structured record committed by the caller.
|
|
204
|
+
*/
|
|
205
|
+
export function emitCompressionAudit(
|
|
206
|
+
logger: CompressionAuditLogger,
|
|
207
|
+
record: CompressionAuditRecord,
|
|
208
|
+
): void {
|
|
209
|
+
try {
|
|
210
|
+
logger.info(formatCompressionAudit(record))
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Swallow logger failures: audit publication must not roll back a committed rewrite.
|
|
214
|
+
}
|
|
215
|
+
}
|