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.
Files changed (208) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +6 -0
  4. package/README.md +90 -9
  5. package/bin/tinker.js +39 -0
  6. package/node_modules/ansi-regex/index.d.ts +33 -0
  7. package/node_modules/ansi-regex/index.js +14 -0
  8. package/node_modules/ansi-regex/license +9 -0
  9. package/node_modules/ansi-regex/package.json +61 -0
  10. package/node_modules/ansi-regex/readme.md +66 -0
  11. package/node_modules/ansi-styles/index.d.ts +236 -0
  12. package/node_modules/ansi-styles/index.js +223 -0
  13. package/node_modules/ansi-styles/license +9 -0
  14. package/node_modules/ansi-styles/package.json +54 -0
  15. package/node_modules/ansi-styles/readme.md +173 -0
  16. package/node_modules/chalk/license +9 -0
  17. package/node_modules/chalk/package.json +83 -0
  18. package/node_modules/chalk/readme.md +297 -0
  19. package/node_modules/chalk/source/index.d.ts +325 -0
  20. package/node_modules/chalk/source/index.js +225 -0
  21. package/node_modules/chalk/source/utilities.js +33 -0
  22. package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  23. package/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  24. package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  25. package/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  26. package/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  27. package/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  28. package/node_modules/character-entities/index.d.ts +6 -0
  29. package/node_modules/character-entities/index.js +2132 -0
  30. package/node_modules/character-entities/license +22 -0
  31. package/node_modules/character-entities/package.json +78 -0
  32. package/node_modules/character-entities/readme.md +152 -0
  33. package/node_modules/decode-named-character-reference/index.d.ts +13 -0
  34. package/node_modules/decode-named-character-reference/index.d.ts.map +1 -0
  35. package/node_modules/decode-named-character-reference/index.dom.d.ts +6 -0
  36. package/node_modules/decode-named-character-reference/index.dom.d.ts.map +1 -0
  37. package/node_modules/decode-named-character-reference/index.dom.js +32 -0
  38. package/node_modules/decode-named-character-reference/index.js +19 -0
  39. package/node_modules/decode-named-character-reference/license +22 -0
  40. package/node_modules/decode-named-character-reference/package.json +90 -0
  41. package/node_modules/decode-named-character-reference/readme.md +136 -0
  42. package/node_modules/get-east-asian-width/index.d.ts +60 -0
  43. package/node_modules/get-east-asian-width/index.js +30 -0
  44. package/node_modules/get-east-asian-width/license +9 -0
  45. package/node_modules/get-east-asian-width/lookup-data.js +21 -0
  46. package/node_modules/get-east-asian-width/lookup.js +138 -0
  47. package/node_modules/get-east-asian-width/package.json +71 -0
  48. package/node_modules/get-east-asian-width/readme.md +65 -0
  49. package/node_modules/get-east-asian-width/utilities.js +24 -0
  50. package/node_modules/has-flag/index.d.ts +39 -0
  51. package/node_modules/has-flag/index.js +8 -0
  52. package/node_modules/has-flag/license +9 -0
  53. package/node_modules/has-flag/package.json +49 -0
  54. package/node_modules/has-flag/readme.md +74 -0
  55. package/node_modules/is-fullwidth-code-point/index.d.ts +17 -0
  56. package/node_modules/is-fullwidth-code-point/index.js +12 -0
  57. package/node_modules/is-fullwidth-code-point/license +9 -0
  58. package/node_modules/is-fullwidth-code-point/package.json +53 -0
  59. package/node_modules/is-fullwidth-code-point/readme.md +31 -0
  60. package/node_modules/markdansi/LICENSE +21 -0
  61. package/node_modules/markdansi/README.md +167 -0
  62. package/node_modules/markdansi/dist/ast.d.ts +99 -0
  63. package/node_modules/markdansi/dist/ast.js +1 -0
  64. package/node_modules/markdansi/dist/cli.d.ts +17 -0
  65. package/node_modules/markdansi/dist/cli.js +208 -0
  66. package/node_modules/markdansi/dist/hyperlink.d.ts +9 -0
  67. package/node_modules/markdansi/dist/hyperlink.js +26 -0
  68. package/node_modules/markdansi/dist/index.d.ts +10 -0
  69. package/node_modules/markdansi/dist/index.js +16 -0
  70. package/node_modules/markdansi/dist/parser.d.ts +2 -0
  71. package/node_modules/markdansi/dist/parser.js +205 -0
  72. package/node_modules/markdansi/dist/render.d.ts +9 -0
  73. package/node_modules/markdansi/dist/render.js +680 -0
  74. package/node_modules/markdansi/dist/stream.d.ts +39 -0
  75. package/node_modules/markdansi/dist/stream.js +192 -0
  76. package/node_modules/markdansi/dist/theme.d.ts +18 -0
  77. package/node_modules/markdansi/dist/theme.js +105 -0
  78. package/node_modules/markdansi/dist/types.d.ts +58 -0
  79. package/node_modules/markdansi/dist/types.js +1 -0
  80. package/node_modules/markdansi/dist/wrap.d.ts +10 -0
  81. package/node_modules/markdansi/dist/wrap.js +73 -0
  82. package/node_modules/markdansi/docs/spec.md +110 -0
  83. package/node_modules/markdansi/package.json +78 -0
  84. package/node_modules/markdansi/tsconfig.json +18 -0
  85. package/node_modules/marked/LICENSE +44 -0
  86. package/node_modules/marked/README.md +115 -0
  87. package/node_modules/marked/bin/main.js +284 -0
  88. package/node_modules/marked/bin/marked.js +16 -0
  89. package/node_modules/marked/lib/marked.d.ts +760 -0
  90. package/node_modules/marked/lib/marked.esm.js +77 -0
  91. package/node_modules/marked/lib/marked.esm.js.map +7 -0
  92. package/node_modules/marked/lib/marked.umd.js +79 -0
  93. package/node_modules/marked/lib/marked.umd.js.map +7 -0
  94. package/node_modules/marked/man/marked.1 +113 -0
  95. package/node_modules/marked/man/marked.1.md +93 -0
  96. package/node_modules/marked/package.json +103 -0
  97. package/node_modules/slice-ansi/index.d.ts +19 -0
  98. package/node_modules/slice-ansi/index.js +317 -0
  99. package/node_modules/slice-ansi/license +10 -0
  100. package/node_modules/slice-ansi/package.json +59 -0
  101. package/node_modules/slice-ansi/readme.md +55 -0
  102. package/node_modules/slice-ansi/tokenize-ansi.js +752 -0
  103. package/node_modules/string-width/index.d.ts +39 -0
  104. package/node_modules/string-width/index.js +203 -0
  105. package/node_modules/string-width/license +9 -0
  106. package/node_modules/string-width/package.json +65 -0
  107. package/node_modules/string-width/readme.md +66 -0
  108. package/node_modules/strip-ansi/index.d.ts +15 -0
  109. package/node_modules/strip-ansi/index.js +19 -0
  110. package/node_modules/strip-ansi/license +9 -0
  111. package/node_modules/strip-ansi/package.json +59 -0
  112. package/node_modules/strip-ansi/readme.md +37 -0
  113. package/node_modules/supports-color/browser.d.ts +1 -0
  114. package/node_modules/supports-color/browser.js +35 -0
  115. package/node_modules/supports-color/index.d.ts +55 -0
  116. package/node_modules/supports-color/index.js +202 -0
  117. package/node_modules/supports-color/license +9 -0
  118. package/node_modules/supports-color/package.json +64 -0
  119. package/node_modules/supports-color/readme.md +75 -0
  120. package/node_modules/supports-hyperlinks/browser.js +10 -0
  121. package/node_modules/supports-hyperlinks/index.d.ts +25 -0
  122. package/node_modules/supports-hyperlinks/index.js +163 -0
  123. package/node_modules/supports-hyperlinks/license +10 -0
  124. package/node_modules/supports-hyperlinks/package.json +47 -0
  125. package/node_modules/supports-hyperlinks/readme.md +45 -0
  126. package/package.json +41 -10
  127. package/patches/markdansi@0.3.2.patch +22 -2
  128. package/src/agent/context-builder.ts +24 -10
  129. package/src/agent/context-meter.ts +89 -5
  130. package/src/agent/loop.ts +107 -10
  131. package/src/agent/runtime-session.ts +1437 -82
  132. package/src/agent/session-ledger.ts +169 -29
  133. package/src/agent/types.ts +12 -1
  134. package/src/agent/user-prompt-projection.ts +62 -0
  135. package/src/cli/config.ts +57 -14
  136. package/src/cli/model-profiles.ts +124 -0
  137. package/src/cli/run-runner.ts +4 -1
  138. package/src/cli/tui-runner.tsx +68 -30
  139. package/src/context/compiled-context-hash.ts +1 -1
  140. package/src/context/compiled-context-validator.ts +92 -15
  141. package/src/context/context-automation-policy.ts +121 -0
  142. package/src/context/context-manager.ts +390 -11
  143. package/src/context/context-policy.ts +8 -0
  144. package/src/context/context-protocol-validator.ts +11 -1
  145. package/src/context/context-revision-compiler.ts +190 -27
  146. package/src/context/context-revision.ts +105 -19
  147. package/src/context/context-surface.ts +329 -0
  148. package/src/context/prefix-retirement-planner.ts +570 -0
  149. package/src/context/protocol-frame.ts +30 -3
  150. package/src/context/recall-retirement-contract.ts +27 -0
  151. package/src/context/swap-planner.ts +34 -10
  152. package/src/events/observation-text-log.ts +3 -3
  153. package/src/events/stdout-event-printer.ts +39 -3
  154. package/src/events/types.ts +172 -35
  155. package/src/ids/runtime-id.ts +6 -0
  156. package/src/ids/uuid-v7.ts +7 -0
  157. package/src/image/image-asset-store.ts +319 -0
  158. package/src/image/image-input-policy.ts +14 -0
  159. package/src/image/image-probe.ts +233 -0
  160. package/src/image/image-types.ts +262 -0
  161. package/src/instructions/project-instructions.ts +4 -1
  162. package/src/mcp/mcp-manager.ts +83 -19
  163. package/src/model/fake-model-client.ts +9 -1
  164. package/src/model/input-token-estimator.ts +25 -0
  165. package/src/model/model-client.ts +60 -0
  166. package/src/model/model-request-preflight.ts +1 -0
  167. package/src/model/moonshot-input-token-estimator.ts +107 -0
  168. package/src/model/openai-chat-mapping.ts +77 -1
  169. package/src/model/openai-chat-model-client.ts +389 -59
  170. package/src/model/openai-chat-stream.ts +272 -0
  171. package/src/model/prompt-prefix-hash.ts +2 -4
  172. package/src/model/token-estimator.ts +4 -0
  173. package/src/observation/observation-builder.ts +29 -0
  174. package/src/session/resume-projection.ts +94 -34
  175. package/src/session/session-catalog.ts +4 -4
  176. package/src/session/session-errors.ts +1 -1
  177. package/src/session/session-history-reader.ts +151 -4
  178. package/src/session/session-last-response-reader.ts +189 -0
  179. package/src/session/session-schema.ts +349 -35
  180. package/src/session/session-store.ts +3266 -255
  181. package/src/session/sqlite-session-ledger.ts +9 -4
  182. package/src/skills/skill-catalog.ts +182 -0
  183. package/src/skills/skill-context.ts +364 -0
  184. package/src/skills/skill-loader.ts +779 -0
  185. package/src/skills/skill-tool.ts +297 -0
  186. package/src/tools/edit.ts +51 -64
  187. package/src/tools/ensure-parent-directory.ts +6 -0
  188. package/src/tools/read.ts +2 -2
  189. package/src/tools/recall.ts +43 -40
  190. package/src/tools/registry.ts +24 -3
  191. package/src/tools/ripgrep.ts +3 -2
  192. package/src/tools/types.ts +43 -4
  193. package/src/tools/write.ts +20 -31
  194. package/src/tui/app.tsx +333 -96
  195. package/src/tui/clipboard.ts +5 -0
  196. package/src/tui/components/mcp-panel.tsx +28 -0
  197. package/src/tui/components/prompt-input.tsx +790 -257
  198. package/src/tui/components/skills-panel.tsx +31 -0
  199. package/src/tui/components/timeline.tsx +30 -1
  200. package/src/tui/event-store.ts +85 -2
  201. package/src/tui/file-mention.ts +234 -0
  202. package/src/tui/line-editor.ts +1 -0
  203. package/src/tui/project-slash-commands.ts +229 -0
  204. package/src/tui/prompt-draft.ts +510 -0
  205. package/src/tui/prompt-history.ts +294 -22
  206. package/src/tui/slash-commands.ts +46 -2
  207. package/src/tui/tui-session-controller.ts +110 -48
  208. package/src/tui/workspace-file-search.ts +94 -0
@@ -11,10 +11,11 @@ import { ContextProtocolValidator } from "./context-protocol-validator";
11
11
  import type {
12
12
  CompiledContextEntry,
13
13
  CompiledRevisionContext,
14
- StoredContextSnapshotV5,
15
- StoredInitialContextRevisionV5,
14
+ StoredContextSnapshotV8,
15
+ StoredInitialContextRevisionV8,
16
16
  SwapOverride,
17
17
  } from "./context-revision";
18
+ import type { StoredContextSurfaceV8 } from "./context-surface";
18
19
  import {
19
20
  immutableRecord,
20
21
  materializeAgentMessages,
@@ -34,7 +35,7 @@ export class ContextRevisionCompiler {
34
35
  private readonly compiledValidator = new CompiledContextValidator(),
35
36
  ) {}
36
37
 
37
- compileActive(snapshot: StoredContextSnapshotV5): CompiledRevisionContext {
38
+ compileActive(snapshot: StoredContextSnapshotV8): CompiledRevisionContext {
38
39
  validateSnapshotIdentity(snapshot);
39
40
  this.protocolValidator.validate(snapshot.canonical);
40
41
  const overrides = overrideMap(snapshot.activeOverrides);
@@ -42,11 +43,15 @@ export class ContextRevisionCompiler {
42
43
  canonical: snapshot.canonical,
43
44
  revisionId: snapshot.revision.revisionId,
44
45
  overrides,
46
+ keepFromOrdinal: snapshot.revision.keepFromOrdinal,
47
+ systemPrompt: snapshot.surface.systemPrompt,
48
+ surfaceSha256: snapshot.surface.surfaceSha256,
45
49
  });
46
50
  this.compiledValidator.validateActive(
47
51
  compiled,
48
52
  snapshot.canonical,
49
53
  snapshot.activeOverrides,
54
+ snapshot.surface,
50
55
  );
51
56
  if (
52
57
  compiled.manifest.canonicalSequenceHash !==
@@ -65,11 +70,40 @@ export class ContextRevisionCompiler {
65
70
  return compiled;
66
71
  }
67
72
 
73
+ compileForIdentityRekey(input: {
74
+ canonical: ProtocolContextView;
75
+ revisionId: ContextRevisionId;
76
+ activeOverrides: readonly SwapOverride[];
77
+ keepFromOrdinal: number;
78
+ surface: StoredContextSurfaceV8;
79
+ }): CompiledRevisionContext {
80
+ this.protocolValidator.validate(input.canonical);
81
+ const compiled = compileEntries({
82
+ canonical: input.canonical,
83
+ revisionId: input.revisionId,
84
+ overrides: overrideMap(input.activeOverrides),
85
+ keepFromOrdinal: input.keepFromOrdinal,
86
+ systemPrompt: input.surface.systemPrompt,
87
+ surfaceSha256: input.surface.surfaceSha256,
88
+ });
89
+ this.compiledValidator.validateActive(
90
+ compiled,
91
+ input.canonical,
92
+ input.activeOverrides,
93
+ input.surface,
94
+ );
95
+ return compiled;
96
+ }
97
+
68
98
  compileProspective(input: {
69
99
  active: CompiledRevisionContext;
70
100
  canonical: ProtocolContextView;
71
101
  activeOverrides: readonly SwapOverride[];
72
102
  addedOverrides: readonly SwapOverride[];
103
+ activeSurface: StoredContextSurfaceV8;
104
+ surface?: StoredContextSurfaceV8;
105
+ keepFromOrdinal?: number;
106
+ allowCombinedSurfaceAndOverrides?: boolean;
73
107
  }): CompiledRevisionContext {
74
108
  this.protocolValidator.validate(input.canonical);
75
109
  if (
@@ -86,21 +120,53 @@ export class ContextRevisionCompiler {
86
120
  input.active,
87
121
  input.canonical,
88
122
  input.activeOverrides,
123
+ input.activeSurface,
89
124
  );
90
- const candidateOverrides = [...input.activeOverrides, ...input.addedOverrides];
125
+ const keepFromOrdinal =
126
+ input.keepFromOrdinal ?? input.active.manifest.keepFromOrdinal;
127
+ if (
128
+ !Number.isSafeInteger(keepFromOrdinal) ||
129
+ keepFromOrdinal < input.active.manifest.keepFromOrdinal
130
+ ) {
131
+ throw new ContextRevisionError(
132
+ "Prospective keep boundary must move monotonically forward.",
133
+ );
134
+ }
135
+ const changes = [
136
+ input.addedOverrides.length > 0,
137
+ input.surface !== undefined &&
138
+ input.surface.surfaceSha256 !== input.activeSurface.surfaceSha256,
139
+ keepFromOrdinal > input.active.manifest.keepFromOrdinal,
140
+ ].filter(Boolean).length;
141
+ if (changes > 1 && input.allowCombinedSurfaceAndOverrides !== true) {
142
+ throw new ContextRevisionError(
143
+ "A prospective context revision cannot combine revision semantics.",
144
+ );
145
+ }
146
+ const candidateOverrides =
147
+ keepFromOrdinal > input.active.manifest.keepFromOrdinal
148
+ ? input.activeOverrides.filter(
149
+ (override) => override.ordinal >= keepFromOrdinal,
150
+ )
151
+ : [...input.activeOverrides, ...input.addedOverrides];
91
152
  const overrides = overrideMap(candidateOverrides);
92
153
  if (overrides.size !== candidateOverrides.length) {
93
154
  throw new ContextRevisionError("Prospective overrides contain duplicate IDs.");
94
155
  }
156
+ const surface = input.surface ?? input.activeSurface;
95
157
  const compiled = compileEntries({
96
158
  canonical: input.canonical,
97
159
  revisionId: input.active.revisionId,
98
160
  overrides,
161
+ keepFromOrdinal,
162
+ systemPrompt: surface.systemPrompt,
163
+ surfaceSha256: surface.surfaceSha256,
99
164
  });
100
165
  this.compiledValidator.validateProspective(
101
166
  compiled,
102
167
  input.canonical,
103
168
  candidateOverrides,
169
+ surface,
104
170
  );
105
171
  return compiled;
106
172
  }
@@ -110,29 +176,59 @@ function compileEntries(input: {
110
176
  canonical: ProtocolContextView;
111
177
  revisionId: CompiledRevisionContext["revisionId"];
112
178
  overrides: ReadonlyMap<string, SwapOverride>;
179
+ keepFromOrdinal: number;
180
+ systemPrompt: string;
181
+ surfaceSha256: string;
113
182
  }): CompiledRevisionContext {
114
- const materialized = materializeAgentMessages(input.canonical.messages);
115
- const entries = input.canonical.messages.map((record, index) => {
183
+ const records =
184
+ input.keepFromOrdinal === 1
185
+ ? input.canonical.messages
186
+ : [
187
+ requireItem(input.canonical.messages, 0, "canonical system message"),
188
+ ...input.canonical.messages.slice(input.keepFromOrdinal - 1),
189
+ ];
190
+ const materialized = materializeAgentMessages(records);
191
+ const entries = records.map((record, index) => {
116
192
  const canonicalMessage = requireItem(materialized, index, "canonical message");
117
193
  const override = input.overrides.get(record.messageId);
194
+ const surfacedMessage =
195
+ record.ordinal === 1
196
+ ? surfacedSystemMessage(canonicalMessage, input.systemPrompt)
197
+ : canonicalMessage;
118
198
  const message =
119
199
  override === undefined
120
- ? canonicalMessage
121
- : swappedToolMessage(canonicalMessage, override);
200
+ ? surfacedMessage
201
+ : swappedToolMessage(surfacedMessage, override);
202
+ const representation =
203
+ override !== undefined
204
+ ? "swapped"
205
+ : record.ordinal === 1 && input.systemPrompt !== record.content
206
+ ? "surface"
207
+ : "canonical";
122
208
  return Object.freeze<CompiledContextEntry>({
123
209
  frameId: record.frameId,
124
210
  messageId: record.messageId,
125
211
  ordinal: record.ordinal,
126
- representation: override === undefined ? "canonical" : "swapped",
212
+ representation,
127
213
  sourceContentSha256: record.contentSha256,
128
214
  message: immutableRecord(message),
129
215
  });
130
216
  });
131
217
  const manifest = Object.freeze({
132
- frameCount: input.canonical.frames.length,
133
- messageCount: entries.length,
218
+ canonicalFrameCount: input.canonical.frames.length,
219
+ canonicalMessageCount: input.canonical.messages.length,
220
+ activeFrameCount:
221
+ input.keepFromOrdinal === 1
222
+ ? input.canonical.frames.length
223
+ : 1 +
224
+ input.canonical.frames.filter(
225
+ (frame) => frame.firstOrdinal >= input.keepFromOrdinal,
226
+ ).length,
227
+ activeMessageCount: entries.length,
228
+ keepFromOrdinal: input.keepFromOrdinal,
134
229
  canonicalSequenceHash: canonicalSequenceHash(input.canonical),
135
230
  renderedMessageHash: renderedMessageHash(entries),
231
+ surfaceSha256: input.surfaceSha256,
136
232
  });
137
233
  return Object.freeze({
138
234
  sessionId: input.canonical.sessionId,
@@ -143,6 +239,19 @@ function compileEntries(input: {
143
239
  });
144
240
  }
145
241
 
242
+ function surfacedSystemMessage(
243
+ message: AgentMessage,
244
+ systemPrompt: string,
245
+ ): AgentMessage {
246
+ if (message.role !== "system") {
247
+ throw new ContextRevisionError("Canonical ordinal 1 is not a system message.");
248
+ }
249
+ if (systemPrompt.trim() === "") {
250
+ throw new ContextRevisionError("Active context surface prompt is empty.");
251
+ }
252
+ return { role: "system", content: systemPrompt };
253
+ }
254
+
146
255
  function swappedToolMessage(
147
256
  message: AgentMessage,
148
257
  override: SwapOverride,
@@ -158,18 +267,25 @@ function swappedToolMessage(
158
267
  };
159
268
  }
160
269
 
161
- function validateSnapshotIdentity(snapshot: StoredContextSnapshotV5): void {
270
+ function validateSnapshotIdentity(snapshot: StoredContextSnapshotV8): void {
162
271
  if (
163
272
  snapshot.meta.sessionId !== snapshot.canonical.sessionId ||
164
273
  snapshot.revision.sessionId !== snapshot.canonical.sessionId ||
165
- snapshot.meta.activeRevisionId !== snapshot.revision.revisionId
274
+ snapshot.meta.activeRevisionId !== snapshot.revision.revisionId ||
275
+ snapshot.surface.sessionId !== snapshot.canonical.sessionId ||
276
+ snapshot.surface.surfaceId !== snapshot.revision.surfaceId ||
277
+ snapshot.surface.surfaceSha256 !== snapshot.revision.surfaceSha256
166
278
  ) {
167
279
  throw new ContextRevisionError(
168
280
  "Active context revision identity does not match canonical history.",
169
281
  );
170
282
  }
171
- if (snapshot.revision.keepFromOrdinal !== 1) {
172
- throw new ContextRevisionError("Unsupported active context revision.");
283
+ if (
284
+ !Number.isSafeInteger(snapshot.revision.keepFromOrdinal) ||
285
+ snapshot.revision.keepFromOrdinal < 1 ||
286
+ snapshot.revision.keepFromOrdinal > snapshot.revision.sourceThroughOrdinal
287
+ ) {
288
+ throw new ContextRevisionError("Active context revision boundary is invalid.");
173
289
  }
174
290
  const firstFrame = snapshot.canonical.frames[0];
175
291
  const firstMessage = snapshot.canonical.messages[0];
@@ -202,25 +318,67 @@ function validateSnapshotIdentity(snapshot: StoredContextSnapshotV5): void {
202
318
  snapshot.revision.parentRevisionId !== null ||
203
319
  snapshot.revision.sourceThroughOrdinal !== 1 ||
204
320
  snapshot.revision.addedOverrideCount !== 0 ||
205
- snapshot.revision.totalOverrideCount !== 0 ||
321
+ snapshot.revision.keepFromOrdinal !== 1 ||
322
+ snapshot.revision.activeOverrideCount !== 0 ||
206
323
  snapshot.activeOverrides.length !== 0
207
324
  ) {
208
325
  throw new ContextRevisionError("Initial context revision invariant failed.");
209
326
  }
210
327
  } else if (
211
- snapshot.revision.revisionNumber < 2 ||
212
- snapshot.revision.addedOverrideCount < 1 ||
213
- snapshot.revision.totalOverrideCount < snapshot.revision.addedOverrideCount ||
214
- snapshot.revision.policyVersion !== "swap-only-v1" ||
215
- snapshot.revision.rendererFormat !== "swap-observation-v1" ||
216
- snapshot.activeOverrides.length !== snapshot.revision.totalOverrideCount
328
+ snapshot.revision.kind === "swap_only" &&
329
+ (snapshot.revision.revisionNumber < 2 ||
330
+ snapshot.revision.addedOverrideCount < 1 ||
331
+ snapshot.revision.activeOverrideCount < snapshot.revision.addedOverrideCount ||
332
+ snapshot.revision.policyVersion !== "swap-only-v1" ||
333
+ snapshot.revision.rendererFormat !== "swap-observation-v1" ||
334
+ snapshot.activeOverrides.length !== snapshot.revision.activeOverrideCount)
217
335
  ) {
218
336
  throw new ContextRevisionError("Swap context revision invariant failed.");
337
+ } else if (
338
+ snapshot.revision.kind === "surface_refresh" &&
339
+ (snapshot.revision.revisionNumber < 2 ||
340
+ snapshot.revision.addedOverrideCount !== 0 ||
341
+ snapshot.activeOverrides.length !== snapshot.revision.activeOverrideCount)
342
+ ) {
343
+ throw new ContextRevisionError("Surface context revision invariant failed.");
344
+ } else if (
345
+ snapshot.revision.kind === "prefix_retirement" &&
346
+ (snapshot.revision.revisionNumber < 2 ||
347
+ snapshot.revision.keepFromOrdinal <= 1 ||
348
+ snapshot.revision.addedOverrideCount !== 0 ||
349
+ snapshot.revision.retiredThroughOrdinal !==
350
+ snapshot.revision.keepFromOrdinal - 1 ||
351
+ snapshot.revision.retiredTurnCount < 1 ||
352
+ snapshot.revision.retiredFrameCount < 1 ||
353
+ snapshot.revision.retiredMessageCount < 1 ||
354
+ snapshot.activeOverrides.length !== snapshot.revision.activeOverrideCount)
355
+ ) {
356
+ throw new ContextRevisionError("Prefix retirement revision invariant failed.");
357
+ } else if (
358
+ snapshot.revision.kind === "skills_update" &&
359
+ (snapshot.revision.revisionNumber < 2 ||
360
+ snapshot.revision.addedOverrideCount < 1 ||
361
+ snapshot.revision.activeOverrideCount < snapshot.revision.addedOverrideCount ||
362
+ snapshot.revision.policyVersion !== "agent-skills-v1" ||
363
+ snapshot.revision.rendererFormat !== "skill-activation-receipt-v1" ||
364
+ snapshot.activeOverrides.length !== snapshot.revision.activeOverrideCount)
365
+ ) {
366
+ throw new ContextRevisionError("Agent Skills context revision invariant failed.");
367
+ }
368
+
369
+ if (
370
+ snapshot.activeOverrides.some(
371
+ (override) => override.ordinal < snapshot.revision.keepFromOrdinal,
372
+ )
373
+ ) {
374
+ throw new ContextRevisionError(
375
+ "Active context revision contains an override before its keep boundary.",
376
+ );
219
377
  }
220
378
 
221
379
  if (
222
380
  activeOverrideManifestHash(snapshot.activeOverrides) !==
223
- snapshot.revision.overrideManifestSha256
381
+ snapshot.revision.activeOverrideManifestSha256
224
382
  ) {
225
383
  throw new ContextRevisionError(
226
384
  "Active context revision override manifest does not match stored overrides.",
@@ -231,8 +389,9 @@ function validateSnapshotIdentity(snapshot: StoredContextSnapshotV5): void {
231
389
  export function createInitialContextRevision(input: {
232
390
  revisionId: ContextRevisionId;
233
391
  canonical: ProtocolContextView;
392
+ surface: StoredContextSurfaceV8;
234
393
  createdAt: string;
235
- }): StoredInitialContextRevisionV5 {
394
+ }): StoredInitialContextRevisionV8 {
236
395
  const firstFrame = input.canonical.frames[0];
237
396
  const firstMessage = input.canonical.messages[0];
238
397
  if (
@@ -243,7 +402,9 @@ export function createInitialContextRevision(input: {
243
402
  firstFrame.firstOrdinal !== 1 ||
244
403
  firstFrame.lastOrdinal !== 1 ||
245
404
  firstMessage?.role !== "system" ||
246
- firstMessage.ordinal !== 1
405
+ firstMessage.ordinal !== 1 ||
406
+ input.surface.sessionId !== input.canonical.sessionId ||
407
+ input.surface.systemPrompt !== firstMessage.content
247
408
  ) {
248
409
  throw new ContextRevisionError(
249
410
  "Initial context revision requires exactly one closed system frame.",
@@ -255,11 +416,13 @@ export function createInitialContextRevision(input: {
255
416
  revisionNumber: 1,
256
417
  parentRevisionId: null,
257
418
  kind: "initial_full",
419
+ surfaceId: input.surface.surfaceId,
420
+ surfaceSha256: input.surface.surfaceSha256,
258
421
  keepFromOrdinal: 1,
259
422
  sourceThroughOrdinal: 1,
260
423
  addedOverrideCount: 0,
261
- totalOverrideCount: 0,
262
- overrideManifestSha256: activeOverrideManifestHash([]),
424
+ activeOverrideCount: 0,
425
+ activeOverrideManifestSha256: activeOverrideManifestHash([]),
263
426
  canonicalSequenceSha256: canonicalSequenceHash(input.canonical, 1),
264
427
  renderedMessageSha256: canonicalRenderedMessageHash(input.canonical, 1),
265
428
  createdAt: input.createdAt,
@@ -1,41 +1,47 @@
1
1
  import type { AgentMessage } from "../agent/types";
2
2
  import type {
3
3
  ContextRevisionId,
4
+ ContextSurfaceId,
4
5
  MessageId,
5
6
  ProtocolFrameId,
6
7
  SessionId,
7
8
  } from "../ids/runtime-id";
8
9
  import type { ModelRequestInput } from "../model/model-client";
9
10
  import type { MessageSource } from "./context-source";
11
+ import type { ContextSurfaceChanges, StoredContextSurfaceV8 } from "./context-surface";
10
12
  import type { ProtocolContextView } from "./protocol-frame";
11
13
 
12
- export type StoredInitialContextRevisionV5 = {
14
+ export type StoredInitialContextRevisionV8 = {
13
15
  readonly revisionId: ContextRevisionId;
14
16
  readonly sessionId: SessionId;
15
17
  readonly revisionNumber: 1;
16
18
  readonly parentRevisionId: null;
17
19
  readonly kind: "initial_full";
20
+ readonly surfaceId: ContextSurfaceId;
21
+ readonly surfaceSha256: string;
18
22
  readonly keepFromOrdinal: 1;
19
23
  readonly sourceThroughOrdinal: 1;
20
24
  readonly addedOverrideCount: 0;
21
- readonly totalOverrideCount: 0;
22
- readonly overrideManifestSha256: string;
25
+ readonly activeOverrideCount: 0;
26
+ readonly activeOverrideManifestSha256: string;
23
27
  readonly canonicalSequenceSha256: string;
24
28
  readonly renderedMessageSha256: string;
25
29
  readonly createdAt: string;
26
30
  };
27
31
 
28
- export type StoredSwapContextRevisionV5 = {
32
+ export type StoredSwapContextRevisionV8 = {
29
33
  readonly revisionId: ContextRevisionId;
30
34
  readonly sessionId: SessionId;
31
35
  readonly revisionNumber: number;
32
36
  readonly parentRevisionId: ContextRevisionId;
33
37
  readonly kind: "swap_only";
34
- readonly keepFromOrdinal: 1;
38
+ readonly surfaceId: ContextSurfaceId;
39
+ readonly surfaceSha256: string;
40
+ readonly keepFromOrdinal: number;
35
41
  readonly sourceThroughOrdinal: number;
36
42
  readonly addedOverrideCount: number;
37
- readonly totalOverrideCount: number;
38
- readonly overrideManifestSha256: string;
43
+ readonly activeOverrideCount: number;
44
+ readonly activeOverrideManifestSha256: string;
39
45
  readonly canonicalSequenceSha256: string;
40
46
  readonly renderedMessageSha256: string;
41
47
  readonly policyVersion: "swap-only-v1";
@@ -44,9 +50,77 @@ export type StoredSwapContextRevisionV5 = {
44
50
  readonly createdAt: string;
45
51
  };
46
52
 
47
- export type StoredContextRevisionV5 =
48
- | StoredInitialContextRevisionV5
49
- | StoredSwapContextRevisionV5;
53
+ export type StoredSurfaceRefreshContextRevisionV8 = {
54
+ readonly revisionId: ContextRevisionId;
55
+ readonly sessionId: SessionId;
56
+ readonly revisionNumber: number;
57
+ readonly parentRevisionId: ContextRevisionId;
58
+ readonly kind: "surface_refresh";
59
+ readonly surfaceId: ContextSurfaceId;
60
+ readonly surfaceSha256: string;
61
+ readonly keepFromOrdinal: number;
62
+ readonly sourceThroughOrdinal: number;
63
+ readonly addedOverrideCount: 0;
64
+ readonly activeOverrideCount: number;
65
+ readonly activeOverrideManifestSha256: string;
66
+ readonly canonicalSequenceSha256: string;
67
+ readonly renderedMessageSha256: string;
68
+ readonly changeManifestSha256: string;
69
+ readonly createdAt: string;
70
+ };
71
+
72
+ export type StoredPrefixRetirementContextRevisionV8 = {
73
+ readonly revisionId: ContextRevisionId;
74
+ readonly sessionId: SessionId;
75
+ readonly revisionNumber: number;
76
+ readonly parentRevisionId: ContextRevisionId;
77
+ readonly kind: "prefix_retirement";
78
+ readonly surfaceId: ContextSurfaceId;
79
+ readonly surfaceSha256: string;
80
+ readonly keepFromOrdinal: number;
81
+ readonly sourceThroughOrdinal: number;
82
+ readonly addedOverrideCount: 0;
83
+ readonly activeOverrideCount: number;
84
+ readonly activeOverrideManifestSha256: string;
85
+ readonly canonicalSequenceSha256: string;
86
+ readonly renderedMessageSha256: string;
87
+ readonly policyVersion: "recall-first-retirement-v1";
88
+ readonly planSha256: string;
89
+ readonly retiredThroughOrdinal: number;
90
+ readonly retiredTurnCount: number;
91
+ readonly retiredFrameCount: number;
92
+ readonly retiredMessageCount: number;
93
+ readonly createdAt: string;
94
+ };
95
+
96
+ export type StoredSkillsUpdateContextRevisionV8 = {
97
+ readonly revisionId: ContextRevisionId;
98
+ readonly sessionId: SessionId;
99
+ readonly revisionNumber: number;
100
+ readonly parentRevisionId: ContextRevisionId;
101
+ readonly kind: "skills_update";
102
+ readonly surfaceId: ContextSurfaceId;
103
+ readonly surfaceSha256: string;
104
+ readonly keepFromOrdinal: number;
105
+ readonly sourceThroughOrdinal: number;
106
+ readonly addedOverrideCount: number;
107
+ readonly activeOverrideCount: number;
108
+ readonly activeOverrideManifestSha256: string;
109
+ readonly canonicalSequenceSha256: string;
110
+ readonly renderedMessageSha256: string;
111
+ readonly policyVersion: "agent-skills-v1";
112
+ readonly rendererFormat: "skill-activation-receipt-v1";
113
+ readonly changeManifestSha256: string;
114
+ readonly activationManifestSha256: string;
115
+ readonly createdAt: string;
116
+ };
117
+
118
+ export type StoredContextRevisionV8 =
119
+ | StoredInitialContextRevisionV8
120
+ | StoredSwapContextRevisionV8
121
+ | StoredSurfaceRefreshContextRevisionV8
122
+ | StoredPrefixRetirementContextRevisionV8
123
+ | StoredSkillsUpdateContextRevisionV8;
50
124
 
51
125
  export type SwapOverride = {
52
126
  readonly frameId: ProtocolFrameId;
@@ -59,21 +133,23 @@ export type SwapOverride = {
59
133
  readonly originalBytes: number;
60
134
  readonly renderedBytes: number;
61
135
  readonly byteSavings: number;
136
+ readonly rendererFormat?: "swap-observation-v1" | "skill-activation-receipt-v1";
62
137
  };
63
138
 
64
- export type StoredSwapOverrideV5 = SwapOverride & {
139
+ export type StoredContextOverrideV8 = SwapOverride & {
65
140
  readonly introducedRevisionId: ContextRevisionId;
66
- readonly rendererFormat: "swap-observation-v1";
141
+ readonly rendererFormat: "swap-observation-v1" | "skill-activation-receipt-v1";
67
142
  readonly createdAt: string;
68
143
  };
69
144
 
70
- export type StoredContextSnapshotV5 = {
145
+ export type StoredContextSnapshotV8 = {
71
146
  readonly meta: {
72
147
  readonly sessionId: SessionId;
73
148
  readonly activeRevisionId: ContextRevisionId;
74
149
  };
75
- readonly revision: StoredContextRevisionV5;
76
- readonly activeOverrides: readonly StoredSwapOverrideV5[];
150
+ readonly revision: StoredContextRevisionV8;
151
+ readonly surface: StoredContextSurfaceV8;
152
+ readonly activeOverrides: readonly StoredContextOverrideV8[];
77
153
  readonly canonical: ProtocolContextView;
78
154
  };
79
155
 
@@ -81,16 +157,20 @@ export type CompiledContextEntry = {
81
157
  readonly frameId: ProtocolFrameId;
82
158
  readonly messageId: MessageId;
83
159
  readonly ordinal: number;
84
- readonly representation: "canonical" | "swapped";
160
+ readonly representation: "canonical" | "surface" | "swapped";
85
161
  readonly sourceContentSha256: string;
86
162
  readonly message: AgentMessage;
87
163
  };
88
164
 
89
165
  export type CompiledContextManifest = {
90
- readonly frameCount: number;
91
- readonly messageCount: number;
166
+ readonly canonicalFrameCount: number;
167
+ readonly canonicalMessageCount: number;
168
+ readonly activeFrameCount: number;
169
+ readonly activeMessageCount: number;
170
+ readonly keepFromOrdinal: number;
92
171
  readonly canonicalSequenceHash: string;
93
172
  readonly renderedMessageHash: string;
173
+ readonly surfaceSha256: string;
94
174
  };
95
175
 
96
176
  export type CompiledRevisionContext = {
@@ -103,9 +183,15 @@ export type CompiledRevisionContext = {
103
183
 
104
184
  export type BuiltContextRequest = {
105
185
  readonly canonical: ProtocolContextView;
106
- readonly revision: StoredContextRevisionV5;
186
+ readonly revision: StoredContextRevisionV8;
187
+ readonly surface: StoredContextSurfaceV8;
107
188
  readonly activeOverrides: readonly SwapOverride[];
108
189
  readonly compiled: CompiledRevisionContext;
109
190
  readonly request: ModelRequestInput;
110
191
  readonly candidateUserPromptIncluded: boolean;
111
192
  };
193
+
194
+ export type SurfaceRefreshPlan = {
195
+ readonly surface: StoredContextSurfaceV8;
196
+ readonly changes: ContextSurfaceChanges;
197
+ };