@sema-agent/core 5.64.0 → 6.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 +70 -0
- package/dist/agents/subagent.d.ts +2 -2
- package/dist/agents/subagent.js +11 -0
- package/dist/agents/verify.d.ts +1 -1
- package/dist/brain/anthropic.js +1 -1
- package/dist/brain/errors.d.ts +29 -0
- package/dist/brain/errors.js +20 -0
- package/dist/brain/open-responses.js +2 -2
- package/dist/brain/route-adjudicator.d.ts +8 -1
- package/dist/brain/route-adjudicator.js +1 -0
- package/dist/brain/status-sink.js +12 -1
- package/dist/brain/stream-engine.js +17 -6
- package/dist/core/auto-compaction.d.ts +26 -0
- package/dist/core/auto-compaction.js +7 -2
- package/dist/core/auto-mode-arming.d.ts +138 -0
- package/dist/core/auto-mode-arming.js +181 -0
- package/dist/core/auto-mode-defaults.d.ts +13 -0
- package/dist/core/auto-mode-defaults.js +5 -0
- package/dist/core/auto-mode-prompt.d.ts +14 -3
- package/dist/core/auto-mode-prompt.js +10 -7
- package/dist/core/auto-mode-rebuild.d.ts +75 -0
- package/dist/core/auto-mode-rebuild.js +41 -0
- package/dist/core/auto-mode.d.ts +15 -0
- package/dist/core/auto-mode.js +4 -2
- package/dist/core/checkpoint-store.d.ts +113 -4
- package/dist/core/context-edit.d.ts +47 -5
- package/dist/core/context-guard.d.ts +1 -1
- package/dist/core/file-history-retention.d.ts +106 -0
- package/dist/core/file-history-retention.js +36 -0
- package/dist/core/file-history-store.d.ts +768 -0
- package/dist/core/file-history-store.js +880 -0
- package/dist/core/governance-codes.d.ts +2 -1
- package/dist/core/governance-codes.js +14 -0
- package/dist/core/hooks.d.ts +48 -8
- package/dist/core/hooks.js +39 -22
- package/dist/core/lsp.d.ts +2 -2
- package/dist/core/mcp.d.ts +29 -7
- package/dist/core/memory-engine/consolidation-driver.d.ts +11 -0
- package/dist/core/memory-engine/consolidation-driver.js +71 -4
- package/dist/core/memory-engine/consolidation.d.ts +25 -2
- package/dist/core/memory-engine/consolidation.js +4 -1
- package/dist/core/memory-engine/distiller.d.ts +84 -1
- package/dist/core/memory-engine/distiller.js +68 -0
- package/dist/core/memory-engine/dual-root.js +6 -0
- package/dist/core/memory-engine/engine.d.ts +329 -15
- package/dist/core/memory-engine/engine.js +364 -34
- package/dist/core/memory-engine/file-backend.d.ts +30 -0
- package/dist/core/memory-engine/file-backend.js +14 -13
- package/dist/core/memory-engine/frontmatter.d.ts +22 -1
- package/dist/core/memory-engine/frontmatter.js +3 -0
- package/dist/core/memory-engine/header-hints.d.ts +5 -0
- package/dist/core/memory-engine/index.d.ts +5 -4
- package/dist/core/memory-engine/index.js +5 -4
- package/dist/core/memory-engine/layout.d.ts +88 -2
- package/dist/core/memory-engine/layout.js +112 -3
- package/dist/core/memory-engine/provenance-wording.d.ts +7 -0
- package/dist/core/memory-engine/provenance-wording.js +3 -0
- package/dist/core/memory-engine/tools.d.ts +89 -8
- package/dist/core/memory-engine/tools.js +263 -22
- package/dist/core/memory-engine/types.d.ts +80 -1
- package/dist/core/memory-recall.d.ts +6 -0
- package/dist/core/memory.d.ts +27 -1
- package/dist/core/memory.js +16 -2
- package/dist/core/permission-rule-consent.d.ts +20 -0
- package/dist/core/permission-rule-consent.js +12 -3
- package/dist/core/permission-rule-model.d.ts +67 -7
- package/dist/core/permission-rule-model.js +53 -7
- package/dist/core/permission-rule-store.js +15 -10
- package/dist/core/permission-rule-sync.js +15 -11
- package/dist/core/remote-env.d.ts +3 -3
- package/dist/core/retention-policy.d.ts +9 -0
- package/dist/core/retention-policy.js +5 -2
- package/dist/core/retention.d.ts +13 -2
- package/dist/core/runner/assemble-result.d.ts +19 -1
- package/dist/core/runner/assemble-result.js +17 -2
- package/dist/core/runner/compaction-call-options.d.ts +93 -0
- package/dist/core/runner/compaction-call-options.js +3 -0
- package/dist/core/runner/memory-capture-optout.d.ts +80 -0
- package/dist/core/runner/memory-capture-optout.js +53 -0
- package/dist/core/runner/prepare-config-doors.d.ts +5 -0
- package/dist/core/runner/prepare-config-doors.js +16 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +119 -5
- package/dist/core/runner/prepare-hands-readface.js +103 -8
- package/dist/core/runner/prepare-memory.d.ts +88 -0
- package/dist/core/runner/prepare-memory.js +306 -25
- package/dist/core/runner/prepare-task.d.ts +156 -5
- package/dist/core/runner/prepare-task.js +488 -98
- package/dist/core/runner/runtask.d.ts +27 -20
- package/dist/core/runner/runtask.js +283 -99
- package/dist/core/runner/session-file-state-replay.d.ts +18 -10
- package/dist/core/runner/session-file-state-replay.js +52 -1
- package/dist/core/runner/tool-disclosure.js +2 -1
- package/dist/core/runner/turn-attachments.d.ts +22 -12
- package/dist/core/session-store.d.ts +1 -1
- package/dist/core/session-store.js +6 -1
- package/dist/core/session.d.ts +34 -1
- package/dist/core/store-contracts/file-history-store-contract.d.ts +3 -0
- package/dist/core/store-contracts/file-history-store-contract.js +720 -0
- package/dist/core/stub-env.d.ts +4 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/task-registry-shared.js +30 -2
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +172 -1
- package/dist/core/tool-policy.js +32 -1
- package/dist/core/tool-result-store.js +2 -1
- package/dist/core/trace.d.ts +24 -0
- package/dist/core/types.d.ts +875 -97
- package/dist/core/types.js +4 -3
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/untrusted-text.js +8 -0
- package/dist/core/workflow-run-store-contract.js +17 -0
- package/dist/core/workflow-run-store.d.ts +20 -0
- package/dist/core/workflow-run-store.js +1 -0
- package/dist/engine/compaction/compaction.d.ts +88 -10
- package/dist/engine/compaction/compaction.js +109 -30
- package/dist/engine/execution-env/node-execution-env.d.ts +9 -1
- package/dist/engine/execution-env/node-execution-env.js +28 -0
- package/dist/engine/harness/agent-harness.d.ts +52 -1
- package/dist/engine/harness/agent-harness.js +36 -1
- package/dist/engine/harness/types.d.ts +44 -1
- package/dist/engine/llm/types.d.ts +50 -4
- package/dist/engine/loop/agent-loop.d.ts +5 -1
- package/dist/engine/loop/agent-loop.js +25 -0
- package/dist/engine/loop/types.d.ts +19 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +1 -1
- package/dist/engine/session/session.js +1 -1
- package/dist/index.d.ts +18 -8
- package/dist/index.js +14 -6
- package/dist/orchestration/run-workflow-tool.d.ts +20 -2
- package/dist/orchestration/run-workflow-tool.js +22 -3
- package/dist/orchestration/workflow-governance.d.ts +59 -1
- package/dist/orchestration/workflow-governance.js +61 -8
- package/dist/orchestration/workflow-meta.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +56 -13
- package/dist/orchestration/workflow-types.d.ts +112 -1
- package/dist/orchestration/workflow-types.js +2 -2
- package/dist/orchestration/workflow.d.ts +20 -0
- package/dist/orchestration/workflow.js +182 -14
- package/dist/prompt-assembly/event-registry.js +1 -1
- package/dist/prompts/default.d.ts +15 -7
- package/dist/prompts/default.js +3 -0
- package/dist/stores/file/file-history-store.d.ts +368 -0
- package/dist/stores/file/file-history-store.js +1248 -0
- package/dist/stores/file/index.d.ts +22 -13
- package/dist/stores/file/index.js +4 -4
- package/dist/stores/file/permission-rule-store.js +1 -0
- package/dist/stores/file/strategy-store.d.ts +3 -3
- package/dist/tools/fs/bash-readonly-classifier.d.ts +87 -3
- package/dist/tools/fs/bash-readonly-classifier.js +106 -4
- package/dist/tools/fs/fs-bash.js +9 -5
- package/dist/tools/fs/fs-shared.d.ts +52 -1
- package/dist/tools/fs/fs-shared.js +14 -0
- package/dist/tools/fs/fs-write.d.ts +5 -5
- package/dist/tools/fs/fs-write.js +71 -14
- package/dist/tools/fs/index.d.ts +6 -1
- package/dist/tools/fs/index.js +1 -1
- package/dist/tools/web.js +2 -1
- package/package.json +5 -1
- package/test/export-surface.snapshot.json +159 -23
- package/dist/core/file-snapshot-store.d.ts +0 -165
- package/dist/core/file-snapshot-store.js +0 -259
- package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +0 -13
- package/dist/core/store-contracts/file-snapshot-store-contract.js +0 -134
- package/dist/stores/file/file-snapshot-store.d.ts +0 -58
- package/dist/stores/file/file-snapshot-store.js +0 -353
|
@@ -34,21 +34,22 @@ import { toImageContent } from "./image.js";
|
|
|
34
34
|
import { OUTPUT_TOOL_NAME, SKILLS_LISTING_PROBE_HEADER, resolveOutputRetries } from "./synthetic-tools.js";
|
|
35
35
|
import { cacheFamilyOf, usageCostMicroUsd } from "./usage-accounting.js";
|
|
36
36
|
import { assembleResult, errorCodeOf } from "./assemble-result.js";
|
|
37
|
-
import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, advanceCadenceClock, agentListingDeltaHeader, attachmentEnvelopeTags, 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";
|
|
38
|
-
import { buildWorkingFileAttachments, centerAdoptionOption, emitInputTruncated, forkContextOption } from "./compaction-call-options.js";
|
|
39
|
-
import { effectiveDelegationFacts, gatedCallIdOf, prepareTask, resolveCheckpointStore } from "./prepare-task.js";
|
|
37
|
+
import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, TOTAL_TOKENS_REMINDER_DEFAULT_MODE, AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, advanceCadenceClock, agentListingDeltaHeader, attachmentEnvelopeTags, 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";
|
|
38
|
+
import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFilesOption, emitInputTruncated, forkContextOption } from "./compaction-call-options.js";
|
|
39
|
+
import { effectiveDelegationFacts, gatedCallIdOf, placementValueOrAbsent, prepareTask, resolveCheckpointStore } from "./prepare-task.js";
|
|
40
|
+
import { SessionReadFileStates } from "./prepare-hands-readface.js";
|
|
40
41
|
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
41
42
|
import { TOOL_SEARCH_NAME } from "./tool-disclosure.js";
|
|
42
43
|
import { hasVerifiableStructureSignal } from "./grounding-signal.js";
|
|
43
44
|
import { hasDestroy, isIsolated } from "../remote-env.js";
|
|
44
45
|
import { hasBackgroundShell, sweepBackgroundShells } from "../background-shell.js";
|
|
45
|
-
import { cloneObserverInput, formatHookFeedback, hookSeatExpiredError, mintHookInvocationIdentity, resolveHookTimeoutMs, runHookSeat } from "../hooks.js";
|
|
46
|
+
import { cloneObserverInput, formatHookFeedback, hookSeatExpiredError, MAX_HOOK_TIMEOUT_MS, mintHookInvocationIdentity, resolveHookTimeoutMs, runHookSeat } from "../hooks.js";
|
|
46
47
|
import { buildHumanInputEvent, frameMidTurnUserInput, projectHumanInput } from "../human-input-projection.js";
|
|
47
48
|
import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY, sanitizeUntrustedText, SHELLED_BODY_ENVELOPE_TAGS } from "../untrusted-text.js";
|
|
48
49
|
import { appendInterruptionMarker, reconcileInterruptedSession } from "../session-reconcile.js";
|
|
49
50
|
import { RunnerSharedToolResultStore } from "../tool-result-store.js";
|
|
50
51
|
import { formatDiagnosticsBlock } from "../lsp-diagnostics.js";
|
|
51
|
-
import { checkToolPolicyProjection, constraintChainDigest,
|
|
52
|
+
import { checkToolPolicyProjection, constraintChainDigest, constraintChainEntryOfSuppliedLayer, isApprovalSettledBy, refuseOutOfContractDecision, screenApproverAttribution, toolPolicyNameSets } from "../tool-policy.js";
|
|
52
53
|
import { defaultTaskRegistry } from "../task-registry.js";
|
|
53
54
|
import { discloseDroppedPending, isDelegatedAgentTerminal, isSystemInjectionPriority, isTerminalTaskNotification, PendingSessionNotifications, renderTaskNotificationXml, SYSTEM_INJECTION_PRIORITIES, SystemInjectionQueue, taskNotificationDedupKey } from "../task-notification.js";
|
|
54
55
|
import { ToolDetachHub } from "../tool-detach.js";
|
|
@@ -57,7 +58,7 @@ import { workflowSizeGuidelineChangeNotice } from "../../orchestration/workflow-
|
|
|
57
58
|
import { structuredFrom, toolOutputFrom } from "./tool-output-projection.js";
|
|
58
59
|
function createRunState() {
|
|
59
60
|
return {
|
|
60
|
-
telemetry: { cacheFamily: "input-excludes-cached", pricing: { inputPer1M: 0, outputPer1M: 0 }, pricingConfigured: true, unpricedSpend: false, tracer: undefined, taskId: "", taskStart: 0, taskStartMonotonic: 0, cacheBreakReported: false },
|
|
61
|
+
telemetry: { cacheFamily: "input-excludes-cached", pricing: { inputPer1M: 0, outputPer1M: 0 }, pricingConfigured: true, unpricedSpend: false, tracer: undefined, taskId: "", runId: "", taskStart: 0, taskStartMonotonic: 0, cacheBreakReported: false },
|
|
61
62
|
degrade: { degradeToModel: undefined, degraded: undefined, outputErrorStreak: 0, outputInvalid: false, recordDegraded: () => { } },
|
|
62
63
|
limits: { turnsExceeded: false, budgetHit: undefined, budgetAxis: undefined, platformTerminal: undefined, outputRetryCap: 0, effectiveMaxTurns: undefined },
|
|
63
64
|
budget: { remainingMicroUsd: undefined, maxCostMicroUsd: undefined, remainingTokens: undefined, maxTokensWindow: undefined, overBudget: () => undefined, streamCancel: false, callOutputChars: 0, lastStreamBudgetCheck: 0, projectedOverBudget: () => undefined },
|
|
@@ -84,6 +85,7 @@ function sameAcceptedSteerInput(a, b) {
|
|
|
84
85
|
a.actor?.issuer === b.actor?.issuer);
|
|
85
86
|
}
|
|
86
87
|
const MAX_CONSECUTIVE_COMPACTION_FAILURES = 3;
|
|
88
|
+
const RESUME_PREFLIGHT_DEFAULT_TIMEOUT_MS = 10_000;
|
|
87
89
|
const STOP_HOOK_BLOCK_CAP = 8;
|
|
88
90
|
const COMPACTION_REGROWTH_FACTOR = 1.5;
|
|
89
91
|
const COMPACTION_FREED_EPSILON = 256;
|
|
@@ -123,8 +125,6 @@ const SUGGESTIONS_DEFAULT_COUNT = 3;
|
|
|
123
125
|
const SUGGESTIONS_MAX_COUNT = 8;
|
|
124
126
|
const SUGGESTIONS_TIMEOUT_MS = 30_000;
|
|
125
127
|
const SUGGESTIONS_TRANSCRIPT_MESSAGES = 12;
|
|
126
|
-
const SNAPSHOT_TIMEOUT_MS = 30_000;
|
|
127
|
-
const SNAPSHOT_TOO_LARGE_TTL_MS = 30 * 60_000;
|
|
128
128
|
const LIMIT_APPROACH_DEFAULT_THRESHOLDS = [0.8, 0.95];
|
|
129
129
|
const DEFAULT_PRECALL_OUTPUT_TOKENS = 4096;
|
|
130
130
|
function limitApproachFrames(index, axis, percent, mark) {
|
|
@@ -606,7 +606,13 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
606
606
|
const mcpRemovals = mcpInstructionsOn && mcpDelta.pendingRemovals.length > 0 ? [...mcpDelta.pendingRemovals] : undefined;
|
|
607
607
|
const mcpDropped = mcpInstructionsOn && prepared.mcp.droppedTools.length > 0 ? selectMcpDroppedBatch(prepared.mcp.droppedTools) : undefined;
|
|
608
608
|
const budgetUsdOn = rs.attach.attachmentsCfg?.budgetUsd === true && rs.budget.maxCostMicroUsd !== undefined && rs.turn.lastTurnHadToolCalls;
|
|
609
|
-
const
|
|
609
|
+
const totalTokensDeclared = rs.attach.attachmentsCfg?.totalTokensReminder;
|
|
610
|
+
const totalTokensMode = rs.attach.attachmentsCfg?.totalTokensReminderMode ?? TOTAL_TOKENS_REMINDER_DEFAULT_MODE;
|
|
611
|
+
const totalTokensArmedByDefault = totalTokensDeclared === undefined &&
|
|
612
|
+
eventDefaultOn("total_tokens_reminder") &&
|
|
613
|
+
totalTokensMode !== "fixed" &&
|
|
614
|
+
totalTokensMode !== "infinite";
|
|
615
|
+
const totalTokensOn = (totalTokensDeclared === true || totalTokensArmedByDefault) && rs.turn.lastTurnHadToolCalls;
|
|
610
616
|
const toolSearchReminderOn = rs.attach.attachmentsCfg?.toolSearchReminder === true && prepared.deferredToolNames !== undefined;
|
|
611
617
|
const undiscoveredTools = toolSearchReminderOn
|
|
612
618
|
? [...prepared.deferredToolNames].filter((n) => !prepared.activeTools.has(n)).sort()
|
|
@@ -896,6 +902,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
896
902
|
overheadTokens: prepared.promptOverheadTokens,
|
|
897
903
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
898
904
|
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
905
|
+
...contextInstructionFilesOption(prepared),
|
|
899
906
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
900
907
|
...runnerHooks.seamCCompactionOptions(prepared),
|
|
901
908
|
...gitRestateOption(prepared),
|
|
@@ -1164,6 +1171,8 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
1164
1171
|
if (event.entryId !== undefined && (m.role === "user" || m.role === "assistant" || m.role === "toolResult")) {
|
|
1165
1172
|
emitCommitted(event.entryId, m.role, m.role === "toolResult" ? m.toolCallId : undefined);
|
|
1166
1173
|
}
|
|
1174
|
+
if (event.entryId !== undefined && m.role === "user")
|
|
1175
|
+
prepared.fileHistoryBoundary?.begin(event.entryId);
|
|
1167
1176
|
if (event.entryId !== undefined && m.role === "user" && prepared.gitStatusRef.pendingReceipt !== undefined) {
|
|
1168
1177
|
const pr = prepared.gitStatusRef.pendingReceipt;
|
|
1169
1178
|
const c = m.content;
|
|
@@ -1452,9 +1461,11 @@ export class Runner {
|
|
|
1452
1461
|
deps;
|
|
1453
1462
|
sessions;
|
|
1454
1463
|
sessionLocks = new Map();
|
|
1455
|
-
|
|
1464
|
+
sessionReadStates = new SessionReadFileStates();
|
|
1456
1465
|
pendingSessionNotifications = new PendingSessionNotifications();
|
|
1457
1466
|
parentConstraintRegistry = new Map();
|
|
1467
|
+
suspendedEnvReaps = new Map();
|
|
1468
|
+
locallyClaimedTokens = new Set();
|
|
1458
1469
|
static PARENT_CONSTRAINT_REGISTRY_CAP = 1024;
|
|
1459
1470
|
constructor(deps) {
|
|
1460
1471
|
this.deps = deps;
|
|
@@ -1602,7 +1613,7 @@ export class Runner {
|
|
|
1602
1613
|
deliverEngineNotice(this.deps.onNotice, {
|
|
1603
1614
|
code: "config.models_swapped",
|
|
1604
1615
|
message: `model catalog swapped: ${Object.keys(next.models).length} model(s), ${tiers ? Object.keys(tiers).length : 0} tier binding(s); in-flight tasks finish on their resolved models, new tasks resolve against the new catalog`,
|
|
1605
|
-
detail: { models: Object.keys(next.models).length, tiers: tiers ? Object.keys(tiers).length : 0 },
|
|
1616
|
+
detail: { models: Object.keys(next.models).length, tiers: tiers ? Object.keys(tiers).length : 0, occurrenceId: uuidv7() },
|
|
1606
1617
|
});
|
|
1607
1618
|
if (movedEntries.length > 0) {
|
|
1608
1619
|
const RENDER_CAP = 8;
|
|
@@ -1613,7 +1624,7 @@ export class Runner {
|
|
|
1613
1624
|
rendered.map((e) => `"${e.modelId}" ${e.from || "(config root)"} → ${e.to || "(config root)"}`).join("; ") +
|
|
1614
1625
|
(movedEntries.length > rendered.length ? `; +${movedEntries.length - rendered.length} more` : "") +
|
|
1615
1626
|
" — if the provider changed (not just its domain), update the credential reference in the same step",
|
|
1616
|
-
detail: { entries: rendered, total: movedEntries.length },
|
|
1627
|
+
detail: { entries: rendered, total: movedEntries.length, occurrenceId: uuidv7() },
|
|
1617
1628
|
});
|
|
1618
1629
|
}
|
|
1619
1630
|
}
|
|
@@ -1626,6 +1637,7 @@ export class Runner {
|
|
|
1626
1637
|
"(Note the parameter order: runTaskStream(spec, resume?, internals?) — internals is the THIRD parameter.)");
|
|
1627
1638
|
}
|
|
1628
1639
|
const entryActor = spec.actor === undefined ? undefined : snapshotActorAssertion(spec.actor);
|
|
1640
|
+
const entryTracer = { tracer: spec.tracer ?? this.deps.tracer };
|
|
1629
1641
|
const queue = new PushQueue();
|
|
1630
1642
|
const detachHub = new ToolDetachHub();
|
|
1631
1643
|
let resultValue;
|
|
@@ -1647,6 +1659,7 @@ export class Runner {
|
|
|
1647
1659
|
let steerChain = Promise.resolve();
|
|
1648
1660
|
const acceptedSteerInputs = new Map();
|
|
1649
1661
|
const notifyRef = {};
|
|
1662
|
+
const captureOptOutRef = {};
|
|
1650
1663
|
const manualCompactRef = { requested: false, waiters: [] };
|
|
1651
1664
|
const drainManualCompactWaiters = (outcome) => {
|
|
1652
1665
|
manualCompactRef.requested = false;
|
|
@@ -1663,8 +1676,11 @@ export class Runner {
|
|
|
1663
1676
|
await this.runLocked(spec, queue, (r) => {
|
|
1664
1677
|
resultValue = r;
|
|
1665
1678
|
const pcs = internals?.inheritedGate?.parentConstraints;
|
|
1679
|
+
if (resume !== undefined)
|
|
1680
|
+
this.locallyClaimedTokens.delete(resume.cp.token);
|
|
1666
1681
|
if (resume !== undefined && r.checkpointToken !== resume.cp.token) {
|
|
1667
1682
|
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
1683
|
+
this.suspendedEnvReaps.delete(resume.cp.token);
|
|
1668
1684
|
}
|
|
1669
1685
|
if (r.status === "suspended" && r.checkpointToken !== undefined && pcs !== undefined && pcs.length > 0) {
|
|
1670
1686
|
if (this.parentConstraintRegistry.size >= Runner.PARENT_CONSTRAINT_REGISTRY_CAP) {
|
|
@@ -1681,7 +1697,8 @@ export class Runner {
|
|
|
1681
1697
|
publishReady(h);
|
|
1682
1698
|
}, (s) => {
|
|
1683
1699
|
reapHandle = s;
|
|
1684
|
-
|
|
1700
|
+
this.suspendedEnvReaps.set(s.token, s);
|
|
1701
|
+
}, manualCompactRef, taskIdRef, resume, { ...(internals ?? {}), detachHub }, notifyRef, captureOptOutRef, entryActor, entryTracer);
|
|
1685
1702
|
}
|
|
1686
1703
|
finally {
|
|
1687
1704
|
releaseLock?.();
|
|
@@ -1698,6 +1715,7 @@ export class Runner {
|
|
|
1698
1715
|
const reopenReason = code === "resume.tool_unavailable" ? "tool_unavailable" : "env_failed";
|
|
1699
1716
|
const reopenable = resume !== undefined && resume.pendingActionStarted !== true && reopenReason !== undefined && !(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true);
|
|
1700
1717
|
let reopenCommitted = false;
|
|
1718
|
+
let reopenStateUnknown = false;
|
|
1701
1719
|
if (reopenable && resume?.onEnvRestoreFailed) {
|
|
1702
1720
|
try {
|
|
1703
1721
|
await resume.onEnvRestoreFailed(reopenReason);
|
|
@@ -1708,15 +1726,26 @@ export class Runner {
|
|
|
1708
1726
|
const original = err instanceof Error ? err : new Error(String(err));
|
|
1709
1727
|
const reopenMsg = reopenErr instanceof Error ? reopenErr.message : String(reopenErr);
|
|
1710
1728
|
const definitive = errorCodeOf(reopenErr) === "checkpoint.reopen_failed";
|
|
1729
|
+
reopenStateUnknown = !definitive;
|
|
1711
1730
|
err = Object.assign(new Error(definitive
|
|
1712
1731
|
? `${reopenMsg} (original resume failure: ${original.message})`
|
|
1713
1732
|
: `checkpoint reopen threw mid-flight — state UNKNOWN, confirm via the checkpoint store before retrying: ${reopenMsg} (original resume failure: ${original.message})`, { cause: original }), { code: "checkpoint.reopen_failed" });
|
|
1714
1733
|
code = "checkpoint.reopen_failed";
|
|
1715
1734
|
}
|
|
1716
1735
|
}
|
|
1736
|
+
if (resume)
|
|
1737
|
+
this.locallyClaimedTokens.delete(resume.cp.token);
|
|
1717
1738
|
if (resume && !reopenCommitted) {
|
|
1718
1739
|
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
1719
1740
|
await settleTeardownLeg(() => this.sessions.unpin?.(resume.cp.sessionId), "sessions.unpin (resume-failure leg)", (e) => this.deps.onError?.(e, { phase: "config", sessionId: resume.cp.sessionId }));
|
|
1741
|
+
if (!reopenStateUnknown) {
|
|
1742
|
+
const failedReap = this.suspendedEnvReaps.get(resume.cp.token);
|
|
1743
|
+
this.suspendedEnvReaps.delete(resume.cp.token);
|
|
1744
|
+
if (failedReap?.env !== undefined && hasDestroy(failedReap.env)) {
|
|
1745
|
+
const failedEnv = failedReap.env;
|
|
1746
|
+
await settleTeardownLeg(() => failedEnv.destroy(), "terminal resume-failure env destroy", (e) => this.deps.onError?.(e, { phase: "config", sessionId: resume.cp.sessionId }));
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1720
1749
|
}
|
|
1721
1750
|
if (resultValue !== undefined) {
|
|
1722
1751
|
try {
|
|
@@ -1740,6 +1769,7 @@ export class Runner {
|
|
|
1740
1769
|
resultValue = {
|
|
1741
1770
|
taskId: taskIdRef.current ?? "unknown",
|
|
1742
1771
|
sessionId: taskIdRef.sessionId ?? "unknown",
|
|
1772
|
+
...(taskIdRef.runId !== undefined ? { runId: taskIdRef.runId } : {}),
|
|
1743
1773
|
status: "failed",
|
|
1744
1774
|
result: "",
|
|
1745
1775
|
errorMessage: err instanceof Error ? err.message : String(err),
|
|
@@ -1755,10 +1785,11 @@ export class Runner {
|
|
|
1755
1785
|
})(),
|
|
1756
1786
|
stats: { turns: 0, tokens: 0, toolCalls: 0, cachedTokens: 0, costMicroUsd: 0 },
|
|
1757
1787
|
};
|
|
1758
|
-
emitTrace(
|
|
1788
|
+
emitTrace(entryTracer.tracer, () => ({
|
|
1759
1789
|
kind: "task.end",
|
|
1760
1790
|
version: 1,
|
|
1761
1791
|
taskId: taskIdRef.current ?? "unknown",
|
|
1792
|
+
...(taskIdRef.runId !== undefined ? { runId: taskIdRef.runId } : {}),
|
|
1762
1793
|
status: "failed",
|
|
1763
1794
|
errorCode: code,
|
|
1764
1795
|
turns: 0,
|
|
@@ -1802,9 +1833,13 @@ export class Runner {
|
|
|
1802
1833
|
reportErr(err);
|
|
1803
1834
|
return;
|
|
1804
1835
|
}
|
|
1805
|
-
if (!won)
|
|
1836
|
+
if (!won) {
|
|
1837
|
+
if (!this.locallyClaimedTokens.has(rh.token))
|
|
1838
|
+
this.suspendedEnvReaps.delete(rh.token);
|
|
1806
1839
|
return;
|
|
1840
|
+
}
|
|
1807
1841
|
this.parentConstraintRegistry.delete(rh.token);
|
|
1842
|
+
this.suspendedEnvReaps.delete(rh.token);
|
|
1808
1843
|
if (rh.env && hasDestroy(rh.env)) {
|
|
1809
1844
|
try {
|
|
1810
1845
|
await rh.env.destroy();
|
|
@@ -1962,6 +1997,7 @@ export class Runner {
|
|
|
1962
1997
|
detail: {
|
|
1963
1998
|
inputId: effectiveInputId,
|
|
1964
1999
|
sessionId: h.sessionId,
|
|
2000
|
+
runId: h.runId,
|
|
1965
2001
|
...(actor?.id !== undefined ? { actorId: actor.id } : {}),
|
|
1966
2002
|
...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}),
|
|
1967
2003
|
},
|
|
@@ -2042,6 +2078,26 @@ export class Runner {
|
|
|
2042
2078
|
}
|
|
2043
2079
|
notifyRef.inject(payload, priority !== undefined ? { priority } : undefined);
|
|
2044
2080
|
},
|
|
2081
|
+
optOutMemoryCapture: async (options) => {
|
|
2082
|
+
const reasonIn = options?.reason;
|
|
2083
|
+
if (reasonIn !== undefined && typeof reasonIn !== "string") {
|
|
2084
|
+
const e = new Error(`cannot opt out of memory capture: options.reason must be a string when present`);
|
|
2085
|
+
e.code = "steering.invalid_content";
|
|
2086
|
+
throw e;
|
|
2087
|
+
}
|
|
2088
|
+
const reason = reasonIn;
|
|
2089
|
+
if (resultValue)
|
|
2090
|
+
throw steeringError("the task has already finished");
|
|
2091
|
+
const h = handle ?? (await orTimeout(ready));
|
|
2092
|
+
if (!h)
|
|
2093
|
+
throw steeringError("the task is not running");
|
|
2094
|
+
if (captureOptOutRef.flip === undefined) {
|
|
2095
|
+
const e = new Error(`cannot opt out of memory capture: this run mounted no memory session (no memory spec / no backend / prepare degraded memory-less) — there is nothing to opt out of`);
|
|
2096
|
+
e.code = "memory.capture_optout_unavailable";
|
|
2097
|
+
throw e;
|
|
2098
|
+
}
|
|
2099
|
+
return captureOptOutRef.flip(reason);
|
|
2100
|
+
},
|
|
2045
2101
|
compact: async (opts) => {
|
|
2046
2102
|
if (resultValue)
|
|
2047
2103
|
throw steeringError("the task has already finished");
|
|
@@ -2095,6 +2151,60 @@ export class Runner {
|
|
|
2095
2151
|
h.abortController.abort();
|
|
2096
2152
|
void h.harness.abort();
|
|
2097
2153
|
},
|
|
2154
|
+
halt: async () => {
|
|
2155
|
+
const haltRefused = (msg) => {
|
|
2156
|
+
const e = new Error(`cannot halt: ${msg}`);
|
|
2157
|
+
e.code = "steering.not_running";
|
|
2158
|
+
return e;
|
|
2159
|
+
};
|
|
2160
|
+
if (resultValue)
|
|
2161
|
+
throw haltRefused("the task has already finished");
|
|
2162
|
+
const h = handle ?? (await orTimeout(ready));
|
|
2163
|
+
if (!h)
|
|
2164
|
+
throw haltRefused("the task is not running");
|
|
2165
|
+
const apply = () => {
|
|
2166
|
+
const abortOwnedBeforeHalt = h.abortController.signal.aborted;
|
|
2167
|
+
const receipt = h.harness.halt();
|
|
2168
|
+
if (receipt.accepted && !abortOwnedBeforeHalt)
|
|
2169
|
+
h.loop.userHalted = true;
|
|
2170
|
+
if (receipt.turnCut) {
|
|
2171
|
+
deliverEngineNotice(this.deps.onNotice, {
|
|
2172
|
+
code: "task.turn_interrupted",
|
|
2173
|
+
message: "a bare user halt cut the running turn: in-flight work was cut at a manufactured boundary " +
|
|
2174
|
+
"(finished tool calls keep their real results; never-started ones settle as interrupted) and " +
|
|
2175
|
+
"the run is collecting to a clean, resumable stop — no further model turn will start.",
|
|
2176
|
+
detail: {
|
|
2177
|
+
cause: "user_halt",
|
|
2178
|
+
sessionId: h.sessionId,
|
|
2179
|
+
runId: h.runId,
|
|
2180
|
+
...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}),
|
|
2181
|
+
},
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
return { turnCut: receipt.turnCut };
|
|
2185
|
+
};
|
|
2186
|
+
try {
|
|
2187
|
+
if (resultValue !== undefined || h.loop.ended)
|
|
2188
|
+
throw haltRefused("the task is no longer running");
|
|
2189
|
+
return apply();
|
|
2190
|
+
}
|
|
2191
|
+
catch (e) {
|
|
2192
|
+
if (!(e instanceof Error && e.code === "invalid_state"))
|
|
2193
|
+
throw e;
|
|
2194
|
+
}
|
|
2195
|
+
const birthDeadline = Date.now() + READY_TIMEOUT_MS;
|
|
2196
|
+
while (resultValue === undefined && !h.loop.ended && Date.now() < birthDeadline) {
|
|
2197
|
+
try {
|
|
2198
|
+
return apply();
|
|
2199
|
+
}
|
|
2200
|
+
catch (e2) {
|
|
2201
|
+
if (!(e2 instanceof Error && e2.code === "invalid_state"))
|
|
2202
|
+
throw e2;
|
|
2203
|
+
}
|
|
2204
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
2205
|
+
}
|
|
2206
|
+
throw haltRefused("the task is no longer running");
|
|
2207
|
+
},
|
|
2098
2208
|
destroy: () => (destroyOnce ??= (async () => {
|
|
2099
2209
|
const h = handle ?? (await orTimeout(ready));
|
|
2100
2210
|
if (h) {
|
|
@@ -2106,7 +2216,7 @@ export class Runner {
|
|
|
2106
2216
|
})()),
|
|
2107
2217
|
};
|
|
2108
2218
|
}
|
|
2109
|
-
async runLocked(spec, queue, setResult, onSuggestions, onReady, onSuspend, manualCompactRef, taskIdRef, resume, internals, notifyRef, entryActor) {
|
|
2219
|
+
async runLocked(spec, queue, setResult, onSuggestions, onReady, onSuspend, manualCompactRef, taskIdRef, resume, internals, notifyRef, captureOptOutRef, entryActor, entryTracer) {
|
|
2110
2220
|
const prepareResume = resume
|
|
2111
2221
|
? {
|
|
2112
2222
|
leafId: resume.cp.leafId,
|
|
@@ -2210,6 +2320,7 @@ export class Runner {
|
|
|
2210
2320
|
peerSelfRef,
|
|
2211
2321
|
peerInboundChainRef,
|
|
2212
2322
|
detachHub,
|
|
2323
|
+
sessionReadStates: this.sessionReadStates,
|
|
2213
2324
|
onTaskNotification: (notification, opts) => {
|
|
2214
2325
|
try {
|
|
2215
2326
|
upstreamTaskNotification?.(notification, opts);
|
|
@@ -2218,7 +2329,7 @@ export class Runner {
|
|
|
2218
2329
|
}
|
|
2219
2330
|
injectTaskNotification(notification, opts);
|
|
2220
2331
|
},
|
|
2221
|
-
}, this);
|
|
2332
|
+
}, this, taskIdRef);
|
|
2222
2333
|
notificationHarness = prepared.harness;
|
|
2223
2334
|
notificationSessionId = prepared.sessionId;
|
|
2224
2335
|
if (taskIdRef)
|
|
@@ -2258,7 +2369,7 @@ export class Runner {
|
|
|
2258
2369
|
undrainedUserAtEnd = counts;
|
|
2259
2370
|
return;
|
|
2260
2371
|
}
|
|
2261
|
-
for (const notice of undrainedUserInputNotices(counts, spec.taskId, prepared.sessionId)) {
|
|
2372
|
+
for (const notice of undrainedUserInputNotices(counts, spec.taskId ?? prepared.sessionId, prepared.sessionId, prepared.runId)) {
|
|
2262
2373
|
deliverEngineNotice(this.deps.onNotice, notice);
|
|
2263
2374
|
}
|
|
2264
2375
|
};
|
|
@@ -2269,6 +2380,9 @@ export class Runner {
|
|
|
2269
2380
|
};
|
|
2270
2381
|
if (notifyRef)
|
|
2271
2382
|
notifyRef.inject = injectTaskNotification;
|
|
2383
|
+
if (captureOptOutRef && prepared.memoryEngineSession?.captureOptOut !== undefined) {
|
|
2384
|
+
captureOptOutRef.flip = prepared.memoryEngineSession.captureOptOut.flip;
|
|
2385
|
+
}
|
|
2272
2386
|
try {
|
|
2273
2387
|
internals?.onNotifyInjectorReady?.(injectTaskNotification);
|
|
2274
2388
|
}
|
|
@@ -2287,8 +2401,8 @@ export class Runner {
|
|
|
2287
2401
|
}
|
|
2288
2402
|
}
|
|
2289
2403
|
}
|
|
2290
|
-
const loopLatch = { ended: false, userInterrupted: false };
|
|
2291
|
-
onReady({ harness: prepared.harness, abortController: prepared.abortController, loop: loopLatch, reminderMark: prepared.reminderMark, sessionId: prepared.sessionId, hookTimeoutMs: prepared.hookTimeoutMs, hookIdentity: prepared.hookIdentity });
|
|
2404
|
+
const loopLatch = { ended: false, userInterrupted: false, userHalted: false };
|
|
2405
|
+
onReady({ harness: prepared.harness, abortController: prepared.abortController, loop: loopLatch, reminderMark: prepared.reminderMark, sessionId: prepared.sessionId, runId: prepared.runId, hookTimeoutMs: prepared.hookTimeoutMs, hookIdentity: prepared.hookIdentity });
|
|
2292
2406
|
const stats = { turns: 0, tokens: 0, toolCalls: 0, promptTokens: 0, totalInputTokens: 0, cachedTokens: 0, cacheWriteTokens: 0, cacheWriteTokensLong: 0, outputTokens: 0, costMicroUsd: 0 };
|
|
2293
2407
|
prepared.liveSpendRef.get = () => ({ costMicroUsd: stats.costMicroUsd, tokens: stats.tokens, turns: stats.turns, walltimeMs: Math.round(performance.now() - rs.telemetry.taskStartMonotonic) });
|
|
2294
2408
|
if (resume &&
|
|
@@ -2329,8 +2443,9 @@ export class Runner {
|
|
|
2329
2443
|
rs.telemetry.cacheBreakReported = false;
|
|
2330
2444
|
rs.limits.outputRetryCap = resolveOutputRetries(spec.outputRetries);
|
|
2331
2445
|
rs.limits.effectiveMaxTurns = resolveMaxTurns(spec.limits);
|
|
2332
|
-
rs.telemetry.tracer = spec.tracer ?? this.deps.tracer;
|
|
2446
|
+
rs.telemetry.tracer = entryTracer !== undefined ? entryTracer.tracer : (spec.tracer ?? this.deps.tracer);
|
|
2333
2447
|
rs.telemetry.taskId = runSourceTaskId;
|
|
2448
|
+
rs.telemetry.runId = prepared.runId;
|
|
2334
2449
|
if (taskIdRef) {
|
|
2335
2450
|
taskIdRef.current = rs.telemetry.taskId;
|
|
2336
2451
|
taskIdRef.sessionId = prepared.sessionId;
|
|
@@ -2345,7 +2460,7 @@ export class Runner {
|
|
|
2345
2460
|
}
|
|
2346
2461
|
};
|
|
2347
2462
|
try {
|
|
2348
|
-
void Promise.resolve(this.sessions.noteTaskRun?.(prepared.sessionId, rs.telemetry.taskId)).catch(discloseNoteTaskRunFailure);
|
|
2463
|
+
void Promise.resolve(this.sessions.noteTaskRun?.(prepared.sessionId, rs.telemetry.taskId, rs.telemetry.runId)).catch(discloseNoteTaskRunFailure);
|
|
2349
2464
|
}
|
|
2350
2465
|
catch (err) {
|
|
2351
2466
|
discloseNoteTaskRunFailure(err);
|
|
@@ -2631,7 +2746,7 @@ export class Runner {
|
|
|
2631
2746
|
const writeFamilyOf = (name) => writeFamilyByName.get(name) ?? writeFamilyOfCanonical(name);
|
|
2632
2747
|
const toolStartAt = new Map();
|
|
2633
2748
|
const startedToolCallIds = new Set();
|
|
2634
|
-
emitTrace(rs.telemetry.tracer, () => ({ kind: "task.start", version: 1, taskId: rs.telemetry.taskId, model: prepared.model.id, engineVersion: engineVersion(), ts: rs.telemetry.taskStart }));
|
|
2749
|
+
emitTrace(rs.telemetry.tracer, () => ({ kind: "task.start", version: 1, taskId: rs.telemetry.taskId, runId: rs.telemetry.runId, model: prepared.model.id, engineVersion: engineVersion(), ts: rs.telemetry.taskStart }));
|
|
2635
2750
|
emitTrace(rs.telemetry.tracer, () => ({
|
|
2636
2751
|
kind: "prompt.assembled",
|
|
2637
2752
|
version: 1,
|
|
@@ -2723,7 +2838,9 @@ export class Runner {
|
|
|
2723
2838
|
}
|
|
2724
2839
|
}
|
|
2725
2840
|
};
|
|
2841
|
+
const ownCommittedTailRef = { current: undefined };
|
|
2726
2842
|
const emitCommitted = (entryId, role, toolCallId) => {
|
|
2843
|
+
ownCommittedTailRef.current = entryId;
|
|
2727
2844
|
if (role === "toolResult" && toolCallId !== undefined)
|
|
2728
2845
|
startedToolCallIds.delete(toolCallId);
|
|
2729
2846
|
queue.push({ type: "message_committed", entryId, role, ...(toolCallId !== undefined ? { toolCallId } : {}), ...ident() });
|
|
@@ -2739,6 +2856,7 @@ export class Runner {
|
|
|
2739
2856
|
...(s.detail !== undefined ? { detail: s.detail } : {}),
|
|
2740
2857
|
...(s.retryInSec !== undefined ? { retryInSec: s.retryInSec } : {}),
|
|
2741
2858
|
...(s.retryInMs !== undefined ? { retryInMs: s.retryInMs } : {}),
|
|
2859
|
+
...(s.retryAtMs !== undefined ? { retryAtMs: s.retryAtMs } : {}),
|
|
2742
2860
|
...(s.attempt !== undefined ? { attempt: s.attempt } : {}),
|
|
2743
2861
|
...(s.maxRetries !== undefined ? { maxRetries: s.maxRetries } : {}),
|
|
2744
2862
|
...(s.errClass !== undefined ? { errClass: s.errClass } : {}),
|
|
@@ -3056,6 +3174,7 @@ export class Runner {
|
|
|
3056
3174
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
3057
3175
|
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
3058
3176
|
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
3177
|
+
...contextInstructionFilesOption(prepared),
|
|
3059
3178
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
3060
3179
|
...this.seamCCompactionOptions(prepared),
|
|
3061
3180
|
...gitRestateOption(prepared),
|
|
@@ -3456,6 +3575,7 @@ export class Runner {
|
|
|
3456
3575
|
detail: {
|
|
3457
3576
|
...(steer.inputId !== undefined ? { inputId: steer.inputId } : {}),
|
|
3458
3577
|
sessionId: prepared.sessionId,
|
|
3578
|
+
runId: prepared.runId,
|
|
3459
3579
|
...(spec.taskId !== undefined ? { taskId: spec.taskId } : {}),
|
|
3460
3580
|
},
|
|
3461
3581
|
});
|
|
@@ -3836,7 +3956,7 @@ export class Runner {
|
|
|
3836
3956
|
steer: Math.max(0, undrainedUserAtEnd.steer - migratedParked.steer),
|
|
3837
3957
|
followUp: Math.max(0, undrainedUserAtEnd.followUp - migratedParked.followUp),
|
|
3838
3958
|
};
|
|
3839
|
-
for (const notice of undrainedUserInputNotices(remaining, spec.taskId, prepared.sessionId)) {
|
|
3959
|
+
for (const notice of undrainedUserInputNotices(remaining, spec.taskId ?? prepared.sessionId, prepared.sessionId, prepared.runId)) {
|
|
3840
3960
|
deliverEngineNotice(this.deps.onNotice, notice);
|
|
3841
3961
|
}
|
|
3842
3962
|
}
|
|
@@ -3844,6 +3964,7 @@ export class Runner {
|
|
|
3844
3964
|
emitTrace(rs.telemetry.tracer, () => ({ kind: "compaction.announce_dropped", version: 1, taskId: rs.telemetry.taskId, ts: Date.now() }));
|
|
3845
3965
|
}
|
|
3846
3966
|
const comp = await this.finish(spec, prepared, {
|
|
3967
|
+
telemetry: { tracer: rs.telemetry.tracer, taskId: rs.telemetry.taskId },
|
|
3847
3968
|
skipCompaction: durablyPaused || compactionBreaker.failures >= MAX_CONSECUTIVE_COMPACTION_FAILURES,
|
|
3848
3969
|
minTokens: rs.counters.compactionFloor,
|
|
3849
3970
|
brain: compactionBrain,
|
|
@@ -3928,10 +4049,12 @@ export class Runner {
|
|
|
3928
4049
|
}
|
|
3929
4050
|
const result = assembleResult(spec, prepared.sessionId, final, stats, {
|
|
3930
4051
|
threw,
|
|
4052
|
+
runId: prepared.runId,
|
|
3931
4053
|
model: prepared.model.id,
|
|
3932
4054
|
unpricedSpend: rs.telemetry.unpricedSpend,
|
|
3933
4055
|
rewindNotes: prepared.rewindNotes,
|
|
3934
4056
|
haltedOnUserRejection: prepared.batchHaltRef.current !== undefined,
|
|
4057
|
+
userHalted: loopLatch.userHalted,
|
|
3935
4058
|
strandedHumanAnswers,
|
|
3936
4059
|
remoteEnvFailures: prepared.remoteEnvFailures,
|
|
3937
4060
|
effectiveReadFace: prepared.effectiveReadFace,
|
|
@@ -3985,6 +4108,7 @@ export class Runner {
|
|
|
3985
4108
|
r.errorMessage = `${r.errorMessage ?? "the resume leg did not complete"} — the approved action never started, and reopening the checkpoint FAILED: its state is unprovable from here. Re-read it before deciding; do NOT issue a fresh approval on the assumption the old one is dead`;
|
|
3986
4109
|
}
|
|
3987
4110
|
}
|
|
4111
|
+
prepared.sealReadStateSeat?.(ownCommittedTailRef.current);
|
|
3988
4112
|
{
|
|
3989
4113
|
const wss = prepared.workspaceStateSettle;
|
|
3990
4114
|
if (wss !== undefined && result.status !== "suspended" && result.status !== "needs_review") {
|
|
@@ -4073,6 +4197,7 @@ export class Runner {
|
|
|
4073
4197
|
kind: "task.end",
|
|
4074
4198
|
version: 1,
|
|
4075
4199
|
taskId: rs.telemetry.taskId,
|
|
4200
|
+
runId: rs.telemetry.runId,
|
|
4076
4201
|
status: result.status,
|
|
4077
4202
|
errorCode: result.errorCode,
|
|
4078
4203
|
turns: stats.turns,
|
|
@@ -4116,9 +4241,7 @@ export class Runner {
|
|
|
4116
4241
|
manualCompactRef.emitMooted = undefined;
|
|
4117
4242
|
queue.push({ type: "done", result });
|
|
4118
4243
|
queue.close();
|
|
4119
|
-
|
|
4120
|
-
await this.snapshotTurn(prepared);
|
|
4121
|
-
}
|
|
4244
|
+
await prepared.fileHistoryBoundary?.settle();
|
|
4122
4245
|
if (spec.suggestNextPrompts && result.status === "completed") {
|
|
4123
4246
|
onSuggestions(this.suggestNextPrompts(spec, prepared, result));
|
|
4124
4247
|
}
|
|
@@ -4197,7 +4320,7 @@ export class Runner {
|
|
|
4197
4320
|
if (!sameRouteIdentity(model, prepared.model)) {
|
|
4198
4321
|
const verdict = await adjudicateDerivedRoute({ brain: this.deps.brain, model, getApiKeyAndHeaders: spec.getApiKeyAndHeaders });
|
|
4199
4322
|
if (verdict !== undefined && !verdict.ok) {
|
|
4200
|
-
deliverEngineNotice(this.deps.onNotice, fallbackToPrimaryNotice({ seat: "prompt-suggestions", from: model.id, to: prepared.model.id, verdict, sessionId: prepared.sessionId }));
|
|
4323
|
+
deliverEngineNotice(this.deps.onNotice, fallbackToPrimaryNotice({ seat: "prompt-suggestions", from: model.id, to: prepared.model.id, verdict, sessionId: prepared.sessionId, runId: prepared.runId }));
|
|
4201
4324
|
model = prepared.model;
|
|
4202
4325
|
thinking = prepared.thinking;
|
|
4203
4326
|
}
|
|
@@ -4230,71 +4353,6 @@ export class Runner {
|
|
|
4230
4353
|
clearTimeout(timer);
|
|
4231
4354
|
}
|
|
4232
4355
|
}
|
|
4233
|
-
async snapshotTurn(prepared) {
|
|
4234
|
-
const store = this.deps.fileSnapshotStore;
|
|
4235
|
-
const env = prepared.ownedEnv ?? this.deps.executionEnv;
|
|
4236
|
-
if (!store || !env)
|
|
4237
|
-
return;
|
|
4238
|
-
try {
|
|
4239
|
-
const leafId = await prepared.session.getLeafId();
|
|
4240
|
-
if (!leafId)
|
|
4241
|
-
return;
|
|
4242
|
-
const root = prepared.taskRootPath;
|
|
4243
|
-
const refusal = this.snapshotTooLargeRoots.get(root);
|
|
4244
|
-
if (refusal !== undefined) {
|
|
4245
|
-
if (Date.now() - refusal.refusedAt < SNAPSHOT_TOO_LARGE_TTL_MS) {
|
|
4246
|
-
if (!refusal.skipAnnounced) {
|
|
4247
|
-
refusal.skipAnnounced = true;
|
|
4248
|
-
try {
|
|
4249
|
-
this.deps.onError?.(new Error(`rewind-files snapshot skipped for this working-tree root: a too_large refusal is still inside its ${SNAPSHOT_TOO_LARGE_TTL_MS / 60_000}-minute cooldown (re-probed at ${new Date(refusal.refusedAt + SNAPSHOT_TOO_LARGE_TTL_MS).toISOString()}) — turns completed during the cooldown capture no snapshot and cannot be rewound to. Announced once per cooldown window.`), { phase: "rewind", sessionId: prepared.sessionId, classification: "too_large" });
|
|
4250
|
-
}
|
|
4251
|
-
catch {
|
|
4252
|
-
}
|
|
4253
|
-
}
|
|
4254
|
-
return;
|
|
4255
|
-
}
|
|
4256
|
-
this.snapshotTooLargeRoots.delete(root);
|
|
4257
|
-
}
|
|
4258
|
-
const ac = new AbortController();
|
|
4259
|
-
let timer;
|
|
4260
|
-
const timeout = new Promise((resolve) => {
|
|
4261
|
-
timer = setTimeout(() => {
|
|
4262
|
-
ac.abort();
|
|
4263
|
-
resolve({ ok: false, error: { code: "aborted", message: "snapshot timed out" } });
|
|
4264
|
-
}, SNAPSHOT_TIMEOUT_MS);
|
|
4265
|
-
});
|
|
4266
|
-
const work = store.snapshot(prepared.sessionId, leafId, env, root, ac.signal);
|
|
4267
|
-
work.catch(() => { });
|
|
4268
|
-
let r;
|
|
4269
|
-
try {
|
|
4270
|
-
r = await Promise.race([work, timeout]);
|
|
4271
|
-
}
|
|
4272
|
-
finally {
|
|
4273
|
-
clearTimeout(timer);
|
|
4274
|
-
}
|
|
4275
|
-
if (!r.ok) {
|
|
4276
|
-
const tooLarge = r.error.code === "too_large";
|
|
4277
|
-
const refusedAt = Date.now();
|
|
4278
|
-
if (tooLarge && !this.snapshotTooLargeRoots.has(root))
|
|
4279
|
-
this.snapshotTooLargeRoots.set(root, { refusedAt, skipAnnounced: false });
|
|
4280
|
-
try {
|
|
4281
|
-
this.deps.onError?.(new Error(`rewind-files snapshot failed (${r.error.code}): ${r.error.message}` +
|
|
4282
|
-
(tooLarge
|
|
4283
|
-
? ` — skipping further snapshots for this root (this process) during a ${SNAPSHOT_TOO_LARGE_TTL_MS / 60_000}-minute cooldown, until ${new Date(refusedAt + SNAPSHOT_TOO_LARGE_TTL_MS).toISOString()}, when the tree is re-probed automatically. Raise the store's snapshotBounds to accept a tree this size; shrinking the tree also re-enables rewind, but only at that re-probe — not immediately`
|
|
4284
|
-
: "")), { phase: "rewind", sessionId: prepared.sessionId, ...(tooLarge ? { classification: "too_large" } : {}) });
|
|
4285
|
-
}
|
|
4286
|
-
catch {
|
|
4287
|
-
}
|
|
4288
|
-
}
|
|
4289
|
-
}
|
|
4290
|
-
catch (err) {
|
|
4291
|
-
try {
|
|
4292
|
-
this.deps.onError?.(err, { phase: "rewind", sessionId: prepared.sessionId });
|
|
4293
|
-
}
|
|
4294
|
-
catch {
|
|
4295
|
-
}
|
|
4296
|
-
}
|
|
4297
|
-
}
|
|
4298
4356
|
async runTask(spec, internals) {
|
|
4299
4357
|
const stream = this.runTaskStream(spec, undefined, internals);
|
|
4300
4358
|
for await (const _ of stream) {
|
|
@@ -4314,6 +4372,7 @@ export class Runner {
|
|
|
4314
4372
|
throw new CheckpointError("checkpoint.invalid_outcome", `resume outcome must be an object naming its gate (got ${outcome === null ? "null" : typeof outcome})`);
|
|
4315
4373
|
}
|
|
4316
4374
|
const config = typeof taskConfig === "object" && taskConfig !== null ? { ...taskConfig } : taskConfig;
|
|
4375
|
+
internals = internals !== undefined ? { ...internals } : undefined;
|
|
4317
4376
|
const store = resolveCheckpointStore(config, this.deps);
|
|
4318
4377
|
if (!store) {
|
|
4319
4378
|
throw new CheckpointError("checkpoint.not_found", "no CheckpointStore wired — cannot resume (set RunnerDeps.checkpointStore or taskConfig.checkpointStore)");
|
|
@@ -4663,12 +4722,13 @@ export class Runner {
|
|
|
4663
4722
|
"(corrupt / inconsistently-minted row) — the frozen deny data the resume would execute is not the data the " +
|
|
4664
4723
|
"digest authenticates; rejected pre-CAS (the checkpoint stays pending)");
|
|
4665
4724
|
}
|
|
4666
|
-
const suppliedDigest = constraintChainDigest((internals?.inheritedGate?.parentConstraints ?? []).map((pc) =>
|
|
4725
|
+
const suppliedDigest = constraintChainDigest((internals?.inheritedGate?.parentConstraints ?? []).map((pc, i) => constraintChainEntryOfSuppliedLayer(pc, persistedChain[i])));
|
|
4667
4726
|
if (suppliedDigest !== expectedDigest) {
|
|
4668
4727
|
throw new CheckpointError("resume.parent_constraint_mismatch", "the re-supplied parent-constraint chain's projection content does not match what the checkpoint recorded " +
|
|
4669
4728
|
`(recorded ${expectedDigest}, re-supplied ${suppliedDigest}) — a same-shape chain with different frozen ` +
|
|
4670
4729
|
"deny data would run the resumed leg under a different ancestor gate than it suspended with; " +
|
|
4671
|
-
"rejected pre-CAS (the checkpoint stays pending) — re-resume with the original chain's policies"
|
|
4730
|
+
"rejected pre-CAS (the checkpoint stays pending) — re-resume with the original chain's policies " +
|
|
4731
|
+
"(including, when the row recorded one, the ancestor's auto-mode arming recipe verbatim)");
|
|
4672
4732
|
}
|
|
4673
4733
|
}
|
|
4674
4734
|
}
|
|
@@ -4694,6 +4754,15 @@ export class Runner {
|
|
|
4694
4754
|
"running the resumed leg under a different identity would move its usage-ledger bucket, scope derivation and attribution; " +
|
|
4695
4755
|
"refused pre-CAS (the checkpoint stays pending): re-resume with the original principal, or omit the field to inherit the recorded one");
|
|
4696
4756
|
}
|
|
4757
|
+
{
|
|
4758
|
+
const recordedPlacementRoot = placementValueOrAbsent(cp.state.placementRootSessionId);
|
|
4759
|
+
const suppliedPlacementRoot = placementValueOrAbsent(internals?.placementRoot);
|
|
4760
|
+
if (recordedPlacementRoot !== undefined && suppliedPlacementRoot !== undefined && suppliedPlacementRoot !== recordedPlacementRoot) {
|
|
4761
|
+
throw new CheckpointError("resume.placement_mismatch", `the resume supplied explicit placement root ${JSON.stringify(suppliedPlacementRoot)} but this checkpoint recorded placement root ${JSON.stringify(recordedPlacementRoot)} at suspend — ` +
|
|
4762
|
+
"resuming under a different placement fixed point would re-place the leg (and its descendants) on another target; " +
|
|
4763
|
+
"refused pre-CAS (the checkpoint stays pending): re-resume with the recorded root, or omit internals.placementRoot to inherit it");
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4697
4766
|
const owesDelivery = outcomeGate !== "resource_limit" ||
|
|
4698
4767
|
readPendingSteerQueue(cp.state).length > 0 ||
|
|
4699
4768
|
(cp.state.runningBackgroundTasks?.length ?? 0) > 0;
|
|
@@ -4869,7 +4938,121 @@ export class Runner {
|
|
|
4869
4938
|
if (outcomeForStore === undefined) {
|
|
4870
4939
|
throw new CheckpointError("checkpoint.invalid_outcome", `resume outcome (gate "${describeSuppliedValue(outcomeGate)}") matched the checkpoint gate but no lane captured it — refusing pre-CAS rather than passing the caller's live object to the store and the resumed run`);
|
|
4871
4940
|
}
|
|
4941
|
+
if (this.deps.resumePreflight !== undefined) {
|
|
4942
|
+
const preflight = this.deps.resumePreflight;
|
|
4943
|
+
const rawDeadline = this.deps.resumePreflightTimeoutMs;
|
|
4944
|
+
let preflightTimeoutMs = RESUME_PREFLIGHT_DEFAULT_TIMEOUT_MS;
|
|
4945
|
+
if (rawDeadline !== undefined) {
|
|
4946
|
+
if (typeof rawDeadline === "number" && Number.isFinite(rawDeadline) && rawDeadline > 0 && rawDeadline <= MAX_HOOK_TIMEOUT_MS) {
|
|
4947
|
+
preflightTimeoutMs = rawDeadline;
|
|
4948
|
+
}
|
|
4949
|
+
else {
|
|
4950
|
+
try {
|
|
4951
|
+
this.deps.onError?.(new Error(`RunnerDeps.resumePreflightTimeoutMs is not a positive finite number within the seat ceiling of ${MAX_HOOK_TIMEOUT_MS}ms (got ${describeSuppliedValue(rawDeadline)}) — the resume preflight falls back to its own ${RESUME_PREFLIGHT_DEFAULT_TIMEOUT_MS}ms default`), { phase: "config", sessionId: cp.sessionId });
|
|
4952
|
+
}
|
|
4953
|
+
catch {
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
const info = {
|
|
4958
|
+
token,
|
|
4959
|
+
sessionId: cp.sessionId,
|
|
4960
|
+
...(cp.state.placementRootSessionId !== undefined ? { placementRootSessionId: cp.state.placementRootSessionId } : {}),
|
|
4961
|
+
...(cp.principal ? { principal: cp.principal } : {}),
|
|
4962
|
+
...(cp.state.workspaceHandle !== undefined ? { workspaceHandle: structuredClone(cp.state.workspaceHandle) } : {}),
|
|
4963
|
+
gateKind: cp.gate.kind,
|
|
4964
|
+
};
|
|
4965
|
+
const refusalTail = "; the checkpoint stays pending and the same token is redeemable once the obstacle clears";
|
|
4966
|
+
let verdict;
|
|
4967
|
+
try {
|
|
4968
|
+
const seat = await runHookSeat("resumePreflight", {
|
|
4969
|
+
timeoutMs: preflightTimeoutMs,
|
|
4970
|
+
...(resumeSignal !== undefined ? { signal: resumeSignal } : {}),
|
|
4971
|
+
abortEnds: true,
|
|
4972
|
+
onBadTimeout: (badErr) => {
|
|
4973
|
+
try {
|
|
4974
|
+
this.deps.onError?.(badErr instanceof Error ? badErr : new Error(String(badErr)), { phase: "hook", sessionId: cp.sessionId });
|
|
4975
|
+
}
|
|
4976
|
+
catch {
|
|
4977
|
+
}
|
|
4978
|
+
},
|
|
4979
|
+
owner: this.deps,
|
|
4980
|
+
}, (sig) => preflight(info, sig));
|
|
4981
|
+
if (seat.expired) {
|
|
4982
|
+
throw new CheckpointError("resume.preflight_rejected", seat.cause === "timeout"
|
|
4983
|
+
? `the deployment's resumePreflight did not answer within its ${preflightTimeoutMs}ms deadline while screening this resume — refused fail-closed (retry-later arm)${refusalTail}`
|
|
4984
|
+
: `the resume was cancelled while the deployment's resumePreflight was still screening it — refused (retry-later arm)${refusalTail}`);
|
|
4985
|
+
}
|
|
4986
|
+
verdict = seat.value;
|
|
4987
|
+
}
|
|
4988
|
+
catch (preflightErr) {
|
|
4989
|
+
if (preflightErr instanceof CheckpointError)
|
|
4990
|
+
throw preflightErr;
|
|
4991
|
+
const err = preflightErr instanceof Error ? preflightErr : new Error(String(preflightErr));
|
|
4992
|
+
try {
|
|
4993
|
+
this.deps.onError?.(err, { phase: "hook", sessionId: cp.sessionId });
|
|
4994
|
+
}
|
|
4995
|
+
catch {
|
|
4996
|
+
}
|
|
4997
|
+
throw new CheckpointError("resume.preflight_rejected", `the deployment's resumePreflight crashed while screening this resume (${inlineUntrusted(err.message)}) — refused fail-closed (retry-later arm)${refusalTail}`);
|
|
4998
|
+
}
|
|
4999
|
+
const verdictOk = verdict !== null && typeof verdict === "object" ? verdict.ok : undefined;
|
|
5000
|
+
if (verdictOk !== true) {
|
|
5001
|
+
const bag = verdict !== null && typeof verdict === "object" ? verdict : undefined;
|
|
5002
|
+
const disposition = bag?.disposition;
|
|
5003
|
+
const suppliedMessage = bag?.message;
|
|
5004
|
+
const retryAfterMs = bag?.retryAfterMs;
|
|
5005
|
+
const readableMessage = typeof suppliedMessage === "string" && suppliedMessage !== "" ? suppliedMessage : undefined;
|
|
5006
|
+
const said = readableMessage !== undefined ? `: ${inlineUntrusted(readableMessage)}` : " (no readable verdict — fail-closed)";
|
|
5007
|
+
if (disposition === "terminal" && readableMessage !== undefined) {
|
|
5008
|
+
this.locallyClaimedTokens.add(token);
|
|
5009
|
+
let settled;
|
|
5010
|
+
try {
|
|
5011
|
+
settled = await store.expire(token, cp.scope);
|
|
5012
|
+
}
|
|
5013
|
+
catch (expireErr) {
|
|
5014
|
+
this.locallyClaimedTokens.delete(token);
|
|
5015
|
+
throw expireErr;
|
|
5016
|
+
}
|
|
5017
|
+
if (!settled) {
|
|
5018
|
+
this.locallyClaimedTokens.delete(token);
|
|
5019
|
+
const live = await store.get(token);
|
|
5020
|
+
if (live?.status === "pending") {
|
|
5021
|
+
throw new CheckpointError("resume.preflight_rejected", `the deployment's resumePreflight ruled this resume PERMANENTLY blocked${said}, but the row moved under this refusal (a concurrent resolve/reopen cycle) — nothing was settled here; the row is pending again, re-resume against the current state (the preflight screens every attempt)`);
|
|
5022
|
+
}
|
|
5023
|
+
throw new CheckpointError("resume.preflight_rejected", `the deployment's resumePreflight ruled this resume PERMANENTLY blocked${said} — a concurrent actor had already settled the row (${describeSuppliedValue(live?.status ?? "consumed")}); nothing was settled by this refusal`);
|
|
5024
|
+
}
|
|
5025
|
+
this.parentConstraintRegistry.delete(token);
|
|
5026
|
+
const terminalReap = this.suspendedEnvReaps.get(token);
|
|
5027
|
+
this.suspendedEnvReaps.delete(token);
|
|
5028
|
+
this.locallyClaimedTokens.delete(token);
|
|
5029
|
+
if (terminalReap?.env !== undefined && hasDestroy(terminalReap.env)) {
|
|
5030
|
+
const terminalEnv = terminalReap.env;
|
|
5031
|
+
await settleTeardownLeg(() => terminalEnv.destroy(), "terminal-preflight env destroy", (envErr) => {
|
|
5032
|
+
try {
|
|
5033
|
+
this.deps.onError?.(envErr, { phase: "config", sessionId: terminalReap.sessionId });
|
|
5034
|
+
}
|
|
5035
|
+
catch {
|
|
5036
|
+
}
|
|
5037
|
+
});
|
|
5038
|
+
}
|
|
5039
|
+
try {
|
|
5040
|
+
this.deps.onError?.(new Error(`resumePreflight ruled this row PERMANENTLY blocked${said} — the row was settled terminally (expired) by this refusal's single-shot CAS (token no longer redeemable)`), { phase: "hook", sessionId: cp.sessionId });
|
|
5041
|
+
}
|
|
5042
|
+
catch {
|
|
5043
|
+
}
|
|
5044
|
+
throw new CheckpointError("resume.preflight_rejected", `the deployment's resumePreflight ruled this resume PERMANENTLY blocked${said} — the row was settled terminally (expired by this refusal's single-shot CAS); the token is not redeemable`);
|
|
5045
|
+
}
|
|
5046
|
+
const waitHint = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs >= 0 ? retryAfterMs : undefined;
|
|
5047
|
+
throw new CheckpointError("resume.preflight_rejected", `the deployment's resumePreflight refused this resume${said}${refusalTail}${waitHint !== undefined ? ` (deployment wait hint: ${String(waitHint)}ms)` : ""}`, waitHint !== undefined ? { retryAfterMs: waitHint } : undefined);
|
|
5048
|
+
}
|
|
5049
|
+
if (recheckGovernanceWindow !== undefined)
|
|
5050
|
+
await recheckGovernanceWindow();
|
|
5051
|
+
}
|
|
5052
|
+
this.locallyClaimedTokens.add(token);
|
|
4872
5053
|
const won = await store.resolve(token, cp.scope, outcomeForStore, { rev: cp.rev ?? 0 });
|
|
5054
|
+
if (!won)
|
|
5055
|
+
this.locallyClaimedTokens.delete(token);
|
|
4873
5056
|
if (!won) {
|
|
4874
5057
|
const live = await store.get(token);
|
|
4875
5058
|
if (live?.status === "pending") {
|
|
@@ -5223,9 +5406,10 @@ export class Runner {
|
|
|
5223
5406
|
minTokens: opts?.minTokens,
|
|
5224
5407
|
overheadTokens: prepared.promptOverheadTokens,
|
|
5225
5408
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
5226
|
-
onInputTruncated: emitInputTruncated(spec.tracer ?? this.deps.tracer, spec.taskId ?? prepared.sessionId),
|
|
5409
|
+
onInputTruncated: emitInputTruncated(opts?.telemetry?.tracer ?? spec.tracer ?? this.deps.tracer, opts?.telemetry?.taskId ?? spec.taskId ?? prepared.sessionId),
|
|
5227
5410
|
...(opts?.windowSafety ?? {}),
|
|
5228
5411
|
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
5412
|
+
...contextInstructionFilesOption(prepared),
|
|
5229
5413
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
5230
5414
|
...this.seamCCompactionOptions(prepared),
|
|
5231
5415
|
...gitRestateOption(prepared),
|
|
@@ -5236,17 +5420,17 @@ export class Runner {
|
|
|
5236
5420
|
});
|
|
5237
5421
|
this.recordCompactionReuse(prepared, finishComp);
|
|
5238
5422
|
if (finishComp.unevaluableWindow) {
|
|
5239
|
-
discloseUnevaluableWindow(finishComp.unevaluableWindow, prepared, spec.tracer ?? this.deps.tracer, spec.taskId ?? prepared.sessionId, this.deps.onError);
|
|
5423
|
+
discloseUnevaluableWindow(finishComp.unevaluableWindow, prepared, opts?.telemetry?.tracer ?? spec.tracer ?? this.deps.tracer, opts?.telemetry?.taskId ?? spec.taskId ?? prepared.sessionId, this.deps.onError);
|
|
5240
5424
|
}
|
|
5241
5425
|
comp = finishComp;
|
|
5242
5426
|
}
|
|
5243
5427
|
catch (err) {
|
|
5244
5428
|
const failMsg = String(err instanceof Error ? err.message : err);
|
|
5245
5429
|
const failReason = failMsg.length > 512 ? `${failMsg.slice(0, 512)}…` : failMsg;
|
|
5246
|
-
emitTrace(spec.tracer ?? this.deps.tracer, () => ({
|
|
5430
|
+
emitTrace(opts?.telemetry?.tracer ?? spec.tracer ?? this.deps.tracer, () => ({
|
|
5247
5431
|
kind: "compaction.failed",
|
|
5248
5432
|
version: 1,
|
|
5249
|
-
taskId: spec.taskId ?? prepared.sessionId,
|
|
5433
|
+
taskId: opts?.telemetry?.taskId ?? spec.taskId ?? prepared.sessionId,
|
|
5250
5434
|
trigger: "auto",
|
|
5251
5435
|
reason: failReason,
|
|
5252
5436
|
ts: Date.now(),
|