@sema-agent/core 7.3.0 → 7.4.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 +49 -0
- package/dist/agents/peer-admission.d.ts +18 -3
- package/dist/agents/peer-admission.js +79 -4
- package/dist/agents/peer-held-queue.d.ts +101 -0
- package/dist/agents/peer-held-queue.js +229 -0
- package/dist/agents/peer-idle.d.ts +109 -0
- package/dist/agents/peer-idle.js +240 -0
- package/dist/agents/peer-notice-route.d.ts +33 -0
- package/dist/agents/peer-notice-route.js +46 -0
- package/dist/agents/peer-notices.d.ts +103 -0
- package/dist/agents/peer-notices.js +206 -0
- package/dist/agents/peer-session-drain.d.ts +39 -4
- package/dist/agents/peer-session-drain.js +248 -42
- package/dist/agents/send-message-tool.d.ts +8 -1
- package/dist/agents/send-message-tool.js +96 -30
- package/dist/agents/subagent.js +1 -0
- package/dist/brain/status-sink.d.ts +10 -0
- package/dist/brain/status-sink.js +13 -4
- package/dist/brain/stream-engine.d.ts +11 -0
- package/dist/brain/stream-engine.js +39 -3
- package/dist/core/arg-summary.d.ts +13 -3
- package/dist/core/arg-summary.js +138 -7
- package/dist/core/auto-mode-defaults.d.ts +11 -0
- package/dist/core/auto-mode-defaults.js +2 -0
- package/dist/core/auto-mode.d.ts +59 -0
- package/dist/core/auto-mode.js +57 -1
- package/dist/core/checkpoint-store.js +2 -2
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +8 -0
- package/dist/core/hooks.d.ts +30 -0
- package/dist/core/hooks.js +43 -8
- package/dist/core/mailbox-store.d.ts +33 -1
- package/dist/core/mailbox-store.js +42 -2
- package/dist/core/runner/assemble-result.d.ts +5 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/denial-limit-arms.d.ts +149 -0
- package/dist/core/runner/denial-limit-arms.js +91 -0
- package/dist/core/runner/edited-files-ledger.d.ts +33 -0
- package/dist/core/runner/edited-files-ledger.js +14 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +5 -0
- package/dist/core/runner/prepare-hands-readface.js +1 -0
- package/dist/core/runner/prepare-task.d.ts +62 -1
- package/dist/core/runner/prepare-task.js +135 -89
- package/dist/core/runner/runtask.js +12 -0
- package/dist/core/sensitive-path-policy.d.ts +27 -6
- package/dist/core/sensitive-path-policy.js +57 -2
- package/dist/core/task-notification.d.ts +24 -2
- package/dist/core/task-notification.js +6 -1
- package/dist/core/tool-policy.d.ts +55 -4
- package/dist/core/tool-policy.js +28 -5
- package/dist/core/tools.js +1 -0
- package/dist/core/types.d.ts +251 -15
- package/dist/core/wiring-manifest.d.ts +41 -5
- package/dist/core/wiring-manifest.js +8 -0
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +3 -0
- package/dist/engine/harness/types.d.ts +3 -0
- package/dist/engine/loop/agent-loop.d.ts +7 -0
- package/dist/engine/loop/agent-loop.js +79 -0
- package/dist/engine/loop/types.d.ts +42 -0
- package/dist/index.d.ts +12 -6
- package/dist/index.js +10 -4
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/orchestration/workflow.js +7 -3
- package/dist/tools/fs/fs-write.d.ts +4 -4
- package/dist/tools/fs/fs-write.js +99 -14
- package/dist/tools/fs/index.d.ts +7 -1
- package/dist/tools/fs/index.js +1 -1
- package/dist/tools/fs/safety.d.ts +29 -8
- package/dist/tools/fs/safety.js +11 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +181 -1
|
@@ -5,7 +5,8 @@ import { AgentHarness, DEFAULT_CHARS_PER_TOKEN, DEFAULT_CLAMP_TOLERANCE, DEFAULT
|
|
|
5
5
|
const PROMPT_HASH_SALT = randomBytes(16);
|
|
6
6
|
import { sanitizeCompactionSettings } from "../auto-compaction.js";
|
|
7
7
|
import { projectStaleToolResults, resolveStaleToolResultOffload } from "./compaction-call-options.js";
|
|
8
|
-
import { createAutoModeDecider } from "../auto-mode.js";
|
|
8
|
+
import { createAutoModeDecider, createAutoModeDenialTracker } from "../auto-mode.js";
|
|
9
|
+
import { attachRebuiltDenialTrackers, createDenialLimitStop, headlessDenyAtFold, headlessDenyAtRecheck, judgeInheritedClassifier, settleDenialLimitFallback } from "./denial-limit-arms.js";
|
|
9
10
|
import { autoModeArmingRecipeOf } from "../auto-mode-arming.js";
|
|
10
11
|
import { buildAutoModePrompt, renderAutoModeAction, renderAutoModeWindow } from "../auto-mode-prompt.js";
|
|
11
12
|
import { resolveTaskModel } from "../roles.js";
|
|
@@ -63,6 +64,7 @@ import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js"
|
|
|
63
64
|
import { NAMESPACED_NAME_SHAPES, prepareSafetyScan } from "./prepare-safety-scan.js";
|
|
64
65
|
import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
|
|
65
66
|
import { prepareHandsMount, resolveHandsLessReadFace } from "./prepare-hands-readface.js";
|
|
67
|
+
import { createEditedFilesLedger } from "./edited-files-ledger.js";
|
|
66
68
|
import { prepareWorkspaceRestore, remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./prepare-workspace-restore.js";
|
|
67
69
|
import { defaultPromptProvider, buildEnvironmentContext, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
|
|
68
70
|
import { applyGitFrameGuard, probeGitStatusLane } from "./git-status-frame.js";
|
|
@@ -85,6 +87,7 @@ import { createMonitorTool } from "../../tools/monitor.js";
|
|
|
85
87
|
import { createWorktreeTools } from "../../tools/worktree.js";
|
|
86
88
|
import { announcePeerLaneMount, bindPeerLaneDrain, listAgentsMountable, mountListAgents, peerLaneSendMessageSeats } from "../../agents/peer-session-drain.js";
|
|
87
89
|
import { CROSS_SESSION_CLASSIFIER_RULE } from "../../agents/cross-session-envelope.js";
|
|
90
|
+
import { NodeExecutionEnv } from "../../engine/execution-env/node-execution-env.js";
|
|
88
91
|
import { applyCompactionToReadFileState, isReadDedupStubResult, FULL_SHELL_CONTRACT_ID, HAND_TOOL_EFFECTS } from "../../tools/fs/index.js";
|
|
89
92
|
import { decodeTextBytes } from "../../tools/fs/encoding.js";
|
|
90
93
|
import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, classifyQuestionOutcome, isLiveQuestionFace, validateAskQuestions, } from "../ask-question.js";
|
|
@@ -635,6 +638,45 @@ function createFileHistoryBoundarySeat(opts) {
|
|
|
635
638
|
},
|
|
636
639
|
};
|
|
637
640
|
}
|
|
641
|
+
async function resolveFileHistoryCoordinates(enabled, env, taskRoot, lineage, sessionId) {
|
|
642
|
+
if (!enabled)
|
|
643
|
+
return { historyRoot: taskRoot, historyScope: sessionId, historyFs: "" };
|
|
644
|
+
const canonRoot = await env.canonicalPath(taskRoot);
|
|
645
|
+
const historyRoot = canonRoot.ok ? canonRoot.value : taskRoot;
|
|
646
|
+
const historyFs = fileHistoryFilesystemIdentity(env);
|
|
647
|
+
return { historyRoot, historyScope: resolveFileHistoryScope(lineage, historyRoot, historyFs, sessionId), historyFs };
|
|
648
|
+
}
|
|
649
|
+
export function resolveFileHistoryScope(lineage, historyRoot, historyFs, sessionId) {
|
|
650
|
+
if (lineage === undefined || lineage.scope === "" || lineage.root !== historyRoot || lineage.fs !== historyFs)
|
|
651
|
+
return sessionId;
|
|
652
|
+
return lineage.scope;
|
|
653
|
+
}
|
|
654
|
+
const envFilesystemTokens = new WeakMap();
|
|
655
|
+
let envFilesystemSeq = 0;
|
|
656
|
+
export function fileHistoryFilesystemIdentity(env) {
|
|
657
|
+
if (isRemoteExecutionEnv(env)) {
|
|
658
|
+
try {
|
|
659
|
+
const h = env.workspaceHandle();
|
|
660
|
+
return JSON.stringify(["remote", h.provider, h.sandboxId, h.deviceId !== undefined && h.deviceId !== "" ? h.deviceId : null]);
|
|
661
|
+
}
|
|
662
|
+
catch {
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
else if (env.hostLocalPaths === true || (env.hostLocalPaths === undefined && env instanceof NodeExecutionEnv)) {
|
|
666
|
+
return "host";
|
|
667
|
+
}
|
|
668
|
+
let token = envFilesystemTokens.get(env);
|
|
669
|
+
if (token === undefined) {
|
|
670
|
+
token = `instance:${++envFilesystemSeq}`;
|
|
671
|
+
envFilesystemTokens.set(env, token);
|
|
672
|
+
}
|
|
673
|
+
return token;
|
|
674
|
+
}
|
|
675
|
+
function childScopeRewindRefusal(rootScope, target) {
|
|
676
|
+
const e = new Error(`rewind-files: this run is a delegated child recording its edits into the ROOT session "${rootScope}"'s file history, so restoring files to entry "${target}" is the root session's action (rewindFilesTo / resumeAt+restoreFiles on that session), not the child's — the files were NOT rewound`);
|
|
677
|
+
e.code = "rewind.child_scope_unsupported";
|
|
678
|
+
return e;
|
|
679
|
+
}
|
|
638
680
|
export function gatedCallIdOf(p) {
|
|
639
681
|
if (p.suspendRef.token !== undefined)
|
|
640
682
|
return p.suspendRef.gatedCallId;
|
|
@@ -1210,6 +1252,18 @@ function autoModeLatchHealthy(d) {
|
|
|
1210
1252
|
return false;
|
|
1211
1253
|
}
|
|
1212
1254
|
}
|
|
1255
|
+
function autoModeArmReasonOf(intent, facePresent, capsAutoMode, capsFaulted) {
|
|
1256
|
+
if (!intent)
|
|
1257
|
+
return "no_intent";
|
|
1258
|
+
if (!facePresent)
|
|
1259
|
+
return "no_face";
|
|
1260
|
+
if (capsAutoMode === false)
|
|
1261
|
+
return capsFaulted ? "resolver_fault" : "denied";
|
|
1262
|
+
return "armed";
|
|
1263
|
+
}
|
|
1264
|
+
function validateInputFaultNotice(onError, sessionId) {
|
|
1265
|
+
return ({ toolName, toolCallId, error }) => onError?.(new Error(`tool input pre-validation (validateInput) threw for ${toolName} (call ${toolCallId}) — read as no verdict; the call proceeded to the gate: ${error instanceof Error ? error.message : String(error)}`), { phase: "hook", sessionId });
|
|
1266
|
+
}
|
|
1213
1267
|
function refuseInvalidAutoModeSeat(spec) {
|
|
1214
1268
|
if (spec.autoModeRequested !== undefined && spec.autoModeRequested !== true) {
|
|
1215
1269
|
const e = new Error(`autoModeRequested must be the literal true when present (got ${JSON.stringify(spec.autoModeRequested)}) — omit it for a non-auto task; a non-boolean or false value is refused rather than read as either polarity.`);
|
|
@@ -1474,9 +1528,6 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1474
1528
|
throw e;
|
|
1475
1529
|
}
|
|
1476
1530
|
const fileHistoryStore = resolveWiredFileHistoryStore(deps.fileHistoryStore);
|
|
1477
|
-
if (fileHistoryStore !== undefined) {
|
|
1478
|
-
await adoptForkedFileHistory(fileHistoryStore, session, sessionId, deps.onError);
|
|
1479
|
-
}
|
|
1480
1531
|
const legacyRewindFiles = spec.rewindFiles;
|
|
1481
1532
|
if (legacyRewindFiles === true) {
|
|
1482
1533
|
if (spec.resumeAt !== undefined) {
|
|
@@ -1509,12 +1560,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1509
1560
|
});
|
|
1510
1561
|
}
|
|
1511
1562
|
const fileHistoryEnabled = fileHistoryStore !== undefined && handsEnabled;
|
|
1512
|
-
|
|
1513
|
-
if (
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
}
|
|
1563
|
+
const { historyRoot, historyScope, historyFs } = await resolveFileHistoryCoordinates(fileHistoryEnabled, executionEnv, taskRootFinal, internals?.fileHistoryLineage, sessionId);
|
|
1564
|
+
if (fileHistoryStore !== undefined && internals?.fileHistoryLineage === undefined)
|
|
1565
|
+
await adoptForkedFileHistory(fileHistoryStore, session, sessionId, deps.onError);
|
|
1566
|
+
if (rewindTarget !== undefined && historyScope !== sessionId)
|
|
1567
|
+
throw childScopeRewindRefusal(historyScope, rewindTarget);
|
|
1518
1568
|
if (fileHistoryStore === undefined) {
|
|
1519
1569
|
if (rewindTarget !== undefined) {
|
|
1520
1570
|
const e = new Error(`rewind-files: restoring files to entry "${rewindTarget}" requires a history backend, but this deployment wired no RunnerDeps.fileHistoryStore — no file history was ever recorded, so the files were NOT rewound`);
|
|
@@ -1591,14 +1641,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1591
1641
|
}
|
|
1592
1642
|
const trackFileEdit = fileHistoryEnabled
|
|
1593
1643
|
? async (req) => {
|
|
1594
|
-
const r = await fileHistoryStore.trackEdit(
|
|
1644
|
+
const r = await fileHistoryStore.trackEdit(historyScope, req.key, executionEnv, historyRoot, req.signal);
|
|
1595
1645
|
if (r.ok) {
|
|
1596
1646
|
if (!r.minted)
|
|
1597
1647
|
return { ok: true };
|
|
1598
1648
|
return {
|
|
1599
1649
|
ok: true,
|
|
1600
1650
|
annul: async (proof) => {
|
|
1601
|
-
const a = await fileHistoryStore.annulTrack(
|
|
1651
|
+
const a = await fileHistoryStore.annulTrack(historyScope, req.key, historyRoot, proof === "verify" ? { env: executionEnv, ...(req.signal !== undefined ? { signal: req.signal } : {}) } : undefined);
|
|
1602
1652
|
if (a.ok)
|
|
1603
1653
|
return;
|
|
1604
1654
|
try {
|
|
@@ -1623,7 +1673,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1623
1673
|
};
|
|
1624
1674
|
}
|
|
1625
1675
|
: undefined;
|
|
1626
|
-
const
|
|
1676
|
+
const { note: noteFileEdited, snapshot: editedFilesSnapshot } = createEditedFilesLedger();
|
|
1677
|
+
const fileHistoryBoundary = fileHistoryEnabled && historyScope === sessionId
|
|
1627
1678
|
? createFileHistoryBoundarySeat({ store: fileHistoryStore, sessionId, env: executionEnv, root: historyRoot, onError: deps.onError })
|
|
1628
1679
|
: undefined;
|
|
1629
1680
|
const harnessRef = {};
|
|
@@ -1680,7 +1731,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1680
1731
|
: shellGateRank[liveShellGate] >= shellGateRank[seedShellGate]
|
|
1681
1732
|
? liveShellGate
|
|
1682
1733
|
: seedShellGate;
|
|
1683
|
-
const inheritedParentConstraints = liveInheritedGate?.parentConstraints;
|
|
1734
|
+
const inheritedParentConstraints = attachRebuiltDenialTrackers(liveInheritedGate?.parentConstraints, deps.autoMode?.denialLimit);
|
|
1684
1735
|
const autoModeIntent = autoModeSeat || liveInheritedGate?.autoModeRequested === true || seedInheritedGate?.autoModeRequested === true;
|
|
1685
1736
|
const liveAdmittedOrg = liveInheritedGate?.admittedOrgScopes;
|
|
1686
1737
|
const seedAdmittedOrg = seedInheritedGate?.admittedOrgScopes;
|
|
@@ -1769,7 +1820,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1769
1820
|
...(durableMandate ? { durableMandate: true } : {}),
|
|
1770
1821
|
...(contentMandate ? { contentMandate: true } : {}),
|
|
1771
1822
|
...(autoModeDecider !== undefined
|
|
1772
|
-
? { autoMode: { decider: autoModeDecider, ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1823
|
+
? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1773
1824
|
: {}),
|
|
1774
1825
|
},
|
|
1775
1826
|
]
|
|
@@ -1785,7 +1836,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1785
1836
|
...(durableMandate ? { durableMandate: true } : {}),
|
|
1786
1837
|
...(contentMandate ? { contentMandate: true } : {}),
|
|
1787
1838
|
...(autoModeDecider !== undefined
|
|
1788
|
-
? { autoMode: { decider: autoModeDecider, ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1839
|
+
? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1789
1840
|
: {}),
|
|
1790
1841
|
},
|
|
1791
1842
|
]
|
|
@@ -1811,6 +1862,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1811
1862
|
spec.handsReadOnly !== true &&
|
|
1812
1863
|
!(toolFaceSnapshot.exclude?.includes("Bash") ?? false);
|
|
1813
1864
|
let autoModeDecider;
|
|
1865
|
+
let autoModeDenialTracking;
|
|
1866
|
+
const { gateStopRef, stopForDenialLimit } = createDenialLimitStop({ sessionId, runId, onNotice: deps.onNotice, abort: () => { abortController.abort(); void harness.abort(); } });
|
|
1814
1867
|
let autoModeArming;
|
|
1815
1868
|
const delegationEntryCapsResolved = resolveDelegationEntryCaps(deps.delegationEntryCaps);
|
|
1816
1869
|
const enrichSpecToolCtx = (ctx) => ({
|
|
@@ -1852,6 +1905,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1852
1905
|
},
|
|
1853
1906
|
getApiKeyAndHeaders: spec.getApiKeyAndHeaders,
|
|
1854
1907
|
parentCwd: taskRootFinal,
|
|
1908
|
+
...(fileHistoryEnabled ? { fileHistoryLineage: { scope: historyScope, root: historyRoot, fs: historyFs } } : {}),
|
|
1855
1909
|
reminderMark,
|
|
1856
1910
|
reminderDisclosureCounts,
|
|
1857
1911
|
...(centerAdoption !== undefined ? { centerArtifactDigest: centerAdoption.artifact.artifactDigest } : {}),
|
|
@@ -1977,6 +2031,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1977
2031
|
}
|
|
1978
2032
|
agentForkDenial = forkGovernanceDenial(spec.enableFork, runtimeCaps?.allowFork);
|
|
1979
2033
|
observersActive = runtimeCaps?.allowObservers === true;
|
|
2034
|
+
const autoModeArmReason = autoModeArmReasonOf(autoModeIntent, deps.autoMode !== undefined, runtimeCaps?.autoMode, runtimeCapsFaulted);
|
|
1980
2035
|
if (autoModeIntent && deps.autoMode !== undefined && runtimeCaps?.autoMode !== false) {
|
|
1981
2036
|
const am = deps.autoMode;
|
|
1982
2037
|
let classifierModel;
|
|
@@ -1992,6 +2047,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1992
2047
|
const classifierLaneRule = peerLaneActive && peerSendMessageBuiltIn;
|
|
1993
2048
|
const classifierSystemPrompt = buildAutoModePrompt(classifierLaneRule ? { ...am, crossSessionMessagesRule: CROSS_SESSION_CLASSIFIER_RULE } : am);
|
|
1994
2049
|
const classifierRuntime = brainToRuntime(deps.brain);
|
|
2050
|
+
autoModeDenialTracking = createAutoModeDenialTracker(am.denialLimit);
|
|
1995
2051
|
autoModeDecider = createAutoModeDecider({
|
|
1996
2052
|
...(am.timeoutMs !== undefined ? { timeoutMs: am.timeoutMs } : {}),
|
|
1997
2053
|
...(am.failureThreshold !== undefined ? { failureThreshold: am.failureThreshold } : {}),
|
|
@@ -2301,7 +2357,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2301
2357
|
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
2302
2358
|
const callIssuedAtRef = {};
|
|
2303
2359
|
const memoryWriteGateRef = {};
|
|
2304
|
-
const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark, reminderDisclosureCounts, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
|
|
2360
|
+
const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark, reminderDisclosureCounts, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
|
|
2305
2361
|
const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
|
|
2306
2362
|
const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher, envHandToolNames, sealReadStateSeat } = handsReadFace;
|
|
2307
2363
|
resolvedReadFace = handsReadFace.resolvedReadFace;
|
|
@@ -2340,6 +2396,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2340
2396
|
enrichCtx: enrichSpecToolCtx,
|
|
2341
2397
|
...(deps.rosterStore !== undefined ? { roster: deps.rosterStore } : {}),
|
|
2342
2398
|
...(deps.peerAdmission !== undefined ? { admission: deps.peerAdmission } : {}),
|
|
2399
|
+
...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}),
|
|
2343
2400
|
...(internals?.peerSelfRef !== undefined ? { peerSelf: internals.peerSelfRef } : {}),
|
|
2344
2401
|
...(internals?.peerInboundChainRef !== undefined ? { peerInbound: internals.peerInboundChainRef } : {}),
|
|
2345
2402
|
...(deps.onBackgroundChildEvent ? { onBackgroundChildEvent: deps.onBackgroundChildEvent } : {}),
|
|
@@ -3613,7 +3670,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3613
3670
|
stream: withBrainCallGuardrail((m, c, o) => deps.brain.stream(m, c, o), brainCallGuardrailMs, brainCallGuardrailRef),
|
|
3614
3671
|
};
|
|
3615
3672
|
const harness = new AgentHarness({
|
|
3616
|
-
abortResultDetails: () => parkContaminationMarker({ suspendRef, reviewRef }),
|
|
3673
|
+
abortResultDetails: () => (gateStopRef.terminal !== undefined ? { code: gateStopRef.terminal.code } : parkContaminationMarker({ suspendRef, reviewRef })),
|
|
3674
|
+
onToolInputValidationFault: validateInputFaultNotice(deps.onError, sessionId),
|
|
3617
3675
|
...(spec.limits?.maxOutputTokens !== undefined && spec.limits.maxOutputTokens > 0
|
|
3618
3676
|
? { maxOutputTokens: spec.limits.maxOutputTokens }
|
|
3619
3677
|
: {}),
|
|
@@ -3969,8 +4027,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3969
4027
|
cwdRef: handsCwdRef,
|
|
3970
4028
|
deniesDirectoryRead: readDenyMatcher !== undefined ? (d) => readDenyMatcher.matchPath(d) !== null : undefined,
|
|
3971
4029
|
});
|
|
3972
|
-
const
|
|
3973
|
-
const recheckApprovedEdit = async (pol, onAskOf, creq, edit, csignal, ancestorDecider) => {
|
|
4030
|
+
const recheckApprovedEdit = async (pol, onAskOf, creq, edit, csignal, ancestorDecider, ancestorTracker) => {
|
|
3974
4031
|
let editArgs = edit;
|
|
3975
4032
|
for (let round = 0;; round++) {
|
|
3976
4033
|
if (round >= 3) {
|
|
@@ -3996,22 +4053,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3996
4053
|
}
|
|
3997
4054
|
if (re.updatedInput !== undefined)
|
|
3998
4055
|
editArgs = re.updatedInput;
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
4007
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
4008
|
-
return {
|
|
4009
|
-
action: "deny",
|
|
4010
|
-
message: `auto-mode classifier blocked the approved edit at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
4011
|
-
decisionReason: "classifier",
|
|
4012
|
-
};
|
|
4013
|
-
}
|
|
4014
|
-
}
|
|
4056
|
+
const judged = await judgeInheritedClassifier({ autoMode: ancestorDecider !== undefined ? { decider: ancestorDecider, denialTracking: ancestorTracker } : undefined, ask: re, req: { ...creq, args: editArgs }, signal: csignal ?? abortController.signal, subject: "the approved edit" });
|
|
4057
|
+
if (judged.kind === "allow")
|
|
4058
|
+
return { action: "allow", updatedInput: editArgs };
|
|
4059
|
+
if (judged.kind === "deny")
|
|
4060
|
+
return judged.result;
|
|
4061
|
+
const { ask: editAsk, fallback: editFallback, mintedHere: editMintedHere } = judged;
|
|
4062
|
+
re = editAsk;
|
|
4015
4063
|
const rr = await resolveAsk({
|
|
4016
4064
|
toolName: creq.toolName,
|
|
4017
4065
|
toolCallId: creq.toolCallId,
|
|
@@ -4022,8 +4070,10 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4022
4070
|
...riskAxesOf(creq.toolName),
|
|
4023
4071
|
...(re.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4024
4072
|
...(re.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: re.persistedRuleShadowed } : {}),
|
|
4073
|
+
...(editFallback !== undefined ? { denialLimitFallback: editFallback } : {}),
|
|
4025
4074
|
ruleEvidence: inheritedAskEvidence,
|
|
4026
|
-
}, onAskOf, csignal ?? abortController.signal);
|
|
4075
|
+
}, onAskOf, csignal ?? abortController.signal, lateAskSettlementObserver({ toolName: creq.toolName, toolCallId: creq.toolCallId, sessionId, runId, ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}), onNotice: deps.onNotice, onError: deps.onError }));
|
|
4076
|
+
settleDenialLimitFallback({ fallback: editFallback, mintedHere: editMintedHere, tracker: ancestorTracker, resolved: rr, headless: headlessDenyAtRecheck, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
4027
4077
|
if (rr.action !== "allow")
|
|
4028
4078
|
return rr;
|
|
4029
4079
|
if (rr.updatedInput === undefined)
|
|
@@ -4076,23 +4126,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4076
4126
|
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
4077
4127
|
};
|
|
4078
4128
|
}
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
4087
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
4088
|
-
return {
|
|
4089
|
-
action: "deny",
|
|
4090
|
-
message: `auto-mode classifier blocked this call at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
4091
|
-
decisionReason: "classifier",
|
|
4092
|
-
};
|
|
4093
|
-
}
|
|
4094
|
-
}
|
|
4095
|
-
if (sandboxAdmissionArmed && policyAskClassOf(pc.policy) === "sandbox_local" && !sandboxBoundaryCapable(creq.toolName)) {
|
|
4129
|
+
const judged = await judgeInheritedClassifier({ autoMode: pc.autoMode, ask: first, req: creq, signal: csignal ?? abortController.signal, subject: "this call" });
|
|
4130
|
+
if (judged.kind === "allow")
|
|
4131
|
+
return { action: "allow" };
|
|
4132
|
+
if (judged.kind === "deny")
|
|
4133
|
+
return judged.result;
|
|
4134
|
+
const { ask: inheritedAsk, fallback, mintedHere } = judged;
|
|
4135
|
+
if (fallback === undefined && sandboxAdmissionArmed && policyAskClassOf(pc.policy) === "sandbox_local" && !sandboxBoundaryCapable(creq.toolName)) {
|
|
4096
4136
|
recordAncestorSandboxAdmission(creq.toolCallId, creq.toolName);
|
|
4097
4137
|
return { action: "allow" };
|
|
4098
4138
|
}
|
|
@@ -4102,27 +4142,29 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4102
4142
|
toolName: creq.toolName,
|
|
4103
4143
|
toolCallId: creq.toolCallId,
|
|
4104
4144
|
args: presentedArgs,
|
|
4105
|
-
...ruleOffersOf(creq.toolName, presentedArgs, { ...(
|
|
4106
|
-
message:
|
|
4145
|
+
...ruleOffersOf(creq.toolName, presentedArgs, { ...(inheritedAsk.action === "ask" ? inheritedAsk : {}), ancestorResolved: true }),
|
|
4146
|
+
message: inheritedAsk.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
4107
4147
|
...askSourceIdentity(),
|
|
4108
4148
|
...riskAxesOf(creq.toolName),
|
|
4109
|
-
...(
|
|
4110
|
-
...(
|
|
4149
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4150
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: inheritedAsk.persistedRuleShadowed } : {}),
|
|
4151
|
+
...(fallback !== undefined ? { denialLimitFallback: fallback } : {}),
|
|
4111
4152
|
ruleEvidence: inheritedAskEvidence,
|
|
4112
|
-
}, pc.onAsk, csignal ?? abortController.signal);
|
|
4153
|
+
}, pc.onAsk, csignal ?? abortController.signal, lateAskSettlementObserver({ toolName: creq.toolName, toolCallId: creq.toolCallId, sessionId, runId, ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}), onNotice: deps.onNotice, onError: deps.onError }));
|
|
4113
4154
|
const askWaitMs = Math.max(0, now() - askT0);
|
|
4114
4155
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
4115
4156
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
4116
|
-
return
|
|
4157
|
+
return inheritedAsk;
|
|
4117
4158
|
return {
|
|
4118
4159
|
action: "deny",
|
|
4119
4160
|
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
4120
4161
|
};
|
|
4121
4162
|
}
|
|
4163
|
+
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
4122
4164
|
if (resolved.action !== "allow")
|
|
4123
4165
|
return resolved;
|
|
4124
4166
|
if (resolved.updatedInput !== undefined) {
|
|
4125
|
-
return recheckApprovedEdit(pc.policy, pc.onAsk, creq, resolved.updatedInput, csignal, pc.autoMode?.decider);
|
|
4167
|
+
return recheckApprovedEdit(pc.policy, pc.onAsk, creq, resolved.updatedInput, csignal, pc.autoMode?.decider, pc.autoMode?.denialTracking);
|
|
4126
4168
|
}
|
|
4127
4169
|
recordInheritedAskGrant(creq.toolCallId, pc.onAsk, resolved.presentedInput, askWaitMs);
|
|
4128
4170
|
return { action: "allow" };
|
|
@@ -4164,24 +4206,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4164
4206
|
};
|
|
4165
4207
|
}
|
|
4166
4208
|
const presentedArgs = decision.updatedInput !== undefined ? decision.updatedInput : creq.args;
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
if (verdict.kind === "block") {
|
|
4175
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
4176
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
4177
|
-
return {
|
|
4178
|
-
action: "deny",
|
|
4179
|
-
message: `auto-mode classifier blocked this call at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
4180
|
-
decisionReason: "classifier",
|
|
4181
|
-
};
|
|
4182
|
-
}
|
|
4183
|
-
}
|
|
4184
|
-
if (sandboxAdmissionArmed && policyAskClassOf(pc.policy) === "sandbox_local" && !sandboxBoundaryCapable(creq.toolName)) {
|
|
4209
|
+
const judged = await judgeInheritedClassifier({ autoMode: pc.autoMode, ask: decision, req: { ...creq, args: presentedArgs }, signal: csignal ?? abortController.signal, subject: "this call" });
|
|
4210
|
+
if (judged.kind === "allow")
|
|
4211
|
+
return decision.updatedInput !== undefined ? { action: "allow", updatedInput: decision.updatedInput } : { action: "allow" };
|
|
4212
|
+
if (judged.kind === "deny")
|
|
4213
|
+
return judged.result;
|
|
4214
|
+
const { ask: inheritedAsk, fallback, mintedHere } = judged;
|
|
4215
|
+
if (fallback === undefined && sandboxAdmissionArmed && policyAskClassOf(pc.policy) === "sandbox_local" && !sandboxBoundaryCapable(creq.toolName)) {
|
|
4185
4216
|
recordAncestorSandboxAdmission(creq.toolCallId, creq.toolName);
|
|
4186
4217
|
return decision.updatedInput !== undefined ? { action: "allow", updatedInput: decision.updatedInput } : { action: "allow" };
|
|
4187
4218
|
}
|
|
@@ -4190,27 +4221,29 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4190
4221
|
toolName: creq.toolName,
|
|
4191
4222
|
toolCallId: creq.toolCallId,
|
|
4192
4223
|
args: presentedArgs,
|
|
4193
|
-
...ruleOffersOf(creq.toolName, presentedArgs, { ...(
|
|
4194
|
-
message:
|
|
4224
|
+
...ruleOffersOf(creq.toolName, presentedArgs, { ...(inheritedAsk.action === "ask" ? inheritedAsk : {}), ancestorResolved: true }),
|
|
4225
|
+
message: inheritedAsk.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
4195
4226
|
...askSourceIdentity(),
|
|
4196
4227
|
...riskAxesOf(creq.toolName),
|
|
4197
|
-
...(
|
|
4198
|
-
...(
|
|
4228
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4229
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: inheritedAsk.persistedRuleShadowed } : {}),
|
|
4230
|
+
...(fallback !== undefined ? { denialLimitFallback: fallback } : {}),
|
|
4199
4231
|
ruleEvidence: inheritedAskEvidence,
|
|
4200
|
-
}, pc.onAsk, csignal ?? abortController.signal);
|
|
4232
|
+
}, pc.onAsk, csignal ?? abortController.signal, lateAskSettlementObserver({ toolName: creq.toolName, toolCallId: creq.toolCallId, sessionId, runId, ...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}), onNotice: deps.onNotice, onError: deps.onError }));
|
|
4201
4233
|
const askWaitMs = Math.max(0, now() - askT0);
|
|
4202
4234
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
4203
4235
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
4204
|
-
return
|
|
4236
|
+
return inheritedAsk;
|
|
4205
4237
|
return {
|
|
4206
4238
|
action: "deny",
|
|
4207
4239
|
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
4208
4240
|
};
|
|
4209
4241
|
}
|
|
4242
|
+
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
4210
4243
|
if (resolved.action !== "allow")
|
|
4211
4244
|
return resolved;
|
|
4212
4245
|
if (resolved.updatedInput !== undefined) {
|
|
4213
|
-
return recheckApprovedEdit(pc.policy, pc.onAsk, creq, resolved.updatedInput, csignal, pc.autoMode?.decider);
|
|
4246
|
+
return recheckApprovedEdit(pc.policy, pc.onAsk, creq, resolved.updatedInput, csignal, pc.autoMode?.decider, pc.autoMode?.denialTracking);
|
|
4214
4247
|
}
|
|
4215
4248
|
if (pc.preToolUse === undefined) {
|
|
4216
4249
|
recordInheritedAskGrant(creq.toolCallId, pc.onAsk, resolved.presentedInput, askWaitMs);
|
|
@@ -4400,10 +4433,21 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4400
4433
|
memoryAdmissionWired: deps.memoryScopeAdmission !== undefined,
|
|
4401
4434
|
retentionPolicyWired: deps.retentionPolicy !== undefined,
|
|
4402
4435
|
...(modelGateManifest !== undefined ? { modelGate: modelGateManifest } : {}),
|
|
4436
|
+
autoMode: { armed: autoModeArmReason === "armed", reason: autoModeArmReason },
|
|
4403
4437
|
});
|
|
4404
4438
|
peerLaneRefs.askEffective = wiringManifest.ask.effective;
|
|
4405
4439
|
if (peerLaneActive && internals?.onTaskNotification !== undefined) {
|
|
4406
|
-
bindPeerLaneDrain(harness, {
|
|
4440
|
+
bindPeerLaneDrain(harness, {
|
|
4441
|
+
deps,
|
|
4442
|
+
sessionId,
|
|
4443
|
+
runId,
|
|
4444
|
+
scope: taskScope,
|
|
4445
|
+
inject: internals.onTaskNotification,
|
|
4446
|
+
ownTokens: () => internals?.peerSelfRef?.current.ownTokens ?? [],
|
|
4447
|
+
refs: peerLaneRefs,
|
|
4448
|
+
selfName: () => internals?.explicitAgentName,
|
|
4449
|
+
parked: () => suspendRef.token !== undefined || reviewRef.token !== undefined,
|
|
4450
|
+
});
|
|
4407
4451
|
}
|
|
4408
4452
|
const parkLaneArmed = wiringManifest.parkLane.effective === true;
|
|
4409
4453
|
announceDurableGateUnavailable({ onNotice: deps.onNotice, forceDurableGate: runtimeCaps?.forceDurableGate === true, storeWired: checkpointStore !== undefined, taskStoreNull: spec.checkpointStore === null, liveApprover: isLiveApproverSeat(frozenOnAsk), liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
|
|
@@ -4465,6 +4509,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4465
4509
|
...riskAxesOf(req.toolName),
|
|
4466
4510
|
...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4467
4511
|
...(decision.action === "ask" && decision.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: decision.persistedRuleShadowed } : {}),
|
|
4512
|
+
...(decision.action === "ask" && decision.denialLimitFallback !== undefined ? { denialLimitFallback: decision.denialLimitFallback } : {}),
|
|
4468
4513
|
...(decision.action === "ask" && decision.probeReason !== undefined ? { probeReason: decision.probeReason } : {}),
|
|
4469
4514
|
...(decision.action === "ask" && decision.probeCause !== undefined ? { probeCause: decision.probeCause } : {}),
|
|
4470
4515
|
...(decision.action === "ask" && decision.ruleEvidence !== undefined ? { ruleEvidence: decision.ruleEvidence } : {}),
|
|
@@ -5276,7 +5321,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
5276
5321
|
...(notifyPermissionDenied ? { permissionDenied: notifyPermissionDenied } : {}),
|
|
5277
5322
|
onHookError: notifyHookError,
|
|
5278
5323
|
shellGated: (e.toolName === "Bash" && shellGatedBash) || (e.toolName === "Monitor" && shellGatedMonitor),
|
|
5279
|
-
...(autoModeDecider ? { autoMode: { decider: autoModeDecider } } : {}),
|
|
5324
|
+
...(autoModeDecider ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}) } } : {}),
|
|
5325
|
+
onHeadlessDenialLimit: stopForDenialLimit,
|
|
5280
5326
|
...(permissionRuleLane
|
|
5281
5327
|
? {
|
|
5282
5328
|
persistedRules: {
|
|
@@ -5714,7 +5760,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
5714
5760
|
const effectiveReadFaceObserved = carrierReadFace();
|
|
5715
5761
|
const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
|
|
5716
5762
|
const preparedHolder = {};
|
|
5717
|
-
const buildPrepared = () => ({ harness, session, sessionId, runId, reminderMark, reminderDisclosureCounts, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
5763
|
+
const buildPrepared = () => ({ harness, session, sessionId, runId, reminderMark, reminderDisclosureCounts, editedFilesSnapshot, taskRootPath: taskRootFinal, model, thinking, compModel: effectiveCompModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, batchHaltRef, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(fileHistoryBoundary !== undefined ? { fileHistoryBoundary } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), ...(sealReadStateSeat !== undefined ? { sealReadStateSeat } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, gateStopRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, microCompact, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(projectInstructionContent !== undefined ? { projectInstructionContent } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, hookTimeoutMs, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
5718
5764
|
const prepared = buildPrepared();
|
|
5719
5765
|
preparedHolder.current = prepared;
|
|
5720
5766
|
return prepared;
|
|
@@ -1779,6 +1779,10 @@ export class Runner {
|
|
|
1779
1779
|
...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
|
|
1780
1780
|
...(taskIdRef.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: taskIdRef.effectiveMemoryScopes } : {}),
|
|
1781
1781
|
...(taskIdRef.effectiveReasoning !== undefined ? { effectiveReasoning: taskIdRef.effectiveReasoning } : {}),
|
|
1782
|
+
...(() => {
|
|
1783
|
+
const observed = taskIdRef.editedFiles?.();
|
|
1784
|
+
return observed !== undefined && observed.length > 0 ? { editedFiles: observed } : {};
|
|
1785
|
+
})(),
|
|
1782
1786
|
...(() => {
|
|
1783
1787
|
const hinted = err.retryAfterMs;
|
|
1784
1788
|
return code === "memory.admission_required" && typeof hinted === "number" && Number.isFinite(hinted) && hinted > 0
|
|
@@ -2349,6 +2353,8 @@ export class Runner {
|
|
|
2349
2353
|
notificationSessionId = prepared.sessionId;
|
|
2350
2354
|
if (taskIdRef)
|
|
2351
2355
|
taskIdRef.effectiveMemoryScopes = prepared.effectiveMemoryScopes;
|
|
2356
|
+
if (taskIdRef)
|
|
2357
|
+
taskIdRef.editedFiles = prepared.editedFilesSnapshot;
|
|
2352
2358
|
const runSourceTaskId = spec.taskId ?? prepared.sessionId;
|
|
2353
2359
|
const parentToolCallId = internals?.parentToolCallId;
|
|
2354
2360
|
const ident = () => parentToolCallId !== undefined ? { eventId: uuidv7(), parentToolCallId, sourceTaskId: runSourceTaskId } : { eventId: uuidv7() };
|
|
@@ -2872,6 +2878,8 @@ export class Runner {
|
|
|
2872
2878
|
...(s.retryInSec !== undefined ? { retryInSec: s.retryInSec } : {}),
|
|
2873
2879
|
...(s.retryInMs !== undefined ? { retryInMs: s.retryInMs } : {}),
|
|
2874
2880
|
...(s.retryAtMs !== undefined ? { retryAtMs: s.retryAtMs } : {}),
|
|
2881
|
+
...(s.elapsedMs !== undefined ? { elapsedMs: s.elapsedMs } : {}),
|
|
2882
|
+
...(s.timeoutMs !== undefined ? { timeoutMs: s.timeoutMs } : {}),
|
|
2875
2883
|
...(s.attempt !== undefined ? { attempt: s.attempt } : {}),
|
|
2876
2884
|
...(s.maxRetries !== undefined ? { maxRetries: s.maxRetries } : {}),
|
|
2877
2885
|
...(s.errClass !== undefined ? { errClass: s.errClass } : {}),
|
|
@@ -3886,6 +3894,9 @@ export class Runner {
|
|
|
3886
3894
|
if (threw === undefined && prepared.brainCallGuardrailRef.timedOut !== undefined) {
|
|
3887
3895
|
threw = prepared.brainCallGuardrailRef.timedOut;
|
|
3888
3896
|
}
|
|
3897
|
+
if (threw === undefined && prepared.gateStopRef.terminal !== undefined) {
|
|
3898
|
+
threw = prepared.gateStopRef.terminal;
|
|
3899
|
+
}
|
|
3889
3900
|
if (rs.limits.platformTerminal !== undefined) {
|
|
3890
3901
|
threw = rs.limits.platformTerminal;
|
|
3891
3902
|
}
|
|
@@ -4069,6 +4080,7 @@ export class Runner {
|
|
|
4069
4080
|
model: prepared.model.id,
|
|
4070
4081
|
unpricedSpend: rs.telemetry.unpricedSpend,
|
|
4071
4082
|
rewindNotes: prepared.rewindNotes,
|
|
4083
|
+
editedFiles: prepared.editedFilesSnapshot(),
|
|
4072
4084
|
haltedOnUserRejection: prepared.batchHaltRef.current !== undefined,
|
|
4073
4085
|
userHalted: loopLatch.userHalted,
|
|
4074
4086
|
strandedHumanAnswers,
|
|
@@ -15,12 +15,22 @@ import type { ToolPolicy } from "./tool-policy.js";
|
|
|
15
15
|
* segments is a wiring ERROR (it would guard nothing) and throws rather than being dropped.
|
|
16
16
|
* Remember this policy guards WRITES only; reads are out of scope by design.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* HRD-PRM-10 — sema's own data root (`$AGENT_DATA_DIR ?? ~/.ai-agent`) is excluded BY CONSTRUCTION,
|
|
19
|
+
* not by the absence of an entry. The exclusion used to be "just don't add a pattern that names it",
|
|
20
|
+
* which held only as long as no entry happened to match one of its ANCESTOR segments. That assumption
|
|
21
|
+
* died the moment the shell's own config root joined the list: the shell sets
|
|
22
|
+
* `AGENT_DATA_DIR = <configRoot>/engine-data` with a configRoot of `~/.sema`, so every path under the
|
|
23
|
+
* data root carries a `.sema` segment, and a pattern guarding the config root swallowed the whole data
|
|
24
|
+
* root with it — including the memory library the model is INSTRUCTED to write with the Write tool
|
|
25
|
+
* (`MEMORY_INSTRUCTION_TEMPLATE`), i.e. every memory write refused, on a default server wiring.
|
|
26
|
+
* So the exclusion is now mechanical: a target INSIDE the data root is matched on its path RELATIVE to
|
|
27
|
+
* that root (see {@link createSensitivePathPolicy}'s `dataRoot`), so the root's own ancestry is not the
|
|
28
|
+
* target's business, while a genuinely sensitive path INSIDE it (`<dataRoot>/x/.ssh/id_rsa`) still
|
|
29
|
+
* matches. The `sessions/` subtree keeps its own owner: `createTranscriptIntegrityPolicy` is wired
|
|
30
|
+
* ALWAYS-ON by the runner and answers `ask` — the design's deliberate verdict, since «reading
|
|
31
|
+
* transcripts is routine» and a legitimate operator write must remain clearable by judgment — and a
|
|
32
|
+
* deny here would outrank that ask under the deny > ask > allow fold and silently convert it into a
|
|
33
|
+
* hard refusal for every deployment that wires this list.
|
|
24
34
|
*/
|
|
25
35
|
export declare const RECOMMENDED_SENSITIVE_PATTERNS: readonly string[];
|
|
26
36
|
/**
|
|
@@ -46,6 +56,17 @@ export declare function createSensitivePathPolicy(opts: {
|
|
|
46
56
|
/** `readonly` accepted so {@link RECOMMENDED_SENSITIVE_PATTERNS} can be passed as-is (widening, non-breaking). */
|
|
47
57
|
patterns: readonly string[];
|
|
48
58
|
rootPath?: string;
|
|
59
|
+
/**
|
|
60
|
+
* HRD-PRM-10 — the engine data root this deployment runs on. Default
|
|
61
|
+
* `$AGENT_DATA_DIR ?? ~/.ai-agent`, the same resolution
|
|
62
|
+
* {@link import("./tool-policy.js").createTranscriptIntegrityPolicy} performs for its own default.
|
|
63
|
+
* A target inside it is judged on its path RELATIVE to it, so the root's own ancestor segments
|
|
64
|
+
* (`.sema`, when a deployment sites its data root under its config root) cannot make the whole
|
|
65
|
+
* subtree — the memory library the model is instructed to WRITE included — read as a guarded path.
|
|
66
|
+
* Pass it explicitly whenever the deployment passes `memoryEngineDir`/a custom data root, so this
|
|
67
|
+
* gate and the transcript gate keep speaking about the same directory.
|
|
68
|
+
*/
|
|
69
|
+
dataRoot?: string;
|
|
49
70
|
/** Override the guarded tool set (default: `Write`, `Edit`, `MultiEdit`-legacy → Edit, `NotebookEdit`). */
|
|
50
71
|
tools?: string[];
|
|
51
72
|
}): ToolPolicy;
|