tinker-agent 1.0.65 → 1.2.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/CHANGELOG.md +36 -0
- package/LICENSE +201 -0
- package/NOTICE +6 -0
- package/README.md +90 -9
- package/bin/tinker.js +39 -0
- package/node_modules/ansi-regex/index.d.ts +33 -0
- package/node_modules/ansi-regex/index.js +14 -0
- package/node_modules/ansi-regex/license +9 -0
- package/node_modules/ansi-regex/package.json +61 -0
- package/node_modules/ansi-regex/readme.md +66 -0
- package/node_modules/ansi-styles/index.d.ts +236 -0
- package/node_modules/ansi-styles/index.js +223 -0
- package/node_modules/ansi-styles/license +9 -0
- package/node_modules/ansi-styles/package.json +54 -0
- package/node_modules/ansi-styles/readme.md +173 -0
- package/node_modules/chalk/license +9 -0
- package/node_modules/chalk/package.json +83 -0
- package/node_modules/chalk/readme.md +297 -0
- package/node_modules/chalk/source/index.d.ts +325 -0
- package/node_modules/chalk/source/index.js +225 -0
- package/node_modules/chalk/source/utilities.js +33 -0
- package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/node_modules/character-entities/index.d.ts +6 -0
- package/node_modules/character-entities/index.js +2132 -0
- package/node_modules/character-entities/license +22 -0
- package/node_modules/character-entities/package.json +78 -0
- package/node_modules/character-entities/readme.md +152 -0
- package/node_modules/decode-named-character-reference/index.d.ts +13 -0
- package/node_modules/decode-named-character-reference/index.d.ts.map +1 -0
- package/node_modules/decode-named-character-reference/index.dom.d.ts +6 -0
- package/node_modules/decode-named-character-reference/index.dom.d.ts.map +1 -0
- package/node_modules/decode-named-character-reference/index.dom.js +32 -0
- package/node_modules/decode-named-character-reference/index.js +19 -0
- package/node_modules/decode-named-character-reference/license +22 -0
- package/node_modules/decode-named-character-reference/package.json +90 -0
- package/node_modules/decode-named-character-reference/readme.md +136 -0
- package/node_modules/get-east-asian-width/index.d.ts +60 -0
- package/node_modules/get-east-asian-width/index.js +30 -0
- package/node_modules/get-east-asian-width/license +9 -0
- package/node_modules/get-east-asian-width/lookup-data.js +21 -0
- package/node_modules/get-east-asian-width/lookup.js +138 -0
- package/node_modules/get-east-asian-width/package.json +71 -0
- package/node_modules/get-east-asian-width/readme.md +65 -0
- package/node_modules/get-east-asian-width/utilities.js +24 -0
- package/node_modules/has-flag/index.d.ts +39 -0
- package/node_modules/has-flag/index.js +8 -0
- package/node_modules/has-flag/license +9 -0
- package/node_modules/has-flag/package.json +49 -0
- package/node_modules/has-flag/readme.md +74 -0
- package/node_modules/is-fullwidth-code-point/index.d.ts +17 -0
- package/node_modules/is-fullwidth-code-point/index.js +12 -0
- package/node_modules/is-fullwidth-code-point/license +9 -0
- package/node_modules/is-fullwidth-code-point/package.json +53 -0
- package/node_modules/is-fullwidth-code-point/readme.md +31 -0
- package/node_modules/markdansi/LICENSE +21 -0
- package/node_modules/markdansi/README.md +167 -0
- package/node_modules/markdansi/dist/ast.d.ts +99 -0
- package/node_modules/markdansi/dist/ast.js +1 -0
- package/node_modules/markdansi/dist/cli.d.ts +17 -0
- package/node_modules/markdansi/dist/cli.js +208 -0
- package/node_modules/markdansi/dist/hyperlink.d.ts +9 -0
- package/node_modules/markdansi/dist/hyperlink.js +26 -0
- package/node_modules/markdansi/dist/index.d.ts +10 -0
- package/node_modules/markdansi/dist/index.js +16 -0
- package/node_modules/markdansi/dist/parser.d.ts +2 -0
- package/node_modules/markdansi/dist/parser.js +205 -0
- package/node_modules/markdansi/dist/render.d.ts +9 -0
- package/node_modules/markdansi/dist/render.js +680 -0
- package/node_modules/markdansi/dist/stream.d.ts +39 -0
- package/node_modules/markdansi/dist/stream.js +192 -0
- package/node_modules/markdansi/dist/theme.d.ts +18 -0
- package/node_modules/markdansi/dist/theme.js +105 -0
- package/node_modules/markdansi/dist/types.d.ts +58 -0
- package/node_modules/markdansi/dist/types.js +1 -0
- package/node_modules/markdansi/dist/wrap.d.ts +10 -0
- package/node_modules/markdansi/dist/wrap.js +73 -0
- package/node_modules/markdansi/docs/spec.md +110 -0
- package/node_modules/markdansi/package.json +78 -0
- package/node_modules/markdansi/tsconfig.json +18 -0
- package/node_modules/marked/LICENSE +44 -0
- package/node_modules/marked/README.md +115 -0
- package/node_modules/marked/bin/main.js +284 -0
- package/node_modules/marked/bin/marked.js +16 -0
- package/node_modules/marked/lib/marked.d.ts +760 -0
- package/node_modules/marked/lib/marked.esm.js +77 -0
- package/node_modules/marked/lib/marked.esm.js.map +7 -0
- package/node_modules/marked/lib/marked.umd.js +79 -0
- package/node_modules/marked/lib/marked.umd.js.map +7 -0
- package/node_modules/marked/man/marked.1 +113 -0
- package/node_modules/marked/man/marked.1.md +93 -0
- package/node_modules/marked/package.json +103 -0
- package/node_modules/slice-ansi/index.d.ts +19 -0
- package/node_modules/slice-ansi/index.js +317 -0
- package/node_modules/slice-ansi/license +10 -0
- package/node_modules/slice-ansi/package.json +59 -0
- package/node_modules/slice-ansi/readme.md +55 -0
- package/node_modules/slice-ansi/tokenize-ansi.js +752 -0
- package/node_modules/string-width/index.d.ts +39 -0
- package/node_modules/string-width/index.js +203 -0
- package/node_modules/string-width/license +9 -0
- package/node_modules/string-width/package.json +65 -0
- package/node_modules/string-width/readme.md +66 -0
- package/node_modules/strip-ansi/index.d.ts +15 -0
- package/node_modules/strip-ansi/index.js +19 -0
- package/node_modules/strip-ansi/license +9 -0
- package/node_modules/strip-ansi/package.json +59 -0
- package/node_modules/strip-ansi/readme.md +37 -0
- package/node_modules/supports-color/browser.d.ts +1 -0
- package/node_modules/supports-color/browser.js +35 -0
- package/node_modules/supports-color/index.d.ts +55 -0
- package/node_modules/supports-color/index.js +202 -0
- package/node_modules/supports-color/license +9 -0
- package/node_modules/supports-color/package.json +64 -0
- package/node_modules/supports-color/readme.md +75 -0
- package/node_modules/supports-hyperlinks/browser.js +10 -0
- package/node_modules/supports-hyperlinks/index.d.ts +25 -0
- package/node_modules/supports-hyperlinks/index.js +163 -0
- package/node_modules/supports-hyperlinks/license +10 -0
- package/node_modules/supports-hyperlinks/package.json +47 -0
- package/node_modules/supports-hyperlinks/readme.md +45 -0
- package/package.json +41 -10
- package/patches/markdansi@0.3.2.patch +22 -2
- package/src/agent/context-builder.ts +24 -10
- package/src/agent/context-meter.ts +89 -5
- package/src/agent/loop.ts +107 -10
- package/src/agent/runtime-session.ts +1437 -82
- package/src/agent/session-ledger.ts +169 -29
- package/src/agent/types.ts +12 -1
- package/src/agent/user-prompt-projection.ts +62 -0
- package/src/cli/config.ts +57 -14
- package/src/cli/model-profiles.ts +124 -0
- package/src/cli/run-runner.ts +4 -1
- package/src/cli/tui-runner.tsx +68 -30
- package/src/context/compiled-context-hash.ts +1 -1
- package/src/context/compiled-context-validator.ts +92 -15
- package/src/context/context-automation-policy.ts +121 -0
- package/src/context/context-manager.ts +390 -11
- package/src/context/context-policy.ts +8 -0
- package/src/context/context-protocol-validator.ts +11 -1
- package/src/context/context-revision-compiler.ts +190 -27
- package/src/context/context-revision.ts +105 -19
- package/src/context/context-surface.ts +329 -0
- package/src/context/prefix-retirement-planner.ts +570 -0
- package/src/context/protocol-frame.ts +30 -3
- package/src/context/recall-retirement-contract.ts +27 -0
- package/src/context/swap-planner.ts +34 -10
- package/src/events/observation-text-log.ts +3 -3
- package/src/events/stdout-event-printer.ts +39 -3
- package/src/events/types.ts +172 -35
- package/src/ids/runtime-id.ts +6 -0
- package/src/ids/uuid-v7.ts +7 -0
- package/src/image/image-asset-store.ts +319 -0
- package/src/image/image-input-policy.ts +14 -0
- package/src/image/image-probe.ts +233 -0
- package/src/image/image-types.ts +262 -0
- package/src/instructions/project-instructions.ts +4 -1
- package/src/mcp/mcp-manager.ts +83 -19
- package/src/model/fake-model-client.ts +9 -1
- package/src/model/input-token-estimator.ts +25 -0
- package/src/model/model-client.ts +60 -0
- package/src/model/model-request-preflight.ts +1 -0
- package/src/model/moonshot-input-token-estimator.ts +107 -0
- package/src/model/openai-chat-mapping.ts +77 -1
- package/src/model/openai-chat-model-client.ts +389 -59
- package/src/model/openai-chat-stream.ts +272 -0
- package/src/model/prompt-prefix-hash.ts +2 -4
- package/src/model/token-estimator.ts +4 -0
- package/src/observation/observation-builder.ts +29 -0
- package/src/session/resume-projection.ts +94 -34
- package/src/session/session-catalog.ts +4 -4
- package/src/session/session-errors.ts +1 -1
- package/src/session/session-history-reader.ts +151 -4
- package/src/session/session-last-response-reader.ts +189 -0
- package/src/session/session-schema.ts +349 -35
- package/src/session/session-store.ts +3266 -255
- package/src/session/sqlite-session-ledger.ts +9 -4
- package/src/skills/skill-catalog.ts +182 -0
- package/src/skills/skill-context.ts +364 -0
- package/src/skills/skill-loader.ts +779 -0
- package/src/skills/skill-tool.ts +297 -0
- package/src/tools/edit.ts +51 -64
- package/src/tools/ensure-parent-directory.ts +6 -0
- package/src/tools/read.ts +2 -2
- package/src/tools/recall.ts +43 -40
- package/src/tools/registry.ts +24 -3
- package/src/tools/ripgrep.ts +3 -2
- package/src/tools/types.ts +43 -4
- package/src/tools/write.ts +20 -31
- package/src/tui/app.tsx +333 -96
- package/src/tui/clipboard.ts +5 -0
- package/src/tui/components/mcp-panel.tsx +28 -0
- package/src/tui/components/prompt-input.tsx +790 -257
- package/src/tui/components/skills-panel.tsx +31 -0
- package/src/tui/components/timeline.tsx +30 -1
- package/src/tui/event-store.ts +85 -2
- package/src/tui/file-mention.ts +234 -0
- package/src/tui/line-editor.ts +1 -0
- package/src/tui/project-slash-commands.ts +229 -0
- package/src/tui/prompt-draft.ts +510 -0
- package/src/tui/prompt-history.ts +294 -22
- package/src/tui/slash-commands.ts +46 -2
- package/src/tui/tui-session-controller.ts +110 -48
- package/src/tui/workspace-file-search.ts +94 -0
|
@@ -10,35 +10,61 @@ import type { ModelClient } from "../model/model-client";
|
|
|
10
10
|
import { promptPrefixFingerprint } from "../model/prompt-prefix-hash";
|
|
11
11
|
import { estimatePromptSegments } from "../model/token-estimator";
|
|
12
12
|
import { SessionError } from "../session/session-errors";
|
|
13
|
-
import
|
|
13
|
+
import {
|
|
14
|
+
skillActivationManifestSha256,
|
|
15
|
+
type CommitSkillsUpdateInput,
|
|
16
|
+
type SessionStore,
|
|
17
|
+
} from "../session/session-store";
|
|
14
18
|
import type { ToolDefinition } from "../tools/types";
|
|
15
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
activeOverrideManifestHash,
|
|
21
|
+
canonicalSequenceHash,
|
|
22
|
+
renderedMessageHash,
|
|
23
|
+
} from "./compiled-context-hash";
|
|
16
24
|
import { CompiledContextError } from "./compiled-context-validator";
|
|
17
|
-
import { swapOnlyPolicyV1 } from "./context-policy";
|
|
25
|
+
import { recallFirstRetirementPolicyV1, swapOnlyPolicyV1 } from "./context-policy";
|
|
18
26
|
import { ContextProtocolError } from "./context-protocol-validator";
|
|
27
|
+
import type { StoredContextSnapshotV8, SwapOverride } from "./context-revision";
|
|
19
28
|
import {
|
|
20
29
|
ContextRevisionCompiler,
|
|
21
30
|
ContextRevisionError,
|
|
22
31
|
} from "./context-revision-compiler";
|
|
32
|
+
import {
|
|
33
|
+
contextSurfaceChangeManifestHash,
|
|
34
|
+
contextSurfaceChanges,
|
|
35
|
+
type StoredContextSurfaceV8,
|
|
36
|
+
} from "./context-surface";
|
|
23
37
|
import {
|
|
24
38
|
assertPlanBaseCurrent,
|
|
25
39
|
SwapPlanner,
|
|
26
40
|
SwapPlanningDiagnosticError,
|
|
27
41
|
SwapPlanStaleError,
|
|
28
42
|
} from "./swap-planner";
|
|
43
|
+
import {
|
|
44
|
+
assertRetirementPlanBaseCurrent,
|
|
45
|
+
PrefixRetirementPlanner,
|
|
46
|
+
PrefixRetirementPlanningError,
|
|
47
|
+
PrefixRetirementPlanStaleError,
|
|
48
|
+
type PrefixRetirementPlan,
|
|
49
|
+
} from "./prefix-retirement-planner";
|
|
29
50
|
|
|
30
51
|
export type ContextCompactionTrigger =
|
|
31
52
|
| { kind: "manual" }
|
|
32
53
|
| { kind: "runtime_pressure" }
|
|
33
54
|
| { kind: "benchmark_forced"; targetTokens: number };
|
|
34
55
|
|
|
56
|
+
export type ContextRetirementTrigger =
|
|
57
|
+
| { kind: "manual" }
|
|
58
|
+
| { kind: "runtime_pressure" }
|
|
59
|
+
| { kind: "benchmark_forced"; targetTokens: number };
|
|
60
|
+
|
|
35
61
|
export type ContextCompactionResult =
|
|
36
62
|
| {
|
|
37
63
|
status: "unchanged";
|
|
38
|
-
outcome: "below_target" | "no_eligible_candidates";
|
|
64
|
+
outcome: "below_trigger" | "below_target" | "no_eligible_candidates";
|
|
39
65
|
revisionId: ReturnType<RuntimeIdFactory["createContextRevisionId"]>;
|
|
40
66
|
revisionNumber: number;
|
|
41
|
-
|
|
67
|
+
activeOverrideCount: number;
|
|
42
68
|
rawTokensBefore: number;
|
|
43
69
|
guardedTokensBefore: number;
|
|
44
70
|
targetTokens: number;
|
|
@@ -53,7 +79,7 @@ export type ContextCompactionResult =
|
|
|
53
79
|
previousRevisionNumber: number;
|
|
54
80
|
revisionNumber: number;
|
|
55
81
|
addedOverrideCount: number;
|
|
56
|
-
|
|
82
|
+
activeOverrideCount: number;
|
|
57
83
|
originalObservationBytes: number;
|
|
58
84
|
projectedObservationBytes: number;
|
|
59
85
|
rawTokensBefore: number;
|
|
@@ -69,6 +95,45 @@ export type ContextCompactionResult =
|
|
|
69
95
|
durationMs: number;
|
|
70
96
|
};
|
|
71
97
|
|
|
98
|
+
export type ContextRetirementResult =
|
|
99
|
+
| {
|
|
100
|
+
status: "unchanged";
|
|
101
|
+
outcome: "below_target" | "no_complete_prefix";
|
|
102
|
+
revisionId: ReturnType<RuntimeIdFactory["createContextRevisionId"]>;
|
|
103
|
+
revisionNumber: number;
|
|
104
|
+
keepFromOrdinal: number;
|
|
105
|
+
activeOverrideCount: number;
|
|
106
|
+
guardedTokensBefore: number;
|
|
107
|
+
targetTokens: number;
|
|
108
|
+
planningDurationMs: number;
|
|
109
|
+
durationMs: number;
|
|
110
|
+
}
|
|
111
|
+
| {
|
|
112
|
+
status: "retired";
|
|
113
|
+
outcome: "target_reached" | "retirement_floor";
|
|
114
|
+
previousRevisionId: ReturnType<RuntimeIdFactory["createContextRevisionId"]>;
|
|
115
|
+
revisionId: ReturnType<RuntimeIdFactory["createContextRevisionId"]>;
|
|
116
|
+
previousRevisionNumber: number;
|
|
117
|
+
revisionNumber: number;
|
|
118
|
+
previousKeepFromOrdinal: number;
|
|
119
|
+
keepFromOrdinal: number;
|
|
120
|
+
retiredTurnCount: number;
|
|
121
|
+
retiredFrameCount: number;
|
|
122
|
+
retiredMessageCount: number;
|
|
123
|
+
activeOverrideCount: number;
|
|
124
|
+
rawTokensBefore: number;
|
|
125
|
+
rawTokensAfter: number;
|
|
126
|
+
guardedTokensBefore: number;
|
|
127
|
+
guardedTokensAfter: number;
|
|
128
|
+
targetTokens: number;
|
|
129
|
+
planHash: string;
|
|
130
|
+
planningDurationMs: number;
|
|
131
|
+
validationDurationMs: number;
|
|
132
|
+
transactionDurationMs: number;
|
|
133
|
+
activationDurationMs: number;
|
|
134
|
+
durationMs: number;
|
|
135
|
+
};
|
|
136
|
+
|
|
72
137
|
export class ContextManagerError extends Error {
|
|
73
138
|
constructor(
|
|
74
139
|
readonly stage: "snapshot" | "plan" | "validate" | "commit" | "activate",
|
|
@@ -85,8 +150,83 @@ export class ContextManagerError extends Error {
|
|
|
85
150
|
|
|
86
151
|
type ModelPreparer = Pick<ModelClient, "prepare">;
|
|
87
152
|
|
|
153
|
+
export function commitAgentSkillsContextUpdate(input: {
|
|
154
|
+
store: SessionStore;
|
|
155
|
+
contextMeter: ContextMeter;
|
|
156
|
+
idFactory: RuntimeIdFactory;
|
|
157
|
+
snapshot: StoredContextSnapshotV8;
|
|
158
|
+
surface: StoredContextSurfaceV8;
|
|
159
|
+
addedOverrides: readonly SwapOverride[];
|
|
160
|
+
settlements: CommitSkillsUpdateInput["settlements"];
|
|
161
|
+
}): ReturnType<SessionStore["commitSkillsUpdate"]> {
|
|
162
|
+
const compiler = new ContextRevisionCompiler();
|
|
163
|
+
let candidateCompiled: ReturnType<ContextRevisionCompiler["compileProspective"]>;
|
|
164
|
+
let changes: ReturnType<typeof contextSurfaceChanges>;
|
|
165
|
+
try {
|
|
166
|
+
input.store.assertContextRevisionIdle();
|
|
167
|
+
const active = compiler.compileActive(input.snapshot);
|
|
168
|
+
changes = contextSurfaceChanges(input.snapshot.surface, input.surface);
|
|
169
|
+
candidateCompiled = compiler.compileProspective({
|
|
170
|
+
active,
|
|
171
|
+
canonical: input.snapshot.canonical,
|
|
172
|
+
activeOverrides: input.snapshot.activeOverrides,
|
|
173
|
+
addedOverrides: input.addedOverrides,
|
|
174
|
+
activeSurface: input.snapshot.surface,
|
|
175
|
+
...(input.surface === input.snapshot.surface ? {} : { surface: input.surface }),
|
|
176
|
+
allowCombinedSurfaceAndOverrides: true,
|
|
177
|
+
});
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw managerError("validate", error);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
let revision: ReturnType<SessionStore["commitSkillsUpdate"]>;
|
|
183
|
+
try {
|
|
184
|
+
revision = input.store.commitSkillsUpdate({
|
|
185
|
+
revisionId: input.idFactory.createContextRevisionId(),
|
|
186
|
+
expectedBaseRevisionId: input.snapshot.revision.revisionId,
|
|
187
|
+
expectedBaseRevisionNumber: input.snapshot.revision.revisionNumber,
|
|
188
|
+
expectedCanonicalThroughOrdinal: input.snapshot.canonical.messages.length,
|
|
189
|
+
expectedBaseActiveOverrideManifestSha256:
|
|
190
|
+
input.snapshot.revision.activeOverrideManifestSha256,
|
|
191
|
+
surface: input.surface,
|
|
192
|
+
changes,
|
|
193
|
+
changeManifestSha256: contextSurfaceChangeManifestHash(changes),
|
|
194
|
+
activationManifestSha256: skillActivationManifestSha256(input.settlements),
|
|
195
|
+
addedOverrides: input.addedOverrides,
|
|
196
|
+
nextActiveOverrideManifestSha256: activeOverrideManifestHash([
|
|
197
|
+
...input.snapshot.activeOverrides,
|
|
198
|
+
...input.addedOverrides,
|
|
199
|
+
]),
|
|
200
|
+
settlements: input.settlements,
|
|
201
|
+
canonicalSequenceSha256: canonicalSequenceHash(input.snapshot.canonical),
|
|
202
|
+
renderedMessageSha256: renderedMessageHash(candidateCompiled.entries),
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
throw managerError("commit", error);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
input.contextMeter.startRevision({
|
|
210
|
+
reason: "context_rebuilt",
|
|
211
|
+
requestConfigHash: input.surface.requestConfigSha256,
|
|
212
|
+
toolSchemaHash: input.surface.toolSchemaSha256,
|
|
213
|
+
});
|
|
214
|
+
} catch (error) {
|
|
215
|
+
throw new ContextManagerError(
|
|
216
|
+
"activate",
|
|
217
|
+
errorCode(error),
|
|
218
|
+
true,
|
|
219
|
+
true,
|
|
220
|
+
"Agent Skills context revision committed but runtime activation failed.",
|
|
221
|
+
{ cause: error },
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return revision;
|
|
225
|
+
}
|
|
226
|
+
|
|
88
227
|
export class ContextManager {
|
|
89
228
|
private readonly planner: SwapPlanner;
|
|
229
|
+
private readonly retirementPlanner: PrefixRetirementPlanner;
|
|
90
230
|
private readonly compiler = new ContextRevisionCompiler();
|
|
91
231
|
private readonly requestBuilder = new ContextBuilder();
|
|
92
232
|
|
|
@@ -103,6 +243,7 @@ export class ContextManager {
|
|
|
103
243
|
},
|
|
104
244
|
) {
|
|
105
245
|
this.planner = new SwapPlanner(input.model);
|
|
246
|
+
this.retirementPlanner = new PrefixRetirementPlanner(input.model);
|
|
106
247
|
}
|
|
107
248
|
|
|
108
249
|
async compact(trigger: ContextCompactionTrigger): Promise<ContextCompactionResult> {
|
|
@@ -125,6 +266,7 @@ export class ContextManager {
|
|
|
125
266
|
planning = this.planner.plan({
|
|
126
267
|
active: built.compiled,
|
|
127
268
|
revision: built.revision,
|
|
269
|
+
surface: built.surface,
|
|
128
270
|
activeOverrides: built.activeOverrides,
|
|
129
271
|
canonical: built.canonical,
|
|
130
272
|
activePrepared,
|
|
@@ -141,6 +283,20 @@ export class ContextManager {
|
|
|
141
283
|
}
|
|
142
284
|
const planningDurationMs = elapsedMs(startedAt);
|
|
143
285
|
|
|
286
|
+
if (planning.outcome === "below_trigger" && trigger.kind === "runtime_pressure") {
|
|
287
|
+
return Object.freeze({
|
|
288
|
+
status: "unchanged",
|
|
289
|
+
outcome: planning.outcome,
|
|
290
|
+
revisionId: built.revision.revisionId,
|
|
291
|
+
revisionNumber: built.revision.revisionNumber,
|
|
292
|
+
activeOverrideCount: built.revision.activeOverrideCount,
|
|
293
|
+
rawTokensBefore: planning.rawTokensBefore,
|
|
294
|
+
guardedTokensBefore: planning.guardedTokensBefore,
|
|
295
|
+
targetTokens: planning.targetTokens,
|
|
296
|
+
planningDurationMs,
|
|
297
|
+
durationMs: elapsedMs(startedAt),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
144
300
|
if (
|
|
145
301
|
planning.outcome === "below_target" ||
|
|
146
302
|
planning.outcome === "no_eligible_candidates"
|
|
@@ -150,7 +306,7 @@ export class ContextManager {
|
|
|
150
306
|
outcome: planning.outcome,
|
|
151
307
|
revisionId: built.revision.revisionId,
|
|
152
308
|
revisionNumber: built.revision.revisionNumber,
|
|
153
|
-
|
|
309
|
+
activeOverrideCount: built.revision.activeOverrideCount,
|
|
154
310
|
rawTokensBefore: planning.rawTokensBefore,
|
|
155
311
|
guardedTokensBefore: planning.guardedTokensBefore,
|
|
156
312
|
targetTokens: planning.targetTokens,
|
|
@@ -188,10 +344,12 @@ export class ContextManager {
|
|
|
188
344
|
canonical: built.canonical,
|
|
189
345
|
activeOverrides: built.activeOverrides,
|
|
190
346
|
addedOverrides: plan.addedOverrides,
|
|
347
|
+
activeSurface: built.surface,
|
|
191
348
|
});
|
|
192
349
|
const candidate = this.requestBuilder.build({
|
|
193
350
|
canonical: built.canonical,
|
|
194
351
|
revision: built.revision,
|
|
352
|
+
surface: built.surface,
|
|
195
353
|
activeOverrides: candidateOverrides,
|
|
196
354
|
compiled: candidateCompiled,
|
|
197
355
|
tools,
|
|
@@ -222,12 +380,12 @@ export class ContextManager {
|
|
|
222
380
|
expectedBaseRevisionId: plan.baseRevisionId,
|
|
223
381
|
expectedBaseRevisionNumber: plan.baseRevisionNumber,
|
|
224
382
|
expectedCanonicalThroughOrdinal: plan.baseCanonicalThroughOrdinal,
|
|
225
|
-
|
|
383
|
+
expectedBaseActiveOverrideManifestSha256: plan.baseActiveOverrideManifestSha256,
|
|
226
384
|
policyVersion: plan.policyVersion,
|
|
227
385
|
rendererFormat: "swap-observation-v1",
|
|
228
386
|
planHash: plan.planHash,
|
|
229
387
|
addedOverrides: plan.addedOverrides,
|
|
230
|
-
|
|
388
|
+
nextActiveOverrideManifestSha256: plan.nextActiveOverrideManifestSha256,
|
|
231
389
|
canonicalSequenceSha256: canonicalSequenceHash(
|
|
232
390
|
built.canonical,
|
|
233
391
|
plan.baseCanonicalThroughOrdinal,
|
|
@@ -277,7 +435,7 @@ export class ContextManager {
|
|
|
277
435
|
previousRevisionNumber: built.revision.revisionNumber,
|
|
278
436
|
revisionNumber: revision.revisionNumber,
|
|
279
437
|
addedOverrideCount: plan.addedOverrides.length,
|
|
280
|
-
|
|
438
|
+
activeOverrideCount: revision.activeOverrideCount,
|
|
281
439
|
originalObservationBytes: planning.originalObservationBytes,
|
|
282
440
|
projectedObservationBytes: planning.projectedObservationBytes,
|
|
283
441
|
rawTokensBefore: plan.rawTokensBefore,
|
|
@@ -293,6 +451,224 @@ export class ContextManager {
|
|
|
293
451
|
durationMs: elapsedMs(startedAt),
|
|
294
452
|
});
|
|
295
453
|
}
|
|
454
|
+
|
|
455
|
+
async retirePrefix(
|
|
456
|
+
trigger: ContextRetirementTrigger,
|
|
457
|
+
): Promise<ContextRetirementResult> {
|
|
458
|
+
const startedAt = performance.now();
|
|
459
|
+
const tools = this.input.tools();
|
|
460
|
+
let built;
|
|
461
|
+
let activePrepared;
|
|
462
|
+
let activeUsage;
|
|
463
|
+
let closedTurns;
|
|
464
|
+
try {
|
|
465
|
+
this.input.store.assertContextRevisionIdle();
|
|
466
|
+
built = this.input.ledger.buildCommittedModelRequest(tools);
|
|
467
|
+
activePrepared = this.input.model.prepare(built.request);
|
|
468
|
+
activeUsage = this.input.contextMeter.measure(activePrepared);
|
|
469
|
+
closedTurns = this.input.store.loadClosedTurnBoundaries();
|
|
470
|
+
} catch (error) {
|
|
471
|
+
throw managerError("snapshot", error);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
let planning;
|
|
475
|
+
try {
|
|
476
|
+
planning = this.retirementPlanner.plan({
|
|
477
|
+
active: built.compiled,
|
|
478
|
+
revision: built.revision,
|
|
479
|
+
surface: built.surface,
|
|
480
|
+
activeOverrides: built.activeOverrides,
|
|
481
|
+
canonical: built.canonical,
|
|
482
|
+
closedTurns,
|
|
483
|
+
activePrepared,
|
|
484
|
+
activeUsage,
|
|
485
|
+
tools,
|
|
486
|
+
policy: recallFirstRetirementPolicyV1,
|
|
487
|
+
trigger: trigger.kind,
|
|
488
|
+
...(trigger.kind === "benchmark_forced"
|
|
489
|
+
? { forcedTargetTokens: trigger.targetTokens }
|
|
490
|
+
: {}),
|
|
491
|
+
});
|
|
492
|
+
} catch (error) {
|
|
493
|
+
throw managerError("plan", error);
|
|
494
|
+
}
|
|
495
|
+
const planningDurationMs = elapsedMs(startedAt);
|
|
496
|
+
if (
|
|
497
|
+
planning.outcome === "below_target" ||
|
|
498
|
+
planning.outcome === "no_complete_prefix"
|
|
499
|
+
) {
|
|
500
|
+
return Object.freeze({
|
|
501
|
+
status: "unchanged",
|
|
502
|
+
outcome: planning.outcome,
|
|
503
|
+
revisionId: built.revision.revisionId,
|
|
504
|
+
revisionNumber: built.revision.revisionNumber,
|
|
505
|
+
keepFromOrdinal: built.revision.keepFromOrdinal,
|
|
506
|
+
activeOverrideCount: built.revision.activeOverrideCount,
|
|
507
|
+
guardedTokensBefore: planning.guardedTokensBefore,
|
|
508
|
+
targetTokens: planning.targetTokens,
|
|
509
|
+
planningDurationMs,
|
|
510
|
+
durationMs: elapsedMs(startedAt),
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (!("plan" in planning)) {
|
|
515
|
+
throw new ContextManagerError(
|
|
516
|
+
"validate",
|
|
517
|
+
"missing_retirement_plan",
|
|
518
|
+
true,
|
|
519
|
+
false,
|
|
520
|
+
"Committable prefix retirement produced no revision plan.",
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
const plan = planning.plan;
|
|
524
|
+
const validationStartedAt = performance.now();
|
|
525
|
+
const nextActiveOverrides = built.activeOverrides.filter(
|
|
526
|
+
(override) => override.ordinal >= plan.nextKeepFromOrdinal,
|
|
527
|
+
);
|
|
528
|
+
let candidateCompiled;
|
|
529
|
+
let candidatePrepared;
|
|
530
|
+
try {
|
|
531
|
+
candidateCompiled = this.compiler.compileProspective({
|
|
532
|
+
active: built.compiled,
|
|
533
|
+
canonical: built.canonical,
|
|
534
|
+
activeOverrides: built.activeOverrides,
|
|
535
|
+
addedOverrides: [],
|
|
536
|
+
activeSurface: built.surface,
|
|
537
|
+
keepFromOrdinal: plan.nextKeepFromOrdinal,
|
|
538
|
+
});
|
|
539
|
+
const candidate = this.requestBuilder.build({
|
|
540
|
+
canonical: built.canonical,
|
|
541
|
+
revision: built.revision,
|
|
542
|
+
surface: built.surface,
|
|
543
|
+
activeOverrides: nextActiveOverrides,
|
|
544
|
+
compiled: candidateCompiled,
|
|
545
|
+
tools,
|
|
546
|
+
});
|
|
547
|
+
candidatePrepared = this.input.model.prepare(candidate.request);
|
|
548
|
+
assertRetirementCandidatePrepared(activePrepared, candidatePrepared, plan);
|
|
549
|
+
|
|
550
|
+
const current = this.input.ledger.buildCommittedModelRequest(tools);
|
|
551
|
+
const currentPrepared = this.input.model.prepare(current.request);
|
|
552
|
+
assertRetirementPlanBaseCurrent(plan, {
|
|
553
|
+
active: current.compiled,
|
|
554
|
+
revision: current.revision,
|
|
555
|
+
surface: current.surface,
|
|
556
|
+
activeOverrides: current.activeOverrides,
|
|
557
|
+
canonical: current.canonical,
|
|
558
|
+
activePrepared: currentPrepared,
|
|
559
|
+
});
|
|
560
|
+
this.input.store.assertContextRevisionIdle();
|
|
561
|
+
} catch (error) {
|
|
562
|
+
throw managerError("validate", error);
|
|
563
|
+
}
|
|
564
|
+
const validationDurationMs = elapsedMs(validationStartedAt);
|
|
565
|
+
|
|
566
|
+
const revisionId = this.input.idFactory.createContextRevisionId();
|
|
567
|
+
const transactionStartedAt = performance.now();
|
|
568
|
+
let revision;
|
|
569
|
+
try {
|
|
570
|
+
revision = this.input.store.commitPrefixRetirementRevision({
|
|
571
|
+
revisionId,
|
|
572
|
+
expectedBaseRevisionId: plan.baseRevisionId,
|
|
573
|
+
expectedBaseRevisionNumber: plan.baseRevisionNumber,
|
|
574
|
+
expectedBaseKeepFromOrdinal: plan.baseKeepFromOrdinal,
|
|
575
|
+
expectedCanonicalThroughOrdinal: plan.baseCanonicalThroughOrdinal,
|
|
576
|
+
expectedSurfaceSha256: plan.baseSurfaceSha256,
|
|
577
|
+
expectedBaseActiveOverrideManifestSha256: plan.baseActiveOverrideManifestSha256,
|
|
578
|
+
policyVersion: plan.policyVersion,
|
|
579
|
+
planHash: plan.planHash,
|
|
580
|
+
nextKeepFromOrdinal: plan.nextKeepFromOrdinal,
|
|
581
|
+
retiredThroughOrdinal: plan.retiredThroughOrdinal,
|
|
582
|
+
retiredTurnCount: plan.retiredTurnCount,
|
|
583
|
+
retiredFrameCount: plan.retiredFrameCount,
|
|
584
|
+
retiredMessageCount: plan.retiredMessageCount,
|
|
585
|
+
nextActiveOverrideCount: plan.nextActiveOverrideCount,
|
|
586
|
+
nextActiveOverrideManifestSha256: plan.nextActiveOverrideManifestSha256,
|
|
587
|
+
canonicalSequenceSha256: plan.canonicalSequenceSha256,
|
|
588
|
+
renderedMessageSha256: plan.renderedMessageSha256,
|
|
589
|
+
});
|
|
590
|
+
} catch (error) {
|
|
591
|
+
throw managerError("commit", error);
|
|
592
|
+
}
|
|
593
|
+
const transactionDurationMs = elapsedMs(transactionStartedAt);
|
|
594
|
+
|
|
595
|
+
const activationStartedAt = performance.now();
|
|
596
|
+
try {
|
|
597
|
+
this.input.contextMeter.startRevision({
|
|
598
|
+
reason: "context_rebuilt",
|
|
599
|
+
requestConfigHash: candidatePrepared.requestConfigHash,
|
|
600
|
+
toolSchemaHash: candidatePrepared.toolSchemaHash,
|
|
601
|
+
});
|
|
602
|
+
this.input.committedPrefixAuditor.audit(revisionId, candidatePrepared);
|
|
603
|
+
const usage = this.input.contextMeter.measure(candidatePrepared);
|
|
604
|
+
if (usage.source !== "estimated_full") {
|
|
605
|
+
throw new Error(
|
|
606
|
+
"First context measurement after prefix retirement was not a full estimate.",
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
await this.input.onUsageUpdated(usage);
|
|
610
|
+
} catch (error) {
|
|
611
|
+
throw new ContextManagerError(
|
|
612
|
+
"activate",
|
|
613
|
+
errorCode(error),
|
|
614
|
+
true,
|
|
615
|
+
true,
|
|
616
|
+
"Prefix retirement committed but runtime activation failed.",
|
|
617
|
+
{ cause: error },
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
const activationDurationMs = elapsedMs(activationStartedAt);
|
|
621
|
+
|
|
622
|
+
return Object.freeze({
|
|
623
|
+
status: "retired",
|
|
624
|
+
outcome: planning.outcome,
|
|
625
|
+
previousRevisionId: built.revision.revisionId,
|
|
626
|
+
revisionId,
|
|
627
|
+
previousRevisionNumber: built.revision.revisionNumber,
|
|
628
|
+
revisionNumber: revision.revisionNumber,
|
|
629
|
+
previousKeepFromOrdinal: built.revision.keepFromOrdinal,
|
|
630
|
+
keepFromOrdinal: revision.keepFromOrdinal,
|
|
631
|
+
retiredTurnCount: plan.retiredTurnCount,
|
|
632
|
+
retiredFrameCount: plan.retiredFrameCount,
|
|
633
|
+
retiredMessageCount: plan.retiredMessageCount,
|
|
634
|
+
activeOverrideCount: revision.activeOverrideCount,
|
|
635
|
+
rawTokensBefore: plan.rawTokensBefore,
|
|
636
|
+
rawTokensAfter: plan.rawTokensAfter,
|
|
637
|
+
guardedTokensBefore: plan.guardedTokensBefore,
|
|
638
|
+
guardedTokensAfter: plan.guardedTokensAfter,
|
|
639
|
+
targetTokens: plan.targetTokens,
|
|
640
|
+
planHash: plan.planHash,
|
|
641
|
+
planningDurationMs,
|
|
642
|
+
validationDurationMs,
|
|
643
|
+
transactionDurationMs,
|
|
644
|
+
activationDurationMs,
|
|
645
|
+
durationMs: elapsedMs(startedAt),
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function assertRetirementCandidatePrepared(
|
|
651
|
+
active: ReturnType<ModelPreparer["prepare"]>,
|
|
652
|
+
candidate: ReturnType<ModelPreparer["prepare"]>,
|
|
653
|
+
plan: PrefixRetirementPlan,
|
|
654
|
+
): void {
|
|
655
|
+
const rawTokens = estimatePromptSegments(candidate.promptSegments).totalTokens;
|
|
656
|
+
const fingerprint = promptPrefixFingerprint(candidate);
|
|
657
|
+
if (
|
|
658
|
+
candidate.provider !== active.provider ||
|
|
659
|
+
candidate.model !== active.model ||
|
|
660
|
+
candidate.requestConfigHash !== active.requestConfigHash ||
|
|
661
|
+
candidate.toolSchemaHash !== active.toolSchemaHash ||
|
|
662
|
+
candidate.requestMaxOutputTokens !== active.requestMaxOutputTokens ||
|
|
663
|
+
rawTokens !== plan.rawTokensAfter ||
|
|
664
|
+
fingerprint.prefixHash !== plan.projectedPrefixHash ||
|
|
665
|
+
plan.rawTokensAfter >= plan.rawTokensBefore ||
|
|
666
|
+
plan.guardedTokensAfter >= plan.guardedTokensBefore
|
|
667
|
+
) {
|
|
668
|
+
throw new Error(
|
|
669
|
+
"Prepared candidate does not match its validated prefix retirement plan.",
|
|
670
|
+
);
|
|
671
|
+
}
|
|
296
672
|
}
|
|
297
673
|
|
|
298
674
|
function assertCandidatePrepared(
|
|
@@ -325,7 +701,9 @@ function managerError(
|
|
|
325
701
|
return error;
|
|
326
702
|
}
|
|
327
703
|
const fatal = isFatalContextError(error) || stage === "commit";
|
|
328
|
-
const diagnostic =
|
|
704
|
+
const diagnostic =
|
|
705
|
+
error instanceof SwapPlanningDiagnosticError ||
|
|
706
|
+
error instanceof PrefixRetirementPlanningError;
|
|
329
707
|
return new ContextManagerError(
|
|
330
708
|
stage,
|
|
331
709
|
diagnostic ? error.code : errorCode(error),
|
|
@@ -342,6 +720,7 @@ function isFatalContextError(error: unknown): boolean {
|
|
|
342
720
|
error instanceof ContextRevisionError ||
|
|
343
721
|
error instanceof CompiledContextError ||
|
|
344
722
|
error instanceof SwapPlanStaleError ||
|
|
723
|
+
error instanceof PrefixRetirementPlanStaleError ||
|
|
345
724
|
error instanceof CommittedPrefixAuditError ||
|
|
346
725
|
error instanceof SessionError
|
|
347
726
|
);
|
|
@@ -6,3 +6,11 @@ export const swapOnlyPolicyV1 = Object.freeze({
|
|
|
6
6
|
} as const);
|
|
7
7
|
|
|
8
8
|
export type SwapOnlyPolicyV1 = typeof swapOnlyPolicyV1;
|
|
9
|
+
|
|
10
|
+
export const recallFirstRetirementPolicyV1 = Object.freeze({
|
|
11
|
+
version: "recall-first-retirement-v1",
|
|
12
|
+
protectedRecentTurnCount: 8,
|
|
13
|
+
targetInputRatio: 0.6,
|
|
14
|
+
} as const);
|
|
15
|
+
|
|
16
|
+
export type RecallFirstRetirementPolicyV1 = typeof recallFirstRetirementPolicyV1;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { MessageId, ProtocolFrameId, ToolCallId } from "../ids/runtime-id";
|
|
2
2
|
import {
|
|
3
3
|
contentHash,
|
|
4
|
+
userMessageHash,
|
|
4
5
|
rawResultHash,
|
|
5
6
|
type CanonicalMessageRecord,
|
|
6
7
|
type ProtocolContextView,
|
|
@@ -103,7 +104,16 @@ export class ContextProtocolValidator {
|
|
|
103
104
|
|
|
104
105
|
if (
|
|
105
106
|
options.fullIntegrity === true &&
|
|
106
|
-
message.contentSha256 !==
|
|
107
|
+
message.contentSha256 !==
|
|
108
|
+
(message.role === "user"
|
|
109
|
+
? userMessageHash({
|
|
110
|
+
role: "user",
|
|
111
|
+
content: message.content,
|
|
112
|
+
...(message.attachments === undefined
|
|
113
|
+
? {}
|
|
114
|
+
: { attachments: message.attachments }),
|
|
115
|
+
})
|
|
116
|
+
: contentHash(message.content))
|
|
107
117
|
) {
|
|
108
118
|
fail(
|
|
109
119
|
"content_hash_mismatch",
|