@sema-agent/core 2.13.0 → 4.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 +2345 -0
- package/dist/agents/cascade.d.ts +6 -1
- package/dist/agents/cascade.js +76 -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 +110 -3
- package/dist/agents/retain-ledger.d.ts +20 -2
- package/dist/agents/retain-ledger.js +38 -8
- package/dist/agents/roster-store.d.ts +4 -0
- package/dist/agents/roster-store.js +20 -1
- package/dist/agents/subagent.js +66 -64
- package/dist/agents/teacher.d.ts +1 -9
- package/dist/agents/teacher.js +23 -24
- package/dist/agents/team.js +7 -4
- package/dist/agents/verify.d.ts +15 -2
- package/dist/agents/verify.js +39 -3
- package/dist/bin/sema-tb.js +2 -2
- package/dist/brain/anthropic.js +24 -21
- package/dist/brain/circuit-breaker.d.ts +1 -0
- package/dist/brain/circuit-breaker.js +26 -9
- package/dist/brain/degrading.js +13 -1
- package/dist/brain/failover.js +2 -0
- package/dist/brain/openai.js +24 -21
- package/dist/brain/repetition.js +10 -1
- package/dist/brain/routing.js +5 -1
- package/dist/brain/status-sink.js +5 -1
- 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 +34 -15
- package/dist/core/auto-compaction.js +33 -32
- 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 +7 -13
- package/dist/core/checkpoint-store.js +39 -15
- package/dist/core/consolidate-scope.js +4 -3
- package/dist/core/context-edit.js +3 -0
- package/dist/core/context-guard.js +3 -0
- package/dist/core/file-snapshot-store.d.ts +8 -0
- package/dist/core/file-snapshot-store.js +4 -3
- package/dist/core/git-worktree-env.d.ts +6 -1
- package/dist/core/git-worktree-env.js +12 -1
- package/dist/core/hooks.d.ts +4 -1
- package/dist/core/hooks.js +35 -7
- package/dist/core/lsp-diagnostics.js +13 -7
- package/dist/core/lsp-protocol.d.ts +1 -1
- package/dist/core/lsp-protocol.js +20 -8
- package/dist/core/lsp-session.d.ts +12 -2
- package/dist/core/lsp-session.js +114 -49
- package/dist/core/lsp.d.ts +13 -1
- package/dist/core/lsp.js +65 -9
- package/dist/core/mailbox-store.d.ts +7 -10
- package/dist/core/mcp.d.ts +7 -10
- package/dist/core/mcp.js +7 -3
- package/dist/core/memory-engine/data-plane.js +4 -0
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/memory-engine/engine.js +96 -31
- package/dist/core/memory-engine/file-backend.d.ts +2 -2
- package/dist/core/memory-engine/file-backend.js +38 -39
- package/dist/core/memory-engine/layout.d.ts +8 -0
- package/dist/core/memory-engine/layout.js +71 -4
- package/dist/core/memory-engine/scope-contract.js +9 -3
- package/dist/core/memory-engine/types.d.ts +1 -1
- package/dist/core/memory.js +3 -0
- package/dist/core/permission-rules.d.ts +2 -1
- package/dist/core/permission-rules.js +24 -3
- package/dist/core/runner/active-skill-scope.d.ts +0 -1
- package/dist/core/runner/active-skill-scope.js +1 -15
- package/dist/core/runner/assemble-result.d.ts +3 -8
- package/dist/core/runner/assemble-result.js +3 -5
- 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 +31 -53
- package/dist/core/runner/runtask.d.ts +1 -0
- package/dist/core/runner/runtask.js +86 -178
- package/dist/core/runner/session-rule-policy.js +4 -1
- 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/runner/usage-accounting.d.ts +6 -0
- package/dist/core/runner/usage-accounting.js +9 -8
- package/dist/core/safe-notify.d.ts +17 -0
- package/dist/core/safe-notify.js +59 -0
- package/dist/core/secret-env.js +5 -1
- package/dist/core/sensitive-path-policy.js +11 -4
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/store-contracts/session-repo-contract.js +40 -0
- 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 +15 -14
- package/dist/core/task-registry-shared.d.ts +22 -0
- package/dist/core/task-registry-shared.js +16 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +40 -57
- package/dist/core/tool-errors.js +5 -4
- package/dist/core/tool-name-aliases.js +2 -1
- package/dist/core/tool-policy.js +72 -19
- 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 +3 -9
- package/dist/core/types.d.ts +16 -12
- package/dist/core/untrusted-egress.js +7 -5
- 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/compaction.d.ts +1 -0
- package/dist/engine/compaction/compaction.js +14 -5
- package/dist/engine/compaction/utils.js +4 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +2 -24
- 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 +11 -4
- package/dist/engine/loop/types.d.ts +11 -9
- package/dist/engine/lsp/frame-decoder.js +6 -3
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -0
- package/dist/engine/lsp/node-lsp-manager.js +103 -26
- package/dist/engine/lsp/stdio-lsp-transport.js +16 -7
- package/dist/engine/session/memory-repo.d.ts +2 -6
- package/dist/engine/session/session.d.ts +5 -30
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/internal/harness-types.d.ts +3 -1
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/orchestration/run-spec.js +7 -4
- package/dist/orchestration/run-workflow-tool.js +3 -35
- package/dist/orchestration/workflow-governance.js +43 -9
- package/dist/orchestration/workflow-sandbox-conformance.js +85 -51
- package/dist/orchestration/workflow-script-store.js +34 -4
- package/dist/orchestration/workflow.d.ts +3 -11
- package/dist/orchestration/workflow.js +164 -204
- package/dist/prompt-assembly/artifact-store.d.ts +2 -0
- package/dist/prompt-assembly/artifact-store.js +39 -24
- package/dist/prompt-assembly/assemble.js +38 -7
- package/dist/prompt-assembly/epoch.js +19 -2
- package/dist/prompt-assembly/event-registry.js +3 -3
- package/dist/prompt-assembly/explain.js +1 -1
- package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
- package/dist/prompt-assembly/tool-catalog.js +16 -1
- package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
- package/dist/prompt-assembly/turn-snapshot.js +4 -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/fs-atomic.d.ts +3 -0
- package/dist/stores/file/fs-atomic.js +53 -8
- package/dist/stores/file/index.d.ts +1 -0
- package/dist/stores/file/index.js +7 -0
- 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 +4 -6
- package/dist/stores/file/session-store.js +28 -1
- 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 +2 -0
- package/dist/tools/fs/bash-readonly-classifier.js +73 -21
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +407 -91
- package/dist/tools/fs/fs-pdf.d.ts +2 -12
- package/dist/tools/fs/fs-shared.js +2 -2
- 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/loop-tick.js +1 -1
- package/dist/tools/monitor.d.ts +1 -0
- package/dist/tools/monitor.js +57 -9
- package/dist/tools/worktree.d.ts +4 -7
- package/dist/tools/worktree.js +235 -143
- package/package.json +9 -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";
|
|
@@ -87,20 +88,6 @@ function batchResponseDigest(result) {
|
|
|
87
88
|
? `${text.slice(0, BATCH_RESPONSE_MAX_CHARS)}…[+${text.length - BATCH_RESPONSE_MAX_CHARS} chars truncated]`
|
|
88
89
|
: text;
|
|
89
90
|
}
|
|
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
91
|
const BATCH_CONTEXT_MIN_KEEP_BYTES = 160;
|
|
105
92
|
const BATCH_TRUNCATION_MARKER = "\n…[truncated]";
|
|
106
93
|
const SUGGESTIONS_DEFAULT_COUNT = 3;
|
|
@@ -118,6 +105,10 @@ function resolveMaxTurns(limits) {
|
|
|
118
105
|
}
|
|
119
106
|
return DEFAULT_MAX_TURNS;
|
|
120
107
|
}
|
|
108
|
+
function resumeDecisionWasNegative(resume) {
|
|
109
|
+
const o = resume.outcome;
|
|
110
|
+
return o.decision === "reject" || o.decision === "deny";
|
|
111
|
+
}
|
|
121
112
|
const DEFERRED_REISSUE = "[DEFERRED] This tool call shared a batch with a call that suspended for durable approval, so it was " +
|
|
122
113
|
"NOT executed on resume. If you still need it, issue it again now.";
|
|
123
114
|
function deepJsonEqual(a, b) {
|
|
@@ -341,8 +332,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
341
332
|
const scan = await Promise.race([
|
|
342
333
|
prepared.detectExternalChanges(maxFiles),
|
|
343
334
|
new Promise((resolve) => {
|
|
344
|
-
|
|
345
|
-
t.unref?.();
|
|
335
|
+
setTimeout(() => resolve({ changed: [], evicted: [] }), SCAN_CEILING_MS);
|
|
346
336
|
}),
|
|
347
337
|
]);
|
|
348
338
|
for (const p of scan.evicted)
|
|
@@ -475,8 +465,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
475
465
|
probed = await Promise.race([
|
|
476
466
|
rs.attach.instrProbe(prepared.instructionSources),
|
|
477
467
|
new Promise((resolve) => {
|
|
478
|
-
|
|
479
|
-
t.unref?.();
|
|
468
|
+
setTimeout(() => resolve(null), PROBE_CEILING_MS);
|
|
480
469
|
}),
|
|
481
470
|
]);
|
|
482
471
|
}
|
|
@@ -506,16 +495,17 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
506
495
|
const batch = rs.turn.toolBatch;
|
|
507
496
|
rs.turn.toolBatch = [];
|
|
508
497
|
batchArgs?.clear();
|
|
509
|
-
|
|
498
|
+
const injectedThisTurn = finalVerifyInjectedThisTurn ? "final_verification" : rs.counters.finalizeInjected ? "finalize" : undefined;
|
|
499
|
+
if (!boundarySteered && !prepared.abortController.signal.aborted) {
|
|
510
500
|
try {
|
|
511
|
-
const r = await postToolBatchHook(batch);
|
|
512
|
-
if (r?.additionalContext) {
|
|
501
|
+
const r = await postToolBatchHook(batch, injectedThisTurn !== undefined ? { injectedThisTurn } : undefined);
|
|
502
|
+
if (r?.additionalContext && injectedThisTurn === undefined) {
|
|
513
503
|
const body = sanitizeUntrustedText(r.additionalContext);
|
|
514
504
|
const budget = ATTACHMENT_BYTE_CAP - boundaryAttachmentBytes;
|
|
515
505
|
if (budget >= BATCH_CONTEXT_MIN_KEEP_BYTES) {
|
|
516
|
-
const clipped =
|
|
506
|
+
const clipped = clipToBytes(body, budget) === body
|
|
517
507
|
? body
|
|
518
|
-
: `${
|
|
508
|
+
: `${clipToBytes(body, budget - Buffer.byteLength(BATCH_TRUNCATION_MARKER, "utf8"))}${BATCH_TRUNCATION_MARKER}`;
|
|
519
509
|
batchContextBlock = `<system-reminder>\n${clipped}\n</system-reminder>`;
|
|
520
510
|
}
|
|
521
511
|
}
|
|
@@ -605,10 +595,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
605
595
|
const comp = await maybeCompact({
|
|
606
596
|
session: prepared.session,
|
|
607
597
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
608
|
-
...(
|
|
609
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
610
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
611
|
-
})(),
|
|
598
|
+
...centerAdoptionOption(prepared),
|
|
612
599
|
model: event.model,
|
|
613
600
|
compactionModel: prepared.compModel,
|
|
614
601
|
brain: compactionBrain,
|
|
@@ -620,22 +607,11 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
620
607
|
...(manualCancelSignal !== undefined ? { manualCancelSignal } : {}),
|
|
621
608
|
minTokens: forceManual ? 0 : rs.counters.compactionFloor,
|
|
622
609
|
force: forceManual,
|
|
623
|
-
onInputTruncated: (
|
|
610
|
+
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
624
611
|
forceUnderThreshold: trimPressure,
|
|
625
612
|
overheadTokens: prepared.promptOverheadTokens,
|
|
626
613
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
627
|
-
workingFileAttachments: spec
|
|
628
|
-
? {
|
|
629
|
-
readFile: prepared.readTaskFile,
|
|
630
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
631
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
632
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
633
|
-
...(prepared.instructionSources
|
|
634
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
635
|
-
: {}),
|
|
636
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
637
|
-
}
|
|
638
|
-
: undefined,
|
|
614
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
639
615
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
640
616
|
...runnerHooks.seamCCompactionOptions(prepared),
|
|
641
617
|
...windowSafetyOptions(event.model),
|
|
@@ -811,16 +787,18 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
811
787
|
rs.turn.turnUsageMissing = true;
|
|
812
788
|
const u = m.usage;
|
|
813
789
|
stats.tokens += u.totalTokens || 0;
|
|
814
|
-
const { totalInputTokens:
|
|
790
|
+
const { totalInputTokens: turnTotal, uncachedInputTokens: turnUncached, costMicroUsd: turnCostMicroUsd, } = usageCostMicroUsd(rs.telemetry.cacheFamily, u, rs.telemetry.pricing);
|
|
815
791
|
if (!rs.telemetry.pricingConfigured)
|
|
816
792
|
rs.telemetry.unpricedSpend = true;
|
|
817
|
-
stats.promptTokens +=
|
|
793
|
+
stats.promptTokens += turnUncached;
|
|
794
|
+
stats.totalInputTokens += turnTotal;
|
|
818
795
|
stats.cachedTokens += u.cacheRead || 0;
|
|
819
796
|
stats.cacheWriteTokens += u.cacheWrite || 0;
|
|
820
797
|
stats.outputTokens += u.output || 0;
|
|
821
798
|
stats.costMicroUsd += turnCostMicroUsd;
|
|
822
|
-
rs.turn.turnUsage ??= { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costMicroUsd: 0 };
|
|
823
|
-
rs.turn.turnUsage.inputTokens +=
|
|
799
|
+
rs.turn.turnUsage ??= { inputTokens: 0, totalInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costMicroUsd: 0 };
|
|
800
|
+
rs.turn.turnUsage.inputTokens += turnUncached;
|
|
801
|
+
rs.turn.turnUsage.totalInputTokens += turnTotal;
|
|
824
802
|
rs.turn.turnUsage.outputTokens += u.output || 0;
|
|
825
803
|
rs.turn.turnUsage.cacheReadTokens += u.cacheRead || 0;
|
|
826
804
|
rs.turn.turnUsage.cacheWriteTokens += u.cacheWrite || 0;
|
|
@@ -846,7 +824,8 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
846
824
|
model: m.model,
|
|
847
825
|
provider: m.provider,
|
|
848
826
|
turn: stats.turns + 1,
|
|
849
|
-
promptTokens:
|
|
827
|
+
promptTokens: turnUncached,
|
|
828
|
+
totalInputTokens: turnTotal,
|
|
850
829
|
completionTokens: u.output || 0,
|
|
851
830
|
cacheRead: u.cacheRead || 0,
|
|
852
831
|
cacheWrite: u.cacheWrite || 0,
|
|
@@ -890,7 +869,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
890
869
|
if (m.role === "assistant" && typeof m.stopReason === "string") {
|
|
891
870
|
rs.turn.turnStopReason = m.stopReason;
|
|
892
871
|
}
|
|
893
|
-
if (m.role === "assistant" && m
|
|
872
|
+
if (m.role === "assistant" && isWalltimeCutMessage(m)) {
|
|
894
873
|
rs.counters.callCutoffs += 1;
|
|
895
874
|
if (prepared.callCapRef)
|
|
896
875
|
prepared.callCapRef.finalizeMode = true;
|
|
@@ -1262,7 +1241,6 @@ export class Runner {
|
|
|
1262
1241
|
let t;
|
|
1263
1242
|
const timeout = new Promise((res2) => {
|
|
1264
1243
|
t = setTimeout(() => res2(undefined), READY_TIMEOUT_MS);
|
|
1265
|
-
t.unref?.();
|
|
1266
1244
|
});
|
|
1267
1245
|
return Promise.race([p, timeout]).finally(() => clearTimeout(t));
|
|
1268
1246
|
};
|
|
@@ -1313,7 +1291,7 @@ export class Runner {
|
|
|
1313
1291
|
const settled = run.catch(async (err) => {
|
|
1314
1292
|
let code = errorCodeOf(err);
|
|
1315
1293
|
const reopenReason = code === "resume.tool_unavailable" ? "tool_unavailable" : "env_failed";
|
|
1316
|
-
const reopenable = resume !== undefined && resume.pendingActionStarted !== true && reopenReason !== undefined;
|
|
1294
|
+
const reopenable = resume !== undefined && resume.pendingActionStarted !== true && reopenReason !== undefined && !(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true);
|
|
1317
1295
|
let reopenCommitted = false;
|
|
1318
1296
|
if (reopenable && resume?.onEnvRestoreFailed) {
|
|
1319
1297
|
try {
|
|
@@ -1333,11 +1311,7 @@ export class Runner {
|
|
|
1333
1311
|
}
|
|
1334
1312
|
if (resume && !reopenCommitted) {
|
|
1335
1313
|
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
1336
|
-
|
|
1337
|
-
await this.sessions.unpin?.(resume.cp.sessionId);
|
|
1338
|
-
}
|
|
1339
|
-
catch {
|
|
1340
|
-
}
|
|
1314
|
+
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
1315
|
}
|
|
1342
1316
|
if (resultValue !== undefined) {
|
|
1343
1317
|
try {
|
|
@@ -1650,7 +1624,7 @@ export class Runner {
|
|
|
1650
1624
|
}
|
|
1651
1625
|
}
|
|
1652
1626
|
onReady({ harness: prepared.harness, abortController: prepared.abortController });
|
|
1653
|
-
const stats = { turns: 0, tokens: 0, toolCalls: 0, promptTokens: 0, cachedTokens: 0, cacheWriteTokens: 0, cacheWriteTokensLong: 0, outputTokens: 0, costMicroUsd: 0 };
|
|
1627
|
+
const stats = { turns: 0, tokens: 0, toolCalls: 0, promptTokens: 0, totalInputTokens: 0, cachedTokens: 0, cacheWriteTokens: 0, cacheWriteTokensLong: 0, outputTokens: 0, costMicroUsd: 0 };
|
|
1654
1628
|
prepared.liveSpendRef.get = () => ({ costMicroUsd: stats.costMicroUsd, tokens: stats.tokens, turns: stats.turns, walltimeMs: Math.round(performance.now() - rs.telemetry.taskStartMonotonic) });
|
|
1655
1629
|
if (resume &&
|
|
1656
1630
|
resume.cp.suspendedAt !== undefined &&
|
|
@@ -2132,9 +2106,10 @@ export class Runner {
|
|
|
2132
2106
|
const priced = this.deps.pricing?.[m.id] !== undefined || m.cost !== undefined;
|
|
2133
2107
|
if (!priced)
|
|
2134
2108
|
rs.telemetry.unpricedSpend = true;
|
|
2135
|
-
const { totalInputTokens, costMicroUsd } = usageCostMicroUsd(fam, u, price);
|
|
2109
|
+
const { totalInputTokens, uncachedInputTokens, costMicroUsd } = usageCostMicroUsd(fam, u, price);
|
|
2136
2110
|
stats.tokens += u.totalTokens || 0;
|
|
2137
|
-
stats.promptTokens +=
|
|
2111
|
+
stats.promptTokens += uncachedInputTokens;
|
|
2112
|
+
stats.totalInputTokens += totalInputTokens;
|
|
2138
2113
|
stats.cachedTokens += u.cacheRead || 0;
|
|
2139
2114
|
stats.cacheWriteTokens += u.cacheWrite || 0;
|
|
2140
2115
|
stats.outputTokens += u.output || 0;
|
|
@@ -2142,7 +2117,7 @@ export class Runner {
|
|
|
2142
2117
|
stats.compactionMicroUsd = (stats.compactionMicroUsd ?? 0) + costMicroUsd;
|
|
2143
2118
|
emitTrace(rs.telemetry.tracer, () => ({
|
|
2144
2119
|
kind: "brain.call", version: 1, taskId: rs.telemetry.taskId, model: m.id, provider: m.provider,
|
|
2145
|
-
promptTokens: totalInputTokens, completionTokens: u.output || 0,
|
|
2120
|
+
promptTokens: uncachedInputTokens, totalInputTokens, completionTokens: u.output || 0,
|
|
2146
2121
|
cacheRead: u.cacheRead || 0, cacheWrite: u.cacheWrite || 0,
|
|
2147
2122
|
latencyMs: 0, ...(priced ? { costMicroUsd } : {}), ...(typeof msg?.stopReason === "string" ? { stopReason: msg.stopReason } : {}), ts: Date.now(),
|
|
2148
2123
|
}));
|
|
@@ -2323,9 +2298,9 @@ export class Runner {
|
|
|
2323
2298
|
truncatedOutput: {},
|
|
2324
2299
|
malformedToolUse: {},
|
|
2325
2300
|
thinkingOnly: {},
|
|
2326
|
-
degenerateOutput: { detect: (m) => m
|
|
2301
|
+
degenerateOutput: { detect: (m) => isDegenerateCutMessage(m) },
|
|
2327
2302
|
walltimeCutoff: {
|
|
2328
|
-
detect: (m) => m
|
|
2303
|
+
detect: (m) => isWalltimeCutMessage(m),
|
|
2329
2304
|
hasLiveWriteoutWindow: () => {
|
|
2330
2305
|
const ref = prepared.callCapRef;
|
|
2331
2306
|
if (ref === undefined)
|
|
@@ -2348,10 +2323,7 @@ export class Runner {
|
|
|
2348
2323
|
const comp = await maybeCompact({
|
|
2349
2324
|
session: prepared.session,
|
|
2350
2325
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
2351
|
-
...(
|
|
2352
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
2353
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
2354
|
-
})(),
|
|
2326
|
+
...centerAdoptionOption(prepared),
|
|
2355
2327
|
model: prepared.harness.getModel(),
|
|
2356
2328
|
compactionModel: prepared.compModel,
|
|
2357
2329
|
brain: compactionBrain,
|
|
@@ -2364,19 +2336,8 @@ export class Runner {
|
|
|
2364
2336
|
force: true,
|
|
2365
2337
|
overheadTokens: prepared.promptOverheadTokens,
|
|
2366
2338
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
2367
|
-
onInputTruncated: (
|
|
2368
|
-
workingFileAttachments: spec
|
|
2369
|
-
? {
|
|
2370
|
-
readFile: prepared.readTaskFile,
|
|
2371
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
2372
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
2373
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
2374
|
-
...(prepared.instructionSources
|
|
2375
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
2376
|
-
: {}),
|
|
2377
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
2378
|
-
}
|
|
2379
|
-
: undefined,
|
|
2339
|
+
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
2340
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
2380
2341
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
2381
2342
|
...this.seamCCompactionOptions(prepared),
|
|
2382
2343
|
...windowSafetyOptions(prepared.harness.getModel()),
|
|
@@ -2498,6 +2459,8 @@ export class Runner {
|
|
|
2498
2459
|
resume.pendingActionStarted = true;
|
|
2499
2460
|
}
|
|
2500
2461
|
});
|
|
2462
|
+
if (resume.outcome.gate === "policy_ask")
|
|
2463
|
+
resume.decisionDelivered = true;
|
|
2501
2464
|
}
|
|
2502
2465
|
if (walltimeExhaustedResume) {
|
|
2503
2466
|
timeout.fired = true;
|
|
@@ -2529,6 +2492,8 @@ export class Runner {
|
|
|
2529
2492
|
if (steer.trusted)
|
|
2530
2493
|
engineSegments.push({ start, end: continuation.length });
|
|
2531
2494
|
}
|
|
2495
|
+
if (resume !== undefined)
|
|
2496
|
+
resume.decisionDelivered = true;
|
|
2532
2497
|
final = await withBrainSinks(() => prepared.harness.prompt(continuation, { engineSegments }));
|
|
2533
2498
|
}
|
|
2534
2499
|
}
|
|
@@ -2639,17 +2604,8 @@ export class Runner {
|
|
|
2639
2604
|
}
|
|
2640
2605
|
catch (err) {
|
|
2641
2606
|
if (errorCodeOf(err) === "resume.tool_unavailable") {
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
}
|
|
2645
|
-
catch {
|
|
2646
|
-
}
|
|
2647
|
-
try {
|
|
2648
|
-
if (prepared.ownedEnv && hasDestroy(prepared.ownedEnv))
|
|
2649
|
-
await prepared.ownedEnv.destroy();
|
|
2650
|
-
}
|
|
2651
|
-
catch {
|
|
2652
|
-
}
|
|
2607
|
+
await settleTeardownLeg(() => prepared.mcp.dispose(), "mcp.dispose (tool_unavailable leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2608
|
+
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 }));
|
|
2653
2609
|
throw err;
|
|
2654
2610
|
}
|
|
2655
2611
|
threw = err;
|
|
@@ -2738,20 +2694,20 @@ export class Runner {
|
|
|
2738
2694
|
tokens: prepared.nestedStats.tokens,
|
|
2739
2695
|
turns: prepared.nestedStats.turns,
|
|
2740
2696
|
tasks: prepared.nestedStats.tasks,
|
|
2741
|
-
costMicroUsd: prepared.nestedStats.costMicroUsd
|
|
2697
|
+
...(prepared.nestedStats.anyUnpriced ? {} : { costMicroUsd: prepared.nestedStats.costMicroUsd }),
|
|
2742
2698
|
};
|
|
2743
2699
|
}
|
|
2744
|
-
if (stats.
|
|
2745
|
-
const rawHit = stats.cachedTokens / stats.
|
|
2746
|
-
if (stats.cachedTokens > stats.
|
|
2747
|
-
this.deps.onError?.(new Error(`prompt-cache: usage/api mismatch — cachedTokens (${stats.cachedTokens}) >
|
|
2700
|
+
if (stats.totalInputTokens > 0) {
|
|
2701
|
+
const rawHit = stats.cachedTokens / stats.totalInputTokens;
|
|
2702
|
+
if (stats.cachedTokens > stats.totalInputTokens) {
|
|
2703
|
+
this.deps.onError?.(new Error(`prompt-cache: usage/api mismatch — cachedTokens (${stats.cachedTokens}) > totalInputTokens (${stats.totalInputTokens}); the cache family is likely wrong. Does model.api match the brain serving it? Override with model.params.promptCacheFamily = "input-includes-cached" | "input-excludes-cached".`), { phase: "prompt-cache", sessionId: prepared.sessionId });
|
|
2748
2704
|
}
|
|
2749
2705
|
stats.cacheHitRate = Math.min(1, rawHit);
|
|
2750
|
-
if (!rs.telemetry.cacheBreakReported && stats.turns >= 2 && stats.
|
|
2706
|
+
if (!rs.telemetry.cacheBreakReported && stats.turns >= 2 && stats.totalInputTokens >= 8000 && stats.cacheHitRate < 0.15) {
|
|
2751
2707
|
const cause = rs.degrade.degraded
|
|
2752
2708
|
? `a mid-task model switch (${rs.degrade.degraded.from} → ${rs.degrade.degraded.to}, degradation) reset the prefix cache — this is the likely cause`
|
|
2753
2709
|
: `the cacheable prefix looks unstable. Keep volatile content (memory/timestamps/ids) out of the prompt prefix and tool order stable, or it's a server-side/TTL miss`;
|
|
2754
|
-
this.deps.onError?.(new Error(`prompt-cache: low prefix-cache hit rate ${(stats.cacheHitRate * 100).toFixed(0)}% over ${stats.turns} turns (${stats.
|
|
2710
|
+
this.deps.onError?.(new Error(`prompt-cache: low prefix-cache hit rate ${(stats.cacheHitRate * 100).toFixed(0)}% over ${stats.turns} turns (${stats.totalInputTokens} prompt tokens) — ${cause}. See design/09.`), { phase: "prompt-cache", sessionId: prepared.sessionId });
|
|
2755
2711
|
}
|
|
2756
2712
|
}
|
|
2757
2713
|
if (prepared.resourceLedger &&
|
|
@@ -2823,6 +2779,8 @@ export class Runner {
|
|
|
2823
2779
|
resume.pendingActionStarted !== true &&
|
|
2824
2780
|
result.status !== "completed" &&
|
|
2825
2781
|
result.status !== "suspended" &&
|
|
2782
|
+
result.status !== "needs_review" &&
|
|
2783
|
+
!(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true) &&
|
|
2826
2784
|
resume.onEnvRestoreFailed !== undefined) {
|
|
2827
2785
|
try {
|
|
2828
2786
|
await resume.onEnvRestoreFailed("env_failed");
|
|
@@ -2843,15 +2801,11 @@ export class Runner {
|
|
|
2843
2801
|
const curWt = prepared.worktreeSessionRef?.current;
|
|
2844
2802
|
const changed = curCwd !== wss.restoredHandsCwd || curWt?.worktreeDir !== wss.restoredWorktreeDir;
|
|
2845
2803
|
if (curCwd !== undefined || curWt !== undefined || changed || wss.baselineUnknown === true) {
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
});
|
|
2852
|
-
}
|
|
2853
|
-
catch {
|
|
2854
|
-
}
|
|
2804
|
+
await settleTeardownLeg(() => prepared.session.appendWorkspaceState({
|
|
2805
|
+
taskRoot: wss.rootCanonical,
|
|
2806
|
+
...(curCwd !== undefined ? { handsCwd: curCwd } : {}),
|
|
2807
|
+
...(curWt !== undefined ? { activeWorktree: { ...curWt } } : {}),
|
|
2808
|
+
}), "session.appendWorkspaceState (settle leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2855
2809
|
}
|
|
2856
2810
|
}
|
|
2857
2811
|
}
|
|
@@ -2859,8 +2813,8 @@ export class Runner {
|
|
|
2859
2813
|
if (stopFailureHook !== undefined &&
|
|
2860
2814
|
result.status === "failed" &&
|
|
2861
2815
|
final?.stopReason === "error" &&
|
|
2862
|
-
final
|
|
2863
|
-
final
|
|
2816
|
+
!isDegenerateCutMessage(final) &&
|
|
2817
|
+
!isWalltimeCutMessage(final) &&
|
|
2864
2818
|
threw === undefined &&
|
|
2865
2819
|
rs.limits.budgetHit === undefined &&
|
|
2866
2820
|
!rs.degrade.outputInvalid &&
|
|
@@ -2901,19 +2855,12 @@ export class Runner {
|
|
|
2901
2855
|
}
|
|
2902
2856
|
}
|
|
2903
2857
|
if (resume && committedToken === undefined) {
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
this.deps.onError?.(err, { phase: "config", sessionId: prepared.sessionId });
|
|
2910
|
-
}
|
|
2911
|
-
catch {
|
|
2912
|
-
}
|
|
2913
|
-
}
|
|
2858
|
+
await settleTeardownLeg(() => this.sessions.unpin?.(resume.cp.sessionId), "sessions.unpin (resumed-terminal leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2859
|
+
}
|
|
2860
|
+
if (prepared.memoryEngineSession) {
|
|
2861
|
+
const mes = prepared.memoryEngineSession;
|
|
2862
|
+
await settleTeardownLeg(() => mes.harvest(), "memoryEngineSession.harvest (settle leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2914
2863
|
}
|
|
2915
|
-
if (prepared.memoryEngineSession)
|
|
2916
|
-
await prepared.memoryEngineSession.harvest();
|
|
2917
2864
|
emitTrace(rs.telemetry.tracer, () => ({
|
|
2918
2865
|
kind: "task.end",
|
|
2919
2866
|
version: 1,
|
|
@@ -2967,28 +2914,19 @@ export class Runner {
|
|
|
2967
2914
|
isIsolated(prepared.ownedEnv) &&
|
|
2968
2915
|
prepared.suspendRef.token === undefined &&
|
|
2969
2916
|
prepared.reviewRef.token === undefined;
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
});
|
|
2984
|
-
}
|
|
2985
|
-
catch (e) {
|
|
2986
|
-
try {
|
|
2987
|
-
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
2988
|
-
}
|
|
2989
|
-
catch {
|
|
2990
|
-
}
|
|
2991
|
-
}
|
|
2917
|
+
await settleTeardownLeg(() => defaultTaskRegistry.settleKilledForOwner({ owner: spec.taskId ?? prepared.sessionId, scope: spec.principal ?? "default", sessionId: prepared.sessionId }, {
|
|
2918
|
+
source: abortedLive &&
|
|
2919
|
+
!timeout.fired &&
|
|
2920
|
+
!rs.limits.turnsExceeded &&
|
|
2921
|
+
rs.limits.budgetHit === undefined &&
|
|
2922
|
+
prepared.suspendRef.token === undefined &&
|
|
2923
|
+
prepared.reviewRef.token === undefined
|
|
2924
|
+
? "user"
|
|
2925
|
+
: "parent",
|
|
2926
|
+
skipSessionScoped: true,
|
|
2927
|
+
envDying: ownedEnvDying,
|
|
2928
|
+
retainProcesses: spec.retainBackgroundProcesses === true,
|
|
2929
|
+
}), "taskRegistry.settleKilledForOwner", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
2992
2930
|
const bgEnv = prepared.ownedEnv ?? this.deps.executionEnv;
|
|
2993
2931
|
const retainBgBySpec = spec.retainBackgroundProcesses === true && !ownedEnvDying;
|
|
2994
2932
|
if (bgEnv && hasBackgroundShell(bgEnv) && !retainBgBySpec) {
|
|
@@ -3000,7 +2938,7 @@ export class Runner {
|
|
|
3000
2938
|
...defaultTaskRegistry.timeoutResidentShellIds(bgEnv),
|
|
3001
2939
|
...defaultTaskRegistry.retainedShellIds(bgEnv),
|
|
3002
2940
|
];
|
|
3003
|
-
await sweepBackgroundShells(bgEnv, defaultTaskRegistry, keepAlive.length > 0 ? { except: keepAlive } : undefined);
|
|
2941
|
+
await settleTeardownLeg(() => sweepBackgroundShells(bgEnv, defaultTaskRegistry, keepAlive.length > 0 ? { except: keepAlive } : undefined), "sweepBackgroundShells", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3004
2942
|
}
|
|
3005
2943
|
catch (e) {
|
|
3006
2944
|
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
@@ -3015,14 +2953,9 @@ export class Runner {
|
|
|
3015
2953
|
scope: spec.principal ?? "default",
|
|
3016
2954
|
}, { skipSessionScoped: true });
|
|
3017
2955
|
if (prepared.subagentRetain) {
|
|
3018
|
-
|
|
3019
|
-
await prepared.subagentRetain.disposeAll();
|
|
3020
|
-
}
|
|
3021
|
-
catch (e) {
|
|
3022
|
-
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
3023
|
-
}
|
|
2956
|
+
await settleTeardownLeg(() => prepared.subagentRetain.disposeAll(), "subagentRetain.disposeAll", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3024
2957
|
}
|
|
3025
|
-
await this.teardownOwnedEnv(prepared);
|
|
2958
|
+
await settleTeardownLeg(() => this.teardownOwnedEnv(prepared), "teardownOwnedEnv", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3026
2959
|
}
|
|
3027
2960
|
}
|
|
3028
2961
|
async suggestNextPrompts(spec, prepared, result) {
|
|
@@ -3035,7 +2968,6 @@ export class Runner {
|
|
|
3035
2968
|
ac.abort();
|
|
3036
2969
|
resolve([]);
|
|
3037
2970
|
}, SUGGESTIONS_TIMEOUT_MS);
|
|
3038
|
-
timer.unref?.();
|
|
3039
2971
|
});
|
|
3040
2972
|
const work = (async () => {
|
|
3041
2973
|
let model = prepared.model;
|
|
@@ -3107,7 +3039,6 @@ export class Runner {
|
|
|
3107
3039
|
ac.abort();
|
|
3108
3040
|
resolve({ ok: false, error: { code: "aborted", message: "snapshot timed out" } });
|
|
3109
3041
|
}, SNAPSHOT_TIMEOUT_MS);
|
|
3110
|
-
timer.unref?.();
|
|
3111
3042
|
});
|
|
3112
3043
|
const work = store.snapshot(prepared.sessionId, leafId, env, root, ac.signal);
|
|
3113
3044
|
work.catch(() => { });
|
|
@@ -3526,10 +3457,7 @@ export class Runner {
|
|
|
3526
3457
|
const finishComp = await maybeCompact({
|
|
3527
3458
|
session: prepared.session,
|
|
3528
3459
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
3529
|
-
...(
|
|
3530
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
3531
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
3532
|
-
})(),
|
|
3460
|
+
...centerAdoptionOption(prepared),
|
|
3533
3461
|
model: prepared.model,
|
|
3534
3462
|
compactionModel: prepared.compModel,
|
|
3535
3463
|
brain: opts?.brain ?? this.deps.brain,
|
|
@@ -3540,28 +3468,9 @@ export class Runner {
|
|
|
3540
3468
|
minTokens: opts?.minTokens,
|
|
3541
3469
|
overheadTokens: prepared.promptOverheadTokens,
|
|
3542
3470
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
3543
|
-
onInputTruncated: (
|
|
3544
|
-
kind: "compaction.input_truncated",
|
|
3545
|
-
version: 1,
|
|
3546
|
-
taskId: spec.taskId ?? prepared.sessionId,
|
|
3547
|
-
label: info.label,
|
|
3548
|
-
droppedChars: info.droppedChars,
|
|
3549
|
-
keptChars: info.keptChars,
|
|
3550
|
-
ts: Date.now(),
|
|
3551
|
-
})),
|
|
3471
|
+
onInputTruncated: emitInputTruncated(spec.tracer ?? this.deps.tracer, spec.taskId ?? prepared.sessionId),
|
|
3552
3472
|
...(opts?.windowSafety ?? {}),
|
|
3553
|
-
workingFileAttachments: spec
|
|
3554
|
-
? {
|
|
3555
|
-
readFile: prepared.readTaskFile,
|
|
3556
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
3557
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
3558
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
3559
|
-
...(prepared.instructionSources
|
|
3560
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
3561
|
-
: {}),
|
|
3562
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
3563
|
-
}
|
|
3564
|
-
: undefined,
|
|
3473
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
3565
3474
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
3566
3475
|
...this.seamCCompactionOptions(prepared),
|
|
3567
3476
|
...this.compactionHookOptions(spec, prepared.sessionId, "auto"),
|
|
@@ -3630,7 +3539,6 @@ function startTimeout(harness, abortController, remainingMs, softSuspendable = f
|
|
|
3630
3539
|
abortController.abort();
|
|
3631
3540
|
void harness.abort();
|
|
3632
3541
|
}, hardMs);
|
|
3633
|
-
timer.unref?.();
|
|
3634
3542
|
state.clear = () => clearTimeout(timer);
|
|
3635
3543
|
}
|
|
3636
3544
|
return state;
|
|
@@ -1,10 +1,13 @@
|
|
|
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
4
|
import { canonicalToolName } from "../tool-name-aliases.js";
|
|
4
5
|
export const PATH_WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit"]);
|
|
5
6
|
export function isWithin(root, p) {
|
|
7
|
+
if (!root)
|
|
8
|
+
return false;
|
|
6
9
|
const norm = (x) => {
|
|
7
|
-
let n = x.replace(/\\/g, "/");
|
|
10
|
+
let n = isWinFormPath(x) ? x.replace(/\\/g, "/") : x;
|
|
8
11
|
if (/^[A-Za-z]:(\/|$)/.test(n))
|
|
9
12
|
n = n[0].toLowerCase() + n.slice(1);
|
|
10
13
|
return n;
|
|
@@ -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>;
|