@sema-agent/core 5.12.0 → 5.13.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 +24 -0
- package/dist/agents/subagent.js +4 -2
- package/dist/core/checkpoint-store.d.ts +8 -1
- package/dist/core/checkpoint-store.js +3 -1
- package/dist/core/compliance.d.ts +11 -0
- package/dist/core/compliance.js +34 -0
- package/dist/core/governance-codes.d.ts +12 -0
- package/dist/core/governance-codes.js +24 -0
- package/dist/core/locked-config.d.ts +27 -0
- package/dist/core/locked-config.js +42 -0
- package/dist/core/memory-admission.d.ts +47 -0
- package/dist/core/memory-admission.js +156 -0
- package/dist/core/memory.d.ts +2 -0
- package/dist/core/memory.js +3 -2
- package/dist/core/retention.d.ts +36 -0
- package/dist/core/retention.js +31 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +9 -0
- package/dist/core/runner/prepare-memory.js +28 -2
- package/dist/core/runner/prepare-task.d.ts +2 -0
- package/dist/core/runner/prepare-task.js +130 -17
- package/dist/core/runner/runtask.js +72 -41
- package/dist/core/session-store.d.ts +1 -0
- package/dist/core/session-store.js +1 -0
- package/dist/core/tool-result-store.d.ts +2 -0
- package/dist/core/tool-result-store.js +1 -0
- package/dist/core/types.d.ts +6 -1
- package/dist/engine/harness/agent-harness.js +11 -1
- package/dist/engine/llm/validation.js +11 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { admitMemoryScopes } from "../memory-admission.js";
|
|
1
2
|
import { adoptLegacyRepoDirs, deriveRepoControlPlaneDir, deriveProjectControlDir, deriveProjectMemoryDir, deriveRepoMemoryDir, drainMemoryAnnouncements, enqueueMemoryAnnouncement, lookupProjectIdHint, recordProjectIdHint, resolveMemoryEngineRoot } from "../memory-engine/layout.js";
|
|
2
3
|
import { classifyScopePlanes, derivePersonalControlDir, derivePersonalMemoryDir, mergeHarvestReports, mergeInjections, needsDualRoots, parsedProjectPlane } from "../memory-engine/dual-root.js";
|
|
3
4
|
import { normalizeMemorySpec } from "../memory.js";
|
|
@@ -5,8 +6,33 @@ import { MemoryEngine } from "../memory-engine/engine.js";
|
|
|
5
6
|
import { assertScopeContractPlacement, parseScopeKey, resolveProjectId } from "../memory-engine/scope-contract.js";
|
|
6
7
|
import { FileMemoryEngineBackend } from "../memory-engine/file-backend.js";
|
|
7
8
|
export async function prepareMemory(input) {
|
|
8
|
-
const { spec, deps, sessionId, taskRootPath, memoryWriteGateRef } = input;
|
|
9
|
+
const { spec, deps, sessionId, taskRootPath, memoryWriteGateRef, admissionCtx } = input;
|
|
9
10
|
const memorySpec = normalizeMemorySpec(spec.memory);
|
|
11
|
+
let admittedOrgScopes = [];
|
|
12
|
+
let ownOrgVerdict;
|
|
13
|
+
if (memorySpec && memorySpec.enabled && deps.memoryBackend) {
|
|
14
|
+
const outcome = await admitMemoryScopes({
|
|
15
|
+
memorySpec,
|
|
16
|
+
principal: spec.principal,
|
|
17
|
+
admission: deps.memoryScopeAdmission,
|
|
18
|
+
deploymentScopes: new Set(deps.deploymentMemoryScopes ?? []),
|
|
19
|
+
orgMemoryDenied: admissionCtx.orgMemoryDenied,
|
|
20
|
+
complianceDegraded: admissionCtx.complianceDegraded,
|
|
21
|
+
parentAdmittedOrgScopes: admissionCtx.parentAdmittedOrgScopes,
|
|
22
|
+
priorOwnVerdict: admissionCtx.priorOwnVerdict,
|
|
23
|
+
governedProvenance: admissionCtx.governedProvenance,
|
|
24
|
+
});
|
|
25
|
+
admittedOrgScopes = outcome.admittedOrgScopes;
|
|
26
|
+
ownOrgVerdict = outcome.ownVerdict;
|
|
27
|
+
for (const droppedScope of outcome.droppedDeploymentScopes) {
|
|
28
|
+
deps.onError?.(new Error(`org memory scope "${droppedScope}" (deployment-declared) was narrowed away (admission resolver or the session's frozen verdict) — the layer is not mounted this session.`), { phase: "memory", sessionId });
|
|
29
|
+
}
|
|
30
|
+
if (outcome.writeScopeNarrowed) {
|
|
31
|
+
deps.onError?.(new Error(`org memory writeScope "${String(memorySpec.writeScope)}" was not explicitly granted by admission — the session's memory write face is read-only (org layers default read-only).`), { phase: "memory", sessionId });
|
|
32
|
+
}
|
|
33
|
+
memorySpec.scopes = outcome.scopes;
|
|
34
|
+
memorySpec.writeScope = outcome.writeScope;
|
|
35
|
+
}
|
|
10
36
|
const useMemoryEngine = Boolean(memorySpec && memorySpec.enabled && deps.memoryBackend);
|
|
11
37
|
let memoryEngineSession;
|
|
12
38
|
if (useMemoryEngine && memorySpec) {
|
|
@@ -193,5 +219,5 @@ export async function prepareMemory(input) {
|
|
|
193
219
|
if (memoryBlock !== undefined && injection.indexSeed !== undefined)
|
|
194
220
|
seedFiles = [injection.indexSeed];
|
|
195
221
|
}
|
|
196
|
-
return { memoryEngineSession, memoryBlock, ...(seedFiles !== undefined ? { seedFiles } : {}) };
|
|
222
|
+
return { memoryEngineSession, memoryBlock, admittedOrgScopes, ownOrgVerdict, ...(seedFiles !== undefined ? { seedFiles } : {}) };
|
|
197
223
|
}
|
|
@@ -304,6 +304,8 @@ export interface InheritedGate {
|
|
|
304
304
|
rules: SessionPermissionRules;
|
|
305
305
|
}>;
|
|
306
306
|
shellGate?: "off" | "always" | "classify";
|
|
307
|
+
admittedOrgScopes?: readonly string[];
|
|
308
|
+
orgAdmissionGoverned?: true;
|
|
307
309
|
parentConstraints?: ReadonlyArray<{
|
|
308
310
|
policy: ToolPolicy;
|
|
309
311
|
onAsk?: OnAsk;
|
|
@@ -38,6 +38,10 @@ import { OUTPUT_TOOL_NAME, REPORT_FINDINGS_TOOL_NAME, SKILL_CONTENT_MAX_CHARS, S
|
|
|
38
38
|
import { compileOutputSchema } from "./strict-output-schema.js";
|
|
39
39
|
import { TOOL_SEARCH_NAME, buildDeferredRegistry, classifyDeferred, extractDiscoveredToolNames, createPlaceholderTool, createToolSearchTool, } from "./tool-disclosure.js";
|
|
40
40
|
import { composeMemoryBlock } from "../memory.js";
|
|
41
|
+
import { preflightLockedConfig } from "../locked-config.js";
|
|
42
|
+
import { COMPLIANCE_CAPABILITIES, WEB_FETCH_TOOL_NAME, complianceCallDenial, resolveComplianceDenies } from "../compliance.js";
|
|
43
|
+
import { assertRetentionCapability } from "../retention.js";
|
|
44
|
+
import { foldAdmissionFreeze } from "../memory-admission.js";
|
|
41
45
|
import { prepareMemory } from "./prepare-memory.js";
|
|
42
46
|
import { defaultPromptProvider, buildEnvironmentContext, buildGitSnapshot, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
|
|
43
47
|
import { assemblePrompt } from "../../prompt-assembly/assemble.js";
|
|
@@ -69,7 +73,7 @@ import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-
|
|
|
69
73
|
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
70
74
|
import { resolveKey } from "../../tools/fs/safety.js";
|
|
71
75
|
import { wholeFileRecordsFromTranscript } from "./session-file-state-replay.js";
|
|
72
|
-
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, } from "../checkpoint-store.js";
|
|
76
|
+
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, } from "../checkpoint-store.js";
|
|
73
77
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
74
78
|
import { GLOBAL_USAGE_KEY, resolveUsageWindows, usageRetryAfterMs } from "../usage-window-store.js";
|
|
75
79
|
const RECONCILE_MAX_RETRIES = 3;
|
|
@@ -337,6 +341,16 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
337
341
|
e.code = "config.empty_objective";
|
|
338
342
|
throw e;
|
|
339
343
|
}
|
|
344
|
+
const lockedPreflight = preflightLockedConfig(spec, deps);
|
|
345
|
+
assertRetentionCapability({
|
|
346
|
+
policy: deps.retentionPolicy,
|
|
347
|
+
locked: lockedPreflight.lockedKeys.has("retentionPolicy"),
|
|
348
|
+
stores: [
|
|
349
|
+
{ name: "sessionStore", store: sessions },
|
|
350
|
+
{ name: "checkpointStore", store: resolveCheckpointStore(spec, deps) },
|
|
351
|
+
{ name: "toolResultStore", store: deps.toolResultStore },
|
|
352
|
+
],
|
|
353
|
+
});
|
|
340
354
|
resolveTaskLimits(spec.limits);
|
|
341
355
|
if (spec.resourceSuspend !== undefined) {
|
|
342
356
|
const rsus = spec.resourceSuspend;
|
|
@@ -940,9 +954,24 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
940
954
|
? liveShellGate
|
|
941
955
|
: seedShellGate;
|
|
942
956
|
const inheritedParentConstraints = liveInheritedGate?.parentConstraints;
|
|
957
|
+
const liveAdmittedOrg = liveInheritedGate?.admittedOrgScopes;
|
|
958
|
+
const seedAdmittedOrg = seedInheritedGate?.admittedOrgScopes;
|
|
959
|
+
const inheritedAdmittedOrgScopes = liveAdmittedOrg === undefined ? seedAdmittedOrg : seedAdmittedOrg === undefined ? liveAdmittedOrg : liveAdmittedOrg.filter((s) => seedAdmittedOrg.includes(s));
|
|
960
|
+
const inheritedOrgGoverned = liveInheritedGate?.orgAdmissionGoverned === true || seedInheritedGate?.orgAdmissionGoverned === true;
|
|
961
|
+
const priorOwnOrgVerdict = resume?.seed.inheritedGate?.ownAdmittedOrgScopes !== undefined
|
|
962
|
+
? { scopes: resume.seed.inheritedGate.ownAdmittedOrgScopes, writeScope: resume.seed.inheritedGate.ownAdmittedOrgWriteScope ?? null }
|
|
963
|
+
: undefined;
|
|
964
|
+
const orgGovernedProvenance = deps.memoryScopeAdmission !== undefined ||
|
|
965
|
+
(deps.deploymentMemoryScopes !== undefined && deps.deploymentMemoryScopes.length > 0) ||
|
|
966
|
+
deps.compliancePostureResolver !== undefined ||
|
|
967
|
+
inheritedOrgGoverned ||
|
|
968
|
+
priorOwnOrgVerdict !== undefined;
|
|
943
969
|
const specShellGate = spec.shellGate ?? "off";
|
|
944
970
|
const effectiveShellGate = inheritedShellGate !== undefined && shellGateRank[inheritedShellGate] > shellGateRank[specShellGate] ? inheritedShellGate : specShellGate;
|
|
945
971
|
const ownSessionRulesRef = {};
|
|
972
|
+
const memoryAdmittedOrgScopesRef = { current: [] };
|
|
973
|
+
const ownOrgVerdictRef = { current: undefined };
|
|
974
|
+
const orgAdmissionCheckpointState = () => inheritedAdmittedOrgScopes !== undefined || ownOrgVerdictRef.current !== undefined || orgGovernedProvenance;
|
|
946
975
|
const frozenOnAsk = spec.onAsk ?? deps.onAsk;
|
|
947
976
|
const frozenOnQuestion = spec.onQuestion ?? deps.onQuestion;
|
|
948
977
|
const inheritedGateForChildren = () => {
|
|
@@ -950,7 +979,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
950
979
|
...(inheritedAncestorRules ?? []),
|
|
951
980
|
...(ownSessionRulesRef.current !== undefined ? [ownSessionRulesRef.current] : []),
|
|
952
981
|
];
|
|
953
|
-
const ownCallerPolicy =
|
|
982
|
+
const ownCallerPolicy = lockedPreflight.toolPolicy;
|
|
954
983
|
const durableMandate = runtimeCaps?.forceDurableGate === true || (spec.durableApproval !== undefined && frozenOnAsk === undefined);
|
|
955
984
|
const parentConstraints = [
|
|
956
985
|
...(inheritedParentConstraints ?? []),
|
|
@@ -968,6 +997,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
968
997
|
...(ancestorRules.length > 0 ? { ancestorRules } : {}),
|
|
969
998
|
...(effectiveShellGate !== "off" ? { shellGate: effectiveShellGate } : {}),
|
|
970
999
|
...(parentConstraints.length > 0 ? { parentConstraints } : {}),
|
|
1000
|
+
admittedOrgScopes: memoryAdmittedOrgScopesRef.current,
|
|
1001
|
+
...(orgGovernedProvenance ? { orgAdmissionGoverned: true } : {}),
|
|
971
1002
|
};
|
|
972
1003
|
};
|
|
973
1004
|
let agentForkDenial;
|
|
@@ -1072,6 +1103,39 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1072
1103
|
runtimeCaps = { allowWorkflows: false, allowFork: false };
|
|
1073
1104
|
}
|
|
1074
1105
|
}
|
|
1106
|
+
let complianceDenies = new Set();
|
|
1107
|
+
let complianceDegraded = false;
|
|
1108
|
+
if (deps.compliancePostureResolver) {
|
|
1109
|
+
try {
|
|
1110
|
+
const posture = (await deps.compliancePostureResolver(spec.principal)) ?? undefined;
|
|
1111
|
+
if (posture !== undefined)
|
|
1112
|
+
complianceDenies = resolveComplianceDenies(posture);
|
|
1113
|
+
}
|
|
1114
|
+
catch (err) {
|
|
1115
|
+
deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
|
|
1116
|
+
complianceDenies = new Set(COMPLIANCE_CAPABILITIES);
|
|
1117
|
+
complianceDegraded = true;
|
|
1118
|
+
}
|
|
1119
|
+
const complianceRefuse = (capability, requested) => {
|
|
1120
|
+
const e = new Error(`${requested} is denied for this principal by the compliance posture (capability "${capability}"` +
|
|
1121
|
+
`${complianceDegraded ? "; the posture resolver is currently failing, so every managed capability is denied fail-closed" : ""}) — ` +
|
|
1122
|
+
`the task is refused rather than silently narrowed.`);
|
|
1123
|
+
e.code = complianceDegraded ? "config.compliance_required" : "config.compliance_denied";
|
|
1124
|
+
throw e;
|
|
1125
|
+
};
|
|
1126
|
+
if (complianceDenies.has("mcp_servers") && lockedPreflight.mcp?.length) {
|
|
1127
|
+
complianceRefuse("mcp_servers", "TaskSpec.mcp (MCP server materialization)");
|
|
1128
|
+
}
|
|
1129
|
+
if (complianceDenies.has("workflows") && spec.selfOrchestration === true) {
|
|
1130
|
+
complianceRefuse("workflows", "TaskSpec.selfOrchestration (workflow self-orchestration)");
|
|
1131
|
+
}
|
|
1132
|
+
if (complianceDenies.has("web_fetch")) {
|
|
1133
|
+
const webTool = (spec.tools ?? []).find((t) => t.name === WEB_FETCH_TOOL_NAME || (t.aliases ?? []).includes(WEB_FETCH_TOOL_NAME));
|
|
1134
|
+
if (webTool !== undefined) {
|
|
1135
|
+
complianceRefuse("web_fetch", `TaskSpec.tools["${webTool.name}"] (the WebFetch tool face)`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1075
1139
|
agentForkDenial = forkGovernanceDenial(spec.enableFork, runtimeCaps?.allowFork);
|
|
1076
1140
|
observersActive = runtimeCaps?.allowObservers === true;
|
|
1077
1141
|
if (runtimeCaps?.autoMode === true && deps.autoMode !== undefined) {
|
|
@@ -1220,8 +1284,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1220
1284
|
}
|
|
1221
1285
|
tools.push(createOutputTool(outputRef, spec.outputSchema, compiled.strict ? compiled.modelSchema : undefined));
|
|
1222
1286
|
}
|
|
1223
|
-
mcp =
|
|
1224
|
-
? await materializeMcpTools(
|
|
1287
|
+
mcp = lockedPreflight.mcp?.length
|
|
1288
|
+
? await materializeMcpTools(lockedPreflight.mcp, spec.principal, deps.onElicit, deps.mcpImageResizer)
|
|
1225
1289
|
: { tools: [], toolAxes: [], warnings: [], serverInstructions: [], instructionsDelta: { pendingAdds: [], pendingRemovals: [] }, droppedTools: [], statuses: [], refresh: async () => [], dispose: async () => { } };
|
|
1226
1290
|
for (const w of mcp.warnings)
|
|
1227
1291
|
deps.onError?.(w, { phase: "mcp", sessionId });
|
|
@@ -1241,7 +1305,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1241
1305
|
tools.push(...mcp.tools.map((t) => remoteToolOffload(t)));
|
|
1242
1306
|
const rebuildHarnessToolsRef = {};
|
|
1243
1307
|
const toolCallGateArmedRef = { armed: false };
|
|
1244
|
-
if (
|
|
1308
|
+
if (lockedPreflight.mcp?.length) {
|
|
1245
1309
|
tools.push({
|
|
1246
1310
|
name: "RefreshMcpTools",
|
|
1247
1311
|
label: "RefreshMcpTools",
|
|
@@ -1632,7 +1696,31 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1632
1696
|
.catch(() => undefined);
|
|
1633
1697
|
}
|
|
1634
1698
|
: undefined;
|
|
1635
|
-
const { memoryEngineSession, memoryBlock: memoryBlockFromEngine, seedFiles: memorySeedFiles } = await prepareMemory({
|
|
1699
|
+
const { memoryEngineSession, memoryBlock: memoryBlockFromEngine, seedFiles: memorySeedFiles, admittedOrgScopes: memoryAdmittedOrgScopes, ownOrgVerdict: memoryOwnOrgVerdict, } = await prepareMemory({
|
|
1700
|
+
spec,
|
|
1701
|
+
deps,
|
|
1702
|
+
sessionId,
|
|
1703
|
+
taskRootPath,
|
|
1704
|
+
memoryWriteGateRef,
|
|
1705
|
+
admissionCtx: {
|
|
1706
|
+
orgMemoryDenied: complianceDenies.has("org_memory_mount"),
|
|
1707
|
+
complianceDegraded,
|
|
1708
|
+
parentAdmittedOrgScopes: foldAdmissionFreeze({
|
|
1709
|
+
delegated: internals?.isDelegatedChild === true ||
|
|
1710
|
+
internals?.inheritedGate !== undefined ||
|
|
1711
|
+
(resume?.seed.inheritedGate !== undefined &&
|
|
1712
|
+
(resume.seed.inheritedGate.ancestorRules !== undefined ||
|
|
1713
|
+
resume.seed.inheritedGate.shellGate !== undefined ||
|
|
1714
|
+
resume.seed.inheritedGate.admittedOrgScopes !== undefined ||
|
|
1715
|
+
resume.seed.inheritedGate.requiresParentConstraint)),
|
|
1716
|
+
inherited: inheritedAdmittedOrgScopes,
|
|
1717
|
+
}),
|
|
1718
|
+
priorOwnVerdict: priorOwnOrgVerdict,
|
|
1719
|
+
governedProvenance: orgGovernedProvenance,
|
|
1720
|
+
},
|
|
1721
|
+
});
|
|
1722
|
+
memoryAdmittedOrgScopesRef.current = memoryAdmittedOrgScopes;
|
|
1723
|
+
ownOrgVerdictRef.current = memoryOwnOrgVerdict ?? priorOwnOrgVerdict;
|
|
1636
1724
|
let memoryBlock = memoryBlockFromEngine;
|
|
1637
1725
|
if (memorySeedFiles?.length && seedContextFiles) {
|
|
1638
1726
|
try {
|
|
@@ -1737,7 +1825,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1737
1825
|
{ entries: [], seedAnnounced: true }
|
|
1738
1826
|
: undefined;
|
|
1739
1827
|
const provider = spec.promptProvider ?? deps.promptProvider ?? defaultPromptProvider;
|
|
1740
|
-
const promptPolicyEnabled = Boolean(
|
|
1828
|
+
const promptPolicyEnabled = Boolean(lockedPreflight.toolPolicy);
|
|
1741
1829
|
const promptHooks = spec.hooks ?? deps.hooks;
|
|
1742
1830
|
const promptHooksEnabled = Boolean(promptHooks?.preToolUse || promptHooks?.postToolUse);
|
|
1743
1831
|
const failClosedReason = selfOrchestrationFailClosedReason(spec, deps);
|
|
@@ -2328,7 +2416,6 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2328
2416
|
}));
|
|
2329
2417
|
},
|
|
2330
2418
|
...(spec.streamingToolExecution === true ? { streamingToolExecution: true } : {}),
|
|
2331
|
-
followUpMode: "all",
|
|
2332
2419
|
env: executionEnv,
|
|
2333
2420
|
session,
|
|
2334
2421
|
tools: harnessTools,
|
|
@@ -2368,7 +2455,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2368
2455
|
releaseSignal = () => sig.removeEventListener("abort", onExternalAbort);
|
|
2369
2456
|
}
|
|
2370
2457
|
}
|
|
2371
|
-
const policy =
|
|
2458
|
+
const policy = lockedPreflight.toolPolicy;
|
|
2372
2459
|
const auditPolicyNames = (auditee) => {
|
|
2373
2460
|
const nameGroups = toolPolicyNameSets(auditee);
|
|
2374
2461
|
if (nameGroups.length > 0) {
|
|
@@ -2456,7 +2543,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2456
2543
|
for (const layer of narrowingLayers)
|
|
2457
2544
|
auditPolicyNames(layer);
|
|
2458
2545
|
const denyNarrowingPolicy = narrowingLayers.length === 0 ? undefined : narrowingLayers.length === 1 ? narrowingLayers[0] : combinePolicies(...narrowingLayers);
|
|
2459
|
-
const basePolicyForResumeEdit =
|
|
2546
|
+
const basePolicyForResumeEdit = lockedPreflight.toolPolicy;
|
|
2460
2547
|
const sameInstanceAncestorCount = policy === undefined ? 0 : (inheritedParentConstraints ?? []).reduce((n, pc) => (pc.policy === policy ? n + 1 : n), 0);
|
|
2461
2548
|
const sharedFirstDecision = new Map();
|
|
2462
2549
|
const SHARED_FIRST_DECISION_CAP = 256;
|
|
@@ -2994,10 +3081,20 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2994
3081
|
inheritedGate: (() => {
|
|
2995
3082
|
const requiresParentConstraint = (inheritedParentConstraints?.length ?? 0) > 0 || seedInheritedGate?.requiresParentConstraint === true;
|
|
2996
3083
|
const parentConstraintCount = (inheritedParentConstraints?.length ?? 0) > 0 ? inheritedParentConstraints.length : seedInheritedGate?.parentConstraintCount;
|
|
2997
|
-
return inheritedAncestorRules !== undefined ||
|
|
3084
|
+
return inheritedAncestorRules !== undefined ||
|
|
3085
|
+
inheritedShellGate !== undefined ||
|
|
3086
|
+
inheritedAdmittedOrgScopes !== undefined ||
|
|
3087
|
+
ownOrgVerdictRef.current !== undefined ||
|
|
3088
|
+
orgGovernedProvenance ||
|
|
3089
|
+
requiresParentConstraint
|
|
2998
3090
|
? {
|
|
2999
3091
|
...(inheritedAncestorRules !== undefined ? { ancestorRules: structuredClone(inheritedAncestorRules) } : {}),
|
|
3000
3092
|
...(inheritedShellGate !== undefined ? { shellGate: inheritedShellGate } : {}),
|
|
3093
|
+
...(inheritedAdmittedOrgScopes !== undefined ? { admittedOrgScopes: [...inheritedAdmittedOrgScopes] } : {}),
|
|
3094
|
+
...(ownOrgVerdictRef.current !== undefined
|
|
3095
|
+
? { ownAdmittedOrgScopes: [...ownOrgVerdictRef.current.scopes], ownAdmittedOrgWriteScope: ownOrgVerdictRef.current.writeScope }
|
|
3096
|
+
: {}),
|
|
3097
|
+
...(orgGovernedProvenance ? { orgAdmissionGoverned: true } : {}),
|
|
3001
3098
|
requiresParentConstraint,
|
|
3002
3099
|
...(requiresParentConstraint && parentConstraintCount !== undefined ? { parentConstraintCount } : {}),
|
|
3003
3100
|
}
|
|
@@ -3112,7 +3209,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3112
3209
|
const mintedAt = Date.now();
|
|
3113
3210
|
const cp = {
|
|
3114
3211
|
token,
|
|
3115
|
-
version: resourceLedgerOut.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
3212
|
+
version: orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : resourceLedgerOut.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : RESOURCE_CHECKPOINT_VERSION,
|
|
3116
3213
|
scope,
|
|
3117
3214
|
sessionId,
|
|
3118
3215
|
leafId,
|
|
@@ -3194,7 +3291,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3194
3291
|
const mintedAt = Date.now();
|
|
3195
3292
|
const cp = {
|
|
3196
3293
|
token,
|
|
3197
|
-
version: reviewLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3294
|
+
version: orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : reviewLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3198
3295
|
scope,
|
|
3199
3296
|
sessionId,
|
|
3200
3297
|
leafId,
|
|
@@ -3230,8 +3327,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3230
3327
|
: undefined;
|
|
3231
3328
|
const suspendAsk = checkpointStore && (durableApproval || irreversibleTools.size > 0 || egressTools.size > 0)
|
|
3232
3329
|
? async (req, postHookArgs, safety, approverUnavailable) => {
|
|
3233
|
-
if (
|
|
3234
|
-
onAsk !== undefined &&
|
|
3330
|
+
if (onAsk !== undefined &&
|
|
3235
3331
|
runtimeCaps?.forceDurableGate !== true &&
|
|
3236
3332
|
approverUnavailable !== true &&
|
|
3237
3333
|
req.toolName !== ASK_USER_QUESTION_TOOL_NAME &&
|
|
@@ -3320,7 +3416,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3320
3416
|
const mintedAt = Date.now();
|
|
3321
3417
|
cp = {
|
|
3322
3418
|
token,
|
|
3323
|
-
version: approvalLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3419
|
+
version: orgAdmissionCheckpointState() ? ORG_ADMISSION_CHECKPOINT_VERSION : approvalLedger.totalTokens !== undefined ? TOKEN_CHECKPOINT_VERSION : BINDING_CHECKPOINT_VERSION,
|
|
3324
3420
|
scope,
|
|
3325
3421
|
sessionId,
|
|
3326
3422
|
leafId,
|
|
@@ -3381,11 +3477,28 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3381
3477
|
if (eff !== undefined && !toolEffects.has(t.name))
|
|
3382
3478
|
toolEffects.set(t.name, eff);
|
|
3383
3479
|
}
|
|
3384
|
-
toolCallGateArmedRef.armed =
|
|
3480
|
+
toolCallGateArmedRef.armed =
|
|
3481
|
+
effectivePolicy !== undefined ||
|
|
3482
|
+
hooks?.preToolUse !== undefined ||
|
|
3483
|
+
egressTools.size > 0 ||
|
|
3484
|
+
irreversibleTools.size > 0 ||
|
|
3485
|
+
spec.enablePlanMode === true ||
|
|
3486
|
+
complianceDenies.has("web_fetch");
|
|
3385
3487
|
if (toolCallGateArmedRef.armed) {
|
|
3386
3488
|
harness.on("tool_call", async (e) => {
|
|
3387
3489
|
blockedToolCalls.delete(e.toolCallId);
|
|
3388
3490
|
inheritedAskGrants.delete(e.toolCallId);
|
|
3491
|
+
{
|
|
3492
|
+
const complianceDeny = complianceCallDenial(complianceDenies, e.toolName);
|
|
3493
|
+
if (complianceDeny !== undefined) {
|
|
3494
|
+
if (blockedTracked)
|
|
3495
|
+
blockedToolCalls.add(e.toolCallId);
|
|
3496
|
+
if (notifyPermissionDenied) {
|
|
3497
|
+
await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: complianceDeny, source: "safety" });
|
|
3498
|
+
}
|
|
3499
|
+
return { block: true, reason: formatHookFeedback(complianceDeny), preToolContext: [] };
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3389
3502
|
if (planModeRef.active && (toolEffects.get(e.toolName) ?? "write") !== "read") {
|
|
3390
3503
|
if (blockedTracked)
|
|
3391
3504
|
blockedToolCalls.add(e.toolCallId);
|
|
@@ -1450,6 +1450,12 @@ export class Runner {
|
|
|
1450
1450
|
errorMessage: err instanceof Error ? err.message : String(err),
|
|
1451
1451
|
errorCode: code,
|
|
1452
1452
|
...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
|
|
1453
|
+
...(() => {
|
|
1454
|
+
const hinted = err.retryAfterMs;
|
|
1455
|
+
return code === "memory.admission_required" && typeof hinted === "number" && Number.isFinite(hinted) && hinted > 0
|
|
1456
|
+
? { retryAfterMs: hinted }
|
|
1457
|
+
: {};
|
|
1458
|
+
})(),
|
|
1453
1459
|
stats: { turns: 0, tokens: 0, toolCalls: 0, cachedTokens: 0, costMicroUsd: 0 },
|
|
1454
1460
|
};
|
|
1455
1461
|
emitTrace(spec.tracer ?? this.deps.tracer, () => ({
|
|
@@ -1703,9 +1709,7 @@ export class Runner {
|
|
|
1703
1709
|
queue.push({ type: "task_notification", notification: item.payload, ...notificationIdent() });
|
|
1704
1710
|
if (notificationHarness) {
|
|
1705
1711
|
const xml = renderTaskNotificationXml(item.payload);
|
|
1706
|
-
const deliver =
|
|
1707
|
-
? notificationHarness.followUp(xml, { provenance: "engine-note", enginePayload: item.payload })
|
|
1708
|
-
: notificationHarness.steer(xml, { provenance: "engine-note", enginePayload: item.payload });
|
|
1712
|
+
const deliver = notificationHarness.steer(xml, { provenance: "engine-note", enginePayload: item.payload });
|
|
1709
1713
|
void deliver.then(() => item.onDisposition?.("queued"), () => {
|
|
1710
1714
|
parkTaskNotification(item.payload, item.priority);
|
|
1711
1715
|
item.onDisposition?.("parked");
|
|
@@ -2323,6 +2327,22 @@ export class Runner {
|
|
|
2323
2327
|
});
|
|
2324
2328
|
const stopHook = (spec.hooks ?? this.deps.hooks)?.stop;
|
|
2325
2329
|
const finalVerificationOn = spec.finalVerification === true;
|
|
2330
|
+
const finalVerifyBudgetFill = () => {
|
|
2331
|
+
let worst = 0;
|
|
2332
|
+
if (rs.budget.maxTokensWindow !== undefined && rs.budget.maxTokensWindow > 0)
|
|
2333
|
+
worst = Math.max(worst, stats.tokens / rs.budget.maxTokensWindow);
|
|
2334
|
+
if (rs.budget.maxCostMicroUsd !== undefined && rs.budget.maxCostMicroUsd > 0)
|
|
2335
|
+
worst = Math.max(worst, stats.costMicroUsd / rs.budget.maxCostMicroUsd);
|
|
2336
|
+
if (walltimeMonotonicDeadline !== undefined && prepared.suspendForResource === undefined) {
|
|
2337
|
+
const windowMs = walltimeMonotonicDeadline - rs.telemetry.taskStartMonotonic;
|
|
2338
|
+
if (windowMs > 0)
|
|
2339
|
+
worst = Math.max(worst, (performance.now() - rs.telemetry.taskStartMonotonic) / windowMs);
|
|
2340
|
+
}
|
|
2341
|
+
return worst;
|
|
2342
|
+
};
|
|
2343
|
+
const emitFinalVerifyEcho = (body) => {
|
|
2344
|
+
queue.push({ type: "steering_injected", source: "final_verification", preview: body.slice(0, 220), ...ident() });
|
|
2345
|
+
};
|
|
2326
2346
|
if (stopHook || finalVerificationOn) {
|
|
2327
2347
|
let consecutiveBlocks = 0;
|
|
2328
2348
|
prepared.harness.setStopGate(async () => {
|
|
@@ -2332,58 +2352,69 @@ export class Runner {
|
|
|
2332
2352
|
(rs.counters.finalVerifyInjections === 0 || (rs.counters.finalVerifyInjections === 1 && rs.counters.groundingSignalPreR9 && !rs.counters.groundingSignalPostR9)) &&
|
|
2333
2353
|
rs.counters.wroteThisRun &&
|
|
2334
2354
|
prepared.outputRef.set !== true &&
|
|
2335
|
-
!(rs.limits.effectiveMaxTurns !== undefined && rs.limits.effectiveMaxTurns > 0 && stats.turns >= rs.limits.effectiveMaxTurns - 1)
|
|
2355
|
+
!(rs.limits.effectiveMaxTurns !== undefined && rs.limits.effectiveMaxTurns > 0 && stats.turns >= rs.limits.effectiveMaxTurns - 1) &&
|
|
2356
|
+
finalVerifyBudgetFill() < 0.9) {
|
|
2336
2357
|
rs.counters.finalVerifyInjections += 1;
|
|
2337
2358
|
if (rs.counters.finalVerifyInjections === 2) {
|
|
2359
|
+
const reentryBody = "<system-reminder>[final verification] Your tool calls in this run worked with raw bytes, structural parsing, " +
|
|
2360
|
+
"or checksum/digest computation — the deliverable very likely embeds verifiable structure (structural fields, an " +
|
|
2361
|
+
"embedded checksum-family value, reference data it must match, or a replayable deterministic path). You MUST " +
|
|
2362
|
+
"execute the grounding check that structure supports — recompute the embedded value and compare it against the " +
|
|
2363
|
+
"declared one, re-parse the structure from the raw bytes and reconcile it with your output, compare against the " +
|
|
2364
|
+
"reference data, or replay the deterministic path — and REPORT the check's concrete result before finishing. " +
|
|
2365
|
+
"A closing statement without a reported check result is not verification. If you already ran such a check, state " +
|
|
2366
|
+
"its concrete result now; if the check mismatches, fix the deliverable first. This is the final reminder from " +
|
|
2367
|
+
"this verification gate — it will not intervene again.</system-reminder>";
|
|
2368
|
+
emitFinalVerifyEcho(reentryBody);
|
|
2338
2369
|
return [
|
|
2339
2370
|
{
|
|
2340
2371
|
role: "user",
|
|
2341
2372
|
engineMinted: true,
|
|
2342
|
-
content:
|
|
2343
|
-
"or checksum/digest computation — the deliverable very likely embeds verifiable structure (structural fields, an " +
|
|
2344
|
-
"embedded checksum-family value, reference data it must match, or a replayable deterministic path). You MUST " +
|
|
2345
|
-
"execute the grounding check that structure supports — recompute the embedded value and compare it against the " +
|
|
2346
|
-
"declared one, re-parse the structure from the raw bytes and reconcile it with your output, compare against the " +
|
|
2347
|
-
"reference data, or replay the deterministic path — and REPORT the check's concrete result before finishing. " +
|
|
2348
|
-
"A closing statement without a reported check result is not verification. If you already ran such a check, state " +
|
|
2349
|
-
"its concrete result now; if the check mismatches, fix the deliverable first. This is the final reminder from " +
|
|
2350
|
-
"this verification gate — it will not intervene again.</system-reminder>",
|
|
2373
|
+
content: reentryBody,
|
|
2351
2374
|
timestamp: Date.now(),
|
|
2352
2375
|
},
|
|
2353
2376
|
];
|
|
2354
2377
|
}
|
|
2378
|
+
const nudgeBody = "<system-reminder>[final verification] Before finishing: re-verify the FINAL deliverable through its REAL entry point, " +
|
|
2379
|
+
"exactly as the acceptance criteria would exercise it — execute the binary/function/endpoint directly and read the ACTUAL " +
|
|
2380
|
+
"output and exit code. Do NOT rely on earlier self-tests, shell redirections, or assumptions (a program that prints to " +
|
|
2381
|
+
"stdout is not a program that writes the required file). If anything mismatches the task's requirements, fix it before " +
|
|
2382
|
+
"finishing. " +
|
|
2383
|
+
"Treat verification writes as state-harmless: when the deliverable itself is a persisted final " +
|
|
2384
|
+
"state (for example a committed or pushed file, a deployed artifact, or a required output file), " +
|
|
2385
|
+
"do not change that state merely to test it. This constrains HOW you verify — it is never a " +
|
|
2386
|
+
"license to skip the real acceptance path or to check a substitute of your own making: expected " +
|
|
2387
|
+
"values must come from the task's requirements, never from content you generated. If the real " +
|
|
2388
|
+
"acceptance path requires a write, use disposable inputs or an isolated target, end in the exact " +
|
|
2389
|
+
"required final state, and verify that final state before finishing. " +
|
|
2390
|
+
"If the work relied on a third-party API, library, or model, check the usage contract the object itself declares " +
|
|
2391
|
+
"(docstrings, metadata, configuration — e.g. prompt conventions shipped with a model) and confirm your calls follow " +
|
|
2392
|
+
"it rather than a default symmetric usage. Verify not only that the deliverable EXISTS but that the METHOD that " +
|
|
2393
|
+
"produced it matches the task's requirements. " +
|
|
2394
|
+
"Choose the verification SURFACE deliberately: check against the reference data, oracle, or evaluation tooling the " +
|
|
2395
|
+
"task itself provides — re-running your own implementation and getting the same answer is self-consistency, not " +
|
|
2396
|
+
"correctness — and cross-check through an independent second path where the task or environment offers one " +
|
|
2397
|
+
"(checksums, runtime artifacts). Verify the PERSISTED artifact — re-read what is actually on disk or committed, " +
|
|
2398
|
+
"not in-memory state — against every hard constraint from the original task text (numeric bounds, allowed-value " +
|
|
2399
|
+
"lists, naming semantics, required files), reconciling whole-set completeness: nothing missing, nothing duplicated. " +
|
|
2400
|
+
"If the deliverable embeds verifiable structure — structural fields, an embedded checksum-family value, " +
|
|
2401
|
+
"reference data it must match, or a replayable deterministic path — you MUST execute the grounding check " +
|
|
2402
|
+
"that structure supports and REPORT its concrete result in your closing summary: for such a deliverable, " +
|
|
2403
|
+
"no reported check result means the work is not finished. " +
|
|
2404
|
+
"If the task produced neither an executable deliverable nor any verifiable structure or acceptance " +
|
|
2405
|
+
"oracle to check against, briefly confirm completion and stop. " +
|
|
2406
|
+
"Residue YOUR OWN testing created (scratch files, running processes, generated outputs the task does not ask for) " +
|
|
2407
|
+
"is not protected state — if the task's required final state is a clean target, removing your own residue is part " +
|
|
2408
|
+
"of delivering it. " +
|
|
2409
|
+
"Verification must never LAUNDER uncertainty: if part of your conclusion was uncertain before this check, keep " +
|
|
2410
|
+
"reporting it as uncertain unless the check you actually ran resolved it — a re-stated conclusion is not new " +
|
|
2411
|
+
"evidence.</system-reminder>";
|
|
2412
|
+
emitFinalVerifyEcho(nudgeBody);
|
|
2355
2413
|
return [
|
|
2356
2414
|
{
|
|
2357
2415
|
role: "user",
|
|
2358
2416
|
engineMinted: true,
|
|
2359
|
-
content:
|
|
2360
|
-
"exactly as the acceptance criteria would exercise it — execute the binary/function/endpoint directly and read the ACTUAL " +
|
|
2361
|
-
"output and exit code. Do NOT rely on earlier self-tests, shell redirections, or assumptions (a program that prints to " +
|
|
2362
|
-
"stdout is not a program that writes the required file). If anything mismatches the task's requirements, fix it before " +
|
|
2363
|
-
"finishing. " +
|
|
2364
|
-
"Treat verification writes as state-harmless: when the deliverable itself is a persisted final " +
|
|
2365
|
-
"state (for example a committed or pushed file, a deployed artifact, or a required output file), " +
|
|
2366
|
-
"do not change that state merely to test it. This constrains HOW you verify — it is never a " +
|
|
2367
|
-
"license to skip the real acceptance path or to check a substitute of your own making: expected " +
|
|
2368
|
-
"values must come from the task's requirements, never from content you generated. If the real " +
|
|
2369
|
-
"acceptance path requires a write, use disposable inputs or an isolated target, end in the exact " +
|
|
2370
|
-
"required final state, and verify that final state before finishing. " +
|
|
2371
|
-
"If the work relied on a third-party API, library, or model, check the usage contract the object itself declares " +
|
|
2372
|
-
"(docstrings, metadata, configuration — e.g. prompt conventions shipped with a model) and confirm your calls follow " +
|
|
2373
|
-
"it rather than a default symmetric usage. Verify not only that the deliverable EXISTS but that the METHOD that " +
|
|
2374
|
-
"produced it matches the task's requirements. " +
|
|
2375
|
-
"Choose the verification SURFACE deliberately: check against the reference data, oracle, or evaluation tooling the " +
|
|
2376
|
-
"task itself provides — re-running your own implementation and getting the same answer is self-consistency, not " +
|
|
2377
|
-
"correctness — and cross-check through an independent second path where the task or environment offers one " +
|
|
2378
|
-
"(checksums, runtime artifacts). Verify the PERSISTED artifact — re-read what is actually on disk or committed, " +
|
|
2379
|
-
"not in-memory state — against every hard constraint from the original task text (numeric bounds, allowed-value " +
|
|
2380
|
-
"lists, naming semantics, required files), reconciling whole-set completeness: nothing missing, nothing duplicated. " +
|
|
2381
|
-
"If the deliverable embeds verifiable structure — structural fields, an embedded checksum-family value, " +
|
|
2382
|
-
"reference data it must match, or a replayable deterministic path — you MUST execute the grounding check " +
|
|
2383
|
-
"that structure supports and REPORT its concrete result in your closing summary: for such a deliverable, " +
|
|
2384
|
-
"no reported check result means the work is not finished. " +
|
|
2385
|
-
"If the task produced neither an executable deliverable nor any verifiable structure or acceptance " +
|
|
2386
|
-
"oracle to check against, briefly confirm completion and stop.</system-reminder>",
|
|
2417
|
+
content: nudgeBody,
|
|
2387
2418
|
timestamp: Date.now(),
|
|
2388
2419
|
},
|
|
2389
2420
|
];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentTool } from "../internal/harness-types.js";
|
|
2
2
|
export interface ToolResultStore {
|
|
3
|
+
readonly retention?: import("./retention.js").RetentionDeclaration;
|
|
3
4
|
put(ref: string, content: string): Promise<void> | void;
|
|
4
5
|
get(ref: string, opts?: {
|
|
5
6
|
offset?: number;
|
|
@@ -15,6 +16,7 @@ export interface ToolResultSlice {
|
|
|
15
16
|
}
|
|
16
17
|
export declare class InMemoryToolResultStore implements ToolResultStore {
|
|
17
18
|
private readonly opts?;
|
|
19
|
+
readonly retention: "none";
|
|
18
20
|
private readonly map;
|
|
19
21
|
private totalChars;
|
|
20
22
|
constructor(opts?: {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -584,7 +584,7 @@ export type TaskEvent = ({
|
|
|
584
584
|
reason?: string;
|
|
585
585
|
} & TaskEventIdentity) | ({
|
|
586
586
|
type: "steering_injected";
|
|
587
|
-
source: "limit_approach" | "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools";
|
|
587
|
+
source: "limit_approach" | "todo_reminder" | "task_reminder" | "tool_search_usage_reminder" | "changed_files" | "plan_mode" | "date_change" | "instructions_change" | "workflow_size_guideline_change" | "budget_usd" | "background_tasks" | "tools_delta" | "agent_listing" | "skills_listing" | "mcp_instructions" | "mcp_dropped_tools" | "final_verification";
|
|
588
588
|
preview: string;
|
|
589
589
|
} & TaskEventIdentity) | ({
|
|
590
590
|
type: "diagnostics";
|
|
@@ -737,6 +737,11 @@ export interface RunnerDeps {
|
|
|
737
737
|
fileSnapshotStore?: import("./file-snapshot-store.js").FileSnapshotStore;
|
|
738
738
|
sessionPolicyStore?: import("./session-policy-store.js").SessionPolicyStore;
|
|
739
739
|
runtimeCapsResolver?: (principal: string | undefined) => RuntimeCaps | undefined | Promise<RuntimeCaps | undefined>;
|
|
740
|
+
lockedConfig?: import("./locked-config.js").LockedConfig;
|
|
741
|
+
compliancePostureResolver?: (principal: string | undefined) => import("./compliance.js").CompliancePosture | undefined | Promise<import("./compliance.js").CompliancePosture | undefined>;
|
|
742
|
+
memoryScopeAdmission?: import("./memory-admission.js").MemoryScopeAdmission;
|
|
743
|
+
deploymentMemoryScopes?: readonly string[];
|
|
744
|
+
retentionPolicy?: import("./retention.js").RetentionPolicy;
|
|
740
745
|
autoMode?: {
|
|
741
746
|
rules?: import("./auto-mode-prompt.js").AutoModeRules;
|
|
742
747
|
settingsDenyRules?: readonly string[];
|
|
@@ -27,6 +27,7 @@ function createUserMessage(text, images, provenance) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
const engineNotePayloads = new WeakMap();
|
|
30
|
+
const ENGINE_NOTE_STEER_BACKLOG_CAP = 50;
|
|
30
31
|
function createFailureMessage(model, error, aborted) {
|
|
31
32
|
return {
|
|
32
33
|
role: "assistant",
|
|
@@ -418,7 +419,13 @@ export class AgentHarness {
|
|
|
418
419
|
};
|
|
419
420
|
}
|
|
420
421
|
async drainQueuedMessages(queue, mode) {
|
|
421
|
-
|
|
422
|
+
let count = mode === "all" ? queue.length : 1;
|
|
423
|
+
if (mode !== "all" && queue.length > 1 && engineNotePayloads.has(queue[0])) {
|
|
424
|
+
count = 1;
|
|
425
|
+
while (count < queue.length && engineNotePayloads.has(queue[count]))
|
|
426
|
+
count++;
|
|
427
|
+
}
|
|
428
|
+
const messages = queue.splice(0, count);
|
|
422
429
|
if (messages.length === 0) {
|
|
423
430
|
return messages;
|
|
424
431
|
}
|
|
@@ -713,6 +720,9 @@ export class AgentHarness {
|
|
|
713
720
|
async enqueueInjection(queue, text, options) {
|
|
714
721
|
if (AgentHarness.emptyInjection(text, options))
|
|
715
722
|
return;
|
|
723
|
+
if (options?.enginePayload !== undefined && queue.filter((q) => engineNotePayloads.has(q)).length >= ENGINE_NOTE_STEER_BACKLOG_CAP) {
|
|
724
|
+
throw new AgentHarnessError("invalid_state", `engine-note backlog at cap (${ENGINE_NOTE_STEER_BACKLOG_CAP}) — park the payload for the session's next run`);
|
|
725
|
+
}
|
|
716
726
|
const m = createUserMessage(text, options?.images, options);
|
|
717
727
|
if (options?.enginePayload !== undefined)
|
|
718
728
|
engineNotePayloads.set(m, options.enginePayload);
|
|
@@ -288,5 +288,15 @@ export function validateToolArguments(tool, toolCall) {
|
|
|
288
288
|
.Errors(args)
|
|
289
289
|
.map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)
|
|
290
290
|
.join("\n") || "Unknown validation error";
|
|
291
|
-
|
|
291
|
+
const schemaJson = (() => {
|
|
292
|
+
try {
|
|
293
|
+
const s = JSON.stringify(tool.parameters);
|
|
294
|
+
return s.length > VALIDATION_ERROR_SCHEMA_MAX_CHARS ? `${s.slice(0, VALIDATION_ERROR_SCHEMA_MAX_CHARS)}… (schema truncated)` : s;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
return "(schema not serializable)";
|
|
298
|
+
}
|
|
299
|
+
})();
|
|
300
|
+
throw new Error(`Validation failed for tool "${toolCall.name}":\n${errors}\n\nReceived arguments:\n${JSON.stringify(toolCall.arguments, null, 2)}\n\nExpected parameter schema:\n${schemaJson}`);
|
|
292
301
|
}
|
|
302
|
+
const VALIDATION_ERROR_SCHEMA_MAX_CHARS = 4_000;
|