@deepstrike/wasm 0.2.76 → 0.2.78
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/dist/agent.d.ts +6 -2
- package/dist/agent.js +59 -19
- package/dist/index.d.ts +7 -9
- package/dist/index.js +3 -5
- package/dist/memory/attestation.d.ts +38 -0
- package/dist/memory/attestation.js +43 -0
- package/dist/memory/authority.d.ts +2 -0
- package/dist/memory/authority.js +3 -1
- package/dist/memory/candidate-sink.d.ts +66 -0
- package/dist/memory/candidate-sink.js +82 -0
- package/dist/memory/durable.d.ts +4 -2
- package/dist/memory/durable.js +2 -0
- package/dist/memory/index.d.ts +9 -1
- package/dist/memory/index.js +5 -0
- package/dist/memory/lifecycle.d.ts +82 -0
- package/dist/memory/lifecycle.js +46 -0
- package/dist/memory/recall-projection.d.ts +5 -0
- package/dist/memory/recall-projection.js +18 -0
- package/dist/memory/runtime-policy.d.ts +15 -0
- package/dist/memory/runtime-policy.js +26 -0
- package/dist/memory/writer.d.ts +22 -0
- package/dist/memory/writer.js +41 -0
- package/dist/providers/anthropic-compaction.d.ts +84 -0
- package/dist/providers/anthropic-compaction.js +222 -0
- package/dist/providers/anthropic.d.ts +41 -1
- package/dist/providers/anthropic.js +187 -18
- package/dist/providers/base.js +11 -1
- package/dist/runtime/canonical-kernel-step.d.ts +1 -2
- package/dist/runtime/canonical-kernel-step.js +74 -8
- package/dist/runtime/execution-plane.js +1 -1
- package/dist/runtime/index.d.ts +0 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/kernel-event-log.d.ts +8 -0
- package/dist/runtime/kernel-event-log.js +61 -1
- package/dist/runtime/kernel-step.d.ts +13 -2
- package/dist/runtime/os-snapshot.js +1 -0
- package/dist/runtime/runner.d.ts +40 -25
- package/dist/runtime/runner.js +196 -240
- package/dist/runtime/session-event-registry.generated.d.ts +212 -0
- package/dist/runtime/session-event-registry.generated.js +112 -0
- package/dist/runtime/session-log.d.ts +69 -16
- package/dist/runtime/session-log.js +10 -58
- package/dist/runtime/session-repair.d.ts +0 -3
- package/dist/runtime/session-repair.js +0 -3
- package/dist/runtime/sub-agent-orchestrator.d.ts +2 -0
- package/dist/runtime/sub-agent-orchestrator.js +2 -0
- package/dist/runtime/types/agent.d.ts +9 -52
- package/dist/runtime/types/agent.js +8 -45
- package/dist/types.d.ts +10 -5
- package/package.json +3 -3
- package/dist/memory/extraction.d.ts +0 -4
- package/dist/memory/extraction.js +0 -48
- package/dist/runtime/context.d.ts +0 -28
- package/dist/runtime/context.js +0 -16
- package/dist/runtime/evolution.d.ts +0 -189
- package/dist/runtime/evolution.js +0 -25
- package/dist/runtime/reducers.d.ts +0 -15
- package/dist/runtime/reducers.js +0 -57
- package/dist/runtime/verifiable-report.d.ts +0 -59
- package/dist/runtime/verifiable-report.js +0 -64
- package/dist/runtime/workflow-control-flow.d.ts +0 -21
- package/dist/runtime/workflow-control-flow.js +0 -83
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { requestSnapshot } from "./prepared-request.js";
|
|
2
2
|
import { assistantReplayKey, collectStreamMessage, toAnthropicMessages } from "./base.js";
|
|
3
3
|
import { malformedToolArguments, toolArgumentsText } from "../runtime/tool-arguments.js";
|
|
4
|
+
import { OnDemandCompactor, THRESHOLD_COMPACTION_BETA, compactionBlock, resolveCompaction, resumeAfterCompactionPause, withoutCompactionPause, } from "./anthropic-compaction.js";
|
|
4
5
|
/** Anthropic accepts at most this many cache_control breakpoints per request. */
|
|
5
6
|
const MAX_CACHE_BREAKPOINTS = 4;
|
|
6
7
|
/** Rolling cache breakpoints reserved for the message history (system uses ≤2). */
|
|
@@ -117,15 +118,53 @@ function assertCacheBudget(system, toolCount) {
|
|
|
117
118
|
throw new Error(`Anthropic cache_control budget exceeded: ${systemBreakpoints} system + ${toolBreakpoints} tool + ${MESSAGE_CACHE_BREAKPOINTS} message > ${MAX_CACHE_BREAKPOINTS}`);
|
|
118
119
|
}
|
|
119
120
|
}
|
|
121
|
+
const CONTEXT_MANAGEMENT_BETA = "context-management-2025-06-27";
|
|
122
|
+
const PROMPT_CACHING_BETA = "prompt-caching-2024-07-31";
|
|
123
|
+
/** The leading wire messages that are history; the state turn follows them. */
|
|
124
|
+
function historyCount(wireTurns) {
|
|
125
|
+
return wireTurns.filter(index => index >= 0).length;
|
|
126
|
+
}
|
|
127
|
+
function clearToolUsesEdit(config) {
|
|
128
|
+
const c = config === true ? {} : config;
|
|
129
|
+
return {
|
|
130
|
+
type: "clear_tool_uses_20250919",
|
|
131
|
+
...(c.triggerInputTokens !== undefined ? { trigger: { type: "input_tokens", value: c.triggerInputTokens } } : {}),
|
|
132
|
+
...(c.keepToolUses !== undefined ? { keep: { type: "tool_uses", value: c.keepToolUses } } : {}),
|
|
133
|
+
...(c.clearAtLeastInputTokens !== undefined ? { clear_at_least: { type: "input_tokens", value: c.clearAtLeastInputTokens } } : {}),
|
|
134
|
+
...(c.excludeTools?.length ? { exclude_tools: [...c.excludeTools] } : {}),
|
|
135
|
+
...(c.clearToolInputs !== undefined ? { clear_tool_inputs: c.clearToolInputs } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
120
138
|
export class AnthropicProvider {
|
|
121
139
|
apiKey;
|
|
122
140
|
model;
|
|
123
141
|
maxTokens;
|
|
124
142
|
nativeAssistantBlocks = new Map();
|
|
125
|
-
|
|
143
|
+
/** Server-side context edits and the beta each needs. */
|
|
144
|
+
nativeContextEdits = [];
|
|
145
|
+
/** Threshold compaction with a pause: how many history messages stay verbatim behind the block. */
|
|
146
|
+
compactionPauseKeep;
|
|
147
|
+
onDemandCompactor;
|
|
148
|
+
constructor(apiKey, model = "claude-sonnet-4-6", maxTokens = 8096, options = {}) {
|
|
126
149
|
this.apiKey = apiKey;
|
|
127
150
|
this.model = model;
|
|
128
151
|
this.maxTokens = maxTokens;
|
|
152
|
+
// Clearing runs first so the compaction trigger reads the input after tool results are cleared.
|
|
153
|
+
if (options.contextEditing)
|
|
154
|
+
this.nativeContextEdits.push({ beta: CONTEXT_MANAGEMENT_BETA, edit: clearToolUsesEdit(options.contextEditing) });
|
|
155
|
+
const compaction = options.compaction ? resolveCompaction(options.compaction) : undefined;
|
|
156
|
+
if (compaction?.mode === "threshold") {
|
|
157
|
+
this.nativeContextEdits.push({ beta: THRESHOLD_COMPACTION_BETA, edit: compaction.edit });
|
|
158
|
+
if (compaction.edit.pause_after_compaction)
|
|
159
|
+
this.compactionPauseKeep = compaction.keepRecentMessages ?? 0;
|
|
160
|
+
}
|
|
161
|
+
else if (compaction?.mode === "on_demand") {
|
|
162
|
+
this.onDemandCompactor = new OnDemandCompactor(compaction.config, body => this.createMessage(body));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** On-demand compaction in flight settles; for tests and orderly shutdown. */
|
|
166
|
+
compactionIdle() {
|
|
167
|
+
return this.onDemandCompactor?.idle() ?? Promise.resolve();
|
|
129
168
|
}
|
|
130
169
|
descriptor() {
|
|
131
170
|
return {
|
|
@@ -141,6 +180,12 @@ export class AnthropicProvider {
|
|
|
141
180
|
supported: true,
|
|
142
181
|
requiresStrictPairing: true,
|
|
143
182
|
},
|
|
183
|
+
...(this.nativeContextEdits.length || this.onDemandCompactor ? {
|
|
184
|
+
nativeContext: {
|
|
185
|
+
...(this.nativeContextEdits.some(native => native.edit.type === "clear_tool_uses_20250919") ? { toolResultClearing: true } : {}),
|
|
186
|
+
...(this.onDemandCompactor || this.nativeContextEdits.some(native => native.edit.type === "compact_20260112") ? { compaction: true } : {}),
|
|
187
|
+
},
|
|
188
|
+
} : {}),
|
|
144
189
|
};
|
|
145
190
|
}
|
|
146
191
|
requestPlanIdentity() {
|
|
@@ -174,16 +219,37 @@ export class AnthropicProvider {
|
|
|
174
219
|
systemBlocks.push({ type: "text", text: context.systemKnowledge, ...(emitOnSystemBlocks ? { cache_control: cc } : {}) });
|
|
175
220
|
}
|
|
176
221
|
const system = systemBlocks.length ? systemBlocks : (context.systemText || undefined);
|
|
177
|
-
const
|
|
178
|
-
|
|
222
|
+
const replay = (message) => this.nativeAssistantBlocks.get(assistantReplayKey(message));
|
|
223
|
+
let msgs = [];
|
|
224
|
+
// For each wire message, the index of the rendered turn it came from; the state turn is -1.
|
|
225
|
+
let wireTurns = [];
|
|
226
|
+
context.turns.forEach((turn, index) => {
|
|
227
|
+
for (const message of toAnthropicMessages({ systemText: "", turns: [turn] }, replay)) {
|
|
228
|
+
msgs.push(message);
|
|
229
|
+
wireTurns.push(index);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
// The API ignores everything before a compaction block, so it is not sent.
|
|
233
|
+
let head = -1;
|
|
234
|
+
for (let index = msgs.length - 1; index >= 0 && head < 0; index--) {
|
|
235
|
+
const content = msgs[index].content;
|
|
236
|
+
if (Array.isArray(content) && content.some(block => block.type === "compaction"))
|
|
237
|
+
head = index;
|
|
238
|
+
}
|
|
239
|
+
if (head > 0) {
|
|
240
|
+
msgs = msgs.slice(head);
|
|
241
|
+
wireTurns = wireTurns.slice(head);
|
|
242
|
+
}
|
|
243
|
+
applyMessageCacheControl(msgs, typeof context.frozenPrefixLen === "number" && head > 0 ? context.frozenPrefixLen - head : context.frozenPrefixLen, strategy);
|
|
179
244
|
// Append the volatile State turn AFTER the cache breakpoints (uncached tail);
|
|
180
245
|
// absent on un-rebuilt bindings, where the state is already inside `turns`.
|
|
181
246
|
// Render through toAnthropicMessages so assistant tool_use blocks are
|
|
182
247
|
// serialized correctly — raw content would silently drop toolCalls.
|
|
183
248
|
if (context.stateTurn) {
|
|
184
249
|
const stateCtx = { systemText: "", turns: [context.stateTurn] };
|
|
185
|
-
const stateMsgs = toAnthropicMessages(stateCtx,
|
|
250
|
+
const stateMsgs = toAnthropicMessages(stateCtx, replay);
|
|
186
251
|
msgs.push(...stateMsgs);
|
|
252
|
+
wireTurns.push(...stateMsgs.map(() => -1));
|
|
187
253
|
}
|
|
188
254
|
assertCacheBudget(system, tools.length);
|
|
189
255
|
const builtTools = tools.length ? buildAnthropicTools(tools, !Array.isArray(system), strategy) : undefined;
|
|
@@ -200,25 +266,113 @@ export class AnthropicProvider {
|
|
|
200
266
|
if (extensions?.enable_thinking) {
|
|
201
267
|
body.thinking = { type: "enabled", budget_tokens: 8000 };
|
|
202
268
|
}
|
|
269
|
+
// The kernel stopped running these tiers on the strength of the edits, so they ride on every
|
|
270
|
+
// request beside any betas or edits the caller passed.
|
|
271
|
+
if (this.nativeContextEdits.length) {
|
|
272
|
+
const betas = Array.isArray(extensions?.betas) ? extensions.betas.filter((value) => typeof value === "string") : [];
|
|
273
|
+
const callerManagement = extensions?.context_management && typeof extensions.context_management === "object"
|
|
274
|
+
? extensions.context_management
|
|
275
|
+
: {};
|
|
276
|
+
const edits = Array.isArray(callerManagement.edits) ? [...callerManagement.edits] : [];
|
|
277
|
+
for (const native of this.nativeContextEdits) {
|
|
278
|
+
if (!betas.includes(native.beta))
|
|
279
|
+
betas.push(native.beta);
|
|
280
|
+
if (!edits.some(edit => edit?.type === native.edit.type))
|
|
281
|
+
edits.push(native.edit);
|
|
282
|
+
}
|
|
283
|
+
body.betas = betas;
|
|
284
|
+
body.context_management = { ...callerManagement, edits };
|
|
285
|
+
}
|
|
286
|
+
this.onDemandCompactor?.apply(body);
|
|
203
287
|
const frozenBody = requestSnapshot(body);
|
|
204
288
|
return {
|
|
205
289
|
scope: "encoded_body", request: requestSnapshot(frozenBody), state: requestSnapshot(state ?? null),
|
|
206
|
-
stream: signal => this.
|
|
290
|
+
stream: signal => this.streamTurn(context, frozenBody, wireTurns, slotBp, signal),
|
|
207
291
|
};
|
|
208
292
|
}
|
|
293
|
+
/** One turn: the response's events, or — when a compaction pause stops the response at the
|
|
294
|
+
* summary — the continuation's. With a pause configured, events are held until the response
|
|
295
|
+
* shows it is not a pause (any non-usage event) or ends. */
|
|
296
|
+
async *streamTurn(context, body, wireTurns, slotBp, signal) {
|
|
297
|
+
const first = this.streamBody(body, slotBp, signal)[Symbol.asyncIterator]();
|
|
298
|
+
let held = this.compactionPauseKeep !== undefined ? [] : undefined;
|
|
299
|
+
let outcome;
|
|
300
|
+
for (;;) {
|
|
301
|
+
const next = await first.next();
|
|
302
|
+
if (next.done) {
|
|
303
|
+
outcome = next.value;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
if (held && next.value.type !== "usage") {
|
|
307
|
+
yield* held;
|
|
308
|
+
held = undefined;
|
|
309
|
+
}
|
|
310
|
+
if (held)
|
|
311
|
+
held.push(next.value);
|
|
312
|
+
else
|
|
313
|
+
yield next.value;
|
|
314
|
+
}
|
|
315
|
+
const paused = held && outcome.stopReason === "compaction" ? compactionBlock(outcome.nativeBlocks) : undefined;
|
|
316
|
+
let unanchoredBlock;
|
|
317
|
+
if (paused) {
|
|
318
|
+
const resumed = resumeAfterCompactionPause(body.messages, historyCount(wireTurns), paused, this.compactionPauseKeep);
|
|
319
|
+
if (resumed.anchor) {
|
|
320
|
+
const turn = context.turns[wireTurns[resumed.anchor.wireIndex]];
|
|
321
|
+
if (turn)
|
|
322
|
+
this.nativeAssistantBlocks.set(assistantReplayKey(turn), resumed.anchor.content);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
unanchoredBlock = paused;
|
|
326
|
+
}
|
|
327
|
+
const continuation = this.streamBody({ ...withoutCompactionPause(body), messages: resumed.messages }, slotBp, signal)[Symbol.asyncIterator]();
|
|
328
|
+
for (;;) {
|
|
329
|
+
const next = await continuation.next();
|
|
330
|
+
if (next.done) {
|
|
331
|
+
outcome = next.value;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
yield next.value;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else if (held) {
|
|
338
|
+
yield* held;
|
|
339
|
+
}
|
|
340
|
+
this.rememberNativeBlocks({ content: outcome.finalText, toolCalls: outcome.finalToolCalls }, [...(unanchoredBlock ? [unanchoredBlock] : []), ...outcome.nativeBlocks]);
|
|
341
|
+
this.onDemandCompactor?.observe(body, historyCount(wireTurns), outcome.totalTokens);
|
|
342
|
+
}
|
|
343
|
+
headers(body) {
|
|
344
|
+
return {
|
|
345
|
+
"x-api-key": this.apiKey,
|
|
346
|
+
"anthropic-version": "2023-06-01",
|
|
347
|
+
"content-type": "application/json",
|
|
348
|
+
"anthropic-beta": [
|
|
349
|
+
PROMPT_CACHING_BETA,
|
|
350
|
+
...(Array.isArray(body.betas) ? body.betas.filter((value) => typeof value === "string" && value !== PROMPT_CACHING_BETA) : []),
|
|
351
|
+
].filter((value, index, values) => values.indexOf(value) === index).join(","),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/** A non-streaming request; the on-demand compaction request goes this way. */
|
|
355
|
+
async createMessage(body) {
|
|
356
|
+
const resp = await fetch("https://api.anthropic.com/v1/messages", {
|
|
357
|
+
method: "POST",
|
|
358
|
+
headers: this.headers(body),
|
|
359
|
+
// Betas travel in the header; the Messages API refuses them as a body field.
|
|
360
|
+
body: JSON.stringify({ ...body, stream: undefined, betas: undefined }),
|
|
361
|
+
});
|
|
362
|
+
if (!resp.ok) {
|
|
363
|
+
throw Object.assign(new Error(`Anthropic ${resp.status}: ${await resp.text()}`), { status: resp.status });
|
|
364
|
+
}
|
|
365
|
+
return await resp.json();
|
|
366
|
+
}
|
|
209
367
|
async *stream(context, tools, extensions, state, signal) {
|
|
210
368
|
yield* this.prepareRequest(context, tools, extensions, state).stream(signal);
|
|
211
369
|
}
|
|
212
370
|
async *streamBody(body, slotBp, signal) {
|
|
213
371
|
const resp = await fetch("https://api.anthropic.com/v1/messages", {
|
|
214
372
|
method: "POST",
|
|
215
|
-
headers:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
"content-type": "application/json",
|
|
219
|
-
"anthropic-beta": "prompt-caching-2024-07-31",
|
|
220
|
-
},
|
|
221
|
-
body: JSON.stringify(body),
|
|
373
|
+
headers: this.headers(body),
|
|
374
|
+
// Betas travel in the header; the Messages API refuses them as a body field.
|
|
375
|
+
body: JSON.stringify({ ...body, betas: undefined }),
|
|
222
376
|
...(signal ? { signal } : {}), // #2-B-ii: a preempt aborts the in-flight request at the socket.
|
|
223
377
|
});
|
|
224
378
|
if (!resp.ok) {
|
|
@@ -235,6 +389,14 @@ export class AnthropicProvider {
|
|
|
235
389
|
let cacheReadTokens = 0;
|
|
236
390
|
let cacheCreationTokens = 0;
|
|
237
391
|
let outputTokens = 0;
|
|
392
|
+
let stopReason;
|
|
393
|
+
const outcome = () => ({
|
|
394
|
+
nativeBlocks: Object.keys(nativeBlocks).map(Number).sort((a, b) => a - b).map(index => nativeBlocks[index]),
|
|
395
|
+
finalText,
|
|
396
|
+
finalToolCalls,
|
|
397
|
+
...(stopReason ? { stopReason } : {}),
|
|
398
|
+
totalTokens: uncachedInput + cacheReadTokens + cacheCreationTokens + outputTokens,
|
|
399
|
+
});
|
|
238
400
|
while (true) {
|
|
239
401
|
const { done, value } = await reader.read();
|
|
240
402
|
if (done)
|
|
@@ -247,10 +409,15 @@ export class AnthropicProvider {
|
|
|
247
409
|
continue;
|
|
248
410
|
const data = line.slice(6).trim();
|
|
249
411
|
if (data === "[DONE]")
|
|
250
|
-
return;
|
|
412
|
+
return outcome();
|
|
251
413
|
try {
|
|
252
414
|
const evt = JSON.parse(data);
|
|
253
415
|
if (evt.type === "message_start" || evt.type === "message_delta") {
|
|
416
|
+
// stop_reason rides on message_delta; "max_tokens" drives output-cap recovery and
|
|
417
|
+
// "compaction" marks a paused threshold compaction.
|
|
418
|
+
const eventStopReason = evt.delta?.stop_reason ?? undefined;
|
|
419
|
+
if (eventStopReason)
|
|
420
|
+
stopReason = eventStopReason;
|
|
254
421
|
const usage = (evt.usage ?? evt.message?.usage);
|
|
255
422
|
if (usage) {
|
|
256
423
|
// input + cache counts are pinned at message_start; a later
|
|
@@ -264,8 +431,6 @@ export class AnthropicProvider {
|
|
|
264
431
|
const inputTokens = uncachedInput + cacheReadTokens + cacheCreationTokens;
|
|
265
432
|
if (inputTokens > 0 || outputTokens > 0) {
|
|
266
433
|
const bySlot = estimateCacheReadBySlot(cacheReadTokens, slotBp);
|
|
267
|
-
// stop_reason rides on message_delta; "max_tokens" drives output-cap recovery.
|
|
268
|
-
const stopReason = evt.delta?.stop_reason;
|
|
269
434
|
yield {
|
|
270
435
|
type: "usage",
|
|
271
436
|
totalTokens: inputTokens + outputTokens,
|
|
@@ -274,7 +439,7 @@ export class AnthropicProvider {
|
|
|
274
439
|
cacheReadInputTokens: cacheReadTokens,
|
|
275
440
|
cacheCreationInputTokens: cacheCreationTokens,
|
|
276
441
|
...(bySlot ? { cacheReadInputTokensBySlot: bySlot } : {}),
|
|
277
|
-
...(
|
|
442
|
+
...(eventStopReason ? { stopReason: eventStopReason } : {}),
|
|
278
443
|
};
|
|
279
444
|
}
|
|
280
445
|
}
|
|
@@ -298,6 +463,10 @@ export class AnthropicProvider {
|
|
|
298
463
|
nativeBlocks[idx] = { ...nativeBlocks[idx], thinking: String(nativeBlocks[idx]?.thinking ?? "") + d.thinking };
|
|
299
464
|
yield { type: "thinking_delta", delta: d.thinking };
|
|
300
465
|
}
|
|
466
|
+
else if (d.type === "compaction_delta") {
|
|
467
|
+
// The summary arrives whole in one delta; it is replayed, never shown.
|
|
468
|
+
nativeBlocks[idx] = { ...nativeBlocks[idx], content: String(nativeBlocks[idx]?.content ?? "") + String(d.content ?? "") };
|
|
469
|
+
}
|
|
301
470
|
else if (d.type === "signature_delta") {
|
|
302
471
|
nativeBlocks[idx] = { ...nativeBlocks[idx], signature: String(nativeBlocks[idx]?.signature ?? "") + d.signature };
|
|
303
472
|
}
|
|
@@ -326,12 +495,12 @@ export class AnthropicProvider {
|
|
|
326
495
|
catch { /* skip malformed */ }
|
|
327
496
|
}
|
|
328
497
|
}
|
|
329
|
-
|
|
498
|
+
return outcome();
|
|
330
499
|
}
|
|
331
500
|
rememberNativeBlocks(message, blocks) {
|
|
332
501
|
if (!blocks.length)
|
|
333
502
|
return;
|
|
334
|
-
if (!message.toolCalls?.length && !blocks.some(b => b.type === "thinking"))
|
|
503
|
+
if (!message.toolCalls?.length && !blocks.some(b => b.type === "thinking" || b.type === "compaction"))
|
|
335
504
|
return;
|
|
336
505
|
this.nativeAssistantBlocks.set(assistantReplayKey(message), blocks);
|
|
337
506
|
}
|
package/dist/providers/base.js
CHANGED
|
@@ -110,10 +110,20 @@ export function toAnthropicMessages(context, nativeReplay) {
|
|
|
110
110
|
}
|
|
111
111
|
continue;
|
|
112
112
|
}
|
|
113
|
+
if (msg.role === "assistant" && !msg.toolCalls?.length) {
|
|
114
|
+
// A turn that carries a server compaction block goes back as the API sent it: the block is
|
|
115
|
+
// what tells the API to drop everything before it.
|
|
116
|
+
const replay = nativeReplay?.(msg);
|
|
117
|
+
if (replay?.some(block => block.type === "compaction")) {
|
|
118
|
+
// Copies: request-time annotations such as `cache_control` must not land on the replay.
|
|
119
|
+
result.push({ role: "assistant", content: replay.map(block => ({ ...block })) });
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
113
123
|
if (msg.role === "assistant" && msg.toolCalls?.length) {
|
|
114
124
|
const replay = nativeReplay?.(msg);
|
|
115
125
|
if (replay) {
|
|
116
|
-
result.push({ role: "assistant", content: replay });
|
|
126
|
+
result.push({ role: "assistant", content: replay.map(block => ({ ...block })) });
|
|
117
127
|
continue;
|
|
118
128
|
}
|
|
119
129
|
const blocks = [];
|
|
@@ -38,7 +38,7 @@ export interface CanonicalTransition {
|
|
|
38
38
|
}
|
|
39
39
|
export declare function canonicalUnsupportedEffectResolution(effectId: string, effectKind: string): CanonicalKernelInput;
|
|
40
40
|
/** Adapt the core-owned KernelProjection JSON into the WASM action surface. */
|
|
41
|
-
export declare function canonicalActionFromProjectionJson(raw: string): KernelRunnerAction | null;
|
|
41
|
+
export declare function canonicalActionFromProjectionJson(raw: string, observations?: readonly KernelObservation[]): KernelRunnerAction | null;
|
|
42
42
|
export declare class CanonicalKernelRejectedError extends Error {
|
|
43
43
|
readonly fault: Record<string, unknown>;
|
|
44
44
|
constructor(faultJson: string);
|
|
@@ -98,7 +98,6 @@ export interface CanonicalRunnerRuntimeOptions {
|
|
|
98
98
|
maxTurns?: number;
|
|
99
99
|
maxTotalTokens?: number;
|
|
100
100
|
maxWallMs?: number;
|
|
101
|
-
artifactSetDigest?: string;
|
|
102
101
|
memoryBindingId?: string;
|
|
103
102
|
persistPayload?: (callId: string, content: string, previewBytes: number) => Promise<{
|
|
104
103
|
payloadRef: string;
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { normalizeProviderStopReason } from "../providers/stop-reason.js";
|
|
2
2
|
import { sha256Hex } from "./sha256.js";
|
|
3
3
|
import { JournalCasConflictError, MAX_CHAIN_POSITION as JOURNAL_MAX_CHAIN_POSITION, } from "./kernel-journal.js";
|
|
4
|
-
import { encodeCanonicalContentParts, kernelMessageToSdk, renderedContextToSdk, } from "./kernel-step.js";
|
|
4
|
+
import { archivePresentationFromObservations, encodeCanonicalContentParts, kernelMessageToSdk, renderedContextToSdk, } from "./kernel-step.js";
|
|
5
5
|
import { toolArgumentsFromWire } from "./tool-arguments.js";
|
|
6
6
|
export const MAX_CHAIN_POSITION = JOURNAL_MAX_CHAIN_POSITION;
|
|
7
7
|
const utf8ByteLength = (value) => new TextEncoder().encode(value).byteLength;
|
|
8
8
|
function asObject(value) {
|
|
9
9
|
return value && typeof value === "object" ? value : {};
|
|
10
10
|
}
|
|
11
|
+
// Keep structured candidate errors compact and deterministic across SDKs.
|
|
12
|
+
function memoryCandidateErrorJson(value) {
|
|
13
|
+
if (Array.isArray(value))
|
|
14
|
+
return `[${value.map(memoryCandidateErrorJson).join(",")}]`;
|
|
15
|
+
if (value !== null && typeof value === "object") {
|
|
16
|
+
const object = value;
|
|
17
|
+
return `{${Object.keys(object).sort().map(key => `${JSON.stringify(key)}:${memoryCandidateErrorJson(object[key])}`).join(",")}}`;
|
|
18
|
+
}
|
|
19
|
+
return JSON.stringify(value);
|
|
20
|
+
}
|
|
11
21
|
function totalUsageTokens(terminal) {
|
|
12
22
|
const usage = asObject(terminal.usage);
|
|
13
23
|
const input = Number(usage.input_tokens ?? 0);
|
|
@@ -68,7 +78,7 @@ function canonicalDoneFromTerminal(terminal) {
|
|
|
68
78
|
return { kind: "done", effectId: "", result: { termination, turnsUsed, totalTokensUsed: totalUsageTokens(terminal) } };
|
|
69
79
|
}
|
|
70
80
|
/** Adapt the core-owned KernelProjection JSON into the WASM action surface. */
|
|
71
|
-
export function canonicalActionFromProjectionJson(raw) {
|
|
81
|
+
export function canonicalActionFromProjectionJson(raw, observations = []) {
|
|
72
82
|
const projection = asObject(JSON.parse(raw));
|
|
73
83
|
const state = String(projection.state ?? "idle");
|
|
74
84
|
if (state === "idle")
|
|
@@ -107,7 +117,6 @@ export function canonicalActionFromProjectionJson(raw) {
|
|
|
107
117
|
kind: "call_provider",
|
|
108
118
|
effectId,
|
|
109
119
|
context: renderedContextToSdk(context),
|
|
110
|
-
contextEffect: payload,
|
|
111
120
|
tools: (Array.isArray(payload.tools) ? payload.tools : []).map(raw => {
|
|
112
121
|
const tool = asObject(raw);
|
|
113
122
|
return {
|
|
@@ -193,6 +202,7 @@ export function canonicalActionFromProjectionJson(raw) {
|
|
|
193
202
|
}
|
|
194
203
|
return {
|
|
195
204
|
kind: "archive_page_out",
|
|
205
|
+
...archivePresentationFromObservations(observations),
|
|
196
206
|
effectId,
|
|
197
207
|
handleId: String(payload.handle_id ?? ""),
|
|
198
208
|
payload: {
|
|
@@ -781,9 +791,6 @@ export class CanonicalRunnerRuntime {
|
|
|
781
791
|
this.host = new CanonicalKernelHost(kernel, journal, operationId);
|
|
782
792
|
this.memoryBindingId = options.memoryBindingId ?? "wasm-memory";
|
|
783
793
|
this.config = {
|
|
784
|
-
...(options.artifactSetDigest
|
|
785
|
-
? { artifact_set_binding: { artifact_set_digest: options.artifactSetDigest } }
|
|
786
|
-
: {}),
|
|
787
794
|
execution_policy: {
|
|
788
795
|
max_context_tokens: options.maxContextTokens,
|
|
789
796
|
...(options.maxTurns !== undefined ? { max_turns: options.maxTurns } : {}),
|
|
@@ -1142,6 +1149,46 @@ export class CanonicalRunnerRuntime {
|
|
|
1142
1149
|
},
|
|
1143
1150
|
});
|
|
1144
1151
|
break;
|
|
1152
|
+
case "memory_candidate_result":
|
|
1153
|
+
// M2 · the host's answer for a write it holds as a candidate. `pending` is terminal for the
|
|
1154
|
+
// effect and carries no record: nothing is persisted, and the kernel must not present it as
|
|
1155
|
+
// remembered. `accepted` names the record the store now holds, as `memory_persist_result`
|
|
1156
|
+
// does. Malformed receipts and rejections fail non-retryably; a non-null error takes
|
|
1157
|
+
// precedence and fails retryably (the same candidate id is redelivered).
|
|
1158
|
+
if (event.error !== undefined && event.error !== null) {
|
|
1159
|
+
input = this.failedEffect(event, "storage_unavailable", typeof event.error === "string" ? event.error : memoryCandidateErrorJson(event.error), true);
|
|
1160
|
+
break;
|
|
1161
|
+
}
|
|
1162
|
+
if (event.status === "pending") {
|
|
1163
|
+
input = typeof event.candidate_id !== "string" || !event.candidate_id
|
|
1164
|
+
|| typeof event.receipt_id !== "string" || !event.receipt_id
|
|
1165
|
+
? this.failedEffect(event, "storage_unavailable", "memory candidate receipt names no candidate_id/receipt_id", false)
|
|
1166
|
+
: this.succeededEffect(event, {
|
|
1167
|
+
kind: "memory_persisted",
|
|
1168
|
+
candidate: {
|
|
1169
|
+
binding_id: this.memoryBindingId,
|
|
1170
|
+
candidate_id: event.candidate_id,
|
|
1171
|
+
receipt_id: event.receipt_id,
|
|
1172
|
+
},
|
|
1173
|
+
});
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
if (event.status === "accepted") {
|
|
1177
|
+
input = typeof event.record_ref !== "string" || !event.record_ref
|
|
1178
|
+
|| typeof event.digest !== "string" || !event.digest
|
|
1179
|
+
? this.failedEffect(event, "storage_unavailable", "memory candidate accepted without record_ref/digest", false)
|
|
1180
|
+
: this.succeededEffect(event, {
|
|
1181
|
+
kind: "memory_persisted",
|
|
1182
|
+
receipt: {
|
|
1183
|
+
binding_id: this.memoryBindingId,
|
|
1184
|
+
record_ref: event.record_ref,
|
|
1185
|
+
digest: event.digest,
|
|
1186
|
+
},
|
|
1187
|
+
});
|
|
1188
|
+
break;
|
|
1189
|
+
}
|
|
1190
|
+
input = this.failedEffect(event, "storage_unavailable", `memory candidate rejected: ${typeof event.reason_code === "string" && event.reason_code ? event.reason_code : "unspecified"}`, false);
|
|
1191
|
+
break;
|
|
1145
1192
|
case "memory_query_result":
|
|
1146
1193
|
input = event.error
|
|
1147
1194
|
? this.failedEffect(event, "storage_unavailable", String(event.error), true)
|
|
@@ -1157,6 +1204,10 @@ export class CanonicalRunnerRuntime {
|
|
|
1157
1204
|
name: String(record.name ?? ""),
|
|
1158
1205
|
kind: String(record.kind ?? "reference"),
|
|
1159
1206
|
content: String(record.content ?? ""),
|
|
1207
|
+
...(typeof record.description === "string" && record.description.trim()
|
|
1208
|
+
? { description: record.description } : {}),
|
|
1209
|
+
...(typeof asObject(record.provenance).trust === "string"
|
|
1210
|
+
? { trust: String(asObject(record.provenance).trust) } : {}),
|
|
1160
1211
|
...(typeof hit.score === "number" ? { score: hit.score } : {}),
|
|
1161
1212
|
// M3: the store reports the count it holds; the kernel derives the next one.
|
|
1162
1213
|
...(Number(record.recall_count) > 0
|
|
@@ -1342,7 +1393,7 @@ export class CanonicalRunnerRuntime {
|
|
|
1342
1393
|
}
|
|
1343
1394
|
if (transition) {
|
|
1344
1395
|
this.absorbTransition(transition);
|
|
1345
|
-
this.lastAction = canonicalActionFromProjectionJson(this.host.kernel.projectPlannedStepJson(JSON.stringify(transition.plannedStep)));
|
|
1396
|
+
this.lastAction = canonicalActionFromProjectionJson(this.host.kernel.projectPlannedStepJson(JSON.stringify(transition.plannedStep)), transition.plannedStep.observations);
|
|
1346
1397
|
}
|
|
1347
1398
|
if (this.lastAction?.kind !== "unsupported_effect")
|
|
1348
1399
|
return this.lastAction;
|
|
@@ -1506,6 +1557,12 @@ export class CanonicalRunnerRuntime {
|
|
|
1506
1557
|
...(event.tokens !== undefined ? { tokens: Number(event.tokens) } : {}),
|
|
1507
1558
|
});
|
|
1508
1559
|
return true;
|
|
1560
|
+
case "add_dependency_output":
|
|
1561
|
+
(this.initialContext.dependencies ??= []).push({
|
|
1562
|
+
agent_id: String(event.agent_id ?? ""),
|
|
1563
|
+
content: String(event.content ?? ""),
|
|
1564
|
+
});
|
|
1565
|
+
return true;
|
|
1509
1566
|
case "add_knowledge_message":
|
|
1510
1567
|
this.initialContext.knowledge.push({
|
|
1511
1568
|
content: String(event.content ?? ""),
|
|
@@ -1522,10 +1579,18 @@ export class CanonicalRunnerRuntime {
|
|
|
1522
1579
|
return true;
|
|
1523
1580
|
case "set_memory_enabled":
|
|
1524
1581
|
this.featurePolicy().memory_enabled = Boolean(event.enabled);
|
|
1582
|
+
// Only sent when on, so kernels that predate the field still accept memory-enabled runs.
|
|
1583
|
+
if (event.propose_memory)
|
|
1584
|
+
this.featurePolicy().propose_memory_enabled = true;
|
|
1585
|
+
else
|
|
1586
|
+
delete this.featurePolicy().propose_memory_enabled;
|
|
1587
|
+
if (event.enabled && event.recall) {
|
|
1588
|
+
this.config.memory_policy = { ...asObject(this.config.memory_policy), recall: true };
|
|
1589
|
+
}
|
|
1525
1590
|
if (event.enabled) {
|
|
1526
1591
|
this.config.memory_access = {
|
|
1527
1592
|
binding_id: this.memoryBindingId,
|
|
1528
|
-
capabilities: { read:
|
|
1593
|
+
capabilities: { read: event.read !== false, write: event.write !== false },
|
|
1529
1594
|
};
|
|
1530
1595
|
}
|
|
1531
1596
|
return true;
|
|
@@ -1534,6 +1599,7 @@ export class CanonicalRunnerRuntime {
|
|
|
1534
1599
|
return true;
|
|
1535
1600
|
case "set_memory_policy":
|
|
1536
1601
|
this.config.memory_policy = {
|
|
1602
|
+
...(asObject(this.config.memory_policy).recall ? { recall: true } : {}),
|
|
1537
1603
|
...(event.stale_warning_days !== undefined ? { stale_warning_days: event.stale_warning_days } : {}),
|
|
1538
1604
|
...(event.retrieval_top_k !== undefined ? { retrieval_top_k: event.retrieval_top_k } : {}),
|
|
1539
1605
|
...(event.validation_enabled !== undefined ? { validation_enabled: event.validation_enabled } : {}),
|
|
@@ -49,7 +49,7 @@ export class LocalExecutionPlane {
|
|
|
49
49
|
? await ctx.memoryStore.search(ctx.agentId, { scope: ctx.memoryScope, query: String(args?.query ?? ""), top_k: topK, kinds: [] })
|
|
50
50
|
: [];
|
|
51
51
|
const content = entries.length
|
|
52
|
-
? entries.map(e => `[memory record_id=${e.record.record_id} score=${e.score.toFixed(3)}] ${e.record.content}`).join("\n---\n")
|
|
52
|
+
? entries.map(e => `[memory record_id=${e.record.record_id} trust=${e.record.provenance.trust} score=${e.score.toFixed(3)}] ${e.record.content}`).join("\n---\n")
|
|
53
53
|
: "No relevant memories found.";
|
|
54
54
|
yield { type: "tool_result", callId: c.id, name: c.name, content, isError: false };
|
|
55
55
|
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -16,8 +16,6 @@ export { runAgent, runFanout } from "./facade.js";
|
|
|
16
16
|
export type { RunAgentOptions, RunFanoutOptions } from "./facade.js";
|
|
17
17
|
export { McpExecutionPlane } from "./mcp-transport.js";
|
|
18
18
|
export type { McpConnection, McpConnectionFactory, McpCredentialVault, McpServerConfig } from "./mcp-transport.js";
|
|
19
|
-
export { builtinReducers, resolveReducer } from "./reducers.js";
|
|
20
|
-
export type { Reducer, ReducerRegistry, ReducerInput } from "./reducers.js";
|
|
21
19
|
export { getKernel } from "./kernel.js";
|
|
22
20
|
export { ReplayProvider } from "./replay-provider.js";
|
|
23
21
|
export type { ReplayProviderOpts } from "./replay-provider.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -10,7 +10,6 @@ export { MemoryPayloadDriver, PayloadStore } from "./payload-store.js";
|
|
|
10
10
|
export { CanonicalKernelHost, CanonicalKernelRejectedError, CanonicalKernelRebuildRequiredError, CanonicalRunnerRuntime, sha256, } from "./canonical-kernel-step.js";
|
|
11
11
|
export { runAgent, runFanout } from "./facade.js";
|
|
12
12
|
export { McpExecutionPlane } from "./mcp-transport.js";
|
|
13
|
-
export { builtinReducers, resolveReducer } from "./reducers.js";
|
|
14
13
|
export { getKernel } from "./kernel.js";
|
|
15
14
|
export { ReplayProvider } from "./replay-provider.js";
|
|
16
15
|
export { extractRecordedMessages } from "./replay-fixture.js";
|
|
@@ -6,6 +6,14 @@ export declare function categoryForKind(kind: string): KernelEventCategory;
|
|
|
6
6
|
type CompressionAction = Extract<SessionEvent, {
|
|
7
7
|
kind: "compressed";
|
|
8
8
|
}>["action"];
|
|
9
|
+
/** The kernel's pressure actions that name a session-level compression action; any other
|
|
10
|
+
* action (e.g. `none`) is omitted from the event. Shared rule across all four SDKs. */
|
|
11
|
+
export declare function canonicalCompressionAction(action?: string): CompressionAction;
|
|
12
|
+
/**
|
|
13
|
+
* Project one kernel observation onto its session event (null = not persisted). Pinned across
|
|
14
|
+
* SDKs by the `kernel_observation_projection` conformance fixture: an absent optional field is
|
|
15
|
+
* omitted, never written as `null`.
|
|
16
|
+
*/
|
|
9
17
|
export declare function kernelObservationToSessionEvent(obs: KernelObservation, turn: number, opts?: {
|
|
10
18
|
nextArchiveStart?: number;
|
|
11
19
|
latestSeq?: number;
|