@sema-agent/core 5.60.1 → 5.62.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 +125 -0
- package/dist/agents/subagent.d.ts +4 -2
- package/dist/agents/subagent.js +9 -9
- 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-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/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +4 -2
- package/dist/core/hooks.d.ts +83 -4
- package/dist/core/hooks.js +3 -3
- package/dist/core/memory-engine/consolidation-driver.d.ts +19 -1
- package/dist/core/memory-engine/consolidation-driver.js +75 -3
- package/dist/core/memory-engine/consolidation.d.ts +52 -5
- package/dist/core/memory-engine/consolidation.js +3 -1
- package/dist/core/memory-engine/distiller.d.ts +89 -1
- package/dist/core/memory-engine/distiller.js +94 -5
- package/dist/core/memory-engine/engine.d.ts +8 -0
- package/dist/core/memory-engine/engine.js +51 -8
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- 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 +34 -0
- package/dist/core/runner/prepare-config-doors.js +55 -0
- package/dist/core/runner/prepare-task.d.ts +52 -10
- package/dist/core/runner/prepare-task.js +77 -42
- package/dist/core/runner/runtask.d.ts +7 -0
- package/dist/core/runner/runtask.js +254 -38
- 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/task-notification.d.ts +50 -23
- package/dist/core/task-notification.js +20 -4
- package/dist/core/tool-errors.d.ts +2 -1
- package/dist/core/tool-policy.d.ts +27 -0
- package/dist/core/types.d.ts +214 -31
- 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.d.ts +58 -2
- package/dist/engine/harness/agent-harness.js +115 -5
- package/dist/engine/loop/agent-loop.js +153 -15
- package/dist/engine/loop/types.d.ts +32 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/orchestration/run-workflow-tool.d.ts +9 -4
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow.d.ts +2 -2
- package/dist/prompt-assembly/event-registry.js +2 -0
- 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/monitor.d.ts +3 -3
- package/dist/tools/monitor.js +1 -1
- package/dist/tools/scheduler-tools.js +9 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +7 -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);
|
|
@@ -339,7 +394,7 @@ function publishCommittedSuspend(refs, token, gate, scope, remoteHandle, checkpo
|
|
|
339
394
|
function hasConversationContent(branch) {
|
|
340
395
|
return branch.some((e) => e.type === "message" || e.type === "custom_message" || e.type === "compaction");
|
|
341
396
|
}
|
|
342
|
-
function effectiveDelegationFacts(internals, seedIsDelegatedChild) {
|
|
397
|
+
export function effectiveDelegationFacts(internals, seedIsDelegatedChild) {
|
|
343
398
|
const isDelegatedChild = internals?.isDelegatedChild !== undefined ? internals.isDelegatedChild === true : seedIsDelegatedChild === true;
|
|
344
399
|
return { isDelegatedChild, isNonForkChild: isDelegatedChild && internals?.insideFork !== true };
|
|
345
400
|
}
|
|
@@ -475,20 +530,21 @@ const sanitizePreview = (node, depth = 0) => {
|
|
|
475
530
|
function resolveApprovalPreview(tools, toolName, args) {
|
|
476
531
|
const t = tools.find((x) => x.name === toolName || (x.aliases?.includes(toolName) ?? false));
|
|
477
532
|
if (t?.approvalPreview === undefined)
|
|
478
|
-
return
|
|
533
|
+
return {};
|
|
479
534
|
try {
|
|
480
535
|
const raw = t.approvalPreview(args);
|
|
481
536
|
if (raw === undefined)
|
|
482
|
-
return
|
|
537
|
+
return {};
|
|
483
538
|
const bytes = JSON.stringify(raw);
|
|
484
539
|
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
|
-
|
|
540
|
+
return { withheld: "unavailable" };
|
|
541
|
+
if (bytes.length > 16_384) {
|
|
542
|
+
return { preview: { truncated: true, note: `approval preview exceeded 16KiB (${bytes.length} chars serialized)` }, withheld: "oversize" };
|
|
543
|
+
}
|
|
544
|
+
return { preview: sanitizePreview(raw) };
|
|
489
545
|
}
|
|
490
546
|
catch {
|
|
491
|
-
return
|
|
547
|
+
return { withheld: "unavailable" };
|
|
492
548
|
}
|
|
493
549
|
}
|
|
494
550
|
function inheritedAskRuleEvidence(deps) {
|
|
@@ -839,7 +895,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
839
895
|
if (e.type === "task_progress")
|
|
840
896
|
forwardSink(e);
|
|
841
897
|
else if (spec.forwardSubagentEvents === true &&
|
|
842
|
-
(e.type === "text_delta" || e.type === "reasoning_delta" || e.type === "tool_start" || e.type === "tool_end")) {
|
|
898
|
+
(e.type === "text_delta" || e.type === "text_end" || e.type === "reasoning_delta" || e.type === "tool_start" || e.type === "tool_end")) {
|
|
843
899
|
forwardSink(e);
|
|
844
900
|
}
|
|
845
901
|
}
|
|
@@ -3140,6 +3196,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3140
3196
|
if (ask?.requiresRealApproval === true ||
|
|
3141
3197
|
ask?.persistedRuleShadowed !== undefined ||
|
|
3142
3198
|
ask?.decisionReason === "hook" ||
|
|
3199
|
+
ask?.matchedAskRule !== undefined ||
|
|
3143
3200
|
ask?.inheritedUnresolved === true ||
|
|
3144
3201
|
ask?.ancestorResolved === true) {
|
|
3145
3202
|
return {};
|
|
@@ -3550,31 +3607,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3550
3607
|
sessionId,
|
|
3551
3608
|
});
|
|
3552
3609
|
}
|
|
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
|
-
})();
|
|
3610
|
+
const usageGovernance = buildUsageGovernance(usageWindows, deps, spec.principal, sessionId);
|
|
3578
3611
|
const platformSuspendArmed = durableSuspendInfraReady && (envLifetimeSuspendAt !== undefined || usageGovernance !== undefined);
|
|
3579
3612
|
const checkpointStore = resolveCheckpointStore(spec, deps);
|
|
3580
3613
|
const durableApproval = spec.durableApproval ??
|
|
@@ -3667,8 +3700,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3667
3700
|
toolCallId: req.toolCallId,
|
|
3668
3701
|
args: req.args,
|
|
3669
3702
|
...(() => {
|
|
3670
|
-
const
|
|
3671
|
-
return preview !== undefined ? { preview } : {};
|
|
3703
|
+
const p = approvalPreviewOf(req.toolName, req.args);
|
|
3704
|
+
return { ...(p.preview !== undefined ? { preview: p.preview } : {}), ...(p.withheld !== undefined ? { previewWithheld: p.withheld } : {}) };
|
|
3672
3705
|
})(),
|
|
3673
3706
|
...ruleOffersOf(req.toolName, req.args, decision.action === "ask" ? decision : undefined),
|
|
3674
3707
|
message: decision.message ?? `approval required for "${req.toolName}"`,
|
|
@@ -4148,7 +4181,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4148
4181
|
}
|
|
4149
4182
|
};
|
|
4150
4183
|
const suspendAsk = parkLaneArmed && checkpointStore !== undefined
|
|
4151
|
-
? async (req, postHookArgs, safety, liveFaceUnavailable, realApproval, shadowedRule, askDecisionReason, probeReason, probeCause, segmentCoverage) => {
|
|
4184
|
+
? async (req, postHookArgs, safety, liveFaceUnavailable, realApproval, shadowedRule, askDecisionReason, probeReason, probeCause, segmentCoverage, matchedAskRule) => {
|
|
4152
4185
|
const syncFirstEligible = req.toolName === ASK_USER_QUESTION_TOOL_NAME ? contentAskRoutable(req.toolCallId) : isLiveApproverSeat(onAsk);
|
|
4153
4186
|
if (syncFirstEligible &&
|
|
4154
4187
|
runtimeCaps?.forceDurableGate !== true &&
|
|
@@ -4306,10 +4339,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4306
4339
|
toolName: req.toolName,
|
|
4307
4340
|
args: parkedArgs,
|
|
4308
4341
|
...(() => {
|
|
4309
|
-
const
|
|
4310
|
-
const bidi = carriesBidiControls(parkedArgs) || carriesBidiControls(preview);
|
|
4342
|
+
const p = approvalPreviewOf(req.toolName, parkedArgs);
|
|
4343
|
+
const bidi = carriesBidiControls(parkedArgs) || carriesBidiControls(p.preview);
|
|
4311
4344
|
return {
|
|
4312
|
-
...(preview !== undefined ? { preview } : {}),
|
|
4345
|
+
...(p.preview !== undefined ? { preview: p.preview } : {}),
|
|
4346
|
+
...(p.withheld !== undefined ? { previewWithheld: p.withheld } : {}),
|
|
4313
4347
|
...(bidi ? { hasBidiControls: true } : {}),
|
|
4314
4348
|
};
|
|
4315
4349
|
})(),
|
|
@@ -4317,6 +4351,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4317
4351
|
...(realApproval !== undefined ? { requiresRealApproval: true } : {}),
|
|
4318
4352
|
...(shadowedRule !== undefined ? { persistedRuleShadowed: shadowedRule } : {}),
|
|
4319
4353
|
...(askDecisionReason !== undefined ? { decisionReason: askDecisionReason } : {}),
|
|
4354
|
+
...(matchedAskRule !== undefined ? { matchedAskRule } : {}),
|
|
4320
4355
|
...(inheritedUnavailableAsks.has(req.toolCallId) ? { inheritedUnresolved: true } : {}),
|
|
4321
4356
|
...(segmentCoverage !== undefined ? { segmentCoverage } : {}),
|
|
4322
4357
|
}),
|
|
@@ -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
|