@sema-agent/core 3.0.0 → 5.0.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 +2382 -0
- package/dist/agents/cascade.d.ts +3 -1
- package/dist/agents/cascade.js +31 -32
- package/dist/agents/cumulative-stats.d.ts +29 -0
- package/dist/agents/cumulative-stats.js +29 -0
- package/dist/agents/observer.d.ts +4 -0
- package/dist/agents/observer.js +11 -10
- package/dist/agents/repair-loop.d.ts +2 -0
- package/dist/agents/repair-loop.js +48 -24
- package/dist/agents/retain-ledger.d.ts +2 -0
- package/dist/agents/retain-ledger.js +6 -5
- package/dist/agents/roster-store.d.ts +1 -0
- package/dist/agents/roster-store.js +3 -5
- package/dist/agents/send-message-tool.d.ts +1 -0
- package/dist/agents/send-message-tool.js +2 -0
- package/dist/agents/subagent.d.ts +3 -1
- package/dist/agents/subagent.js +79 -94
- package/dist/agents/teacher.d.ts +1 -9
- package/dist/agents/teacher.js +21 -24
- package/dist/agents/tool-filter.js +6 -7
- package/dist/agents/verify.d.ts +1 -0
- package/dist/agents/verify.js +15 -14
- package/dist/brain/anthropic.js +24 -21
- package/dist/brain/openai.js +24 -21
- package/dist/brain/stream-engine.js +5 -2
- package/dist/brain/stream-shared.d.ts +1 -0
- package/dist/brain/stream-shared.js +14 -0
- package/dist/brain/terminal-cause.d.ts +4 -0
- package/dist/brain/terminal-cause.js +12 -0
- package/dist/brain/tool-call-id.d.ts +1 -0
- package/dist/brain/tool-call-id.js +3 -0
- package/dist/brain/tool-call-repair.js +2 -1
- package/dist/core/arg-summary.d.ts +21 -1
- package/dist/core/arg-summary.js +61 -14
- package/dist/core/auto-compaction.d.ts +1 -0
- package/dist/core/auto-compaction.js +16 -25
- package/dist/core/background-agent-store.d.ts +22 -22
- package/dist/core/background-agent-store.js +19 -23
- package/dist/core/checkpoint-store.d.ts +6 -13
- package/dist/core/checkpoint-store.js +11 -5
- package/dist/core/file-snapshot-store.d.ts +8 -0
- package/dist/core/file-snapshot-store.js +4 -3
- package/dist/core/fs-write-gate-policy.js +2 -3
- package/dist/core/hooks.d.ts +4 -1
- package/dist/core/hooks.js +8 -18
- package/dist/core/lsp.js +4 -3
- package/dist/core/mailbox-store.d.ts +7 -10
- package/dist/core/mcp.d.ts +7 -10
- package/dist/core/mcp.js +7 -9
- package/dist/core/memory-engine/engine.d.ts +0 -1
- package/dist/core/memory-engine/engine.js +24 -34
- package/dist/core/memory-engine/file-backend.d.ts +1 -2
- package/dist/core/memory-engine/file-backend.js +25 -36
- package/dist/core/memory-engine/layout.d.ts +8 -0
- package/dist/core/memory-engine/layout.js +60 -4
- package/dist/core/memory-engine/scope-contract.js +9 -3
- package/dist/core/memory-engine/types.d.ts +1 -1
- package/dist/core/permission-rules.js +2 -3
- package/dist/core/runner/active-skill-scope.d.ts +0 -1
- package/dist/core/runner/active-skill-scope.js +2 -17
- package/dist/core/runner/assemble-result.d.ts +2 -7
- package/dist/core/runner/assemble-result.js +3 -4
- package/dist/core/runner/compaction-call-options.d.ts +7 -0
- package/dist/core/runner/compaction-call-options.js +30 -0
- package/dist/core/runner/prepare-task.d.ts +6 -23
- package/dist/core/runner/prepare-task.js +36 -61
- package/dist/core/runner/runtask.d.ts +1 -0
- package/dist/core/runner/runtask.js +84 -172
- package/dist/core/runner/session-rule-policy.js +7 -5
- package/dist/core/runner/teardown-bounded.d.ts +7 -0
- package/dist/core/runner/teardown-bounded.js +36 -0
- package/dist/core/runner/tool-disclosure.d.ts +2 -5
- package/dist/core/runner/turn-attachments.d.ts +5 -15
- package/dist/core/runner/turn-attachments.js +1 -1
- package/dist/core/safe-notify.d.ts +17 -0
- package/dist/core/safe-notify.js +59 -0
- package/dist/core/sensitive-path-policy.js +4 -4
- package/dist/core/session-reconcile.js +1 -2
- package/dist/core/skill-tool-specifier.js +2 -3
- package/dist/core/skills-directory.js +2 -3
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/stub-env.d.ts +2 -6
- package/dist/core/surrogate-safe-slice.d.ts +4 -0
- package/dist/core/surrogate-safe-slice.js +18 -0
- package/dist/core/task-registry-monitor.js +8 -13
- package/dist/core/task-registry-shared.d.ts +23 -1
- package/dist/core/task-registry-shared.js +16 -0
- package/dist/core/task-registry.d.ts +6 -1
- package/dist/core/task-registry.js +52 -87
- package/dist/core/task-tool-shape.d.ts +0 -2
- package/dist/core/task-tool-shape.js +2 -5
- package/dist/core/tool-errors.js +5 -4
- package/dist/core/tool-name-aliases.d.ts +1 -2
- package/dist/core/tool-name-aliases.js +42 -59
- package/dist/core/tool-policy.js +21 -17
- package/dist/core/tool-result-store.d.ts +1 -0
- package/dist/core/tool-result-store.js +17 -1
- package/dist/core/trace.d.ts +9 -9
- package/dist/core/types.d.ts +15 -12
- package/dist/core/untrusted-egress.d.ts +4 -2
- package/dist/core/untrusted-egress.js +28 -14
- package/dist/core/workflow-journal-store.d.ts +9 -20
- package/dist/core/workflow-run-store.d.ts +11 -10
- package/dist/core/workflow-run-store.js +22 -16
- package/dist/engine/compaction/utils.js +4 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +2 -24
- package/dist/engine/execution-env/node-execution-env.js +1 -1
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +13 -33
- package/dist/engine/harness/types.d.ts +29 -67
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +12 -14
- package/dist/engine/loop/types.d.ts +11 -9
- package/dist/engine/session/memory-repo.d.ts +2 -6
- package/dist/engine/session/session.d.ts +5 -30
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -3
- package/dist/internal/harness-types.d.ts +3 -1
- package/dist/orchestration/run-spec.js +6 -4
- package/dist/orchestration/run-workflow-tool.js +3 -36
- package/dist/orchestration/workflow-governance.js +2 -1
- package/dist/orchestration/workflow.d.ts +4 -11
- package/dist/orchestration/workflow.js +164 -204
- package/dist/prompt-assembly/packs/sema-default.js +1 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
- package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
- package/dist/prompts/default.js +1 -3
- package/dist/prompts/simple-sections.d.ts +0 -1
- package/dist/prompts/simple-sections.js +0 -1
- package/dist/stores/file/background-agent-store.d.ts +3 -12
- package/dist/stores/file/background-agent-store.js +3 -41
- package/dist/stores/file/checkpoint-store.js +6 -6
- package/dist/stores/file/mailbox-store.d.ts +2 -6
- package/dist/stores/file/session-policy-store.js +15 -1
- package/dist/stores/file/session-store.d.ts +2 -6
- package/dist/stores/file/workflow-journal-store.d.ts +3 -11
- package/dist/stores/file/workflow-run-store.d.ts +3 -7
- package/dist/stores/file/workflow-run-store.js +4 -17
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -0
- package/dist/tools/fs/bash-readonly-classifier.js +60 -25
- package/dist/tools/fs/fs-bash.js +330 -104
- package/dist/tools/fs/fs-pdf.d.ts +2 -12
- package/dist/tools/fs/fs-shared.js +2 -2
- package/dist/tools/fs/fs-write.js +0 -1
- package/dist/tools/fs/notebook.d.ts +2 -5
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +43 -14
- package/dist/tools/fs/search.js +5 -5
- package/dist/tools/monitor.d.ts +1 -0
- package/dist/tools/monitor.js +7 -5
- package/dist/tools/worktree.d.ts +2 -7
- package/dist/tools/worktree.js +3 -1
- package/package.json +6 -2
|
@@ -9,8 +9,7 @@ import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
|
9
9
|
import { computeCostMicroUsd, modelCostToPricing } from "../pricing.js";
|
|
10
10
|
import { emitTrace } from "../trace.js";
|
|
11
11
|
import { emitTaskOutcome } from "../task-outcome.js";
|
|
12
|
-
import {
|
|
13
|
-
import { WALLTIME_CUTOFF_MESSAGE } from "../../brain/walltime.js";
|
|
12
|
+
import { isDegenerateCutMessage, isWalltimeCutMessage } from "../../brain/terminal-cause.js";
|
|
14
13
|
import { primaryActivityArg } from "../arg-summary.js";
|
|
15
14
|
import { resolveReasoning } from "../../brain/reasoning.js";
|
|
16
15
|
import { readDegradation } from "../../brain/degrading.js";
|
|
@@ -24,8 +23,10 @@ import { toImageContent } from "./image.js";
|
|
|
24
23
|
import { OUTPUT_TOOL_NAME, SKILLS_LISTING_PROBE_HEADER, resolveOutputRetries } from "./synthetic-tools.js";
|
|
25
24
|
import { cacheFamilyOf, usageCostMicroUsd } from "./usage-accounting.js";
|
|
26
25
|
import { assembleResult, errorCodeOf } from "./assemble-result.js";
|
|
27
|
-
import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, advanceCadenceClock, agentListingDeltaHeader, agentListingInitialHeader, replayAnnouncedListing, replayAnnouncedModels, collectDateChange, collectDueAttachments, collectInstructionsChange, commitAgentListing, commitInstructionsChange, commitSkillsListing, createAttachmentState, rebaseCadenceWindows, reduceToolEnd, renderAgentListingDelta, renderMcpDroppedTools, renderMcpInstructionsDelta, renderOrphanedBackgroundTasks, selectMcpDroppedBatch, renderSkillsListingDelta, renderToolsDelta, stampWriteAnchor } from "./turn-attachments.js";
|
|
26
|
+
import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, advanceCadenceClock, agentListingDeltaHeader, agentListingInitialHeader, replayAnnouncedListing, replayAnnouncedModels, clipToBytes, collectDateChange, collectDueAttachments, collectInstructionsChange, commitAgentListing, commitInstructionsChange, commitSkillsListing, createAttachmentState, rebaseCadenceWindows, reduceToolEnd, renderAgentListingDelta, renderMcpDroppedTools, renderMcpInstructionsDelta, renderOrphanedBackgroundTasks, selectMcpDroppedBatch, renderSkillsListingDelta, renderToolsDelta, stampWriteAnchor } from "./turn-attachments.js";
|
|
27
|
+
import { buildWorkingFileAttachments, centerAdoptionOption, emitInputTruncated } from "./compaction-call-options.js";
|
|
28
28
|
import { prepareTask } from "./prepare-task.js";
|
|
29
|
+
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
29
30
|
import { TOOL_SEARCH_NAME } from "./tool-disclosure.js";
|
|
30
31
|
import { hasVerifiableStructureSignal } from "./grounding-signal.js";
|
|
31
32
|
import { hasDestroy, isIsolated } from "../remote-env.js";
|
|
@@ -35,7 +36,6 @@ import { delimitUntrusted, inlineUntrusted, sanitizeUntrustedText } from "../unt
|
|
|
35
36
|
import { reconcileInterruptedSession } from "../session-reconcile.js";
|
|
36
37
|
import { RunnerSharedToolResultStore } from "../tool-result-store.js";
|
|
37
38
|
import { formatDiagnosticsBlock } from "../lsp-diagnostics.js";
|
|
38
|
-
import { canonicalToolName } from "../tool-name-aliases.js";
|
|
39
39
|
import { toolPolicyNameSets } from "../tool-policy.js";
|
|
40
40
|
import { defaultTaskRegistry } from "../task-registry.js";
|
|
41
41
|
import { discloseDroppedPending, PendingSessionNotifications, renderTaskNotificationXml, SystemInjectionQueue, taskNotificationDedupKey } from "../task-notification.js";
|
|
@@ -87,20 +87,6 @@ function batchResponseDigest(result) {
|
|
|
87
87
|
? `${text.slice(0, BATCH_RESPONSE_MAX_CHARS)}…[+${text.length - BATCH_RESPONSE_MAX_CHARS} chars truncated]`
|
|
88
88
|
: text;
|
|
89
89
|
}
|
|
90
|
-
function clipToByteBudget(s, maxBytes) {
|
|
91
|
-
if (Buffer.byteLength(s, "utf8") <= maxBytes)
|
|
92
|
-
return s;
|
|
93
|
-
let lo = 0;
|
|
94
|
-
let hi = s.length;
|
|
95
|
-
while (lo < hi) {
|
|
96
|
-
const mid = (lo + hi + 1) >> 1;
|
|
97
|
-
if (Buffer.byteLength(s.slice(0, mid), "utf8") <= maxBytes)
|
|
98
|
-
lo = mid;
|
|
99
|
-
else
|
|
100
|
-
hi = mid - 1;
|
|
101
|
-
}
|
|
102
|
-
return s.slice(0, lo);
|
|
103
|
-
}
|
|
104
90
|
const BATCH_CONTEXT_MIN_KEEP_BYTES = 160;
|
|
105
91
|
const BATCH_TRUNCATION_MARKER = "\n…[truncated]";
|
|
106
92
|
const SUGGESTIONS_DEFAULT_COUNT = 3;
|
|
@@ -118,6 +104,10 @@ function resolveMaxTurns(limits) {
|
|
|
118
104
|
}
|
|
119
105
|
return DEFAULT_MAX_TURNS;
|
|
120
106
|
}
|
|
107
|
+
function resumeDecisionWasNegative(resume) {
|
|
108
|
+
const o = resume.outcome;
|
|
109
|
+
return o.decision === "reject" || o.decision === "deny";
|
|
110
|
+
}
|
|
121
111
|
const DEFERRED_REISSUE = "[DEFERRED] This tool call shared a batch with a call that suspended for durable approval, so it was " +
|
|
122
112
|
"NOT executed on resume. If you still need it, issue it again now.";
|
|
123
113
|
function deepJsonEqual(a, b) {
|
|
@@ -504,16 +494,17 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
504
494
|
const batch = rs.turn.toolBatch;
|
|
505
495
|
rs.turn.toolBatch = [];
|
|
506
496
|
batchArgs?.clear();
|
|
507
|
-
|
|
497
|
+
const injectedThisTurn = finalVerifyInjectedThisTurn ? "final_verification" : rs.counters.finalizeInjected ? "finalize" : undefined;
|
|
498
|
+
if (!boundarySteered && !prepared.abortController.signal.aborted) {
|
|
508
499
|
try {
|
|
509
|
-
const r = await postToolBatchHook(batch);
|
|
510
|
-
if (r?.additionalContext) {
|
|
500
|
+
const r = await postToolBatchHook(batch, injectedThisTurn !== undefined ? { injectedThisTurn } : undefined);
|
|
501
|
+
if (r?.additionalContext && injectedThisTurn === undefined) {
|
|
511
502
|
const body = sanitizeUntrustedText(r.additionalContext);
|
|
512
503
|
const budget = ATTACHMENT_BYTE_CAP - boundaryAttachmentBytes;
|
|
513
504
|
if (budget >= BATCH_CONTEXT_MIN_KEEP_BYTES) {
|
|
514
|
-
const clipped =
|
|
505
|
+
const clipped = clipToBytes(body, budget) === body
|
|
515
506
|
? body
|
|
516
|
-
: `${
|
|
507
|
+
: `${clipToBytes(body, budget - Buffer.byteLength(BATCH_TRUNCATION_MARKER, "utf8"))}${BATCH_TRUNCATION_MARKER}`;
|
|
517
508
|
batchContextBlock = `<system-reminder>\n${clipped}\n</system-reminder>`;
|
|
518
509
|
}
|
|
519
510
|
}
|
|
@@ -603,10 +594,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
603
594
|
const comp = await maybeCompact({
|
|
604
595
|
session: prepared.session,
|
|
605
596
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
606
|
-
...(
|
|
607
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
608
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
609
|
-
})(),
|
|
597
|
+
...centerAdoptionOption(prepared),
|
|
610
598
|
model: event.model,
|
|
611
599
|
compactionModel: prepared.compModel,
|
|
612
600
|
brain: compactionBrain,
|
|
@@ -618,22 +606,11 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
618
606
|
...(manualCancelSignal !== undefined ? { manualCancelSignal } : {}),
|
|
619
607
|
minTokens: forceManual ? 0 : rs.counters.compactionFloor,
|
|
620
608
|
force: forceManual,
|
|
621
|
-
onInputTruncated: (
|
|
609
|
+
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
622
610
|
forceUnderThreshold: trimPressure,
|
|
623
611
|
overheadTokens: prepared.promptOverheadTokens,
|
|
624
612
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
625
|
-
workingFileAttachments: spec
|
|
626
|
-
? {
|
|
627
|
-
readFile: prepared.readTaskFile,
|
|
628
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
629
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
630
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
631
|
-
...(prepared.instructionSources
|
|
632
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
633
|
-
: {}),
|
|
634
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
635
|
-
}
|
|
636
|
-
: undefined,
|
|
613
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
637
614
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
638
615
|
...runnerHooks.seamCCompactionOptions(prepared),
|
|
639
616
|
...windowSafetyOptions(event.model),
|
|
@@ -770,6 +747,13 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
770
747
|
function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
771
748
|
const { spec, queue, internals, buildFinalizeText, ident, nudgeSchedule, parentToolCallId, subagentName, pushContent, emitCommitted, startedToolCallIds, toolStartAt, turnToolSpan, writeFamilyOf, toolLabels, postToolBatchHook, batchArgs } = deps;
|
|
772
749
|
let lastWorkspaceCwd = prepared.cwdRef?.current;
|
|
750
|
+
const announceWorkspaceMove = () => {
|
|
751
|
+
const cwdNow = prepared.cwdRef?.current;
|
|
752
|
+
if (cwdNow !== undefined && cwdNow !== lastWorkspaceCwd) {
|
|
753
|
+
lastWorkspaceCwd = cwdNow;
|
|
754
|
+
queue.push({ type: "workspace_changed", cwd: cwdNow, ...ident() });
|
|
755
|
+
}
|
|
756
|
+
};
|
|
773
757
|
const onMessageUpdate = (event) => {
|
|
774
758
|
const ev = event.assistantMessageEvent;
|
|
775
759
|
if (rs.turn.callStartAt === undefined)
|
|
@@ -891,7 +875,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
891
875
|
if (m.role === "assistant" && typeof m.stopReason === "string") {
|
|
892
876
|
rs.turn.turnStopReason = m.stopReason;
|
|
893
877
|
}
|
|
894
|
-
if (m.role === "assistant" && m
|
|
878
|
+
if (m.role === "assistant" && isWalltimeCutMessage(m)) {
|
|
895
879
|
rs.counters.callCutoffs += 1;
|
|
896
880
|
if (prepared.callCapRef)
|
|
897
881
|
prepared.callCapRef.finalizeMode = true;
|
|
@@ -1022,7 +1006,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
1022
1006
|
}));
|
|
1023
1007
|
internals?.onActivity?.({ phase: "end", toolCallId: event.toolCallId, toolName: event.toolName, isError: event.isError, at: toolNow });
|
|
1024
1008
|
if (prepared.lspDiagnostics && !event.isError) {
|
|
1025
|
-
const name =
|
|
1009
|
+
const name = event.toolName;
|
|
1026
1010
|
if (name === "Edit" || name === "Write" || name === "NotebookEdit") {
|
|
1027
1011
|
const d = event.result?.details;
|
|
1028
1012
|
const p = typeof d?.filePath === "string" ? d.filePath : typeof d?.notebookPath === "string" ? d.notebookPath : undefined;
|
|
@@ -1048,11 +1032,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
1048
1032
|
})(),
|
|
1049
1033
|
...ident(),
|
|
1050
1034
|
});
|
|
1051
|
-
|
|
1052
|
-
if (cwdNow !== undefined && cwdNow !== lastWorkspaceCwd) {
|
|
1053
|
-
lastWorkspaceCwd = cwdNow;
|
|
1054
|
-
queue.push({ type: "workspace_changed", cwd: cwdNow, ...ident() });
|
|
1055
|
-
}
|
|
1035
|
+
announceWorkspaceMove();
|
|
1056
1036
|
if (spec.outputSchema && event.toolName === OUTPUT_TOOL_NAME) {
|
|
1057
1037
|
if (event.isError) {
|
|
1058
1038
|
rs.degrade.outputErrorStreak += 1;
|
|
@@ -1130,7 +1110,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
1130
1110
|
}
|
|
1131
1111
|
}
|
|
1132
1112
|
};
|
|
1133
|
-
return { onMessageUpdate, onMessageEnd, onToolStart, onToolEnd, onTurnEnd };
|
|
1113
|
+
return { onMessageUpdate, onMessageEnd, onToolStart, onToolEnd, onTurnEnd, announceWorkspaceMove };
|
|
1134
1114
|
}
|
|
1135
1115
|
export class Runner {
|
|
1136
1116
|
deps;
|
|
@@ -1313,7 +1293,7 @@ export class Runner {
|
|
|
1313
1293
|
const settled = run.catch(async (err) => {
|
|
1314
1294
|
let code = errorCodeOf(err);
|
|
1315
1295
|
const reopenReason = code === "resume.tool_unavailable" ? "tool_unavailable" : "env_failed";
|
|
1316
|
-
const reopenable = resume !== undefined && resume.pendingActionStarted !== true && reopenReason !== undefined;
|
|
1296
|
+
const reopenable = resume !== undefined && resume.pendingActionStarted !== true && reopenReason !== undefined && !(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true);
|
|
1317
1297
|
let reopenCommitted = false;
|
|
1318
1298
|
if (reopenable && resume?.onEnvRestoreFailed) {
|
|
1319
1299
|
try {
|
|
@@ -1333,11 +1313,7 @@ export class Runner {
|
|
|
1333
1313
|
}
|
|
1334
1314
|
if (resume && !reopenCommitted) {
|
|
1335
1315
|
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
1336
|
-
|
|
1337
|
-
await this.sessions.unpin?.(resume.cp.sessionId);
|
|
1338
|
-
}
|
|
1339
|
-
catch {
|
|
1340
|
-
}
|
|
1316
|
+
await settleTeardownLeg(() => this.sessions.unpin?.(resume.cp.sessionId), "sessions.unpin (resume-failure leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: resume.cp.sessionId }));
|
|
1341
1317
|
}
|
|
1342
1318
|
if (resultValue !== undefined) {
|
|
1343
1319
|
try {
|
|
@@ -1940,18 +1916,18 @@ export class Runner {
|
|
|
1940
1916
|
}
|
|
1941
1917
|
}
|
|
1942
1918
|
rs.attach.attachmentsInjected = 0;
|
|
1943
|
-
const todoToolMounted = rs.attach.attachState !== undefined && prepared.tools.some((t) =>
|
|
1944
|
-
const taskToolsMounted = rs.attach.attachState !== undefined && prepared.tools.some((t) =>
|
|
1919
|
+
const todoToolMounted = rs.attach.attachState !== undefined && prepared.tools.some((t) => t.name === "TodoWrite");
|
|
1920
|
+
const taskToolsMounted = rs.attach.attachState !== undefined && prepared.tools.some((t) => t.name === "TaskCreate");
|
|
1945
1921
|
const writeFamilyByName = new Map();
|
|
1946
1922
|
if (rs.attach.attachState !== undefined) {
|
|
1947
1923
|
for (const t of prepared.tools) {
|
|
1948
|
-
const family = writeFamilyOfCanonical(
|
|
1924
|
+
const family = writeFamilyOfCanonical(t.name);
|
|
1949
1925
|
if (family !== undefined)
|
|
1950
1926
|
for (const n of [t.name, ...(t.aliases ?? [])])
|
|
1951
1927
|
writeFamilyByName.set(n, family);
|
|
1952
1928
|
}
|
|
1953
1929
|
}
|
|
1954
|
-
const writeFamilyOf = (name) => writeFamilyByName.get(name) ?? writeFamilyOfCanonical(
|
|
1930
|
+
const writeFamilyOf = (name) => writeFamilyByName.get(name) ?? writeFamilyOfCanonical(name);
|
|
1955
1931
|
const toolStartAt = new Map();
|
|
1956
1932
|
const turnToolSpan = {};
|
|
1957
1933
|
const startedToolCallIds = new Set();
|
|
@@ -2117,7 +2093,7 @@ export class Runner {
|
|
|
2117
2093
|
const postToolBatchHook = (spec.hooks ?? this.deps.hooks)?.postToolBatch;
|
|
2118
2094
|
const batchArgs = postToolBatchHook ? new Map() : undefined;
|
|
2119
2095
|
rs.turn.toolBatch = [];
|
|
2120
|
-
const { onMessageUpdate, onMessageEnd, onToolStart, onToolEnd, onTurnEnd } = makeHarnessHandlers(prepared, stats, rs, {
|
|
2096
|
+
const { onMessageUpdate, onMessageEnd, onToolStart, onToolEnd, onTurnEnd, announceWorkspaceMove } = makeHarnessHandlers(prepared, stats, rs, {
|
|
2121
2097
|
spec, queue, internals, buildFinalizeText, ident, nudgeSchedule, parentToolCallId, subagentName,
|
|
2122
2098
|
pushContent, emitCommitted, startedToolCallIds, toolStartAt, turnToolSpan, writeFamilyOf,
|
|
2123
2099
|
toolLabels, postToolBatchHook, batchArgs,
|
|
@@ -2324,9 +2300,9 @@ export class Runner {
|
|
|
2324
2300
|
truncatedOutput: {},
|
|
2325
2301
|
malformedToolUse: {},
|
|
2326
2302
|
thinkingOnly: {},
|
|
2327
|
-
degenerateOutput: { detect: (m) => m
|
|
2303
|
+
degenerateOutput: { detect: (m) => isDegenerateCutMessage(m) },
|
|
2328
2304
|
walltimeCutoff: {
|
|
2329
|
-
detect: (m) => m
|
|
2305
|
+
detect: (m) => isWalltimeCutMessage(m),
|
|
2330
2306
|
hasLiveWriteoutWindow: () => {
|
|
2331
2307
|
const ref = prepared.callCapRef;
|
|
2332
2308
|
if (ref === undefined)
|
|
@@ -2349,10 +2325,7 @@ export class Runner {
|
|
|
2349
2325
|
const comp = await maybeCompact({
|
|
2350
2326
|
session: prepared.session,
|
|
2351
2327
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
2352
|
-
...(
|
|
2353
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
2354
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
2355
|
-
})(),
|
|
2328
|
+
...centerAdoptionOption(prepared),
|
|
2356
2329
|
model: prepared.harness.getModel(),
|
|
2357
2330
|
compactionModel: prepared.compModel,
|
|
2358
2331
|
brain: compactionBrain,
|
|
@@ -2365,19 +2338,8 @@ export class Runner {
|
|
|
2365
2338
|
force: true,
|
|
2366
2339
|
overheadTokens: prepared.promptOverheadTokens,
|
|
2367
2340
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
2368
|
-
onInputTruncated: (
|
|
2369
|
-
workingFileAttachments: spec
|
|
2370
|
-
? {
|
|
2371
|
-
readFile: prepared.readTaskFile,
|
|
2372
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
2373
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
2374
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
2375
|
-
...(prepared.instructionSources
|
|
2376
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
2377
|
-
: {}),
|
|
2378
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
2379
|
-
}
|
|
2380
|
-
: undefined,
|
|
2341
|
+
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
2342
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
2381
2343
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
2382
2344
|
...this.seamCCompactionOptions(prepared),
|
|
2383
2345
|
...windowSafetyOptions(prepared.harness.getModel()),
|
|
@@ -2499,6 +2461,9 @@ export class Runner {
|
|
|
2499
2461
|
resume.pendingActionStarted = true;
|
|
2500
2462
|
}
|
|
2501
2463
|
});
|
|
2464
|
+
if (resume.outcome.gate === "policy_ask")
|
|
2465
|
+
resume.decisionDelivered = true;
|
|
2466
|
+
announceWorkspaceMove();
|
|
2502
2467
|
}
|
|
2503
2468
|
if (walltimeExhaustedResume) {
|
|
2504
2469
|
timeout.fired = true;
|
|
@@ -2530,6 +2495,8 @@ export class Runner {
|
|
|
2530
2495
|
if (steer.trusted)
|
|
2531
2496
|
engineSegments.push({ start, end: continuation.length });
|
|
2532
2497
|
}
|
|
2498
|
+
if (resume !== undefined)
|
|
2499
|
+
resume.decisionDelivered = true;
|
|
2533
2500
|
final = await withBrainSinks(() => prepared.harness.prompt(continuation, { engineSegments }));
|
|
2534
2501
|
}
|
|
2535
2502
|
}
|
|
@@ -2640,17 +2607,8 @@ export class Runner {
|
|
|
2640
2607
|
}
|
|
2641
2608
|
catch (err) {
|
|
2642
2609
|
if (errorCodeOf(err) === "resume.tool_unavailable") {
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
}
|
|
2646
|
-
catch {
|
|
2647
|
-
}
|
|
2648
|
-
try {
|
|
2649
|
-
if (prepared.ownedEnv && hasDestroy(prepared.ownedEnv))
|
|
2650
|
-
await prepared.ownedEnv.destroy();
|
|
2651
|
-
}
|
|
2652
|
-
catch {
|
|
2653
|
-
}
|
|
2610
|
+
await settleTeardownLeg(() => prepared.mcp.dispose(), "mcp.dispose (tool_unavailable leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2611
|
+
await settleTeardownLeg(() => (prepared.ownedEnv && hasDestroy(prepared.ownedEnv) ? prepared.ownedEnv.destroy() : undefined), "ownedEnv.destroy (tool_unavailable leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2654
2612
|
throw err;
|
|
2655
2613
|
}
|
|
2656
2614
|
threw = err;
|
|
@@ -2739,7 +2697,7 @@ export class Runner {
|
|
|
2739
2697
|
tokens: prepared.nestedStats.tokens,
|
|
2740
2698
|
turns: prepared.nestedStats.turns,
|
|
2741
2699
|
tasks: prepared.nestedStats.tasks,
|
|
2742
|
-
costMicroUsd: prepared.nestedStats.costMicroUsd
|
|
2700
|
+
...(prepared.nestedStats.anyUnpriced ? {} : { costMicroUsd: prepared.nestedStats.costMicroUsd }),
|
|
2743
2701
|
};
|
|
2744
2702
|
}
|
|
2745
2703
|
if (stats.totalInputTokens > 0) {
|
|
@@ -2824,6 +2782,8 @@ export class Runner {
|
|
|
2824
2782
|
resume.pendingActionStarted !== true &&
|
|
2825
2783
|
result.status !== "completed" &&
|
|
2826
2784
|
result.status !== "suspended" &&
|
|
2785
|
+
result.status !== "needs_review" &&
|
|
2786
|
+
!(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true) &&
|
|
2827
2787
|
resume.onEnvRestoreFailed !== undefined) {
|
|
2828
2788
|
try {
|
|
2829
2789
|
await resume.onEnvRestoreFailed("env_failed");
|
|
@@ -2844,15 +2804,11 @@ export class Runner {
|
|
|
2844
2804
|
const curWt = prepared.worktreeSessionRef?.current;
|
|
2845
2805
|
const changed = curCwd !== wss.restoredHandsCwd || curWt?.worktreeDir !== wss.restoredWorktreeDir;
|
|
2846
2806
|
if (curCwd !== undefined || curWt !== undefined || changed || wss.baselineUnknown === true) {
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
});
|
|
2853
|
-
}
|
|
2854
|
-
catch {
|
|
2855
|
-
}
|
|
2807
|
+
await settleTeardownLeg(() => prepared.session.appendWorkspaceState({
|
|
2808
|
+
taskRoot: wss.rootCanonical,
|
|
2809
|
+
...(curCwd !== undefined ? { handsCwd: curCwd } : {}),
|
|
2810
|
+
...(curWt !== undefined ? { activeWorktree: { ...curWt } } : {}),
|
|
2811
|
+
}), "session.appendWorkspaceState (settle leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2856
2812
|
}
|
|
2857
2813
|
}
|
|
2858
2814
|
}
|
|
@@ -2860,8 +2816,8 @@ export class Runner {
|
|
|
2860
2816
|
if (stopFailureHook !== undefined &&
|
|
2861
2817
|
result.status === "failed" &&
|
|
2862
2818
|
final?.stopReason === "error" &&
|
|
2863
|
-
final
|
|
2864
|
-
final
|
|
2819
|
+
!isDegenerateCutMessage(final) &&
|
|
2820
|
+
!isWalltimeCutMessage(final) &&
|
|
2865
2821
|
threw === undefined &&
|
|
2866
2822
|
rs.limits.budgetHit === undefined &&
|
|
2867
2823
|
!rs.degrade.outputInvalid &&
|
|
@@ -2902,19 +2858,12 @@ export class Runner {
|
|
|
2902
2858
|
}
|
|
2903
2859
|
}
|
|
2904
2860
|
if (resume && committedToken === undefined) {
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
this.deps.onError?.(err, { phase: "config", sessionId: prepared.sessionId });
|
|
2911
|
-
}
|
|
2912
|
-
catch {
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2861
|
+
await settleTeardownLeg(() => this.sessions.unpin?.(resume.cp.sessionId), "sessions.unpin (resumed-terminal leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2862
|
+
}
|
|
2863
|
+
if (prepared.memoryEngineSession) {
|
|
2864
|
+
const mes = prepared.memoryEngineSession;
|
|
2865
|
+
await settleTeardownLeg(() => mes.harvest(), "memoryEngineSession.harvest (settle leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2915
2866
|
}
|
|
2916
|
-
if (prepared.memoryEngineSession)
|
|
2917
|
-
await prepared.memoryEngineSession.harvest();
|
|
2918
2867
|
emitTrace(rs.telemetry.tracer, () => ({
|
|
2919
2868
|
kind: "task.end",
|
|
2920
2869
|
version: 1,
|
|
@@ -2968,28 +2917,19 @@ export class Runner {
|
|
|
2968
2917
|
isIsolated(prepared.ownedEnv) &&
|
|
2969
2918
|
prepared.suspendRef.token === undefined &&
|
|
2970
2919
|
prepared.reviewRef.token === undefined;
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
});
|
|
2985
|
-
}
|
|
2986
|
-
catch (e) {
|
|
2987
|
-
try {
|
|
2988
|
-
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
2989
|
-
}
|
|
2990
|
-
catch {
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
2920
|
+
await settleTeardownLeg(() => defaultTaskRegistry.settleKilledForOwner({ owner: spec.taskId ?? prepared.sessionId, scope: spec.principal ?? "default", sessionId: prepared.sessionId }, {
|
|
2921
|
+
source: abortedLive &&
|
|
2922
|
+
!timeout.fired &&
|
|
2923
|
+
!rs.limits.turnsExceeded &&
|
|
2924
|
+
rs.limits.budgetHit === undefined &&
|
|
2925
|
+
prepared.suspendRef.token === undefined &&
|
|
2926
|
+
prepared.reviewRef.token === undefined
|
|
2927
|
+
? "user"
|
|
2928
|
+
: "parent",
|
|
2929
|
+
skipSessionScoped: true,
|
|
2930
|
+
envDying: ownedEnvDying,
|
|
2931
|
+
retainProcesses: spec.retainBackgroundProcesses === true,
|
|
2932
|
+
}), "taskRegistry.settleKilledForOwner", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2993
2933
|
const bgEnv = prepared.ownedEnv ?? this.deps.executionEnv;
|
|
2994
2934
|
const retainBgBySpec = spec.retainBackgroundProcesses === true && !ownedEnvDying;
|
|
2995
2935
|
if (bgEnv && hasBackgroundShell(bgEnv) && !retainBgBySpec) {
|
|
@@ -3001,7 +2941,7 @@ export class Runner {
|
|
|
3001
2941
|
...defaultTaskRegistry.timeoutResidentShellIds(bgEnv),
|
|
3002
2942
|
...defaultTaskRegistry.retainedShellIds(bgEnv),
|
|
3003
2943
|
];
|
|
3004
|
-
await sweepBackgroundShells(bgEnv, defaultTaskRegistry, keepAlive.length > 0 ? { except: keepAlive } : undefined);
|
|
2944
|
+
await settleTeardownLeg(() => sweepBackgroundShells(bgEnv, defaultTaskRegistry, keepAlive.length > 0 ? { except: keepAlive } : undefined), "sweepBackgroundShells", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3005
2945
|
}
|
|
3006
2946
|
catch (e) {
|
|
3007
2947
|
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
@@ -3016,14 +2956,9 @@ export class Runner {
|
|
|
3016
2956
|
scope: spec.principal ?? "default",
|
|
3017
2957
|
}, { skipSessionScoped: true });
|
|
3018
2958
|
if (prepared.subagentRetain) {
|
|
3019
|
-
|
|
3020
|
-
await prepared.subagentRetain.disposeAll();
|
|
3021
|
-
}
|
|
3022
|
-
catch (e) {
|
|
3023
|
-
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
3024
|
-
}
|
|
2959
|
+
await settleTeardownLeg(() => prepared.subagentRetain.disposeAll(), "subagentRetain.disposeAll", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3025
2960
|
}
|
|
3026
|
-
await this.teardownOwnedEnv(prepared);
|
|
2961
|
+
await settleTeardownLeg(() => this.teardownOwnedEnv(prepared), "teardownOwnedEnv", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3027
2962
|
}
|
|
3028
2963
|
}
|
|
3029
2964
|
async suggestNextPrompts(spec, prepared, result) {
|
|
@@ -3358,7 +3293,7 @@ export class Runner {
|
|
|
3358
3293
|
return;
|
|
3359
3294
|
if (resume.outcome.gate === "policy_ask" &&
|
|
3360
3295
|
resume.outcome.decision === "allow" &&
|
|
3361
|
-
!prepared.tools.some((t) => t.name ===
|
|
3296
|
+
!prepared.tools.some((t) => t.name === pendingAction.toolName)) {
|
|
3362
3297
|
const e = new Error(`the approved tool "${pendingAction.toolName}" is no longer available on resume — refusing to continue as if it ran; the checkpoint is reopened for a retry with the tool present`);
|
|
3363
3298
|
e.code = "resume.tool_unavailable";
|
|
3364
3299
|
throw e;
|
|
@@ -3423,7 +3358,7 @@ export class Runner {
|
|
|
3423
3358
|
return;
|
|
3424
3359
|
}
|
|
3425
3360
|
}
|
|
3426
|
-
const tool = prepared.tools.find((t) => t.name ===
|
|
3361
|
+
const tool = prepared.tools.find((t) => t.name === pendingAction.toolName);
|
|
3427
3362
|
if (!tool) {
|
|
3428
3363
|
const e = new Error(`the approved tool "${pendingAction.toolName}" is no longer available on resume`);
|
|
3429
3364
|
e.code = "resume.tool_unavailable";
|
|
@@ -3443,7 +3378,7 @@ export class Runner {
|
|
|
3443
3378
|
}
|
|
3444
3379
|
const executedIsError = res.isError === true;
|
|
3445
3380
|
emitEnd(executedIsError);
|
|
3446
|
-
onResolvedToolSuccess?.(
|
|
3381
|
+
onResolvedToolSuccess?.(pendingAction.toolName, executedIsError ? undefined : res.details);
|
|
3447
3382
|
const eid = await prepared.session.appendMessage({
|
|
3448
3383
|
role: "toolResult",
|
|
3449
3384
|
toolCallId: pendingAction.toolCallId,
|
|
@@ -3525,10 +3460,7 @@ export class Runner {
|
|
|
3525
3460
|
const finishComp = await maybeCompact({
|
|
3526
3461
|
session: prepared.session,
|
|
3527
3462
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
3528
|
-
...(
|
|
3529
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
3530
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
3531
|
-
})(),
|
|
3463
|
+
...centerAdoptionOption(prepared),
|
|
3532
3464
|
model: prepared.model,
|
|
3533
3465
|
compactionModel: prepared.compModel,
|
|
3534
3466
|
brain: opts?.brain ?? this.deps.brain,
|
|
@@ -3539,28 +3471,9 @@ export class Runner {
|
|
|
3539
3471
|
minTokens: opts?.minTokens,
|
|
3540
3472
|
overheadTokens: prepared.promptOverheadTokens,
|
|
3541
3473
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
3542
|
-
onInputTruncated: (
|
|
3543
|
-
kind: "compaction.input_truncated",
|
|
3544
|
-
version: 1,
|
|
3545
|
-
taskId: spec.taskId ?? prepared.sessionId,
|
|
3546
|
-
label: info.label,
|
|
3547
|
-
droppedChars: info.droppedChars,
|
|
3548
|
-
keptChars: info.keptChars,
|
|
3549
|
-
ts: Date.now(),
|
|
3550
|
-
})),
|
|
3474
|
+
onInputTruncated: emitInputTruncated(spec.tracer ?? this.deps.tracer, spec.taskId ?? prepared.sessionId),
|
|
3551
3475
|
...(opts?.windowSafety ?? {}),
|
|
3552
|
-
workingFileAttachments: spec
|
|
3553
|
-
? {
|
|
3554
|
-
readFile: prepared.readTaskFile,
|
|
3555
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
3556
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
3557
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
3558
|
-
...(prepared.instructionSources
|
|
3559
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
3560
|
-
: {}),
|
|
3561
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
3562
|
-
}
|
|
3563
|
-
: undefined,
|
|
3476
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
3564
3477
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
3565
3478
|
...this.seamCCompactionOptions(prepared),
|
|
3566
3479
|
...this.compactionHookOptions(spec, prepared.sessionId, "auto"),
|
|
@@ -3629,7 +3542,6 @@ function startTimeout(harness, abortController, remainingMs, softSuspendable = f
|
|
|
3629
3542
|
abortController.abort();
|
|
3630
3543
|
void harness.abort();
|
|
3631
3544
|
}, hardMs);
|
|
3632
|
-
timer.unref?.();
|
|
3633
3545
|
state.clear = () => clearTimeout(timer);
|
|
3634
3546
|
}
|
|
3635
3547
|
return state;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { canonicalizeTarget, fileArgPath } from "../../tools/fs/safety.js";
|
|
2
|
+
import { isWinFormPath } from "../../tools/fs/safety.js";
|
|
2
3
|
import { createCoarseCommandNamePolicy } from "../tool-policy.js";
|
|
3
|
-
import { canonicalToolName } from "../tool-name-aliases.js";
|
|
4
4
|
export const PATH_WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit"]);
|
|
5
5
|
export function isWithin(root, p) {
|
|
6
|
+
if (!root)
|
|
7
|
+
return false;
|
|
6
8
|
const norm = (x) => {
|
|
7
|
-
let n = x.replace(/\\/g, "/");
|
|
9
|
+
let n = isWinFormPath(x) ? x.replace(/\\/g, "/") : x;
|
|
8
10
|
if (/^[A-Za-z]:(\/|$)/.test(n))
|
|
9
11
|
n = n[0].toLowerCase() + n.slice(1);
|
|
10
12
|
return n;
|
|
@@ -19,8 +21,8 @@ export function isWithin(root, p) {
|
|
|
19
21
|
const deny = (reason) => ({ action: "deny", reason, decisionReason: "rule" });
|
|
20
22
|
export function createSessionRulePolicy(rules, opts) {
|
|
21
23
|
const { env, rootPath, toolEffects } = opts;
|
|
22
|
-
const toolDeny = new Set(
|
|
23
|
-
const toolAllow = rules.toolAllow ? new Set(rules.toolAllow
|
|
24
|
+
const toolDeny = new Set(rules.toolDeny ?? []);
|
|
25
|
+
const toolAllow = rules.toolAllow ? new Set(rules.toolAllow) : undefined;
|
|
24
26
|
const cmdPolicy = rules.commandAllow || rules.commandDeny
|
|
25
27
|
? createCoarseCommandNamePolicy({
|
|
26
28
|
...(rules.commandAllow ? { allow: rules.commandAllow } : {}),
|
|
@@ -31,7 +33,7 @@ export function createSessionRulePolicy(rules, opts) {
|
|
|
31
33
|
const allowDirs = rules.allowDirs && rules.allowDirs.length > 0 ? rules.allowDirs : undefined;
|
|
32
34
|
return {
|
|
33
35
|
async check(req, signal) {
|
|
34
|
-
const toolName =
|
|
36
|
+
const toolName = req.toolName;
|
|
35
37
|
if (toolDeny.has(toolName))
|
|
36
38
|
return deny(`tool "${req.toolName}" is denied by a session rule`);
|
|
37
39
|
if (toolAllow && !toolAllow.has(toolName)) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const TEARDOWN_LEG_MAX_MS = 15000;
|
|
2
|
+
export declare function setTeardownLegBudgetForTests(ms: number | undefined): void;
|
|
3
|
+
export declare class TeardownLegTimeoutError extends Error {
|
|
4
|
+
readonly leg: string;
|
|
5
|
+
constructor(leg: string, budgetMs: number);
|
|
6
|
+
}
|
|
7
|
+
export declare function settleTeardownLeg(leg: () => Promise<unknown> | unknown, label: string, report?: (err: Error) => void): Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const TEARDOWN_LEG_MAX_MS = 15_000;
|
|
2
|
+
let teardownLegBudgetMs = TEARDOWN_LEG_MAX_MS;
|
|
3
|
+
export function setTeardownLegBudgetForTests(ms) {
|
|
4
|
+
teardownLegBudgetMs = ms ?? TEARDOWN_LEG_MAX_MS;
|
|
5
|
+
}
|
|
6
|
+
export class TeardownLegTimeoutError extends Error {
|
|
7
|
+
leg;
|
|
8
|
+
constructor(leg, budgetMs) {
|
|
9
|
+
super(`teardown leg "${leg}" did not settle within ${budgetMs}ms — proceeding without it. ` +
|
|
10
|
+
`The leg keeps running detached; whatever it owns (process/env/store row) may be leaked until it settles on its own.`);
|
|
11
|
+
this.name = "TeardownLegTimeoutError";
|
|
12
|
+
this.leg = leg;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function settleTeardownLeg(leg, label, report) {
|
|
16
|
+
let timer;
|
|
17
|
+
try {
|
|
18
|
+
await Promise.race([
|
|
19
|
+
Promise.resolve().then(leg),
|
|
20
|
+
new Promise((_, reject) => {
|
|
21
|
+
timer = setTimeout(() => reject(new TeardownLegTimeoutError(label, teardownLegBudgetMs)), teardownLegBudgetMs);
|
|
22
|
+
}),
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
try {
|
|
27
|
+
report?.(e instanceof Error ? e : new Error(String(e)));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
if (timer !== undefined)
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -2,6 +2,7 @@ import { type TSchema } from "typebox";
|
|
|
2
2
|
import type { AgentMessage, AgentTool, AgentToolResult, AgentToolUpdateCallback, ToolExecutionMode } from "../../internal/harness-types.js";
|
|
3
3
|
import type { Model } from "../../internal/llm.js";
|
|
4
4
|
import type { ToolSpec } from "../types.js";
|
|
5
|
+
import type { ToolFingerprintInput } from "../cache-break-detector.js";
|
|
5
6
|
export declare const TOOL_SEARCH_NAME = "ToolSearch";
|
|
6
7
|
export declare const TOOL_SEARCH_DEFAULT_MAX_RESULTS = 5;
|
|
7
8
|
export interface DeferredToolInfo {
|
|
@@ -14,11 +15,7 @@ export declare function safeName(name: string): string;
|
|
|
14
15
|
export declare function classifyDeferred(opts: {
|
|
15
16
|
specs: ReadonlyArray<ToolSpec>;
|
|
16
17
|
mcpToolNames: ReadonlyArray<string>;
|
|
17
|
-
fullTools: ReadonlyArray<
|
|
18
|
-
name: string;
|
|
19
|
-
description: string;
|
|
20
|
-
parameters: unknown;
|
|
21
|
-
}>;
|
|
18
|
+
fullTools: ReadonlyArray<ToolFingerprintInput>;
|
|
22
19
|
deferMode?: "auto";
|
|
23
20
|
model: Model;
|
|
24
21
|
deferNames?: ReadonlyArray<string>;
|