@sema-agent/core 7.3.1 → 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 +35 -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/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 +120 -89
- package/dist/core/runner/runtask.js +10 -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/types.d.ts +207 -10
- package/dist/index.d.ts +10 -5
- package/dist/index.js +8 -3
- package/dist/orchestration/workflow.js +7 -3
- package/dist/tools/fs/fs-write.d.ts +4 -4
- package/dist/tools/fs/fs-write.js +30 -11
- 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 +169 -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;
|
|
@@ -1486,9 +1528,6 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1486
1528
|
throw e;
|
|
1487
1529
|
}
|
|
1488
1530
|
const fileHistoryStore = resolveWiredFileHistoryStore(deps.fileHistoryStore);
|
|
1489
|
-
if (fileHistoryStore !== undefined) {
|
|
1490
|
-
await adoptForkedFileHistory(fileHistoryStore, session, sessionId, deps.onError);
|
|
1491
|
-
}
|
|
1492
1531
|
const legacyRewindFiles = spec.rewindFiles;
|
|
1493
1532
|
if (legacyRewindFiles === true) {
|
|
1494
1533
|
if (spec.resumeAt !== undefined) {
|
|
@@ -1521,12 +1560,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1521
1560
|
});
|
|
1522
1561
|
}
|
|
1523
1562
|
const fileHistoryEnabled = fileHistoryStore !== undefined && handsEnabled;
|
|
1524
|
-
|
|
1525
|
-
if (
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
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);
|
|
1530
1568
|
if (fileHistoryStore === undefined) {
|
|
1531
1569
|
if (rewindTarget !== undefined) {
|
|
1532
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`);
|
|
@@ -1603,14 +1641,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1603
1641
|
}
|
|
1604
1642
|
const trackFileEdit = fileHistoryEnabled
|
|
1605
1643
|
? async (req) => {
|
|
1606
|
-
const r = await fileHistoryStore.trackEdit(
|
|
1644
|
+
const r = await fileHistoryStore.trackEdit(historyScope, req.key, executionEnv, historyRoot, req.signal);
|
|
1607
1645
|
if (r.ok) {
|
|
1608
1646
|
if (!r.minted)
|
|
1609
1647
|
return { ok: true };
|
|
1610
1648
|
return {
|
|
1611
1649
|
ok: true,
|
|
1612
1650
|
annul: async (proof) => {
|
|
1613
|
-
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);
|
|
1614
1652
|
if (a.ok)
|
|
1615
1653
|
return;
|
|
1616
1654
|
try {
|
|
@@ -1635,7 +1673,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1635
1673
|
};
|
|
1636
1674
|
}
|
|
1637
1675
|
: undefined;
|
|
1638
|
-
const
|
|
1676
|
+
const { note: noteFileEdited, snapshot: editedFilesSnapshot } = createEditedFilesLedger();
|
|
1677
|
+
const fileHistoryBoundary = fileHistoryEnabled && historyScope === sessionId
|
|
1639
1678
|
? createFileHistoryBoundarySeat({ store: fileHistoryStore, sessionId, env: executionEnv, root: historyRoot, onError: deps.onError })
|
|
1640
1679
|
: undefined;
|
|
1641
1680
|
const harnessRef = {};
|
|
@@ -1692,7 +1731,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1692
1731
|
: shellGateRank[liveShellGate] >= shellGateRank[seedShellGate]
|
|
1693
1732
|
? liveShellGate
|
|
1694
1733
|
: seedShellGate;
|
|
1695
|
-
const inheritedParentConstraints = liveInheritedGate?.parentConstraints;
|
|
1734
|
+
const inheritedParentConstraints = attachRebuiltDenialTrackers(liveInheritedGate?.parentConstraints, deps.autoMode?.denialLimit);
|
|
1696
1735
|
const autoModeIntent = autoModeSeat || liveInheritedGate?.autoModeRequested === true || seedInheritedGate?.autoModeRequested === true;
|
|
1697
1736
|
const liveAdmittedOrg = liveInheritedGate?.admittedOrgScopes;
|
|
1698
1737
|
const seedAdmittedOrg = seedInheritedGate?.admittedOrgScopes;
|
|
@@ -1781,7 +1820,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1781
1820
|
...(durableMandate ? { durableMandate: true } : {}),
|
|
1782
1821
|
...(contentMandate ? { contentMandate: true } : {}),
|
|
1783
1822
|
...(autoModeDecider !== undefined
|
|
1784
|
-
? { autoMode: { decider: autoModeDecider, ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1823
|
+
? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1785
1824
|
: {}),
|
|
1786
1825
|
},
|
|
1787
1826
|
]
|
|
@@ -1797,7 +1836,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1797
1836
|
...(durableMandate ? { durableMandate: true } : {}),
|
|
1798
1837
|
...(contentMandate ? { contentMandate: true } : {}),
|
|
1799
1838
|
...(autoModeDecider !== undefined
|
|
1800
|
-
? { autoMode: { decider: autoModeDecider, ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1839
|
+
? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}), ...(autoModeArming !== undefined ? { arming: autoModeArming } : {}) } }
|
|
1801
1840
|
: {}),
|
|
1802
1841
|
},
|
|
1803
1842
|
]
|
|
@@ -1823,6 +1862,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1823
1862
|
spec.handsReadOnly !== true &&
|
|
1824
1863
|
!(toolFaceSnapshot.exclude?.includes("Bash") ?? false);
|
|
1825
1864
|
let autoModeDecider;
|
|
1865
|
+
let autoModeDenialTracking;
|
|
1866
|
+
const { gateStopRef, stopForDenialLimit } = createDenialLimitStop({ sessionId, runId, onNotice: deps.onNotice, abort: () => { abortController.abort(); void harness.abort(); } });
|
|
1826
1867
|
let autoModeArming;
|
|
1827
1868
|
const delegationEntryCapsResolved = resolveDelegationEntryCaps(deps.delegationEntryCaps);
|
|
1828
1869
|
const enrichSpecToolCtx = (ctx) => ({
|
|
@@ -1864,6 +1905,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1864
1905
|
},
|
|
1865
1906
|
getApiKeyAndHeaders: spec.getApiKeyAndHeaders,
|
|
1866
1907
|
parentCwd: taskRootFinal,
|
|
1908
|
+
...(fileHistoryEnabled ? { fileHistoryLineage: { scope: historyScope, root: historyRoot, fs: historyFs } } : {}),
|
|
1867
1909
|
reminderMark,
|
|
1868
1910
|
reminderDisclosureCounts,
|
|
1869
1911
|
...(centerAdoption !== undefined ? { centerArtifactDigest: centerAdoption.artifact.artifactDigest } : {}),
|
|
@@ -2005,6 +2047,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2005
2047
|
const classifierLaneRule = peerLaneActive && peerSendMessageBuiltIn;
|
|
2006
2048
|
const classifierSystemPrompt = buildAutoModePrompt(classifierLaneRule ? { ...am, crossSessionMessagesRule: CROSS_SESSION_CLASSIFIER_RULE } : am);
|
|
2007
2049
|
const classifierRuntime = brainToRuntime(deps.brain);
|
|
2050
|
+
autoModeDenialTracking = createAutoModeDenialTracker(am.denialLimit);
|
|
2008
2051
|
autoModeDecider = createAutoModeDecider({
|
|
2009
2052
|
...(am.timeoutMs !== undefined ? { timeoutMs: am.timeoutMs } : {}),
|
|
2010
2053
|
...(am.failureThreshold !== undefined ? { failureThreshold: am.failureThreshold } : {}),
|
|
@@ -2314,7 +2357,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2314
2357
|
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
2315
2358
|
const callIssuedAtRef = {};
|
|
2316
2359
|
const memoryWriteGateRef = {};
|
|
2317
|
-
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 } : {}) };
|
|
2318
2361
|
const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
|
|
2319
2362
|
const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher, envHandToolNames, sealReadStateSeat } = handsReadFace;
|
|
2320
2363
|
resolvedReadFace = handsReadFace.resolvedReadFace;
|
|
@@ -2353,6 +2396,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2353
2396
|
enrichCtx: enrichSpecToolCtx,
|
|
2354
2397
|
...(deps.rosterStore !== undefined ? { roster: deps.rosterStore } : {}),
|
|
2355
2398
|
...(deps.peerAdmission !== undefined ? { admission: deps.peerAdmission } : {}),
|
|
2399
|
+
...(deps.onNotice !== undefined ? { onNotice: deps.onNotice } : {}),
|
|
2356
2400
|
...(internals?.peerSelfRef !== undefined ? { peerSelf: internals.peerSelfRef } : {}),
|
|
2357
2401
|
...(internals?.peerInboundChainRef !== undefined ? { peerInbound: internals.peerInboundChainRef } : {}),
|
|
2358
2402
|
...(deps.onBackgroundChildEvent ? { onBackgroundChildEvent: deps.onBackgroundChildEvent } : {}),
|
|
@@ -3626,7 +3670,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3626
3670
|
stream: withBrainCallGuardrail((m, c, o) => deps.brain.stream(m, c, o), brainCallGuardrailMs, brainCallGuardrailRef),
|
|
3627
3671
|
};
|
|
3628
3672
|
const harness = new AgentHarness({
|
|
3629
|
-
abortResultDetails: () => parkContaminationMarker({ suspendRef, reviewRef }),
|
|
3673
|
+
abortResultDetails: () => (gateStopRef.terminal !== undefined ? { code: gateStopRef.terminal.code } : parkContaminationMarker({ suspendRef, reviewRef })),
|
|
3630
3674
|
onToolInputValidationFault: validateInputFaultNotice(deps.onError, sessionId),
|
|
3631
3675
|
...(spec.limits?.maxOutputTokens !== undefined && spec.limits.maxOutputTokens > 0
|
|
3632
3676
|
? { maxOutputTokens: spec.limits.maxOutputTokens }
|
|
@@ -3983,8 +4027,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3983
4027
|
cwdRef: handsCwdRef,
|
|
3984
4028
|
deniesDirectoryRead: readDenyMatcher !== undefined ? (d) => readDenyMatcher.matchPath(d) !== null : undefined,
|
|
3985
4029
|
});
|
|
3986
|
-
const
|
|
3987
|
-
const recheckApprovedEdit = async (pol, onAskOf, creq, edit, csignal, ancestorDecider) => {
|
|
4030
|
+
const recheckApprovedEdit = async (pol, onAskOf, creq, edit, csignal, ancestorDecider, ancestorTracker) => {
|
|
3988
4031
|
let editArgs = edit;
|
|
3989
4032
|
for (let round = 0;; round++) {
|
|
3990
4033
|
if (round >= 3) {
|
|
@@ -4010,22 +4053,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4010
4053
|
}
|
|
4011
4054
|
if (re.updatedInput !== undefined)
|
|
4012
4055
|
editArgs = re.updatedInput;
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
4021
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
4022
|
-
return {
|
|
4023
|
-
action: "deny",
|
|
4024
|
-
message: `auto-mode classifier blocked the approved edit at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
4025
|
-
decisionReason: "classifier",
|
|
4026
|
-
};
|
|
4027
|
-
}
|
|
4028
|
-
}
|
|
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;
|
|
4029
4063
|
const rr = await resolveAsk({
|
|
4030
4064
|
toolName: creq.toolName,
|
|
4031
4065
|
toolCallId: creq.toolCallId,
|
|
@@ -4036,8 +4070,10 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4036
4070
|
...riskAxesOf(creq.toolName),
|
|
4037
4071
|
...(re.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4038
4072
|
...(re.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: re.persistedRuleShadowed } : {}),
|
|
4073
|
+
...(editFallback !== undefined ? { denialLimitFallback: editFallback } : {}),
|
|
4039
4074
|
ruleEvidence: inheritedAskEvidence,
|
|
4040
|
-
}, 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 });
|
|
4041
4077
|
if (rr.action !== "allow")
|
|
4042
4078
|
return rr;
|
|
4043
4079
|
if (rr.updatedInput === undefined)
|
|
@@ -4090,23 +4126,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4090
4126
|
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
4091
4127
|
};
|
|
4092
4128
|
}
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
4101
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
4102
|
-
return {
|
|
4103
|
-
action: "deny",
|
|
4104
|
-
message: `auto-mode classifier blocked this call at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
4105
|
-
decisionReason: "classifier",
|
|
4106
|
-
};
|
|
4107
|
-
}
|
|
4108
|
-
}
|
|
4109
|
-
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)) {
|
|
4110
4136
|
recordAncestorSandboxAdmission(creq.toolCallId, creq.toolName);
|
|
4111
4137
|
return { action: "allow" };
|
|
4112
4138
|
}
|
|
@@ -4116,27 +4142,29 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4116
4142
|
toolName: creq.toolName,
|
|
4117
4143
|
toolCallId: creq.toolCallId,
|
|
4118
4144
|
args: presentedArgs,
|
|
4119
|
-
...ruleOffersOf(creq.toolName, presentedArgs, { ...(
|
|
4120
|
-
message:
|
|
4145
|
+
...ruleOffersOf(creq.toolName, presentedArgs, { ...(inheritedAsk.action === "ask" ? inheritedAsk : {}), ancestorResolved: true }),
|
|
4146
|
+
message: inheritedAsk.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
4121
4147
|
...askSourceIdentity(),
|
|
4122
4148
|
...riskAxesOf(creq.toolName),
|
|
4123
|
-
...(
|
|
4124
|
-
...(
|
|
4149
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4150
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: inheritedAsk.persistedRuleShadowed } : {}),
|
|
4151
|
+
...(fallback !== undefined ? { denialLimitFallback: fallback } : {}),
|
|
4125
4152
|
ruleEvidence: inheritedAskEvidence,
|
|
4126
|
-
}, 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 }));
|
|
4127
4154
|
const askWaitMs = Math.max(0, now() - askT0);
|
|
4128
4155
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
4129
4156
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
4130
|
-
return
|
|
4157
|
+
return inheritedAsk;
|
|
4131
4158
|
return {
|
|
4132
4159
|
action: "deny",
|
|
4133
4160
|
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
4134
4161
|
};
|
|
4135
4162
|
}
|
|
4163
|
+
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
4136
4164
|
if (resolved.action !== "allow")
|
|
4137
4165
|
return resolved;
|
|
4138
4166
|
if (resolved.updatedInput !== undefined) {
|
|
4139
|
-
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);
|
|
4140
4168
|
}
|
|
4141
4169
|
recordInheritedAskGrant(creq.toolCallId, pc.onAsk, resolved.presentedInput, askWaitMs);
|
|
4142
4170
|
return { action: "allow" };
|
|
@@ -4178,24 +4206,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4178
4206
|
};
|
|
4179
4207
|
}
|
|
4180
4208
|
const presentedArgs = decision.updatedInput !== undefined ? decision.updatedInput : creq.args;
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
if (verdict.kind === "block") {
|
|
4189
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
4190
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
4191
|
-
return {
|
|
4192
|
-
action: "deny",
|
|
4193
|
-
message: `auto-mode classifier blocked this call at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
4194
|
-
decisionReason: "classifier",
|
|
4195
|
-
};
|
|
4196
|
-
}
|
|
4197
|
-
}
|
|
4198
|
-
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)) {
|
|
4199
4216
|
recordAncestorSandboxAdmission(creq.toolCallId, creq.toolName);
|
|
4200
4217
|
return decision.updatedInput !== undefined ? { action: "allow", updatedInput: decision.updatedInput } : { action: "allow" };
|
|
4201
4218
|
}
|
|
@@ -4204,27 +4221,29 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4204
4221
|
toolName: creq.toolName,
|
|
4205
4222
|
toolCallId: creq.toolCallId,
|
|
4206
4223
|
args: presentedArgs,
|
|
4207
|
-
...ruleOffersOf(creq.toolName, presentedArgs, { ...(
|
|
4208
|
-
message:
|
|
4224
|
+
...ruleOffersOf(creq.toolName, presentedArgs, { ...(inheritedAsk.action === "ask" ? inheritedAsk : {}), ancestorResolved: true }),
|
|
4225
|
+
message: inheritedAsk.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
4209
4226
|
...askSourceIdentity(),
|
|
4210
4227
|
...riskAxesOf(creq.toolName),
|
|
4211
|
-
...(
|
|
4212
|
-
...(
|
|
4228
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4229
|
+
...(inheritedAsk.action === "ask" && inheritedAsk.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: inheritedAsk.persistedRuleShadowed } : {}),
|
|
4230
|
+
...(fallback !== undefined ? { denialLimitFallback: fallback } : {}),
|
|
4213
4231
|
ruleEvidence: inheritedAskEvidence,
|
|
4214
|
-
}, 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 }));
|
|
4215
4233
|
const askWaitMs = Math.max(0, now() - askT0);
|
|
4216
4234
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
4217
4235
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
4218
|
-
return
|
|
4236
|
+
return inheritedAsk;
|
|
4219
4237
|
return {
|
|
4220
4238
|
action: "deny",
|
|
4221
4239
|
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
4222
4240
|
};
|
|
4223
4241
|
}
|
|
4242
|
+
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
4224
4243
|
if (resolved.action !== "allow")
|
|
4225
4244
|
return resolved;
|
|
4226
4245
|
if (resolved.updatedInput !== undefined) {
|
|
4227
|
-
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);
|
|
4228
4247
|
}
|
|
4229
4248
|
if (pc.preToolUse === undefined) {
|
|
4230
4249
|
recordInheritedAskGrant(creq.toolCallId, pc.onAsk, resolved.presentedInput, askWaitMs);
|
|
@@ -4418,7 +4437,17 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4418
4437
|
});
|
|
4419
4438
|
peerLaneRefs.askEffective = wiringManifest.ask.effective;
|
|
4420
4439
|
if (peerLaneActive && internals?.onTaskNotification !== undefined) {
|
|
4421
|
-
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
|
+
});
|
|
4422
4451
|
}
|
|
4423
4452
|
const parkLaneArmed = wiringManifest.parkLane.effective === true;
|
|
4424
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 });
|
|
@@ -4480,6 +4509,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
4480
4509
|
...riskAxesOf(req.toolName),
|
|
4481
4510
|
...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
|
|
4482
4511
|
...(decision.action === "ask" && decision.persistedRuleShadowed !== undefined ? { persistedRuleShadowed: decision.persistedRuleShadowed } : {}),
|
|
4512
|
+
...(decision.action === "ask" && decision.denialLimitFallback !== undefined ? { denialLimitFallback: decision.denialLimitFallback } : {}),
|
|
4483
4513
|
...(decision.action === "ask" && decision.probeReason !== undefined ? { probeReason: decision.probeReason } : {}),
|
|
4484
4514
|
...(decision.action === "ask" && decision.probeCause !== undefined ? { probeCause: decision.probeCause } : {}),
|
|
4485
4515
|
...(decision.action === "ask" && decision.ruleEvidence !== undefined ? { ruleEvidence: decision.ruleEvidence } : {}),
|
|
@@ -5291,7 +5321,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
5291
5321
|
...(notifyPermissionDenied ? { permissionDenied: notifyPermissionDenied } : {}),
|
|
5292
5322
|
onHookError: notifyHookError,
|
|
5293
5323
|
shellGated: (e.toolName === "Bash" && shellGatedBash) || (e.toolName === "Monitor" && shellGatedMonitor),
|
|
5294
|
-
...(autoModeDecider ? { autoMode: { decider: autoModeDecider } } : {}),
|
|
5324
|
+
...(autoModeDecider ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}) } } : {}),
|
|
5325
|
+
onHeadlessDenialLimit: stopForDenialLimit,
|
|
5295
5326
|
...(permissionRuleLane
|
|
5296
5327
|
? {
|
|
5297
5328
|
persistedRules: {
|
|
@@ -5729,7 +5760,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
5729
5760
|
const effectiveReadFaceObserved = carrierReadFace();
|
|
5730
5761
|
const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
|
|
5731
5762
|
const preparedHolder = {};
|
|
5732
|
-
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 } : {}) });
|
|
5733
5764
|
const prepared = buildPrepared();
|
|
5734
5765
|
preparedHolder.current = prepared;
|
|
5735
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() };
|
|
@@ -3888,6 +3894,9 @@ export class Runner {
|
|
|
3888
3894
|
if (threw === undefined && prepared.brainCallGuardrailRef.timedOut !== undefined) {
|
|
3889
3895
|
threw = prepared.brainCallGuardrailRef.timedOut;
|
|
3890
3896
|
}
|
|
3897
|
+
if (threw === undefined && prepared.gateStopRef.terminal !== undefined) {
|
|
3898
|
+
threw = prepared.gateStopRef.terminal;
|
|
3899
|
+
}
|
|
3891
3900
|
if (rs.limits.platformTerminal !== undefined) {
|
|
3892
3901
|
threw = rs.limits.platformTerminal;
|
|
3893
3902
|
}
|
|
@@ -4071,6 +4080,7 @@ export class Runner {
|
|
|
4071
4080
|
model: prepared.model.id,
|
|
4072
4081
|
unpricedSpend: rs.telemetry.unpricedSpend,
|
|
4073
4082
|
rewindNotes: prepared.rewindNotes,
|
|
4083
|
+
editedFiles: prepared.editedFilesSnapshot(),
|
|
4074
4084
|
haltedOnUserRejection: prepared.batchHaltRef.current !== undefined,
|
|
4075
4085
|
userHalted: loopLatch.userHalted,
|
|
4076
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;
|