@sema-agent/core 3.0.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 +2 -1
- package/dist/agents/cascade.js +31 -32
- package/dist/agents/cumulative-stats.d.ts +29 -0
- package/dist/agents/cumulative-stats.js +29 -0
- package/dist/agents/observer.d.ts +4 -0
- package/dist/agents/observer.js +11 -10
- package/dist/agents/repair-loop.js +27 -19
- package/dist/agents/retain-ledger.d.ts +2 -0
- package/dist/agents/retain-ledger.js +6 -5
- package/dist/agents/roster-store.js +3 -5
- package/dist/agents/subagent.js +66 -64
- package/dist/agents/teacher.d.ts +1 -9
- package/dist/agents/teacher.js +21 -24
- package/dist/agents/verify.js +15 -14
- package/dist/brain/anthropic.js +24 -21
- package/dist/brain/openai.js +24 -21
- package/dist/brain/stream-engine.js +5 -2
- package/dist/brain/stream-shared.d.ts +1 -0
- package/dist/brain/stream-shared.js +14 -0
- package/dist/brain/terminal-cause.d.ts +4 -0
- package/dist/brain/terminal-cause.js +12 -0
- package/dist/brain/tool-call-id.d.ts +1 -0
- package/dist/brain/tool-call-id.js +3 -0
- package/dist/brain/tool-call-repair.js +2 -1
- package/dist/core/auto-compaction.js +16 -25
- package/dist/core/background-agent-store.d.ts +22 -22
- package/dist/core/background-agent-store.js +19 -23
- package/dist/core/checkpoint-store.d.ts +6 -13
- package/dist/core/checkpoint-store.js +11 -5
- package/dist/core/file-snapshot-store.d.ts +8 -0
- package/dist/core/file-snapshot-store.js +4 -3
- package/dist/core/hooks.d.ts +3 -1
- package/dist/core/hooks.js +8 -18
- package/dist/core/lsp.js +4 -3
- package/dist/core/mailbox-store.d.ts +7 -10
- package/dist/core/mcp.d.ts +7 -10
- package/dist/core/mcp.js +7 -3
- package/dist/core/memory-engine/engine.d.ts +0 -1
- package/dist/core/memory-engine/engine.js +24 -34
- package/dist/core/memory-engine/file-backend.d.ts +1 -2
- package/dist/core/memory-engine/file-backend.js +25 -36
- package/dist/core/memory-engine/layout.d.ts +8 -0
- package/dist/core/memory-engine/layout.js +60 -4
- package/dist/core/memory-engine/scope-contract.js +9 -3
- package/dist/core/memory-engine/types.d.ts +1 -1
- package/dist/core/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 +2 -7
- package/dist/core/runner/assemble-result.js +3 -4
- package/dist/core/runner/compaction-call-options.d.ts +7 -0
- package/dist/core/runner/compaction-call-options.js +30 -0
- package/dist/core/runner/prepare-task.d.ts +6 -23
- package/dist/core/runner/prepare-task.js +20 -53
- package/dist/core/runner/runtask.d.ts +1 -0
- package/dist/core/runner/runtask.js +65 -156
- 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/safe-notify.d.ts +17 -0
- package/dist/core/safe-notify.js +59 -0
- package/dist/core/sensitive-path-policy.js +2 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/stub-env.d.ts +2 -6
- package/dist/core/surrogate-safe-slice.d.ts +4 -0
- package/dist/core/surrogate-safe-slice.js +18 -0
- package/dist/core/task-registry-monitor.js +8 -13
- package/dist/core/task-registry-shared.d.ts +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 +10 -5
- 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 +2 -9
- package/dist/core/types.d.ts +15 -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/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/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/orchestration/run-spec.js +7 -4
- package/dist/orchestration/run-workflow-tool.js +3 -35
- package/dist/orchestration/workflow.d.ts +3 -11
- package/dist/orchestration/workflow.js +164 -204
- package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
- package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
- package/dist/stores/file/background-agent-store.d.ts +3 -12
- package/dist/stores/file/background-agent-store.js +3 -41
- package/dist/stores/file/checkpoint-store.js +6 -6
- package/dist/stores/file/mailbox-store.d.ts +2 -6
- package/dist/stores/file/session-policy-store.js +15 -1
- package/dist/stores/file/session-store.d.ts +2 -6
- package/dist/stores/file/workflow-journal-store.d.ts +3 -11
- package/dist/stores/file/workflow-run-store.d.ts +3 -7
- package/dist/stores/file/workflow-run-store.js +4 -17
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -0
- package/dist/tools/fs/bash-readonly-classifier.js +60 -25
- package/dist/tools/fs/fs-bash.js +324 -96
- 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/monitor.d.ts +1 -0
- package/dist/tools/monitor.js +7 -5
- package/dist/tools/worktree.d.ts +2 -7
- package/dist/tools/worktree.js +3 -1
- package/package.json +6 -2
|
@@ -9,8 +9,7 @@ import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
|
9
9
|
import { computeCostMicroUsd, modelCostToPricing } from "../pricing.js";
|
|
10
10
|
import { emitTrace } from "../trace.js";
|
|
11
11
|
import { emitTaskOutcome } from "../task-outcome.js";
|
|
12
|
-
import {
|
|
13
|
-
import { WALLTIME_CUTOFF_MESSAGE } from "../../brain/walltime.js";
|
|
12
|
+
import { isDegenerateCutMessage, isWalltimeCutMessage } from "../../brain/terminal-cause.js";
|
|
14
13
|
import { primaryActivityArg } from "../arg-summary.js";
|
|
15
14
|
import { resolveReasoning } from "../../brain/reasoning.js";
|
|
16
15
|
import { readDegradation } from "../../brain/degrading.js";
|
|
@@ -24,8 +23,10 @@ import { toImageContent } from "./image.js";
|
|
|
24
23
|
import { OUTPUT_TOOL_NAME, SKILLS_LISTING_PROBE_HEADER, resolveOutputRetries } from "./synthetic-tools.js";
|
|
25
24
|
import { cacheFamilyOf, usageCostMicroUsd } from "./usage-accounting.js";
|
|
26
25
|
import { assembleResult, errorCodeOf } from "./assemble-result.js";
|
|
27
|
-
import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, advanceCadenceClock, agentListingDeltaHeader, agentListingInitialHeader, replayAnnouncedListing, replayAnnouncedModels, collectDateChange, collectDueAttachments, collectInstructionsChange, commitAgentListing, commitInstructionsChange, commitSkillsListing, createAttachmentState, rebaseCadenceWindows, reduceToolEnd, renderAgentListingDelta, renderMcpDroppedTools, renderMcpInstructionsDelta, renderOrphanedBackgroundTasks, selectMcpDroppedBatch, renderSkillsListingDelta, renderToolsDelta, stampWriteAnchor } from "./turn-attachments.js";
|
|
26
|
+
import { ATTACHMENT_BYTE_CAP, CHANGED_FILES_MAX, AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, advanceCadenceClock, agentListingDeltaHeader, agentListingInitialHeader, replayAnnouncedListing, replayAnnouncedModels, clipToBytes, collectDateChange, collectDueAttachments, collectInstructionsChange, commitAgentListing, commitInstructionsChange, commitSkillsListing, createAttachmentState, rebaseCadenceWindows, reduceToolEnd, renderAgentListingDelta, renderMcpDroppedTools, renderMcpInstructionsDelta, renderOrphanedBackgroundTasks, selectMcpDroppedBatch, renderSkillsListingDelta, renderToolsDelta, stampWriteAnchor } from "./turn-attachments.js";
|
|
27
|
+
import { buildWorkingFileAttachments, centerAdoptionOption, emitInputTruncated } from "./compaction-call-options.js";
|
|
28
28
|
import { prepareTask } from "./prepare-task.js";
|
|
29
|
+
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
29
30
|
import { TOOL_SEARCH_NAME } from "./tool-disclosure.js";
|
|
30
31
|
import { hasVerifiableStructureSignal } from "./grounding-signal.js";
|
|
31
32
|
import { hasDestroy, isIsolated } from "../remote-env.js";
|
|
@@ -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) {
|
|
@@ -504,16 +495,17 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
504
495
|
const batch = rs.turn.toolBatch;
|
|
505
496
|
rs.turn.toolBatch = [];
|
|
506
497
|
batchArgs?.clear();
|
|
507
|
-
|
|
498
|
+
const injectedThisTurn = finalVerifyInjectedThisTurn ? "final_verification" : rs.counters.finalizeInjected ? "finalize" : undefined;
|
|
499
|
+
if (!boundarySteered && !prepared.abortController.signal.aborted) {
|
|
508
500
|
try {
|
|
509
|
-
const r = await postToolBatchHook(batch);
|
|
510
|
-
if (r?.additionalContext) {
|
|
501
|
+
const r = await postToolBatchHook(batch, injectedThisTurn !== undefined ? { injectedThisTurn } : undefined);
|
|
502
|
+
if (r?.additionalContext && injectedThisTurn === undefined) {
|
|
511
503
|
const body = sanitizeUntrustedText(r.additionalContext);
|
|
512
504
|
const budget = ATTACHMENT_BYTE_CAP - boundaryAttachmentBytes;
|
|
513
505
|
if (budget >= BATCH_CONTEXT_MIN_KEEP_BYTES) {
|
|
514
|
-
const clipped =
|
|
506
|
+
const clipped = clipToBytes(body, budget) === body
|
|
515
507
|
? body
|
|
516
|
-
: `${
|
|
508
|
+
: `${clipToBytes(body, budget - Buffer.byteLength(BATCH_TRUNCATION_MARKER, "utf8"))}${BATCH_TRUNCATION_MARKER}`;
|
|
517
509
|
batchContextBlock = `<system-reminder>\n${clipped}\n</system-reminder>`;
|
|
518
510
|
}
|
|
519
511
|
}
|
|
@@ -603,10 +595,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
603
595
|
const comp = await maybeCompact({
|
|
604
596
|
session: prepared.session,
|
|
605
597
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
606
|
-
...(
|
|
607
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
608
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
609
|
-
})(),
|
|
598
|
+
...centerAdoptionOption(prepared),
|
|
610
599
|
model: event.model,
|
|
611
600
|
compactionModel: prepared.compModel,
|
|
612
601
|
brain: compactionBrain,
|
|
@@ -618,22 +607,11 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
|
|
|
618
607
|
...(manualCancelSignal !== undefined ? { manualCancelSignal } : {}),
|
|
619
608
|
minTokens: forceManual ? 0 : rs.counters.compactionFloor,
|
|
620
609
|
force: forceManual,
|
|
621
|
-
onInputTruncated: (
|
|
610
|
+
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
622
611
|
forceUnderThreshold: trimPressure,
|
|
623
612
|
overheadTokens: prepared.promptOverheadTokens,
|
|
624
613
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
625
|
-
workingFileAttachments: spec
|
|
626
|
-
? {
|
|
627
|
-
readFile: prepared.readTaskFile,
|
|
628
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
629
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
630
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
631
|
-
...(prepared.instructionSources
|
|
632
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
633
|
-
: {}),
|
|
634
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
635
|
-
}
|
|
636
|
-
: undefined,
|
|
614
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
637
615
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
638
616
|
...runnerHooks.seamCCompactionOptions(prepared),
|
|
639
617
|
...windowSafetyOptions(event.model),
|
|
@@ -891,7 +869,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
|
|
|
891
869
|
if (m.role === "assistant" && typeof m.stopReason === "string") {
|
|
892
870
|
rs.turn.turnStopReason = m.stopReason;
|
|
893
871
|
}
|
|
894
|
-
if (m.role === "assistant" && m
|
|
872
|
+
if (m.role === "assistant" && isWalltimeCutMessage(m)) {
|
|
895
873
|
rs.counters.callCutoffs += 1;
|
|
896
874
|
if (prepared.callCapRef)
|
|
897
875
|
prepared.callCapRef.finalizeMode = true;
|
|
@@ -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 {
|
|
@@ -2324,9 +2298,9 @@ export class Runner {
|
|
|
2324
2298
|
truncatedOutput: {},
|
|
2325
2299
|
malformedToolUse: {},
|
|
2326
2300
|
thinkingOnly: {},
|
|
2327
|
-
degenerateOutput: { detect: (m) => m
|
|
2301
|
+
degenerateOutput: { detect: (m) => isDegenerateCutMessage(m) },
|
|
2328
2302
|
walltimeCutoff: {
|
|
2329
|
-
detect: (m) => m
|
|
2303
|
+
detect: (m) => isWalltimeCutMessage(m),
|
|
2330
2304
|
hasLiveWriteoutWindow: () => {
|
|
2331
2305
|
const ref = prepared.callCapRef;
|
|
2332
2306
|
if (ref === undefined)
|
|
@@ -2349,10 +2323,7 @@ export class Runner {
|
|
|
2349
2323
|
const comp = await maybeCompact({
|
|
2350
2324
|
session: prepared.session,
|
|
2351
2325
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
2352
|
-
...(
|
|
2353
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
2354
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
2355
|
-
})(),
|
|
2326
|
+
...centerAdoptionOption(prepared),
|
|
2356
2327
|
model: prepared.harness.getModel(),
|
|
2357
2328
|
compactionModel: prepared.compModel,
|
|
2358
2329
|
brain: compactionBrain,
|
|
@@ -2365,19 +2336,8 @@ export class Runner {
|
|
|
2365
2336
|
force: true,
|
|
2366
2337
|
overheadTokens: prepared.promptOverheadTokens,
|
|
2367
2338
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
2368
|
-
onInputTruncated: (
|
|
2369
|
-
workingFileAttachments: spec
|
|
2370
|
-
? {
|
|
2371
|
-
readFile: prepared.readTaskFile,
|
|
2372
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
2373
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
2374
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
2375
|
-
...(prepared.instructionSources
|
|
2376
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
2377
|
-
: {}),
|
|
2378
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
2379
|
-
}
|
|
2380
|
-
: undefined,
|
|
2339
|
+
onInputTruncated: emitInputTruncated(rs.telemetry.tracer, rs.telemetry.taskId),
|
|
2340
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
2381
2341
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
2382
2342
|
...this.seamCCompactionOptions(prepared),
|
|
2383
2343
|
...windowSafetyOptions(prepared.harness.getModel()),
|
|
@@ -2499,6 +2459,8 @@ export class Runner {
|
|
|
2499
2459
|
resume.pendingActionStarted = true;
|
|
2500
2460
|
}
|
|
2501
2461
|
});
|
|
2462
|
+
if (resume.outcome.gate === "policy_ask")
|
|
2463
|
+
resume.decisionDelivered = true;
|
|
2502
2464
|
}
|
|
2503
2465
|
if (walltimeExhaustedResume) {
|
|
2504
2466
|
timeout.fired = true;
|
|
@@ -2530,6 +2492,8 @@ export class Runner {
|
|
|
2530
2492
|
if (steer.trusted)
|
|
2531
2493
|
engineSegments.push({ start, end: continuation.length });
|
|
2532
2494
|
}
|
|
2495
|
+
if (resume !== undefined)
|
|
2496
|
+
resume.decisionDelivered = true;
|
|
2533
2497
|
final = await withBrainSinks(() => prepared.harness.prompt(continuation, { engineSegments }));
|
|
2534
2498
|
}
|
|
2535
2499
|
}
|
|
@@ -2640,17 +2604,8 @@ export class Runner {
|
|
|
2640
2604
|
}
|
|
2641
2605
|
catch (err) {
|
|
2642
2606
|
if (errorCodeOf(err) === "resume.tool_unavailable") {
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
}
|
|
2646
|
-
catch {
|
|
2647
|
-
}
|
|
2648
|
-
try {
|
|
2649
|
-
if (prepared.ownedEnv && hasDestroy(prepared.ownedEnv))
|
|
2650
|
-
await prepared.ownedEnv.destroy();
|
|
2651
|
-
}
|
|
2652
|
-
catch {
|
|
2653
|
-
}
|
|
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 }));
|
|
2654
2609
|
throw err;
|
|
2655
2610
|
}
|
|
2656
2611
|
threw = err;
|
|
@@ -2739,7 +2694,7 @@ export class Runner {
|
|
|
2739
2694
|
tokens: prepared.nestedStats.tokens,
|
|
2740
2695
|
turns: prepared.nestedStats.turns,
|
|
2741
2696
|
tasks: prepared.nestedStats.tasks,
|
|
2742
|
-
costMicroUsd: prepared.nestedStats.costMicroUsd
|
|
2697
|
+
...(prepared.nestedStats.anyUnpriced ? {} : { costMicroUsd: prepared.nestedStats.costMicroUsd }),
|
|
2743
2698
|
};
|
|
2744
2699
|
}
|
|
2745
2700
|
if (stats.totalInputTokens > 0) {
|
|
@@ -2824,6 +2779,8 @@ export class Runner {
|
|
|
2824
2779
|
resume.pendingActionStarted !== true &&
|
|
2825
2780
|
result.status !== "completed" &&
|
|
2826
2781
|
result.status !== "suspended" &&
|
|
2782
|
+
result.status !== "needs_review" &&
|
|
2783
|
+
!(resumeDecisionWasNegative(resume) && resume.decisionDelivered === true) &&
|
|
2827
2784
|
resume.onEnvRestoreFailed !== undefined) {
|
|
2828
2785
|
try {
|
|
2829
2786
|
await resume.onEnvRestoreFailed("env_failed");
|
|
@@ -2844,15 +2801,11 @@ export class Runner {
|
|
|
2844
2801
|
const curWt = prepared.worktreeSessionRef?.current;
|
|
2845
2802
|
const changed = curCwd !== wss.restoredHandsCwd || curWt?.worktreeDir !== wss.restoredWorktreeDir;
|
|
2846
2803
|
if (curCwd !== undefined || curWt !== undefined || changed || wss.baselineUnknown === true) {
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
});
|
|
2853
|
-
}
|
|
2854
|
-
catch {
|
|
2855
|
-
}
|
|
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 }));
|
|
2856
2809
|
}
|
|
2857
2810
|
}
|
|
2858
2811
|
}
|
|
@@ -2860,8 +2813,8 @@ export class Runner {
|
|
|
2860
2813
|
if (stopFailureHook !== undefined &&
|
|
2861
2814
|
result.status === "failed" &&
|
|
2862
2815
|
final?.stopReason === "error" &&
|
|
2863
|
-
final
|
|
2864
|
-
final
|
|
2816
|
+
!isDegenerateCutMessage(final) &&
|
|
2817
|
+
!isWalltimeCutMessage(final) &&
|
|
2865
2818
|
threw === undefined &&
|
|
2866
2819
|
rs.limits.budgetHit === undefined &&
|
|
2867
2820
|
!rs.degrade.outputInvalid &&
|
|
@@ -2902,19 +2855,12 @@ export class Runner {
|
|
|
2902
2855
|
}
|
|
2903
2856
|
}
|
|
2904
2857
|
if (resume && committedToken === undefined) {
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
this.deps.onError?.(err, { phase: "config", sessionId: prepared.sessionId });
|
|
2911
|
-
}
|
|
2912
|
-
catch {
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
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 }));
|
|
2915
2863
|
}
|
|
2916
|
-
if (prepared.memoryEngineSession)
|
|
2917
|
-
await prepared.memoryEngineSession.harvest();
|
|
2918
2864
|
emitTrace(rs.telemetry.tracer, () => ({
|
|
2919
2865
|
kind: "task.end",
|
|
2920
2866
|
version: 1,
|
|
@@ -2968,28 +2914,19 @@ export class Runner {
|
|
|
2968
2914
|
isIsolated(prepared.ownedEnv) &&
|
|
2969
2915
|
prepared.suspendRef.token === undefined &&
|
|
2970
2916
|
prepared.reviewRef.token === undefined;
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
});
|
|
2985
|
-
}
|
|
2986
|
-
catch (e) {
|
|
2987
|
-
try {
|
|
2988
|
-
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
2989
|
-
}
|
|
2990
|
-
catch {
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
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 }));
|
|
2993
2930
|
const bgEnv = prepared.ownedEnv ?? this.deps.executionEnv;
|
|
2994
2931
|
const retainBgBySpec = spec.retainBackgroundProcesses === true && !ownedEnvDying;
|
|
2995
2932
|
if (bgEnv && hasBackgroundShell(bgEnv) && !retainBgBySpec) {
|
|
@@ -3001,7 +2938,7 @@ export class Runner {
|
|
|
3001
2938
|
...defaultTaskRegistry.timeoutResidentShellIds(bgEnv),
|
|
3002
2939
|
...defaultTaskRegistry.retainedShellIds(bgEnv),
|
|
3003
2940
|
];
|
|
3004
|
-
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 }));
|
|
3005
2942
|
}
|
|
3006
2943
|
catch (e) {
|
|
3007
2944
|
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
@@ -3016,14 +2953,9 @@ export class Runner {
|
|
|
3016
2953
|
scope: spec.principal ?? "default",
|
|
3017
2954
|
}, { skipSessionScoped: true });
|
|
3018
2955
|
if (prepared.subagentRetain) {
|
|
3019
|
-
|
|
3020
|
-
await prepared.subagentRetain.disposeAll();
|
|
3021
|
-
}
|
|
3022
|
-
catch (e) {
|
|
3023
|
-
this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId });
|
|
3024
|
-
}
|
|
2956
|
+
await settleTeardownLeg(() => prepared.subagentRetain.disposeAll(), "subagentRetain.disposeAll", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3025
2957
|
}
|
|
3026
|
-
await this.teardownOwnedEnv(prepared);
|
|
2958
|
+
await settleTeardownLeg(() => this.teardownOwnedEnv(prepared), "teardownOwnedEnv", (e) => this.deps.onError?.(e, { phase: "config", sessionId: prepared.sessionId }));
|
|
3027
2959
|
}
|
|
3028
2960
|
}
|
|
3029
2961
|
async suggestNextPrompts(spec, prepared, result) {
|
|
@@ -3525,10 +3457,7 @@ export class Runner {
|
|
|
3525
3457
|
const finishComp = await maybeCompact({
|
|
3526
3458
|
session: prepared.session,
|
|
3527
3459
|
epochDeclaredSections: prepared.epochDeclaredSections,
|
|
3528
|
-
...(
|
|
3529
|
-
const ca = prepared.centerCompactionCandidate?.();
|
|
3530
|
-
return ca !== undefined ? { centerAdoption: ca } : {};
|
|
3531
|
-
})(),
|
|
3460
|
+
...centerAdoptionOption(prepared),
|
|
3532
3461
|
model: prepared.model,
|
|
3533
3462
|
compactionModel: prepared.compModel,
|
|
3534
3463
|
brain: opts?.brain ?? this.deps.brain,
|
|
@@ -3539,28 +3468,9 @@ export class Runner {
|
|
|
3539
3468
|
minTokens: opts?.minTokens,
|
|
3540
3469
|
overheadTokens: prepared.promptOverheadTokens,
|
|
3541
3470
|
...(prepared.activeTools.size > 0 ? { activeTools: [...prepared.activeTools] } : {}),
|
|
3542
|
-
onInputTruncated: (
|
|
3543
|
-
kind: "compaction.input_truncated",
|
|
3544
|
-
version: 1,
|
|
3545
|
-
taskId: spec.taskId ?? prepared.sessionId,
|
|
3546
|
-
label: info.label,
|
|
3547
|
-
droppedChars: info.droppedChars,
|
|
3548
|
-
keptChars: info.keptChars,
|
|
3549
|
-
ts: Date.now(),
|
|
3550
|
-
})),
|
|
3471
|
+
onInputTruncated: emitInputTruncated(spec.tracer ?? this.deps.tracer, spec.taskId ?? prepared.sessionId),
|
|
3551
3472
|
...(opts?.windowSafety ?? {}),
|
|
3552
|
-
workingFileAttachments: spec
|
|
3553
|
-
? {
|
|
3554
|
-
readFile: prepared.readTaskFile,
|
|
3555
|
-
...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
|
|
3556
|
-
...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
|
|
3557
|
-
...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
|
|
3558
|
-
...(prepared.instructionSources
|
|
3559
|
-
? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
|
|
3560
|
-
: {}),
|
|
3561
|
-
...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
|
|
3562
|
-
}
|
|
3563
|
-
: undefined,
|
|
3473
|
+
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
3564
3474
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
3565
3475
|
...this.seamCCompactionOptions(prepared),
|
|
3566
3476
|
...this.compactionHookOptions(spec, prepared.sessionId, "auto"),
|
|
@@ -3629,7 +3539,6 @@ function startTimeout(harness, abortController, remainingMs, softSuspendable = f
|
|
|
3629
3539
|
abortController.abort();
|
|
3630
3540
|
void harness.abort();
|
|
3631
3541
|
}, hardMs);
|
|
3632
|
-
timer.unref?.();
|
|
3633
3542
|
state.clear = () => clearTimeout(timer);
|
|
3634
3543
|
}
|
|
3635
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>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { McpDroppedTool } from "../mcp.js";
|
|
1
2
|
import { type SkillListingEntry } from "./synthetic-tools.js";
|
|
2
3
|
export declare const TODO_REMINDER_CONFIG: {
|
|
3
4
|
readonly TURNS_SINCE_WRITE: 10;
|
|
@@ -112,11 +113,7 @@ export interface AttachmentInputs {
|
|
|
112
113
|
}>;
|
|
113
114
|
removed: readonly string[];
|
|
114
115
|
};
|
|
115
|
-
mcpDroppedTools?: ReadonlyArray<
|
|
116
|
-
server: string;
|
|
117
|
-
tool: string;
|
|
118
|
-
reason: string;
|
|
119
|
-
}>;
|
|
116
|
+
mcpDroppedTools?: ReadonlyArray<McpDroppedTool>;
|
|
120
117
|
}
|
|
121
118
|
export declare function collectDueAttachments(state: AttachmentState, inp: AttachmentInputs): readonly TurnAttachment[];
|
|
122
119
|
export declare function renderToolSearchUsageReminder(undiscovered: readonly string[]): string;
|
|
@@ -178,14 +175,7 @@ export declare function renderMcpInstructionsDelta(added: ReadonlyArray<{
|
|
|
178
175
|
server: string;
|
|
179
176
|
text: string;
|
|
180
177
|
}>, removed: readonly string[]): string | undefined;
|
|
181
|
-
export declare function renderMcpDroppedTools(entries: ReadonlyArray<
|
|
182
|
-
server: string;
|
|
183
|
-
tool: string;
|
|
184
|
-
reason: string;
|
|
185
|
-
}>): string;
|
|
178
|
+
export declare function renderMcpDroppedTools(entries: ReadonlyArray<McpDroppedTool>): string;
|
|
186
179
|
export declare const MCP_DROPPED_BATCH_MAX_BYTES = 4096;
|
|
187
|
-
export declare function selectMcpDroppedBatch<T extends
|
|
188
|
-
|
|
189
|
-
tool: string;
|
|
190
|
-
reason: string;
|
|
191
|
-
}>(entries: ReadonlyArray<T>): T[];
|
|
180
|
+
export declare function selectMcpDroppedBatch<T extends McpDroppedTool>(entries: ReadonlyArray<T>): T[];
|
|
181
|
+
export declare function clipToBytes(s: string, maxBytes: number): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SafeNotifyFailure {
|
|
2
|
+
readonly site: string;
|
|
3
|
+
readonly error: Error;
|
|
4
|
+
readonly failures: number;
|
|
5
|
+
}
|
|
6
|
+
export interface SafeNotifierOptions {
|
|
7
|
+
readonly onError?: (failure: SafeNotifyFailure) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface SafeNotifier {
|
|
10
|
+
notify(run: () => void, site: string): boolean;
|
|
11
|
+
notifyAsync(run: () => unknown, site: string): Promise<boolean>;
|
|
12
|
+
readonly failures: number;
|
|
13
|
+
failuresAt(site: string): number;
|
|
14
|
+
lastErrorAt(site: string): Error | undefined;
|
|
15
|
+
failedSites(): readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function createSafeNotifier(opts?: SafeNotifierOptions): SafeNotifier;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function createSafeNotifier(opts) {
|
|
2
|
+
const onError = opts?.onError;
|
|
3
|
+
let sites;
|
|
4
|
+
let total = 0;
|
|
5
|
+
const record = (site, thrown) => {
|
|
6
|
+
const error = thrown instanceof Error ? thrown : new Error(String(thrown));
|
|
7
|
+
total += 1;
|
|
8
|
+
if (sites === undefined)
|
|
9
|
+
sites = new Map();
|
|
10
|
+
const state = sites.get(site);
|
|
11
|
+
if (state !== undefined) {
|
|
12
|
+
state.count += 1;
|
|
13
|
+
state.last = error;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
sites.set(site, { count: 1, last: error });
|
|
17
|
+
if (onError === undefined)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
onError({ site, error, failures: 1 });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
notify(run, site) {
|
|
27
|
+
try {
|
|
28
|
+
run();
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
record(site, e);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
async notifyAsync(run, site) {
|
|
37
|
+
try {
|
|
38
|
+
await run();
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
record(site, e);
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
get failures() {
|
|
47
|
+
return total;
|
|
48
|
+
},
|
|
49
|
+
failuresAt(site) {
|
|
50
|
+
return sites?.get(site)?.count ?? 0;
|
|
51
|
+
},
|
|
52
|
+
lastErrorAt(site) {
|
|
53
|
+
return sites?.get(site)?.last;
|
|
54
|
+
},
|
|
55
|
+
failedSites() {
|
|
56
|
+
return sites === undefined ? [] : [...sites.keys()];
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -28,8 +28,9 @@ export const RECOMMENDED_SENSITIVE_PATTERNS = [
|
|
|
28
28
|
];
|
|
29
29
|
function segmentGlobToRegExp(segment) {
|
|
30
30
|
const escaped = segment.replace(/[.+^${}()|[\]\\?]/g, "\\$&").replace(/\*/g, "[^/]*");
|
|
31
|
-
return new RegExp(`^${escaped}
|
|
31
|
+
return new RegExp(`^${escaped}$`, CASE_INSENSITIVE_FS ? "i" : "");
|
|
32
32
|
}
|
|
33
|
+
const CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
|
|
33
34
|
function compilePatterns(patterns) {
|
|
34
35
|
const out = [];
|
|
35
36
|
for (const raw of patterns) {
|
|
@@ -20,7 +20,7 @@ export function createCheckpointFixture(over = {}) {
|
|
|
20
20
|
},
|
|
21
21
|
state: {
|
|
22
22
|
activeTools: [],
|
|
23
|
-
nestedStats: { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0 },
|
|
23
|
+
nestedStats: { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0, anyUnpriced: false },
|
|
24
24
|
},
|
|
25
25
|
status: "pending",
|
|
26
26
|
createdAt: 1_700_000_000_000,
|