@sema-agent/core 5.61.0 → 5.63.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 +107 -0
- package/dist/agents/subagent.d.ts +12 -2
- package/dist/agents/subagent.js +3 -2
- package/dist/brain/open-responses.js +8 -3
- package/dist/brain/openai.js +4 -4
- package/dist/brain/stream-engine.d.ts +13 -2
- package/dist/brain/stream-engine.js +3 -3
- package/dist/core/auto-compaction.d.ts +6 -4
- package/dist/core/auto-compaction.js +3 -0
- package/dist/core/auto-mode-prompt-assets.js +1 -1
- package/dist/core/checkpoint-store.d.ts +36 -4
- package/dist/core/checkpoint-store.js +1 -0
- package/dist/core/context-edit.d.ts +36 -29
- package/dist/core/context-edit.js +3 -3
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +86 -4
- package/dist/core/hooks.js +3 -3
- package/dist/core/memory-engine/engine.d.ts +11 -0
- package/dist/core/memory-engine/engine.js +29 -3
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/origin-clearance.d.ts +28 -0
- package/dist/core/park-selfcheck.js +2 -0
- package/dist/core/pricing.d.ts +24 -0
- package/dist/core/pricing.js +18 -0
- package/dist/core/runner/prepare-config-doors.d.ts +36 -2
- package/dist/core/runner/prepare-config-doors.js +66 -8
- package/dist/core/runner/prepare-task.d.ts +113 -12
- package/dist/core/runner/prepare-task.js +239 -131
- package/dist/core/runner/runtask.d.ts +7 -0
- package/dist/core/runner/runtask.js +325 -95
- package/dist/core/runner/turn-attachments.d.ts +137 -5
- package/dist/core/runner/turn-attachments.js +25 -2
- package/dist/core/store-contracts/checkpoint-store-contract.js +19 -0
- package/dist/core/tool-errors.d.ts +2 -1
- package/dist/core/tool-policy.d.ts +27 -0
- package/dist/core/trace.d.ts +5 -4
- package/dist/core/types.d.ts +163 -29
- package/dist/core/untrusted-text.d.ts +5 -4
- package/dist/core/untrusted-text.js +8 -0
- package/dist/core/usage-window-store.d.ts +109 -8
- package/dist/core/usage-window-store.js +79 -12
- package/dist/engine/harness/agent-harness.js +20 -5
- package/dist/engine/harness/types.d.ts +38 -0
- package/dist/engine/loop/agent-loop.js +20 -1
- package/dist/engine/loop/types.d.ts +41 -1
- package/dist/index.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +2 -2
- package/dist/orchestration/workflow-types.d.ts +48 -1
- package/dist/orchestration/workflow-types.js +12 -4
- package/dist/orchestration/workflow.d.ts +14 -3
- package/dist/orchestration/workflow.js +44 -19
- package/dist/prompt-assembly/event-registry.js +2 -0
- package/dist/prompts/default.js +1 -1
- package/dist/server/http.d.ts +1 -1
- package/dist/stores/file/usage-window-store.d.ts +1 -1
- package/dist/stores/file/usage-window-store.js +27 -6
- package/dist/tools/loop-tick.js +1 -1
- package/dist/tools/scheduler-tools.js +9 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +3 -1
|
@@ -95,7 +95,7 @@ import { BINDING_CHECKPOINT_VERSION, mintCheckpointId, mintCheckpointToken, ORG_
|
|
|
95
95
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
96
96
|
import { countElicitOptIns, deriveWiringManifest, resolveAskSeamForm, resolveDeclaredDurability, resolveElicitSeam, resolveQuestionSeam, resolveSubagentTranscriptTier } from "../wiring-manifest.js";
|
|
97
97
|
import { durableParkGapFor } from "../park-selfcheck.js";
|
|
98
|
-
import { GLOBAL_USAGE_KEY, usageRetryAfterMs } from "../usage-window-store.js";
|
|
98
|
+
import { GLOBAL_USAGE_KEY, usageRetryAfterMs, windowsGovernCost } from "../usage-window-store.js";
|
|
99
99
|
import { deliverEngineNotice } from "../types.js";
|
|
100
100
|
let announcedMaterializeEnvBySink = new WeakMap();
|
|
101
101
|
const announcedMaterializeEnvConsole = new Set();
|
|
@@ -228,6 +228,61 @@ const ULTRA_REASONING_TIERS = new Set(["xhigh", "max"]);
|
|
|
228
228
|
const DEFAULT_RESOURCE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
229
229
|
export const ENV_LIFETIME_SUSPEND_MARGIN_MS = 60_000;
|
|
230
230
|
export const USAGE_WINDOW_REAP_MARGIN_MS = 60 * 60 * 1000;
|
|
231
|
+
function buildUsageGovernance(windows, deps, principal, sessionId) {
|
|
232
|
+
if (windows === undefined || windows.length === 0)
|
|
233
|
+
return undefined;
|
|
234
|
+
const store = deps.usageWindowStore;
|
|
235
|
+
if (store === undefined) {
|
|
236
|
+
deps.onError?.(new Error("RunnerDeps.usageWindows is set but INACTIVE: no `usageWindowStore` is wired, so cross-task usage cannot be counted and no window can be enforced. Wire InMemoryUsageWindowStore (process-local) or FileUsageWindowStore (restart-surviving)."), { phase: "config", sessionId });
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
const key = principal || GLOBAL_USAGE_KEY;
|
|
240
|
+
const governsCost = windowsGovernCost(windows);
|
|
241
|
+
let chargedTokens = 0;
|
|
242
|
+
let chargedCostMicroUsd = 0;
|
|
243
|
+
let announcedCostGap = false;
|
|
244
|
+
let recordedUnpricedGap = false;
|
|
245
|
+
return {
|
|
246
|
+
key,
|
|
247
|
+
governsCost,
|
|
248
|
+
async check(now) {
|
|
249
|
+
const readings = await store.read(key, windows, now);
|
|
250
|
+
if (!announcedCostGap && readings.some((r) => r.costUnknown === true)) {
|
|
251
|
+
announcedCostGap = true;
|
|
252
|
+
deps.onError?.(new Error(`the usage window for ledger key ${JSON.stringify(key)} holds spend that nothing could price, so its maxCostUsd ceiling is being evaluated against a LOWER BOUND until that charge ages out of the window. Price every model this deployment can reach (including degrade targets and the compaction model).`), { phase: "config", sessionId });
|
|
253
|
+
}
|
|
254
|
+
return usageRetryAfterMs(readings, windows);
|
|
255
|
+
},
|
|
256
|
+
async commit(cumulativeTokens, cumulativeCostMicroUsd, now) {
|
|
257
|
+
if (!governsCost) {
|
|
258
|
+
const delta = cumulativeTokens - chargedTokens;
|
|
259
|
+
if (delta <= 0)
|
|
260
|
+
return;
|
|
261
|
+
await store.charge(key, delta, now, windows);
|
|
262
|
+
chargedTokens = cumulativeTokens;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (cumulativeCostMicroUsd === undefined) {
|
|
266
|
+
const tokenDelta = cumulativeTokens - chargedTokens;
|
|
267
|
+
if (tokenDelta > 0 || !recordedUnpricedGap) {
|
|
268
|
+
await store.charge(key, Math.max(0, tokenDelta), now, windows, null);
|
|
269
|
+
chargedTokens = Math.max(chargedTokens, cumulativeTokens);
|
|
270
|
+
recordedUnpricedGap = true;
|
|
271
|
+
}
|
|
272
|
+
const e = new Error("a deployment usage window declares maxCostUsd, but this run's spend has NO cost figure (RB-368 unpriced: a model served without a RunnerDeps.pricing entry or a Model.cost declaration). Refused rather than charged a fabricated 0 — the money ceiling would have silently stopped applying. Price every model this run can reach, or drop maxCostUsd from the window.");
|
|
273
|
+
e.code = "config.usage_window_unpriced";
|
|
274
|
+
throw e;
|
|
275
|
+
}
|
|
276
|
+
const tokenDelta = cumulativeTokens - chargedTokens;
|
|
277
|
+
const costDelta = cumulativeCostMicroUsd - chargedCostMicroUsd;
|
|
278
|
+
if (tokenDelta <= 0 && costDelta <= 0)
|
|
279
|
+
return;
|
|
280
|
+
await store.charge(key, Math.max(0, tokenDelta), now, windows, Math.max(0, costDelta));
|
|
281
|
+
chargedTokens = cumulativeTokens;
|
|
282
|
+
chargedCostMicroUsd = cumulativeCostMicroUsd;
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
231
286
|
export function resolveEnvLifetimeExpiry(env, observedAt) {
|
|
232
287
|
const lifetimeMs = env.lifetimeMs;
|
|
233
288
|
if (lifetimeMs === undefined)
|
|
@@ -267,7 +322,7 @@ class ParkRefusal extends Error {
|
|
|
267
322
|
}
|
|
268
323
|
}
|
|
269
324
|
export { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
270
|
-
export { isFableFamilyModelId, resolveModelPromptTraits, resolveTaskLimits } from "./prepare-config-doors.js";
|
|
325
|
+
export { isFableFamilyModelId, resolveAttachmentsConfig, resolveModelPromptTraits, resolveTaskLimits } from "./prepare-config-doors.js";
|
|
271
326
|
export { rebaseWorkspacePath, rebaseWorkspacePathAcross } from "./prepare-workspace-restore.js";
|
|
272
327
|
function buildMicroCompactState(deps, model, sessionId, offloadStore, knob) {
|
|
273
328
|
const triggerWindow = resolveTriggerWindow(model);
|
|
@@ -290,6 +345,7 @@ function buildMicroCompactState(deps, model, sessionId, offloadStore, knob) {
|
|
|
290
345
|
clearOnRejection: knob.clearOnRejection,
|
|
291
346
|
ledger: createClearedProjectionLedger(),
|
|
292
347
|
projectionRef: {},
|
|
348
|
+
inTurnCompactionRef: {},
|
|
293
349
|
...(offloadStore ? { offloadPersist: createOffloadPersist(offloadStore, sessionId, deps.onNotice) } : {}),
|
|
294
350
|
};
|
|
295
351
|
}
|
|
@@ -308,10 +364,75 @@ function recordFrontierClears(args) {
|
|
|
308
364
|
taskId: args.taskId,
|
|
309
365
|
clearedCount: args.pass.clears.length,
|
|
310
366
|
tokensSavedEstimate: args.pass.tokensSavedEstimate,
|
|
311
|
-
trigger:
|
|
367
|
+
trigger: args.trigger,
|
|
312
368
|
ts: Date.now(),
|
|
313
369
|
}));
|
|
314
370
|
}
|
|
371
|
+
function flushProjectionObservations(pending) {
|
|
372
|
+
for (const fire of pending.splice(0)) {
|
|
373
|
+
try {
|
|
374
|
+
fire();
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
export async function runGuardChain(args) {
|
|
381
|
+
const { edited, microCompact, guardAt, charsPerToken, deps, taskId } = args;
|
|
382
|
+
const applyGuardTrim = (view, anchoredTotal) => {
|
|
383
|
+
let trimmed = trimToBudget(view, guardAt, anchoredTotal, charsPerToken);
|
|
384
|
+
const dropped = trimmed.length < view.length;
|
|
385
|
+
if (dropped) {
|
|
386
|
+
args.trimPressureRef.droppedMessages = true;
|
|
387
|
+
const droppedCount = view.length - trimmed.length;
|
|
388
|
+
trimmed = insertTrimNotice(trimmed);
|
|
389
|
+
emitTrace(deps.tracer, () => ({
|
|
390
|
+
kind: "context.trim",
|
|
391
|
+
version: 1,
|
|
392
|
+
taskId,
|
|
393
|
+
dropped: droppedCount,
|
|
394
|
+
ts: Date.now(),
|
|
395
|
+
}));
|
|
396
|
+
}
|
|
397
|
+
return { trimmed, dropped };
|
|
398
|
+
};
|
|
399
|
+
let working = edited;
|
|
400
|
+
let anchoredWorking = estimateContextTokens(working, charsPerToken).tokens;
|
|
401
|
+
if (microCompact.machine === "legacy") {
|
|
402
|
+
const t = applyGuardTrim(working, anchoredWorking);
|
|
403
|
+
return { working, trimmed: t.trimmed, trimDroppedMessages: t.dropped };
|
|
404
|
+
}
|
|
405
|
+
if (microCompact.machine === "off" && anchoredWorking > guardAt) {
|
|
406
|
+
let blockingPass;
|
|
407
|
+
const blockingEdited = clearStaleToolResults(working, {
|
|
408
|
+
budgetTokens: guardAt,
|
|
409
|
+
machine: "cc",
|
|
410
|
+
clearSource: args.replayed,
|
|
411
|
+
onCleared: (pass) => { blockingPass = pass; },
|
|
412
|
+
anchoredTotalTokens: anchoredWorking,
|
|
413
|
+
charsPerToken,
|
|
414
|
+
...(args.offloadStore ? { offload: { persist: createOffloadPersist(args.offloadStore, args.sessionId, deps.onNotice) } } : {}),
|
|
415
|
+
});
|
|
416
|
+
if (blockingPass !== undefined) {
|
|
417
|
+
recordFrontierClears({ pass: blockingPass, index: args.index, edited: blockingEdited, ledger: microCompact.ledger, tracer: deps.tracer, taskId, trigger: "blocking" });
|
|
418
|
+
working = blockingEdited;
|
|
419
|
+
anchoredWorking = estimateContextTokens(working, charsPerToken).tokens;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (anchoredWorking > guardAt && args.recheck !== true) {
|
|
423
|
+
const compacted = (await microCompact.inTurnCompactionRef.current?.(args.signal, anchoredWorking)) === true;
|
|
424
|
+
if (compacted) {
|
|
425
|
+
args.pendingProjectionObservations.length = 0;
|
|
426
|
+
return { earlyReturn: { messages: working, adoptSessionRebuild: true } };
|
|
427
|
+
}
|
|
428
|
+
if (args.signal?.aborted === true) {
|
|
429
|
+
args.pendingProjectionObservations.length = 0;
|
|
430
|
+
return { working, trimmed: working, trimDroppedMessages: false };
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const t = applyGuardTrim(working, anchoredWorking);
|
|
434
|
+
return { working, trimmed: t.trimmed, trimDroppedMessages: t.dropped };
|
|
435
|
+
}
|
|
315
436
|
export function gatedCallIdOf(p) {
|
|
316
437
|
if (p.suspendRef.token !== undefined)
|
|
317
438
|
return p.suspendRef.gatedCallId;
|
|
@@ -339,7 +460,7 @@ function publishCommittedSuspend(refs, token, gate, scope, remoteHandle, checkpo
|
|
|
339
460
|
function hasConversationContent(branch) {
|
|
340
461
|
return branch.some((e) => e.type === "message" || e.type === "custom_message" || e.type === "compaction");
|
|
341
462
|
}
|
|
342
|
-
function effectiveDelegationFacts(internals, seedIsDelegatedChild) {
|
|
463
|
+
export function effectiveDelegationFacts(internals, seedIsDelegatedChild) {
|
|
343
464
|
const isDelegatedChild = internals?.isDelegatedChild !== undefined ? internals.isDelegatedChild === true : seedIsDelegatedChild === true;
|
|
344
465
|
return { isDelegatedChild, isNonForkChild: isDelegatedChild && internals?.insideFork !== true };
|
|
345
466
|
}
|
|
@@ -475,20 +596,21 @@ const sanitizePreview = (node, depth = 0) => {
|
|
|
475
596
|
function resolveApprovalPreview(tools, toolName, args) {
|
|
476
597
|
const t = tools.find((x) => x.name === toolName || (x.aliases?.includes(toolName) ?? false));
|
|
477
598
|
if (t?.approvalPreview === undefined)
|
|
478
|
-
return
|
|
599
|
+
return {};
|
|
479
600
|
try {
|
|
480
601
|
const raw = t.approvalPreview(args);
|
|
481
602
|
if (raw === undefined)
|
|
482
|
-
return
|
|
603
|
+
return {};
|
|
483
604
|
const bytes = JSON.stringify(raw);
|
|
484
605
|
if (bytes === undefined)
|
|
485
|
-
return
|
|
486
|
-
if (bytes.length > 16_384)
|
|
487
|
-
return { truncated: true, note: `approval preview exceeded 16KiB (${bytes.length} chars serialized)` };
|
|
488
|
-
|
|
606
|
+
return { withheld: "unavailable" };
|
|
607
|
+
if (bytes.length > 16_384) {
|
|
608
|
+
return { preview: { truncated: true, note: `approval preview exceeded 16KiB (${bytes.length} chars serialized)` }, withheld: "oversize" };
|
|
609
|
+
}
|
|
610
|
+
return { preview: sanitizePreview(raw) };
|
|
489
611
|
}
|
|
490
612
|
catch {
|
|
491
|
-
return
|
|
613
|
+
return { withheld: "unavailable" };
|
|
492
614
|
}
|
|
493
615
|
}
|
|
494
616
|
function inheritedAskRuleEvidence(deps) {
|
|
@@ -839,7 +961,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
839
961
|
if (e.type === "task_progress")
|
|
840
962
|
forwardSink(e);
|
|
841
963
|
else if (spec.forwardSubagentEvents === true &&
|
|
842
|
-
(e.type === "text_delta" || e.type === "reasoning_delta" || e.type === "tool_start" || e.type === "tool_end")) {
|
|
964
|
+
(e.type === "text_delta" || e.type === "text_end" || e.type === "reasoning_delta" || e.type === "tool_start" || e.type === "tool_end")) {
|
|
843
965
|
forwardSink(e);
|
|
844
966
|
}
|
|
845
967
|
}
|
|
@@ -3140,6 +3262,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3140
3262
|
if (ask?.requiresRealApproval === true ||
|
|
3141
3263
|
ask?.persistedRuleShadowed !== undefined ||
|
|
3142
3264
|
ask?.decisionReason === "hook" ||
|
|
3265
|
+
ask?.matchedAskRule !== undefined ||
|
|
3143
3266
|
ask?.inheritedUnresolved === true ||
|
|
3144
3267
|
ask?.ancestorResolved === true) {
|
|
3145
3268
|
return {};
|
|
@@ -3550,31 +3673,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3550
3673
|
sessionId,
|
|
3551
3674
|
});
|
|
3552
3675
|
}
|
|
3553
|
-
const usageGovernance = (
|
|
3554
|
-
if (usageWindows === undefined || usageWindows.length === 0)
|
|
3555
|
-
return undefined;
|
|
3556
|
-
const store = deps.usageWindowStore;
|
|
3557
|
-
if (store === undefined) {
|
|
3558
|
-
deps.onError?.(new Error("RunnerDeps.usageWindows is set but INACTIVE: no `usageWindowStore` is wired, so cross-task usage cannot be counted and no window can be enforced. Wire InMemoryUsageWindowStore (process-local) or FileUsageWindowStore (restart-surviving)."), { phase: "config", sessionId });
|
|
3559
|
-
return undefined;
|
|
3560
|
-
}
|
|
3561
|
-
const key = spec.principal || GLOBAL_USAGE_KEY;
|
|
3562
|
-
const windows = usageWindows;
|
|
3563
|
-
let charged = 0;
|
|
3564
|
-
return {
|
|
3565
|
-
key,
|
|
3566
|
-
async check(now) {
|
|
3567
|
-
return usageRetryAfterMs(await store.read(key, windows, now));
|
|
3568
|
-
},
|
|
3569
|
-
async commit(cumulativeTokens, now) {
|
|
3570
|
-
const delta = cumulativeTokens - charged;
|
|
3571
|
-
if (delta <= 0)
|
|
3572
|
-
return;
|
|
3573
|
-
await store.charge(key, delta, now, windows);
|
|
3574
|
-
charged = cumulativeTokens;
|
|
3575
|
-
},
|
|
3576
|
-
};
|
|
3577
|
-
})();
|
|
3676
|
+
const usageGovernance = buildUsageGovernance(usageWindows, deps, spec.principal, sessionId);
|
|
3578
3677
|
const platformSuspendArmed = durableSuspendInfraReady && (envLifetimeSuspendAt !== undefined || usageGovernance !== undefined);
|
|
3579
3678
|
const checkpointStore = resolveCheckpointStore(spec, deps);
|
|
3580
3679
|
const durableApproval = spec.durableApproval ??
|
|
@@ -3667,8 +3766,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3667
3766
|
toolCallId: req.toolCallId,
|
|
3668
3767
|
args: req.args,
|
|
3669
3768
|
...(() => {
|
|
3670
|
-
const
|
|
3671
|
-
return preview !== undefined ? { preview } : {};
|
|
3769
|
+
const p = approvalPreviewOf(req.toolName, req.args);
|
|
3770
|
+
return { ...(p.preview !== undefined ? { preview: p.preview } : {}), ...(p.withheld !== undefined ? { previewWithheld: p.withheld } : {}) };
|
|
3672
3771
|
})(),
|
|
3673
3772
|
...ruleOffersOf(req.toolName, req.args, decision.action === "ask" ? decision : undefined),
|
|
3674
3773
|
message: decision.message ?? `approval required for "${req.toolName}"`,
|
|
@@ -4148,7 +4247,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4148
4247
|
}
|
|
4149
4248
|
};
|
|
4150
4249
|
const suspendAsk = parkLaneArmed && checkpointStore !== undefined
|
|
4151
|
-
? async (req, postHookArgs, safety, liveFaceUnavailable, realApproval, shadowedRule, askDecisionReason, probeReason, probeCause, segmentCoverage) => {
|
|
4250
|
+
? async (req, postHookArgs, safety, liveFaceUnavailable, realApproval, shadowedRule, askDecisionReason, probeReason, probeCause, segmentCoverage, matchedAskRule) => {
|
|
4152
4251
|
const syncFirstEligible = req.toolName === ASK_USER_QUESTION_TOOL_NAME ? contentAskRoutable(req.toolCallId) : isLiveApproverSeat(onAsk);
|
|
4153
4252
|
if (syncFirstEligible &&
|
|
4154
4253
|
runtimeCaps?.forceDurableGate !== true &&
|
|
@@ -4306,10 +4405,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4306
4405
|
toolName: req.toolName,
|
|
4307
4406
|
args: parkedArgs,
|
|
4308
4407
|
...(() => {
|
|
4309
|
-
const
|
|
4310
|
-
const bidi = carriesBidiControls(parkedArgs) || carriesBidiControls(preview);
|
|
4408
|
+
const p = approvalPreviewOf(req.toolName, parkedArgs);
|
|
4409
|
+
const bidi = carriesBidiControls(parkedArgs) || carriesBidiControls(p.preview);
|
|
4311
4410
|
return {
|
|
4312
|
-
...(preview !== undefined ? { preview } : {}),
|
|
4411
|
+
...(p.preview !== undefined ? { preview: p.preview } : {}),
|
|
4412
|
+
...(p.withheld !== undefined ? { previewWithheld: p.withheld } : {}),
|
|
4313
4413
|
...(bidi ? { hasBidiControls: true } : {}),
|
|
4314
4414
|
};
|
|
4315
4415
|
})(),
|
|
@@ -4317,6 +4417,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4317
4417
|
...(realApproval !== undefined ? { requiresRealApproval: true } : {}),
|
|
4318
4418
|
...(shadowedRule !== undefined ? { persistedRuleShadowed: shadowedRule } : {}),
|
|
4319
4419
|
...(askDecisionReason !== undefined ? { decisionReason: askDecisionReason } : {}),
|
|
4420
|
+
...(matchedAskRule !== undefined ? { matchedAskRule } : {}),
|
|
4320
4421
|
...(inheritedUnavailableAsks.has(req.toolCallId) ? { inheritedUnresolved: true } : {}),
|
|
4321
4422
|
...(segmentCoverage !== undefined ? { segmentCoverage } : {}),
|
|
4322
4423
|
}),
|
|
@@ -4586,101 +4687,108 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4586
4687
|
const guardAt = guardBudget(model);
|
|
4587
4688
|
const microCompact = buildMicroCompactState(deps, model, sessionId, offloadStore, microCompactKnob);
|
|
4588
4689
|
const charsPerToken = model.charsPerToken ?? DEFAULT_CHARS_PER_TOKEN;
|
|
4589
|
-
harness.on("context", async ({ messages }) => {
|
|
4690
|
+
harness.on("context", async ({ messages, recheck, signal }) => {
|
|
4590
4691
|
batchHaltRef.current = undefined;
|
|
4591
|
-
const
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
: {}),
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
trimmed
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4692
|
+
const pendingProjectionObservations = [];
|
|
4693
|
+
try {
|
|
4694
|
+
const healed = dropEmptyFailureAssistants(messages);
|
|
4695
|
+
const replay = replayClearedProjection(healed, microCompact.ledger);
|
|
4696
|
+
const replayed = replay.messages;
|
|
4697
|
+
const capped = await capAggregateToolResults(replayed, {
|
|
4698
|
+
store: offloadStore,
|
|
4699
|
+
sessionId,
|
|
4700
|
+
onCapped: (info) => pendingProjectionObservations.push(() => emitTrace(deps.tracer, () => ({
|
|
4701
|
+
kind: "tool_result.capped",
|
|
4702
|
+
version: 1,
|
|
4703
|
+
taskId: spec.taskId ?? sessionId,
|
|
4704
|
+
...(info.tool !== undefined ? { tool: info.tool } : {}),
|
|
4705
|
+
sizeChars: info.sizeChars,
|
|
4706
|
+
storeFallback: info.storeFallback,
|
|
4707
|
+
ts: Date.now(),
|
|
4708
|
+
}))),
|
|
4709
|
+
});
|
|
4710
|
+
const mediaCapped = capAggregateMediaBytes(capped, {
|
|
4711
|
+
limitBytes: deps.mediaByteCapBytes ?? AGGREGATE_MEDIA_BUDGET_BYTES,
|
|
4712
|
+
onStripped: (info) => {
|
|
4713
|
+
const onMediaStripped = deps.onMediaStripped;
|
|
4714
|
+
if (onMediaStripped !== undefined)
|
|
4715
|
+
pendingProjectionObservations.push(() => onMediaStripped(info));
|
|
4716
|
+
},
|
|
4717
|
+
});
|
|
4718
|
+
let ccPass;
|
|
4719
|
+
const edited = microCompact.machine === "off" ? mediaCapped : clearStaleToolResults(mediaCapped, {
|
|
4720
|
+
budgetTokens: editAt,
|
|
4721
|
+
machine: microCompact.machine,
|
|
4722
|
+
...(microCompact.machine === "cc" || microCompact.clearOnRejection ? { recognizeCcMarkers: true } : {}),
|
|
4723
|
+
...(microCompact.machine === "cc"
|
|
4724
|
+
? {
|
|
4725
|
+
clearSource: replayed,
|
|
4726
|
+
onCleared: (pass) => { ccPass = pass; },
|
|
4727
|
+
}
|
|
4728
|
+
: {}),
|
|
4729
|
+
anchoredTotalTokens: estimateContextTokens(mediaCapped, charsPerToken).tokens,
|
|
4730
|
+
charsPerToken,
|
|
4731
|
+
...(offloadStore
|
|
4732
|
+
? {
|
|
4733
|
+
offload: {
|
|
4734
|
+
persist: createOffloadPersist(offloadStore, sessionId, deps.onNotice),
|
|
4735
|
+
},
|
|
4736
|
+
}
|
|
4737
|
+
: {}),
|
|
4738
|
+
});
|
|
4739
|
+
if (ccPass !== undefined) {
|
|
4740
|
+
recordFrontierClears({ pass: ccPass, index: replay.index, edited, ledger: microCompact.ledger, tracer: deps.tracer, taskId: spec.taskId ?? sessionId, trigger: "frontier" });
|
|
4741
|
+
}
|
|
4742
|
+
const chain = await runGuardChain({
|
|
4743
|
+
edited, replayed, index: replay.index, microCompact, guardAt, charsPerToken, offloadStore,
|
|
4744
|
+
sessionId, taskId: spec.taskId ?? sessionId, deps, trimPressureRef, recheck, signal,
|
|
4745
|
+
pendingProjectionObservations,
|
|
4746
|
+
});
|
|
4747
|
+
if ("earlyReturn" in chain) {
|
|
4748
|
+
return chain.earlyReturn;
|
|
4749
|
+
}
|
|
4750
|
+
const { working, trimDroppedMessages } = chain;
|
|
4751
|
+
let trimmed = chain.trimmed;
|
|
4752
|
+
trimmed = applyGitFrameGuard({
|
|
4753
|
+
before: working,
|
|
4754
|
+
trimmed,
|
|
4755
|
+
budgetTokens: guardAt,
|
|
4756
|
+
ref: gitStatusRef,
|
|
4757
|
+
charsPerToken,
|
|
4758
|
+
onDegrade: (message) => {
|
|
4759
|
+
try {
|
|
4760
|
+
deps.onError?.(new Error(message), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
|
|
4761
|
+
}
|
|
4762
|
+
catch {
|
|
4763
|
+
}
|
|
4764
|
+
},
|
|
4765
|
+
});
|
|
4766
|
+
const swept = dropOrphanToolResults(trimmed);
|
|
4767
|
+
if (swept.dropped.length > 0) {
|
|
4656
4768
|
try {
|
|
4657
|
-
deps.onError?.(new Error(
|
|
4769
|
+
deps.onError?.(new Error(`context belt: dropped ${swept.dropped.length} orphan toolResult(s) whose tool-call assistant was not in the request view — ` +
|
|
4770
|
+
swept.dropped
|
|
4771
|
+
.map((d) => `toolCallId=${d.toolCallId} at index ${d.index} (prev=${d.prevRole}, next=${d.nextRole})`)
|
|
4772
|
+
.join("; ")), { phase: "hook", sessionId });
|
|
4658
4773
|
}
|
|
4659
4774
|
catch {
|
|
4660
4775
|
}
|
|
4661
|
-
},
|
|
4662
|
-
});
|
|
4663
|
-
const swept = dropOrphanToolResults(trimmed);
|
|
4664
|
-
if (swept.dropped.length > 0) {
|
|
4665
|
-
try {
|
|
4666
|
-
deps.onError?.(new Error(`context belt: dropped ${swept.dropped.length} orphan toolResult(s) whose tool-call assistant was not in the request view — ` +
|
|
4667
|
-
swept.dropped
|
|
4668
|
-
.map((d) => `toolCallId=${d.toolCallId} at index ${d.index} (prev=${d.prevRole}, next=${d.nextRole})`)
|
|
4669
|
-
.join("; ")), { phase: "hook", sessionId });
|
|
4670
|
-
}
|
|
4671
|
-
catch {
|
|
4672
4776
|
}
|
|
4777
|
+
requestLossyRef.current =
|
|
4778
|
+
replayed !== healed ||
|
|
4779
|
+
capped !== replayed ||
|
|
4780
|
+
mediaCapped !== capped ||
|
|
4781
|
+
edited !== mediaCapped ||
|
|
4782
|
+
working !== edited ||
|
|
4783
|
+
trimDroppedMessages ||
|
|
4784
|
+
swept.dropped.length > 0 ||
|
|
4785
|
+
gitStatusRef.overBudgetShrunk === true;
|
|
4786
|
+
microCompact.projectionRef.current = { messages: swept.messages, keyOf: replay.index.keyOf };
|
|
4787
|
+
return { messages: swept.messages };
|
|
4788
|
+
}
|
|
4789
|
+
finally {
|
|
4790
|
+
flushProjectionObservations(pendingProjectionObservations);
|
|
4673
4791
|
}
|
|
4674
|
-
requestLossyRef.current =
|
|
4675
|
-
replayed !== healed ||
|
|
4676
|
-
capped !== replayed ||
|
|
4677
|
-
mediaCapped !== capped ||
|
|
4678
|
-
edited !== mediaCapped ||
|
|
4679
|
-
trimDroppedMessages ||
|
|
4680
|
-
swept.dropped.length > 0 ||
|
|
4681
|
-
gitStatusRef.overBudgetShrunk === true;
|
|
4682
|
-
microCompact.projectionRef.current = { messages: swept.messages, keyOf: replay.index.keyOf };
|
|
4683
|
-
return { messages: swept.messages };
|
|
4684
4792
|
});
|
|
4685
4793
|
const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
|
|
4686
4794
|
const cacheFingerprint = cacheBreakDetector
|
|
@@ -51,6 +51,13 @@ interface ResumeRun {
|
|
|
51
51
|
* wake message second), each under its own trusted framing — the old merge-into-the-slot shape
|
|
52
52
|
* silently DISPLACED the parked (undelivered) supervisor steer. Wake outcomes only. */
|
|
53
53
|
wakeMessage?: Omit<PendingSteerEntry, "seq">;
|
|
54
|
+
/** design/373 §4.3 (D2) — the userPromptSubmit screen's `additionalContext` for {@link wakeMessage},
|
|
55
|
+
* captured at the resume ENTRY (the message is screened once, pre-CAS, on the resuming process's
|
|
56
|
+
* hook) and delivered by the drain as the engine's own reminder AHEAD of the wake frame — carrying
|
|
57
|
+
* it forward is what keeps the hook single-run (re-screening at the drain would be the double-run
|
|
58
|
+
* §4.3-3 reserves for the cross-process parked leg). Present only when a wake message passed a
|
|
59
|
+
* screen that supplied context. */
|
|
60
|
+
wakeMessageHookContext?: string;
|
|
54
61
|
/** Compensation hook (design/45/49): called iff the resumed run fails with `resume.env_failed` (post-CAS
|
|
55
62
|
* workspace `resumeVM` failed) OR `resume.tool_unavailable` (P-7: the approved tool vanished) — in both
|
|
56
63
|
* the CAS already consumed the checkpoint but the pending action never ran. `resumeStream` supplies a
|