@sema-agent/core 1.293.0 → 1.295.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/dist/agents/subagent.d.ts.map +1 -1
- package/dist/agents/subagent.js +25 -3
- package/dist/agents/subagent.js.map +1 -1
- package/dist/bin/sema-tb.d.ts.map +1 -1
- package/dist/bin/sema-tb.js +7 -2
- package/dist/bin/sema-tb.js.map +1 -1
- package/dist/brain/anthropic.d.ts.map +1 -1
- package/dist/brain/anthropic.js +9 -3
- package/dist/brain/anthropic.js.map +1 -1
- package/dist/brain/openai.d.ts +1 -0
- package/dist/brain/openai.d.ts.map +1 -1
- package/dist/brain/openai.js +320 -298
- package/dist/brain/openai.js.map +1 -1
- package/dist/core/checkpoint-store.d.ts +14 -2
- package/dist/core/checkpoint-store.d.ts.map +1 -1
- package/dist/core/checkpoint-store.js.map +1 -1
- package/dist/core/fs-write-gate-policy.d.ts +1 -0
- package/dist/core/fs-write-gate-policy.d.ts.map +1 -1
- package/dist/core/fs-write-gate-policy.js +16 -0
- package/dist/core/fs-write-gate-policy.js.map +1 -1
- package/dist/core/hooks.d.ts +3 -3
- package/dist/core/hooks.d.ts.map +1 -1
- package/dist/core/hooks.js +11 -4
- package/dist/core/hooks.js.map +1 -1
- package/dist/core/present-plan-tool.d.ts.map +1 -1
- package/dist/core/present-plan-tool.js +12 -13
- package/dist/core/present-plan-tool.js.map +1 -1
- package/dist/core/runner/prepare-task.d.ts +17 -1
- package/dist/core/runner/prepare-task.d.ts.map +1 -1
- package/dist/core/runner/prepare-task.js +302 -20
- package/dist/core/runner/prepare-task.js.map +1 -1
- package/dist/core/runner/runtask.d.ts +2 -0
- package/dist/core/runner/runtask.d.ts.map +1 -1
- package/dist/core/runner/runtask.js +68 -10
- package/dist/core/runner/runtask.js.map +1 -1
- package/dist/core/sensitive-path-policy.d.ts +2 -1
- package/dist/core/sensitive-path-policy.d.ts.map +1 -1
- package/dist/core/sensitive-path-policy.js +22 -0
- package/dist/core/sensitive-path-policy.js.map +1 -1
- package/dist/core/task-registry.d.ts +4 -0
- package/dist/core/task-registry.d.ts.map +1 -1
- package/dist/core/task-registry.js +83 -15
- package/dist/core/task-registry.js.map +1 -1
- package/dist/core/tool-policy.d.ts +5 -2
- package/dist/core/tool-policy.d.ts.map +1 -1
- package/dist/core/tool-policy.js +9 -0
- package/dist/core/tool-policy.js.map +1 -1
- package/dist/core/types.d.ts +5 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/engine/compaction/utils.d.ts.map +1 -1
- package/dist/engine/compaction/utils.js +3 -1
- package/dist/engine/compaction/utils.js.map +1 -1
- package/dist/engine/harness/messages.d.ts +2 -0
- package/dist/engine/harness/messages.d.ts.map +1 -1
- package/dist/engine/harness/messages.js +52 -3
- package/dist/engine/harness/messages.js.map +1 -1
- package/dist/engine/llm/types.d.ts.map +1 -1
- package/dist/engine/session/import-validate.d.ts.map +1 -1
- package/dist/engine/session/import-validate.js +64 -0
- package/dist/engine/session/import-validate.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +1 -0
- package/dist/orchestration/run-workflow-tool.d.ts.map +1 -1
- package/dist/orchestration/run-workflow-tool.js +3 -0
- package/dist/orchestration/run-workflow-tool.js.map +1 -1
- package/dist/orchestration/workflow.d.ts +1 -0
- package/dist/orchestration/workflow.d.ts.map +1 -1
- package/dist/orchestration/workflow.js +1 -0
- package/dist/orchestration/workflow.js.map +1 -1
- package/dist/scenarios/full-body.d.ts.map +1 -1
- package/dist/scenarios/full-body.js +3 -2
- package/dist/scenarios/full-body.js.map +1 -1
- package/dist/tools/fs/index.d.ts +4 -1
- package/dist/tools/fs/index.d.ts.map +1 -1
- package/dist/tools/fs/index.js +59 -20
- package/dist/tools/fs/index.js.map +1 -1
- package/dist/tools/fs/safety.d.ts +1 -1
- package/dist/tools/fs/safety.d.ts.map +1 -1
- package/dist/tools/fs/safety.js +3 -1
- package/dist/tools/fs/safety.js.map +1 -1
- package/dist/tools/fs/search.d.ts +7 -2
- package/dist/tools/fs/search.d.ts.map +1 -1
- package/dist/tools/fs/search.js +465 -57
- package/dist/tools/fs/search.js.map +1 -1
- package/dist/tools/monitor.d.ts.map +1 -1
- package/dist/tools/monitor.js +12 -1
- package/dist/tools/monitor.js.map +1 -1
- package/dist/tools/task-list.d.ts.map +1 -1
- package/dist/tools/task-list.js.map +1 -1
- package/dist/tools/worktree.d.ts.map +1 -1
- package/dist/tools/worktree.js +15 -2
- package/dist/tools/worktree.js.map +1 -1
- package/package.json +1 -1
|
@@ -28,6 +28,7 @@ import { reconcileInterruptedSession } from "../session-reconcile.js";
|
|
|
28
28
|
import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
|
|
29
29
|
import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
|
|
30
30
|
import { defineTool } from "../tools.js";
|
|
31
|
+
import { canonicalToolName } from "../tool-name-aliases.js";
|
|
31
32
|
import { pathToUri } from "../lsp-protocol.js";
|
|
32
33
|
import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, firstPartyOffloadPolicy, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, isVolatileOffloadStore, OFFLOAD_TOOL_NAME, makeReadToolResultTool, withToolResultOffload, } from "../tool-result-store.js";
|
|
33
34
|
import { OUTPUT_TOOL_NAME, REPORT_FINDINGS_TOOL_NAME, SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, buildSkillsBlock, makeOutputTool, makeReportBlockedTool, makeReportFindingsTool, makeSkillTool, normalizeSkills } from "./synthetic-tools.js";
|
|
@@ -153,6 +154,16 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
153
154
|
throw e;
|
|
154
155
|
}
|
|
155
156
|
}
|
|
157
|
+
if (spec.agents !== undefined && spec.agents.length > 0) {
|
|
158
|
+
const pool = spec.tools ?? [];
|
|
159
|
+
if (!pool.some((t) => typeof t.withAgents === "function")) {
|
|
160
|
+
const e = new Error(`TaskSpec.agents was provided but no delegation tool (createSubagentTool) is mounted in spec.tools — the per-task agents could never be offered. Mount the delegation tool, or drop spec.agents.`);
|
|
161
|
+
e.code = "config.agents.no_delegation_tool";
|
|
162
|
+
throw e;
|
|
163
|
+
}
|
|
164
|
+
const perTask = spec.agents;
|
|
165
|
+
spec = { ...spec, tools: pool.map((t) => (typeof t.withAgents === "function" ? t.withAgents(perTask) : t)) };
|
|
166
|
+
}
|
|
156
167
|
const resolvedRole = resolveTaskModel(spec, deps);
|
|
157
168
|
const model = resolvedRole.model;
|
|
158
169
|
const thinking = spec.thinking ?? resolvedRole.thinking ?? model.defaultThinking;
|
|
@@ -524,6 +535,62 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
524
535
|
};
|
|
525
536
|
const subagentRetain = spec.retainSubagentSessions ? new SubagentRetainLedger(spec.retainSubagentSessions) : undefined;
|
|
526
537
|
const worktreeIsolation = spec.handsReadOnly !== true ? createSubagentWorktreeHelper(executionEnv, taskRootPath) : undefined;
|
|
538
|
+
const liveInheritedGate = internals?.inheritedGate;
|
|
539
|
+
const seedInheritedGate = resume?.seed.inheritedGate;
|
|
540
|
+
const inheritedAncestorRules = (() => {
|
|
541
|
+
const seedRules = seedInheritedGate?.ancestorRules;
|
|
542
|
+
const liveRules = liveInheritedGate?.ancestorRules;
|
|
543
|
+
if (seedRules === undefined || seedRules.length === 0)
|
|
544
|
+
return liveRules ?? seedRules;
|
|
545
|
+
if (liveRules === undefined || liveRules.length === 0)
|
|
546
|
+
return seedRules;
|
|
547
|
+
const merged = seedRules.map((s) => {
|
|
548
|
+
const live = liveRules.find((l) => l.sessionId === s.sessionId && l.principal === s.principal);
|
|
549
|
+
return live !== undefined && live.rev >= s.rev ? live : s;
|
|
550
|
+
});
|
|
551
|
+
const extras = liveRules.filter((l) => !seedRules.some((s) => s.sessionId === l.sessionId && s.principal === l.principal));
|
|
552
|
+
return [...merged, ...extras];
|
|
553
|
+
})();
|
|
554
|
+
const shellGateRank = { off: 0, classify: 1, always: 2 };
|
|
555
|
+
const liveShellGate = liveInheritedGate?.shellGate;
|
|
556
|
+
const seedShellGate = seedInheritedGate?.shellGate;
|
|
557
|
+
const inheritedShellGate = liveShellGate === undefined
|
|
558
|
+
? seedShellGate
|
|
559
|
+
: seedShellGate === undefined
|
|
560
|
+
? liveShellGate
|
|
561
|
+
: shellGateRank[liveShellGate] >= shellGateRank[seedShellGate]
|
|
562
|
+
? liveShellGate
|
|
563
|
+
: seedShellGate;
|
|
564
|
+
const inheritedParentConstraints = liveInheritedGate?.parentConstraints;
|
|
565
|
+
const specShellGate = spec.shellGate ?? "off";
|
|
566
|
+
const effectiveShellGate = inheritedShellGate !== undefined && shellGateRank[inheritedShellGate] > shellGateRank[specShellGate] ? inheritedShellGate : specShellGate;
|
|
567
|
+
const ownSessionRulesRef = {};
|
|
568
|
+
const frozenOnAsk = spec.onAsk ?? deps.onAsk;
|
|
569
|
+
const inheritedGateForChildren = () => {
|
|
570
|
+
const ancestorRules = [
|
|
571
|
+
...(inheritedAncestorRules ?? []),
|
|
572
|
+
...(ownSessionRulesRef.current !== undefined ? [ownSessionRulesRef.current] : []),
|
|
573
|
+
];
|
|
574
|
+
const ownCallerPolicy = spec.toolPolicy ?? deps.toolPolicy;
|
|
575
|
+
const durableMandate = runtimeCaps?.forceDurableGate === true || (spec.durableApproval !== undefined && frozenOnAsk === undefined);
|
|
576
|
+
const parentConstraints = [
|
|
577
|
+
...(inheritedParentConstraints ?? []),
|
|
578
|
+
...(ownCallerPolicy !== undefined
|
|
579
|
+
? [
|
|
580
|
+
{
|
|
581
|
+
policy: ownCallerPolicy,
|
|
582
|
+
...(frozenOnAsk !== undefined ? { onAsk: frozenOnAsk } : {}),
|
|
583
|
+
...(durableMandate ? { durableMandate: true } : {}),
|
|
584
|
+
},
|
|
585
|
+
]
|
|
586
|
+
: []),
|
|
587
|
+
];
|
|
588
|
+
return {
|
|
589
|
+
...(ancestorRules.length > 0 ? { ancestorRules } : {}),
|
|
590
|
+
...(effectiveShellGate !== "off" ? { shellGate: effectiveShellGate } : {}),
|
|
591
|
+
...(parentConstraints.length > 0 ? { parentConstraints } : {}),
|
|
592
|
+
};
|
|
593
|
+
};
|
|
527
594
|
let agentForkDenial;
|
|
528
595
|
let observersActive = false;
|
|
529
596
|
let autoModeDecider;
|
|
@@ -538,6 +605,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
538
605
|
clientContext: spec.clientContext,
|
|
539
606
|
parentCwd: taskRootPath,
|
|
540
607
|
activeSkillScope: () => skillScope.active(),
|
|
608
|
+
inheritedGateForChildren,
|
|
541
609
|
taskId: hostTaskId,
|
|
542
610
|
sessionId,
|
|
543
611
|
...(spec.backgroundScope !== undefined ? { backgroundScope: spec.backgroundScope } : {}),
|
|
@@ -642,6 +710,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
642
710
|
parentCwd: taskRootPath,
|
|
643
711
|
parentThinking: () => harnessRef.current?.getThinkingLevel() ?? thinking,
|
|
644
712
|
...(forwardEvent ? { forwardEvent } : {}),
|
|
713
|
+
inheritedGateForChildren,
|
|
645
714
|
}));
|
|
646
715
|
}
|
|
647
716
|
const suspendRef = {};
|
|
@@ -830,7 +899,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
830
899
|
}
|
|
831
900
|
}
|
|
832
901
|
tools.push(...band.map((t) => firstPartyOffload(t)));
|
|
833
|
-
const shellGate =
|
|
902
|
+
const shellGate = effectiveShellGate;
|
|
834
903
|
if (shellGate !== "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
835
904
|
shellGatedBash = !egressTools.has("Bash") && !irreversibilityTier.has("Bash");
|
|
836
905
|
irreversibilityTier.set("Bash", shellGate === "always" ? "always" : "maybe");
|
|
@@ -1424,6 +1493,20 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1424
1493
|
toolSearch = makeToolSearchTool({ registry, active: activeTools, rematerialize });
|
|
1425
1494
|
harnessTools = buildToolList(activeTools);
|
|
1426
1495
|
}
|
|
1496
|
+
if (spec.agents !== undefined && spec.agents.length > 0) {
|
|
1497
|
+
const known = new Set(tools.flatMap((t) => [canonicalToolName(t.name), ...(t.aliases ?? []).map((a) => canonicalToolName(a))]));
|
|
1498
|
+
for (const def of spec.agents) {
|
|
1499
|
+
for (const n of def.allowTools ?? []) {
|
|
1500
|
+
if (n === "*")
|
|
1501
|
+
continue;
|
|
1502
|
+
if (!known.has(canonicalToolName(n))) {
|
|
1503
|
+
const e = new Error(`TaskSpec.agents: agent "${def.name}" declares tool "${n}" in its allowed tools, but no such tool exists in this deployment — fix the agent's tools list or mount the tool.`);
|
|
1504
|
+
e.code = "config.agent.unknown_tool";
|
|
1505
|
+
throw e;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1427
1510
|
const agentListingSpec = (spec.tools ?? []).find((t) => t.agentListing !== undefined && t.agentListing.length > 0);
|
|
1428
1511
|
const agentListing = agentListingSpec
|
|
1429
1512
|
? { entries: agentListingSpec.agentListing, toolName: agentListingSpec.name, seedAnnounced: resume !== undefined }
|
|
@@ -1522,8 +1605,28 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1522
1605
|
const rules = await deps.sessionPolicyStore.getRules(spec.sessionId, spec.principal);
|
|
1523
1606
|
if (rules) {
|
|
1524
1607
|
sessionRulePolicy = createSessionRulePolicy(rules, { env: executionEnv, rootPath: taskRootPath, toolEffects });
|
|
1608
|
+
ownSessionRulesRef.current = {
|
|
1609
|
+
sessionId: spec.sessionId,
|
|
1610
|
+
...(spec.principal !== undefined ? { principal: spec.principal } : {}),
|
|
1611
|
+
rev: rules.rev,
|
|
1612
|
+
rules,
|
|
1613
|
+
};
|
|
1525
1614
|
}
|
|
1526
1615
|
}
|
|
1616
|
+
const ancestorRulePolicies = [];
|
|
1617
|
+
for (const snap of inheritedAncestorRules ?? []) {
|
|
1618
|
+
let ancestorRules = snap.rules;
|
|
1619
|
+
if (deps.sessionPolicyStore) {
|
|
1620
|
+
try {
|
|
1621
|
+
const live = await deps.sessionPolicyStore.getRules(snap.sessionId, snap.principal);
|
|
1622
|
+
if (live !== null && live.rev >= snap.rev)
|
|
1623
|
+
ancestorRules = live;
|
|
1624
|
+
}
|
|
1625
|
+
catch {
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
ancestorRulePolicies.push(createSessionRulePolicy(ancestorRules, { env: executionEnv, rootPath: taskRootPath, toolEffects }));
|
|
1629
|
+
}
|
|
1527
1630
|
const skillScopePolicy = hasSkillManifest
|
|
1528
1631
|
? createActiveSkillScopePolicy({
|
|
1529
1632
|
scope: skillScope,
|
|
@@ -1532,12 +1635,177 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1532
1635
|
toolEffects,
|
|
1533
1636
|
})
|
|
1534
1637
|
: undefined;
|
|
1535
|
-
const narrowingLayers = [sessionRulePolicy, skillScopePolicy].filter((p) => p !== undefined);
|
|
1638
|
+
const narrowingLayers = [sessionRulePolicy, ...ancestorRulePolicies, skillScopePolicy].filter((p) => p !== undefined);
|
|
1536
1639
|
const denyNarrowingPolicy = narrowingLayers.length === 0 ? undefined : narrowingLayers.length === 1 ? narrowingLayers[0] : combinePolicies(...narrowingLayers);
|
|
1537
|
-
const
|
|
1640
|
+
const sameInstanceAncestorCount = policy === undefined ? 0 : (inheritedParentConstraints ?? []).reduce((n, pc) => (pc.policy === policy ? n + 1 : n), 0);
|
|
1641
|
+
const sharedFirstDecision = new Map();
|
|
1642
|
+
const SHARED_FIRST_DECISION_CAP = 256;
|
|
1643
|
+
const callerPolicyLayer = policy !== undefined && sameInstanceAncestorCount > 0
|
|
1644
|
+
? {
|
|
1645
|
+
check: async (creq, csignal) => {
|
|
1646
|
+
const decision = await policy.check(creq, csignal ?? abortController.signal);
|
|
1647
|
+
sharedFirstDecision.set(creq.toolCallId, decision);
|
|
1648
|
+
if (sharedFirstDecision.size > SHARED_FIRST_DECISION_CAP) {
|
|
1649
|
+
const oldest = sharedFirstDecision.keys().next().value;
|
|
1650
|
+
if (oldest !== undefined)
|
|
1651
|
+
sharedFirstDecision.delete(oldest);
|
|
1652
|
+
}
|
|
1653
|
+
return decision;
|
|
1654
|
+
},
|
|
1655
|
+
}
|
|
1656
|
+
: policy;
|
|
1657
|
+
const parentConstraintWrappers = (inheritedParentConstraints ?? []).map((pc) => policy !== undefined && pc.policy === policy
|
|
1658
|
+
? {
|
|
1659
|
+
check: async (creq, csignal) => {
|
|
1660
|
+
const first = sharedFirstDecision.get(creq.toolCallId);
|
|
1661
|
+
if (first === undefined) {
|
|
1662
|
+
return {
|
|
1663
|
+
action: "deny",
|
|
1664
|
+
reason: `inherited parent policy could not be arbitrated for "${creq.toolName}" ` +
|
|
1665
|
+
`(shared-instance first decision unavailable); denied fail-closed`,
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
if (first.action === "deny")
|
|
1669
|
+
return first;
|
|
1670
|
+
if (first.action === "allow")
|
|
1671
|
+
return { action: "allow" };
|
|
1672
|
+
if (pc.durableMandate === true) {
|
|
1673
|
+
return {
|
|
1674
|
+
action: "deny",
|
|
1675
|
+
reason: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
1676
|
+
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
const presentedArgs = creq.args;
|
|
1680
|
+
const resolved = await resolveAsk({
|
|
1681
|
+
toolName: creq.toolName,
|
|
1682
|
+
toolCallId: creq.toolCallId,
|
|
1683
|
+
args: presentedArgs,
|
|
1684
|
+
message: first.message ?? first.reason ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
1685
|
+
principal: spec.principal,
|
|
1686
|
+
sourceTaskId: sessionId,
|
|
1687
|
+
}, pc.onAsk, csignal ?? abortController.signal);
|
|
1688
|
+
return resolved.action === "allow" ? { action: "allow" } : resolved;
|
|
1689
|
+
},
|
|
1690
|
+
}
|
|
1691
|
+
: {
|
|
1692
|
+
check: async (creq, csignal) => {
|
|
1693
|
+
let decision;
|
|
1694
|
+
try {
|
|
1695
|
+
decision = await pc.policy.check(creq, csignal ?? abortController.signal);
|
|
1696
|
+
}
|
|
1697
|
+
catch (err) {
|
|
1698
|
+
return {
|
|
1699
|
+
action: "deny",
|
|
1700
|
+
reason: `inherited parent policy errored for "${creq.toolName}": ${err instanceof Error ? err.message : String(err)}`,
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
if (decision.action !== "ask")
|
|
1704
|
+
return decision;
|
|
1705
|
+
if (pc.durableMandate === true) {
|
|
1706
|
+
return {
|
|
1707
|
+
action: "deny",
|
|
1708
|
+
reason: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
1709
|
+
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
const presentedArgs = decision.updatedInput !== undefined ? decision.updatedInput : creq.args;
|
|
1713
|
+
const resolved = await resolveAsk({
|
|
1714
|
+
toolName: creq.toolName,
|
|
1715
|
+
toolCallId: creq.toolCallId,
|
|
1716
|
+
args: presentedArgs,
|
|
1717
|
+
message: decision.message ?? decision.reason ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
|
|
1718
|
+
principal: spec.principal,
|
|
1719
|
+
sourceTaskId: sessionId,
|
|
1720
|
+
}, pc.onAsk, csignal ?? abortController.signal);
|
|
1721
|
+
return resolved.action === "allow" && decision.updatedInput !== undefined
|
|
1722
|
+
? { ...resolved, updatedInput: decision.updatedInput }
|
|
1723
|
+
: resolved;
|
|
1724
|
+
},
|
|
1725
|
+
});
|
|
1726
|
+
const rewriteCapableLayers = policy !== undefined || parentConstraintWrappers.length > 0;
|
|
1727
|
+
const rewriteEmitterIndex = new Map();
|
|
1728
|
+
const rewriteCapableChain = [
|
|
1729
|
+
...(callerPolicyLayer !== undefined ? [callerPolicyLayer] : []),
|
|
1730
|
+
...parentConstraintWrappers,
|
|
1731
|
+
];
|
|
1732
|
+
const callerSlotOffset = callerPolicyLayer !== undefined ? 1 : 0;
|
|
1733
|
+
const sameInstanceAdapterIndices = new Set();
|
|
1734
|
+
(inheritedParentConstraints ?? []).forEach((pc, j) => {
|
|
1735
|
+
if (policy !== undefined && pc.policy === policy)
|
|
1736
|
+
sameInstanceAdapterIndices.add(j + callerSlotOffset);
|
|
1737
|
+
});
|
|
1738
|
+
const instrumentedChain = rewriteCapableChain.map((layer, idx) => ({
|
|
1739
|
+
check: async (creq, csignal) => {
|
|
1740
|
+
const d = await layer.check(creq, csignal);
|
|
1741
|
+
if (d.updatedInput !== undefined)
|
|
1742
|
+
rewriteEmitterIndex.set(creq.toolCallId, idx);
|
|
1743
|
+
return d;
|
|
1744
|
+
},
|
|
1745
|
+
}));
|
|
1746
|
+
const policyLayers = [
|
|
1747
|
+
...narrowingLayers,
|
|
1748
|
+
...instrumentedChain,
|
|
1749
|
+
...(rewriteCapableLayers ? narrowingLayers : []),
|
|
1750
|
+
];
|
|
1538
1751
|
const integrityGuardLayers = [createTranscriptIntegrityPolicy(), createUnverifiableDeletePolicy()];
|
|
1539
|
-
const guardedPolicyLayers =
|
|
1540
|
-
|
|
1752
|
+
const guardedPolicyLayers = rewriteCapableLayers
|
|
1753
|
+
? [...integrityGuardLayers, ...policyLayers, ...integrityGuardLayers]
|
|
1754
|
+
: [...integrityGuardLayers, ...policyLayers];
|
|
1755
|
+
const foldedPolicy = guardedPolicyLayers.length === 1 ? guardedPolicyLayers[0] : combinePolicies(...guardedPolicyLayers);
|
|
1756
|
+
const effectivePolicy = foldedPolicy !== undefined && rewriteCapableLayers
|
|
1757
|
+
? {
|
|
1758
|
+
check: async (req, signal) => {
|
|
1759
|
+
let decision;
|
|
1760
|
+
try {
|
|
1761
|
+
decision = await foldedPolicy.check(req, signal);
|
|
1762
|
+
}
|
|
1763
|
+
catch (err) {
|
|
1764
|
+
rewriteEmitterIndex.delete(req.toolCallId);
|
|
1765
|
+
throw err;
|
|
1766
|
+
}
|
|
1767
|
+
const emitterIdx = rewriteEmitterIndex.get(req.toolCallId);
|
|
1768
|
+
rewriteEmitterIndex.delete(req.toolCallId);
|
|
1769
|
+
if (decision.action === "deny" || decision.updatedInput === undefined)
|
|
1770
|
+
return decision;
|
|
1771
|
+
const recheckPrefix = rewriteCapableChain.slice(0, emitterIdx ?? rewriteCapableChain.length);
|
|
1772
|
+
const postEmitterSameInstanceAdapters = [];
|
|
1773
|
+
if (emitterIdx !== undefined && emitterIdx > 0) {
|
|
1774
|
+
for (let i = emitterIdx + 1; i < rewriteCapableChain.length; i++) {
|
|
1775
|
+
if (sameInstanceAdapterIndices.has(i))
|
|
1776
|
+
postEmitterSameInstanceAdapters.push(rewriteCapableChain[i]);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
const recheckLayers = [...recheckPrefix, ...postEmitterSameInstanceAdapters];
|
|
1780
|
+
const finalReq = { ...req, args: decision.updatedInput };
|
|
1781
|
+
let asked;
|
|
1782
|
+
try {
|
|
1783
|
+
for (const layer of recheckLayers) {
|
|
1784
|
+
const d = await layer.check(finalReq, signal);
|
|
1785
|
+
if (d.action === "deny") {
|
|
1786
|
+
return { ...d, updatedInput: decision.updatedInput };
|
|
1787
|
+
}
|
|
1788
|
+
if (d.updatedInput !== undefined) {
|
|
1789
|
+
return {
|
|
1790
|
+
action: "deny",
|
|
1791
|
+
message: "policy required a rewrite during final-form re-check — the arguments that would execute were not accepted as-is (fail-closed; rewrite chains are not iterated to a fixpoint)",
|
|
1792
|
+
updatedInput: decision.updatedInput,
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
if (d.action === "ask" && asked === undefined)
|
|
1796
|
+
asked = d;
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
finally {
|
|
1800
|
+
rewriteEmitterIndex.delete(req.toolCallId);
|
|
1801
|
+
}
|
|
1802
|
+
if (asked !== undefined && decision.action === "allow") {
|
|
1803
|
+
return { ...asked, updatedInput: decision.updatedInput };
|
|
1804
|
+
}
|
|
1805
|
+
return decision;
|
|
1806
|
+
},
|
|
1807
|
+
}
|
|
1808
|
+
: foldedPolicy;
|
|
1541
1809
|
const hooks = spec.hooks ?? deps.hooks;
|
|
1542
1810
|
const onAsk = spec.onAsk ?? deps.onAsk;
|
|
1543
1811
|
const handWriteTools = handsEnabled
|
|
@@ -1607,16 +1875,18 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1607
1875
|
sourceTaskId: sessionId,
|
|
1608
1876
|
}, onAsk, abortController.signal);
|
|
1609
1877
|
const waitMs = Math.max(0, now() - t0);
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1878
|
+
if (resolved.approverUnavailable !== true) {
|
|
1879
|
+
humanReviewRef.count += 1;
|
|
1880
|
+
humanReviewRef.totalWaitMs += waitMs;
|
|
1881
|
+
const toolArg = primaryActivityArg(req.args);
|
|
1882
|
+
humanReviewRef.gates.push({
|
|
1883
|
+
kind: "human",
|
|
1884
|
+
waitMs,
|
|
1885
|
+
decision: resolved.action === "allow" ? "allow" : "deny",
|
|
1886
|
+
toolName: req.toolName,
|
|
1887
|
+
...(toolArg !== undefined ? { toolArg } : {}),
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1620
1890
|
return resolved;
|
|
1621
1891
|
};
|
|
1622
1892
|
const hooksWithPermissionDenied = hooks?.permissionDenied ? hooks : undefined;
|
|
@@ -1659,6 +1929,18 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1659
1929
|
return live.length > 0 ? live : undefined;
|
|
1660
1930
|
})(),
|
|
1661
1931
|
pendingSteer: undefined,
|
|
1932
|
+
inheritedGate: (() => {
|
|
1933
|
+
const requiresParentConstraint = (inheritedParentConstraints?.length ?? 0) > 0 || seedInheritedGate?.requiresParentConstraint === true;
|
|
1934
|
+
const parentConstraintCount = (inheritedParentConstraints?.length ?? 0) > 0 ? inheritedParentConstraints.length : seedInheritedGate?.parentConstraintCount;
|
|
1935
|
+
return inheritedAncestorRules !== undefined || inheritedShellGate !== undefined || requiresParentConstraint
|
|
1936
|
+
? {
|
|
1937
|
+
...(inheritedAncestorRules !== undefined ? { ancestorRules: structuredClone(inheritedAncestorRules) } : {}),
|
|
1938
|
+
...(inheritedShellGate !== undefined ? { shellGate: inheritedShellGate } : {}),
|
|
1939
|
+
requiresParentConstraint,
|
|
1940
|
+
...(requiresParentConstraint && parentConstraintCount !== undefined ? { parentConstraintCount } : {}),
|
|
1941
|
+
}
|
|
1942
|
+
: undefined;
|
|
1943
|
+
})(),
|
|
1662
1944
|
});
|
|
1663
1945
|
const commitSuspendSaga = async (token, cp, remoteEnv, remoteHandle) => {
|
|
1664
1946
|
if (!checkpointStore)
|
|
@@ -1740,7 +2022,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1740
2022
|
remoteHandle = { ...suspendableEnv.workspaceHandle(), snapshotId: snap.value };
|
|
1741
2023
|
}
|
|
1742
2024
|
else if (parkOnlyRemoteEnv !== undefined) {
|
|
1743
|
-
if (hasBackgroundShell(parkOnlyRemoteEnv))
|
|
2025
|
+
if (hasBackgroundShell(parkOnlyRemoteEnv) && spec.retainBackgroundProcesses !== true)
|
|
1744
2026
|
await parkOnlyRemoteEnv.disposeBackgroundShells();
|
|
1745
2027
|
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
|
|
1746
2028
|
}
|
|
@@ -1808,7 +2090,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1808
2090
|
remoteHandle = { ...suspendableEnv.workspaceHandle(), snapshotId: snap.value };
|
|
1809
2091
|
}
|
|
1810
2092
|
else if (parkOnlyRemoteEnv !== undefined) {
|
|
1811
|
-
if (hasBackgroundShell(parkOnlyRemoteEnv))
|
|
2093
|
+
if (hasBackgroundShell(parkOnlyRemoteEnv) && spec.retainBackgroundProcesses !== true)
|
|
1812
2094
|
await parkOnlyRemoteEnv.disposeBackgroundShells();
|
|
1813
2095
|
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
|
|
1814
2096
|
}
|
|
@@ -1851,8 +2133,8 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1851
2133
|
}
|
|
1852
2134
|
: undefined;
|
|
1853
2135
|
const suspendAsk = checkpointStore && (durableApproval || irreversibleTools.size > 0 || egressTools.size > 0)
|
|
1854
|
-
? async (req, postHookArgs, safety) => {
|
|
1855
|
-
if (safety === undefined &&
|
|
2136
|
+
? async (req, postHookArgs, safety, approverUnavailable) => {
|
|
2137
|
+
if (safety === undefined && onAsk !== undefined && runtimeCaps?.forceDurableGate !== true && approverUnavailable !== true) {
|
|
1856
2138
|
return undefined;
|
|
1857
2139
|
}
|
|
1858
2140
|
let token;
|
|
@@ -1893,7 +2175,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1893
2175
|
remoteHandle = { ...remoteEnv.workspaceHandle(), snapshotId: snap.value };
|
|
1894
2176
|
}
|
|
1895
2177
|
else if (parkOnlyRemoteEnv !== undefined) {
|
|
1896
|
-
if (hasBackgroundShell(parkOnlyRemoteEnv))
|
|
2178
|
+
if (hasBackgroundShell(parkOnlyRemoteEnv) && spec.retainBackgroundProcesses !== true)
|
|
1897
2179
|
await parkOnlyRemoteEnv.disposeBackgroundShells();
|
|
1898
2180
|
remoteHandle = parkOnlyHandle(parkOnlyRemoteEnv);
|
|
1899
2181
|
}
|