@sema-agent/core 5.6.0 → 5.8.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/agents/cascade.d.ts +1 -1
  3. package/dist/agents/subagent.d.ts +4 -7
  4. package/dist/agents/subagent.js +10 -19
  5. package/dist/agents/teacher.js +3 -3
  6. package/dist/agents/team.d.ts +1 -1
  7. package/dist/agents/team.js +1 -1
  8. package/dist/agents/verify.js +1 -1
  9. package/dist/brain/anthropic.js +24 -35
  10. package/dist/brain/openai.js +22 -33
  11. package/dist/brain/stream-engine.d.ts +0 -2
  12. package/dist/brain/stream-engine.js +5 -47
  13. package/dist/brain/stream-shared.d.ts +0 -10
  14. package/dist/brain/stream-shared.js +0 -23
  15. package/dist/brain/terminal-cause.d.ts +0 -1
  16. package/dist/brain/terminal-cause.js +0 -3
  17. package/dist/brain/timeout.d.ts +4 -2
  18. package/dist/brain/timeout.js +4 -14
  19. package/dist/config/catalog.d.ts +3 -11
  20. package/dist/config/catalog.js +30 -69
  21. package/dist/config/defaults.d.ts +0 -3
  22. package/dist/config/defaults.js +0 -3
  23. package/dist/core/auto-compaction.d.ts +2 -11
  24. package/dist/core/auto-compaction.js +3 -67
  25. package/dist/core/checkpoint-store.d.ts +15 -10
  26. package/dist/core/checkpoint-store.js +13 -10
  27. package/dist/core/memory-engine/file-backend.js +20 -17
  28. package/dist/core/memory-engine/layout.d.ts +5 -0
  29. package/dist/core/memory-engine/layout.js +72 -47
  30. package/dist/core/runner/assemble-result.d.ts +2 -8
  31. package/dist/core/runner/assemble-result.js +15 -16
  32. package/dist/core/runner/prepare-task.d.ts +26 -6
  33. package/dist/core/runner/prepare-task.js +203 -141
  34. package/dist/core/runner/runtask.d.ts +0 -2
  35. package/dist/core/runner/runtask.js +267 -253
  36. package/dist/core/secret-env.d.ts +2 -0
  37. package/dist/core/secret-env.js +16 -4
  38. package/dist/core/session-policy-store.d.ts +5 -0
  39. package/dist/core/session-policy-store.js +3 -1
  40. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
  41. package/dist/core/task-notification.d.ts +1 -0
  42. package/dist/core/task-notification.js +3 -0
  43. package/dist/core/task-registry-agent.d.ts +2 -0
  44. package/dist/core/task-registry-agent.js +33 -1
  45. package/dist/core/task-registry.d.ts +2 -0
  46. package/dist/core/task-registry.js +9 -1
  47. package/dist/core/tool-errors.js +10 -2
  48. package/dist/core/trace.d.ts +1 -8
  49. package/dist/core/types.d.ts +24 -30
  50. package/dist/core/usage-window-store.d.ts +39 -0
  51. package/dist/core/usage-window-store.js +115 -0
  52. package/dist/engine/execution-env/node-execution-env.js +0 -22
  53. package/dist/engine/harness/agent-harness.d.ts +0 -7
  54. package/dist/engine/harness/agent-harness.js +13 -53
  55. package/dist/engine/harness/types.d.ts +2 -15
  56. package/dist/engine/llm/types.d.ts +1 -2
  57. package/dist/engine/loop/agent-loop.d.ts +1 -1
  58. package/dist/engine/loop/agent-loop.js +5 -171
  59. package/dist/engine/loop/types.d.ts +0 -18
  60. package/dist/index.d.ts +10 -5
  61. package/dist/index.js +8 -4
  62. package/dist/orchestration/goal.js +1 -5
  63. package/dist/orchestration/run-workflow-tool.d.ts +1 -1
  64. package/dist/orchestration/run-workflow-tool.js +1 -2
  65. package/dist/orchestration/workflow-governance.d.ts +6 -6
  66. package/dist/orchestration/workflow-governance.js +33 -47
  67. package/dist/prompt-assembly/event-registry.js +2 -3
  68. package/dist/stores/cc/lockfile.js +9 -11
  69. package/dist/stores/cc/mailbox-store.js +49 -38
  70. package/dist/stores/file/index.d.ts +3 -0
  71. package/dist/stores/file/index.js +4 -0
  72. package/dist/stores/file/usage-window-store.d.ts +9 -0
  73. package/dist/stores/file/usage-window-store.js +86 -0
  74. package/dist/tools/fs/fs-bash.d.ts +1 -10
  75. package/dist/tools/fs/fs-bash.js +20 -60
  76. package/dist/tools/fs/index.d.ts +0 -2
  77. package/dist/tools/fs/index.js +1 -2
  78. package/package.json +1 -4
  79. package/dist/bin/sema-tb.d.ts +0 -31
  80. package/dist/bin/sema-tb.js +0 -448
  81. package/dist/bin/tb-env.d.ts +0 -2
  82. package/dist/bin/tb-env.js +0 -17
  83. package/dist/brain/walltime.d.ts +0 -1
  84. package/dist/brain/walltime.js +0 -1
  85. package/dist/core/runner/call-cap.d.ts +0 -67
  86. package/dist/core/runner/call-cap.js +0 -145
  87. package/dist/core/runner/cut-kill.d.ts +0 -10
  88. package/dist/core/runner/cut-kill.js +0 -37
@@ -185,9 +185,7 @@ export class AgentHarness {
185
185
  steeringQueueMode;
186
186
  maxOutputTokens;
187
187
  maxOutputTokensPerCall;
188
- callDeadlineMsPerCall;
189
188
  stallTimeoutsPerCall;
190
- toolDeadline;
191
189
  loopTrace;
192
190
  resilience;
193
191
  maxToolConcurrency;
@@ -217,9 +215,7 @@ export class AgentHarness {
217
215
  this.steeringQueueMode = options.steeringMode ?? "one-at-a-time";
218
216
  this.maxOutputTokens = options.maxOutputTokens;
219
217
  this.maxOutputTokensPerCall = options.maxOutputTokensPerCall;
220
- this.callDeadlineMsPerCall = options.callDeadlineMsPerCall;
221
218
  this.stallTimeoutsPerCall = options.stallTimeoutsPerCall;
222
- this.toolDeadline = options.toolDeadline;
223
219
  this.loopTrace = options.loopTrace;
224
220
  this.resilience = options.resilience;
225
221
  this.maxToolConcurrency = options.maxToolConcurrency;
@@ -407,7 +403,6 @@ export class AgentHarness {
407
403
  },
408
404
  reasoning: streamOptions?.reasoning,
409
405
  maxTokens: streamOptions?.maxTokens,
410
- callDeadlineMs: streamOptions?.callDeadlineMs,
411
406
  stallTimeouts: streamOptions?.stallTimeouts,
412
407
  maxTokensDynamic: streamOptions?.maxTokensDynamic,
413
408
  staticReasoningCutDowngrade: streamOptions?.staticReasoningCutDowngrade,
@@ -442,12 +437,9 @@ export class AgentHarness {
442
437
  return {
443
438
  model: turnState.model,
444
439
  reasoning: turnState.thinkingLevel,
445
- liveThinkingLevel: () => self.thinkingLevel,
446
440
  ...(this.maxOutputTokens !== undefined ? { maxTokens: this.maxOutputTokens } : {}),
447
441
  ...(this.maxOutputTokensPerCall !== undefined ? { maxTokensPerCall: this.maxOutputTokensPerCall } : {}),
448
- ...(this.callDeadlineMsPerCall !== undefined ? { callDeadlineMsPerCall: this.callDeadlineMsPerCall } : {}),
449
442
  ...(this.stallTimeoutsPerCall !== undefined ? { stallTimeoutsPerCall: this.stallTimeoutsPerCall } : {}),
450
- ...(this.toolDeadline !== undefined ? { toolDeadline: this.toolDeadline } : {}),
451
443
  ...(this.resilience !== undefined ? { resilience: this.resilience } : {}),
452
444
  ...(this.maxToolConcurrency !== undefined ? { maxToolConcurrency: this.maxToolConcurrency } : {}),
453
445
  ...(this.streamingToolExecution === true && (this.getHandlers("tool_call")?.size ?? 0) === 0
@@ -511,9 +503,6 @@ export class AgentHarness {
511
503
  get degenerateOutput() {
512
504
  return self.loopRecovery?.degenerateOutput;
513
505
  },
514
- get walltimeCutoff() {
515
- return self.loopRecovery?.walltimeCutoff;
516
- },
517
506
  get promptTooLong() {
518
507
  const ptl = self.loopRecovery?.promptTooLong;
519
508
  if (!ptl)
@@ -681,7 +670,7 @@ export class AgentHarness {
681
670
  for (let i = newMessages.length - 1; i >= 0; i--) {
682
671
  const message = newMessages[i];
683
672
  if (message.role === "assistant") {
684
- return mergeTruncatedOutputChain(newMessages, i, this.loopRecovery?.walltimeCutoff?.detect);
673
+ return mergeTruncatedOutputChain(newMessages, i);
685
674
  }
686
675
  }
687
676
  throw new AgentHarnessError("invalid_state", "AgentHarness prompt completed without an assistant message");
@@ -931,54 +920,25 @@ function isEmptyFailureAssistant(message) {
931
920
  return false;
932
921
  return m.content.every((c) => c.type === "text" ? c.text.trim() === "" : c.type === "thinking" ? c.thinking.trim() === "" : false);
933
922
  }
934
- function mergeTruncatedOutputChain(messages, lastAssistantIndex, isWalltimeCutoff) {
923
+ function mergeTruncatedOutputChain(messages, lastAssistantIndex) {
935
924
  const last = messages[lastAssistantIndex];
936
925
  const lastText = last.content.map((c) => (c.type === "text" ? c.text : "")).join("");
937
926
  const parts = [];
938
927
  let i = lastAssistantIndex;
939
928
  while (i - 2 >= 0) {
940
929
  const mid = messages[i - 1];
941
- const downstreamText = parts.join("") + lastText;
942
- const walltimeGate = last.stopReason === "error" || downstreamText.trim() === "";
943
- let head;
944
- let walltimeStep = false;
945
- let nextI = i - 2;
946
- if (mid.role === "custom") {
947
- const h = messages[i - 2];
948
- if (h.role !== "assistant")
949
- break;
950
- const assistant = h;
951
- const step = (mid.customType === "loop:truncated-output-continue" && assistant.stopReason === "length") ||
952
- (mid.customType === "loop:midstream-partial-continue" && assistant.stopReason === "stop") ||
953
- (mid.customType === "loop:walltime-cutoff-recovery" && assistant.stopReason === "error" && walltimeGate);
954
- if (!step)
955
- break;
956
- head = assistant;
957
- walltimeStep = mid.customType === "loop:walltime-cutoff-recovery";
958
- }
959
- else if (mid.role === "user" && isWalltimeCutoff) {
960
- let j = i - 1;
961
- while (j >= 0 && messages[j].role === "user")
962
- j--;
963
- if (j < 0 || j >= i - 1)
964
- break;
965
- const h = messages[j];
966
- if (h.role !== "assistant")
967
- break;
968
- const assistant = h;
969
- if (!(assistant.stopReason === "error" && isWalltimeCutoff(assistant) && walltimeGate))
970
- break;
971
- head = assistant;
972
- walltimeStep = true;
973
- nextI = j;
974
- }
975
- else {
930
+ if (mid.role !== "custom")
976
931
  break;
977
- }
978
- const headText = head.content.map((c) => (c.type === "text" ? c.text : "")).join("");
979
- const needsBreak = walltimeStep && downstreamText !== "" && headText !== "";
980
- parts.unshift(needsBreak ? `${headText}\n\n` : headText);
981
- i = nextI;
932
+ const h = messages[i - 2];
933
+ if (h.role !== "assistant")
934
+ break;
935
+ const head = h;
936
+ const step = (mid.customType === "loop:truncated-output-continue" && head.stopReason === "length") ||
937
+ (mid.customType === "loop:midstream-partial-continue" && head.stopReason === "stop");
938
+ if (!step)
939
+ break;
940
+ parts.unshift(head.content.map((c) => (c.type === "text" ? c.text : "")).join(""));
941
+ i = i - 2;
982
942
  }
983
943
  if (parts.length === 0) {
984
944
  return last;
@@ -88,11 +88,6 @@ export interface ExecutionEnvExecOptions {
88
88
  onStdout?: (chunk: string) => void;
89
89
  onStderr?: (chunk: string) => void;
90
90
  detachSignal?: AbortSignal;
91
- onSpawn?: (handle: {
92
- pid: number;
93
- kill: () => void;
94
- }) => void;
95
- onDetachAdopted?: () => void;
96
91
  autoBackgroundOnTimeout?: boolean;
97
92
  }
98
93
  export interface FileSystem {
@@ -144,6 +139,8 @@ export interface Shell {
144
139
  cleanup(): Promise<void>;
145
140
  }
146
141
  export interface ExecutionEnv extends FileSystem, Shell {
142
+ readonly lifetimeMs?: number;
143
+ readonly lifetimeStartedAt?: number;
147
144
  }
148
145
  export interface SessionTreeEntryBase {
149
146
  type: string;
@@ -544,17 +541,7 @@ export interface AgentHarnessOptions<TSkill extends Skill = Skill, TPromptTempla
544
541
  followUpMode?: QueueMode;
545
542
  maxOutputTokens?: number;
546
543
  maxOutputTokensPerCall?: () => number | undefined;
547
- callDeadlineMsPerCall?: () => number | undefined;
548
544
  stallTimeoutsPerCall?: () => import("../llm/types.js").StallTimeouts | undefined;
549
- toolDeadline?: {
550
- deadlineMs: () => number | undefined;
551
- onCut?: (info: {
552
- toolCallId: string;
553
- toolName: string;
554
- elapsedMs: number;
555
- settled: Promise<void>;
556
- }) => void;
557
- };
558
545
  loopTrace?: (step: import("../loop/agent-loop.js").LoopStep) => void;
559
546
  resilience?: import("../llm/types.js").ResilienceOptions;
560
547
  maxToolConcurrency?: number;
@@ -45,7 +45,6 @@ export interface StreamOptions {
45
45
  maxTokensDynamic?: boolean;
46
46
  staticReasoningCutDowngrade?: boolean;
47
47
  resilience?: ResilienceOptions;
48
- callDeadlineMs?: number;
49
48
  stallTimeouts?: StallTimeouts;
50
49
  maxRetries?: number;
51
50
  maxRetryDelayMs?: number;
@@ -143,7 +142,7 @@ export interface AssistantMessage {
143
142
  usageMissing?: true;
144
143
  stopReason: StopReason;
145
144
  errorMessage?: string;
146
- errorKind?: "length_empty" | "degenerate" | "walltime_cutoff";
145
+ errorKind?: "length_empty" | "degenerate";
147
146
  partialFinalized?: true;
148
147
  repetition?: {
149
148
  cut?: RepetitionEvent;
@@ -1,7 +1,7 @@
1
1
  import { type AgentCoreStreamRuntimeDeps } from "./runtime-deps.js";
2
2
  import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, StreamFn } from "./types.js";
3
3
  export type AgentEventSink = (event: AgentEvent) => Promise<void> | void;
4
- export type LoopContinueReason = "next_turn" | "steer_injected" | "follow_up_injected" | "reactive_compact_retry" | "max_output_tokens_recovery" | "malformed_tool_use_retry" | "thinking_only_retry" | "midstream_partial_recovery" | "degenerate_output_recovery" | "walltime_cutoff_recovery";
4
+ export type LoopContinueReason = "next_turn" | "steer_injected" | "follow_up_injected" | "reactive_compact_retry" | "max_output_tokens_recovery" | "malformed_tool_use_retry" | "thinking_only_retry" | "midstream_partial_recovery" | "degenerate_output_recovery";
5
5
  export type LoopTerminalReason = "completed" | "aborted_before_stream" | "assistant_error" | "stop_requested" | "malformed_tool_use_exhausted" | "truncated_output_exhausted";
6
6
  export type LoopStep = {
7
7
  kind: "continue";
@@ -111,17 +111,6 @@ function createDegenerateRecoveryNudge() {
111
111
  timestamp: Date.now(),
112
112
  };
113
113
  }
114
- function createWalltimeCutoffRecoveryNudge() {
115
- return {
116
- role: "custom",
117
- customType: "loop:walltime-cutoff-recovery",
118
- provenance: "engine-note",
119
- content: "Your previous response crossed the task's wall-clock deadline and was cut off (the partial text above is preserved). " +
120
- "This is the FINAL turn: write your best current answer / deliverables NOW in one short response — no new work, no long commands.",
121
- display: false,
122
- timestamp: Date.now(),
123
- };
124
- }
125
114
  function createReasoningCutContinueNudge() {
126
115
  return {
127
116
  role: "custom",
@@ -154,7 +143,6 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
154
143
  truncatedOutputContinues: 0,
155
144
  staticReasoningCutRecoveries: initialContext.messages.filter((m) => m.role === "assistant" && m.staticReasoningCut === true).length,
156
145
  degenerateContinues: 0,
157
- walltimeCutoffContinues: 0,
158
146
  malformedToolUseRetries: 0,
159
147
  thinkingOnlyRetries: 0,
160
148
  midstreamPartialContinues: 0,
@@ -282,47 +270,8 @@ async function runSingleTurn(state, signal, emit, streamFn, runtime, trace) {
282
270
  if (message.stopReason !== "error")
283
271
  state.degenerateContinues = 0;
284
272
  }
285
- {
286
- const wc = state.config.recovery?.walltimeCutoff;
287
- if (wc &&
288
- message.stopReason === "error" &&
289
- !signal?.aborted &&
290
- wc.detect(message) &&
291
- (wc.hasLiveWriteoutWindow === undefined || wc.hasLiveWriteoutWindow()) &&
292
- executor.admittedCount === 0 &&
293
- message.content.every((b) => b.type !== "toolCall") &&
294
- state.walltimeCutoffContinues < (wc.maxContinues ?? 1)) {
295
- state.walltimeCutoffContinues++;
296
- await emit({ type: "turn_end", message, toolResults: [] });
297
- const drained = (await state.config.getSteeringMessages?.()) || [];
298
- state.pendingMessages = drained.length > 0 ? drained : [createWalltimeCutoffRecoveryNudge()];
299
- const liveLevel = state.config.liveThinkingLevel?.();
300
- if (liveLevel !== undefined)
301
- state.config = Object.assign({}, state.config, { reasoning: liveLevel });
302
- return { kind: "ran", recovered: "walltime_cutoff_recovery" };
303
- }
304
- }
305
273
  if (message.stopReason === "error" || message.stopReason === "aborted") {
306
274
  const errorFinalResults = await harvestExecutorOnErrorFinal(executor, state, message, signal, emit);
307
- if (state.config.recovery?.walltimeCutoff?.detect(message)) {
308
- const covered = new Set(errorFinalResults.map((r) => r.toolCallId));
309
- for (const tc of message.content.filter((c) => c.type === "toolCall")) {
310
- if (covered.has(tc.id))
311
- continue;
312
- const synthetic = {
313
- role: "toolResult",
314
- toolCallId: tc.id,
315
- toolName: tc.name,
316
- content: [{ type: "text", text: "[call aborted by walltime cutoff — never executed]" }],
317
- isError: true,
318
- timestamp: Date.now(),
319
- };
320
- await emitToolResultMessage(synthetic, emit);
321
- state.context.messages.push(synthetic);
322
- state.newMessages.push(synthetic);
323
- errorFinalResults.push(synthetic);
324
- }
325
- }
326
275
  await emit({ type: "turn_end", message, toolResults: errorFinalResults });
327
276
  await emit({ type: "agent_end", messages: state.newMessages });
328
277
  return { kind: "terminal", reason: "assistant_error" };
@@ -440,12 +389,10 @@ async function streamAssistantResponse(context, config, signal, emit, streamFn,
440
389
  const streamFunction = resolveAgentCoreStreamFn(runtime, streamFn);
441
390
  const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
442
391
  const perCallMaxTokens = config.maxTokensPerCall?.();
443
- const perCallDeadlineMs = config.callDeadlineMsPerCall?.();
444
392
  const perCallStallTimeouts = config.stallTimeoutsPerCall?.();
445
393
  const response = await streamFunction(config.model, llmContext, {
446
394
  ...config,
447
395
  ...(perCallMaxTokens !== undefined ? { maxTokens: perCallMaxTokens, maxTokensDynamic: true } : {}),
448
- ...(perCallDeadlineMs !== undefined ? { callDeadlineMs: perCallDeadlineMs } : {}),
449
396
  ...(perCallStallTimeouts !== undefined ? { stallTimeouts: perCallStallTimeouts } : {}),
450
397
  ...(staticReasoningCutDowngrade === true ? { staticReasoningCutDowngrade: true } : {}),
451
398
  apiKey: resolvedApiKey,
@@ -527,28 +474,6 @@ async function executeToolCalls(currentContext, assistantMessage, config, signal
527
474
  }
528
475
  return executeToolCallsPartitioned(currentContext, assistantMessage, toolCalls, config, signal, emit, executor);
529
476
  }
530
- const engineCutResults = new WeakSet();
531
- function isEngineCutResult(result) {
532
- return engineCutResults.has(result);
533
- }
534
- function createEngineCutNotExecutedOutcome(toolCall) {
535
- return {
536
- toolCall,
537
- result: {
538
- content: [
539
- {
540
- type: "text",
541
- text: `[not executed — engine stopped waiting at the write-out deadline] ${toolCall.name} was NOT executed: ` +
542
- `an earlier tool in this batch was cut at the task's write-out deadline, so the engine closed the batch ` +
543
- `immediately to reach the final write-out turn. This call ran no side effects and is safe to re-issue ` +
544
- `later if still needed — but do not start new long-running work now; write out your best current answer.`,
545
- },
546
- ],
547
- details: { engineCut: "walltime_writeout", notExecuted: true },
548
- },
549
- isError: true,
550
- };
551
- }
552
477
  async function executeToolCallsSequential(currentContext, assistantMessage, toolCalls, config, signal, emit) {
553
478
  const finalizedCalls = [];
554
479
  const messages = [];
@@ -562,7 +487,6 @@ async function executeToolCallsSequential(currentContext, assistantMessage, tool
562
487
  });
563
488
  const preparation = await prepareToolCall(currentContext, assistantMessage, toolCall, config, signal);
564
489
  let finalized;
565
- let engineCutRaw = false;
566
490
  if (preparation.kind === "immediate") {
567
491
  finalized = {
568
492
  toolCall,
@@ -571,8 +495,7 @@ async function executeToolCallsSequential(currentContext, assistantMessage, tool
571
495
  };
572
496
  }
573
497
  else {
574
- const executed = await executePreparedToolCall(preparation, config, signal, emit);
575
- engineCutRaw = isEngineCutResult(executed.result);
498
+ const executed = await executePreparedToolCall(preparation, signal, emit);
576
499
  finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
577
500
  }
578
501
  await emitToolExecutionEnd(finalized, emit);
@@ -580,23 +503,6 @@ async function executeToolCallsSequential(currentContext, assistantMessage, tool
580
503
  await emitToolResultMessage(toolResultMessage, emit);
581
504
  finalizedCalls.push(finalized);
582
505
  messages.push(toolResultMessage);
583
- if (engineCutRaw) {
584
- for (const later of toolCalls.slice(i + 1)) {
585
- await emit({
586
- type: "tool_execution_start",
587
- toolCallId: later.id,
588
- toolName: later.name,
589
- args: later.arguments,
590
- });
591
- const skipped = createEngineCutNotExecutedOutcome(later);
592
- await emitToolExecutionEnd(skipped, emit);
593
- const skippedMessage = createToolResultMessage(skipped);
594
- await emitToolResultMessage(skippedMessage, emit);
595
- finalizedCalls.push(skipped);
596
- messages.push(skippedMessage);
597
- }
598
- break;
599
- }
600
506
  if (signal?.aborted) {
601
507
  break;
602
508
  }
@@ -668,7 +574,6 @@ async function executeToolCallsPartitioned(currentContext, assistantMessage, too
668
574
  const cap = resolveToolConcurrency(config.maxToolConcurrency);
669
575
  const allFinalized = [];
670
576
  const messages = [];
671
- let engineCutSeen = false;
672
577
  const remainingCalls = [];
673
578
  for (const toolCall of toolCalls) {
674
579
  const held = executor?.take(toolCall.id);
@@ -676,8 +581,6 @@ async function executeToolCallsPartitioned(currentContext, assistantMessage, too
676
581
  remainingCalls.push(toolCall);
677
582
  continue;
678
583
  }
679
- if (held.executed && isEngineCutResult(held.executed.result))
680
- engineCutSeen = true;
681
584
  const finalized = await finalizeStreamEntry(currentContext, assistantMessage, held, config, signal);
682
585
  await emitToolExecutionEnd(finalized, emit);
683
586
  const toolResultMessage = createToolResultMessage(finalized);
@@ -695,23 +598,6 @@ async function executeToolCallsPartitioned(currentContext, assistantMessage, too
695
598
  outer: for (const batch of batches) {
696
599
  if (signal?.aborted)
697
600
  break;
698
- if (engineCutSeen) {
699
- for (const toolCall of batch.calls) {
700
- await emit({
701
- type: "tool_execution_start",
702
- toolCallId: toolCall.id,
703
- toolName: toolCall.name,
704
- args: toolCall.arguments,
705
- });
706
- const skipped = createEngineCutNotExecutedOutcome(toolCall);
707
- await emitToolExecutionEnd(skipped, emit);
708
- const skippedMessage = createToolResultMessage(skipped);
709
- await emitToolResultMessage(skippedMessage, emit);
710
- allFinalized.push(skipped);
711
- messages.push(skippedMessage);
712
- }
713
- continue;
714
- }
715
601
  const entries = [];
716
602
  for (const toolCall of batch.calls) {
717
603
  await emit({
@@ -739,14 +625,7 @@ async function executeToolCallsPartitioned(currentContext, assistantMessage, too
739
625
  return { messages, terminate: shouldTerminateToolBatch(allFinalized) };
740
626
  async function settleBatch(entries, concurrent) {
741
627
  const runOne = (entry) => async () => {
742
- if (engineCutSeen) {
743
- const skipped = createEngineCutNotExecutedOutcome(entry.toolCall);
744
- await emitToolExecutionEnd(skipped, emit);
745
- return skipped;
746
- }
747
- const executed = await executePreparedToolCall(entry.prepared, config, signal, emit);
748
- if (isEngineCutResult(executed.result))
749
- engineCutSeen = true;
628
+ const executed = await executePreparedToolCall(entry.prepared, signal, emit);
750
629
  const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, entry.prepared, executed, config, signal);
751
630
  await emitToolExecutionEnd(finalized, emit);
752
631
  return finalized;
@@ -828,10 +707,7 @@ class StreamToolExecutor {
828
707
  return;
829
708
  }
830
709
  entry.prepared = preparation;
831
- entry.executed = await executePreparedToolCall(preparation, this.config, this.signal, this.emit);
832
- if (isEngineCutResult(entry.executed.result)) {
833
- this.barrier = true;
834
- }
710
+ entry.executed = await executePreparedToolCall(preparation, this.signal, this.emit);
835
711
  }
836
712
  catch (error) {
837
713
  entry.immediate = {
@@ -993,13 +869,12 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
993
869
  };
994
870
  }
995
871
  }
996
- async function executePreparedToolCall(prepared, config, signal, emit) {
872
+ async function executePreparedToolCall(prepared, signal, emit) {
997
873
  const updateEvents = [];
998
874
  let acceptingUpdates = true;
999
875
  if (signal?.aborted) {
1000
876
  return { result: createErrorToolResult("operation aborted before execution"), isError: true };
1001
877
  }
1002
- const startedAt = Date.now();
1003
878
  const work = (async () => {
1004
879
  try {
1005
880
  const result = await prepared.tool.execute(prepared.toolCall.id, prepared.args, signal, (partialResult) => {
@@ -1027,48 +902,7 @@ async function executePreparedToolCall(prepared, config, signal, emit) {
1027
902
  };
1028
903
  }
1029
904
  })();
1030
- const cutDeadline = config.toolDeadline?.deadlineMs();
1031
- if (cutDeadline === undefined)
1032
- return work;
1033
- let cutTimer;
1034
- const cut = new Promise((resolve) => {
1035
- cutTimer = setTimeout(() => {
1036
- const elapsedMs = Date.now() - startedAt;
1037
- acceptingUpdates = false;
1038
- try {
1039
- config.toolDeadline?.onCut?.({
1040
- toolCallId: prepared.toolCall.id,
1041
- toolName: prepared.toolCall.name,
1042
- elapsedMs,
1043
- settled: work.then(() => undefined, () => undefined),
1044
- });
1045
- }
1046
- catch {
1047
- }
1048
- const cutResult = {
1049
- content: [
1050
- {
1051
- type: "text",
1052
- text: `[tool cut short at the write-out deadline] ${prepared.toolCall.name} had been running for ${Math.round(elapsedMs / 1000)}s ` +
1053
- `when the task's wall-clock write-out window opened — the ENGINE stopped waiting for it so the final answer can still be written out. ` +
1054
- `The tool itself was NOT cancelled and did not fail: it may have completed or may still be running in the background, and its side effects ` +
1055
- `may still land after this message — treat its outcome as UNKNOWN and do NOT blindly re-issue non-idempotent operations. ` +
1056
- `Do not start new long-running work — write out your best current answer now.`,
1057
- },
1058
- ],
1059
- details: { engineCut: "walltime_writeout", elapsedMs },
1060
- };
1061
- engineCutResults.add(cutResult);
1062
- resolve({ result: cutResult, isError: true });
1063
- }, Math.max(0, cutDeadline - Date.now()));
1064
- cutTimer.unref?.();
1065
- });
1066
- try {
1067
- return await Promise.race([work, cut]);
1068
- }
1069
- finally {
1070
- clearTimeout(cutTimer);
1071
- }
905
+ return work;
1072
906
  }
1073
907
  async function finalizeExecutedToolCall(currentContext, assistantMessage, prepared, executed, config, signal) {
1074
908
  let result = executed.result;
@@ -68,29 +68,12 @@ export interface LoopRecoveryOptions {
68
68
  detect: (message: AssistantMessage) => boolean;
69
69
  maxContinues?: number;
70
70
  };
71
- walltimeCutoff?: {
72
- detect: (message: AssistantMessage) => boolean;
73
- maxContinues?: number;
74
- hasLiveWriteoutWindow?: () => boolean;
75
- };
76
- }
77
- export interface ToolCutInfo {
78
- toolCallId: string;
79
- toolName: string;
80
- elapsedMs: number;
81
- settled: Promise<void>;
82
- }
83
- export interface LoopToolDeadline {
84
- deadlineMs: () => number | undefined;
85
- onCut?: (info: ToolCutInfo) => void;
86
71
  }
87
72
  export interface AgentLoopConfig extends SimpleStreamOptions {
88
73
  model: Model;
89
74
  recovery?: LoopRecoveryOptions;
90
75
  maxTokensPerCall?: () => number | undefined;
91
- callDeadlineMsPerCall?: () => number | undefined;
92
76
  stallTimeoutsPerCall?: () => import("../llm/types.js").StallTimeouts | undefined;
93
- toolDeadline?: LoopToolDeadline;
94
77
  maxToolConcurrency?: number;
95
78
  streamingToolExecution?: boolean;
96
79
  convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
@@ -98,7 +81,6 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
98
81
  getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
99
82
  shouldStopAfterTurn?: (context: ShouldStopAfterTurnContext) => boolean | Promise<boolean>;
100
83
  prepareNextTurn?: (context: PrepareNextTurnContext) => AgentLoopTurnUpdate | undefined | Promise<AgentLoopTurnUpdate | undefined>;
101
- liveThinkingLevel?: () => ThinkingLevel;
102
84
  getSteeringMessages?: () => Promise<AgentMessage[]>;
103
85
  getFollowUpMessages?: () => Promise<AgentMessage[]>;
104
86
  toolExecution?: ToolExecutionMode;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- export { Runner, runTask, DEFAULT_MAX_TURNS } from "./core/runner/runtask.js";
1
+ export { Runner, runTask } from "./core/runner/runtask.js";
2
+ export { resolveTaskLimits } from "./core/runner/prepare-task.js";
3
+ export type { BudgetAxis } from "./core/runner/assemble-result.js";
2
4
  export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
3
5
  export type { ResumeTaskConfig } from "./core/runner/runtask.js";
4
6
  export { defineTool } from "./core/tools.js";
@@ -75,7 +77,10 @@ export { HAND_TOOL_EFFECTS, bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW,
75
77
  export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, type BashReadonlyRootBoundary, type CompoundReadonlyVerdict, } from "./tools/fs/index.js";
76
78
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
77
79
  export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, type ToolResultStore, type ToolResultSlice, } from "./core/tool-result-store.js";
78
- export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, WALLTIME_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingWalltimeMs, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type ResourceLedger, type ResourceLimitReason, } from "./core/checkpoint-store.js";
80
+ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
81
+ export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, type UsageWindow, type UsageWindowStore, type UsageWindowReading, type UsageWindowRecord, type UsageSlot, type UsageBucketRow, } from "./core/usage-window-store.js";
82
+ export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
83
+ export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
79
84
  export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
80
85
  export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
81
86
  export type { FileSnapshotStore, FileSnapshotResult, FileSnapshotError, FileSnapshotBounds } from "./core/file-snapshot-store.js";
@@ -86,7 +91,7 @@ export { brainToRuntime } from "./core/runtime.js";
86
91
  export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./core/sensitive-path-policy.js";
87
92
  export { createFsWriteGatePolicy, type FsWriteGatePolicyOptions } from "./core/fs-write-gate-policy.js";
88
93
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
89
- export { DEFAULT_SUBAGENT_TOOL_NAME, SESSION_BG_DEFAULT_TIMEOUT_SEC } from "./agents/subagent.js";
94
+ export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
90
95
  export { renderTaskNotificationXml, taskNotificationDedupKey, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, } from "./core/task-notification.js";
91
96
  export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, type SemaTaskType, type SemaTaskStatus, type SemaTaskHandle, type ParkedClaimTicket, type TaskAccess, type UnifiedTaskOutput, type TaskRetrievalStatus, type StopSource, type RegisterMonitorInput, type MonitorTimers, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
92
97
  export { InMemoryMailboxStore, type MailboxStore, type MailboxMessage, type MailboxLease } from "./core/mailbox-store.js";
@@ -179,7 +184,7 @@ export { MemoryRosterStore, FileRosterStore, type RosterStore, type RosterEntry,
179
184
  export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, type ConfigKnob, type ConfigOverrideDeclaration, type ConfigProvenance, type EffectiveConfigField, } from "./config/catalog.js";
180
185
  export { normalizeAgentName } from "./core/task-registry.js";
181
186
  export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM, TEAMMATE_TASK_LIST_ADDENDUM } from "./prompts/coordinator.js";
182
- export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, FORK_DEFAULT_MAX_TURNS, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
187
+ export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
183
188
  export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
184
189
  export { createSendMessageTool, SEND_MESSAGE_TOOL_NAME, type SendMessageToolOptions } from "./agents/send-message-tool.js";
185
190
  export { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME, type AgentTranscriptToolOptions, } from "./agents/agent-transcript-tool.js";
@@ -200,7 +205,7 @@ export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
200
205
  export { type BrainTimeoutConfig } from "./brain/timeout.js";
201
206
  export { createAssistantMessageEventStream } from "./internal/llm.js";
202
207
  export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
203
- export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
208
+ export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
204
209
  export { Type } from "typebox";
205
210
  export type { TSchema, Static } from "typebox";
206
211
  export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export { Runner, runTask, DEFAULT_MAX_TURNS } from "./core/runner/runtask.js";
1
+ export { Runner, runTask } from "./core/runner/runtask.js";
2
+ export { resolveTaskLimits } from "./core/runner/prepare-task.js";
2
3
  export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
3
4
  export { defineTool } from "./core/tools.js";
4
5
  export { SKILL_TOOL_NAME } from "./core/runner/synthetic-tools.js";
@@ -64,7 +65,10 @@ export { HAND_TOOL_EFFECTS, bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW,
64
65
  export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, } from "./tools/fs/index.js";
65
66
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
66
67
  export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, } from "./core/tool-result-store.js";
67
- export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, WALLTIME_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingWalltimeMs, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
68
+ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
69
+ export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, } from "./core/usage-window-store.js";
70
+ export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
71
+ export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
68
72
  export { InMemoryFileSnapshotStore, DEFAULT_SNAPSHOT_BOUNDS } from "./core/file-snapshot-store.js";
69
73
  export { captureManifest, applyManifest } from "./core/file-snapshot-store.js";
70
74
  export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileFileSnapshotStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, } from "./stores/file/index.js";
@@ -74,7 +78,7 @@ export { brainToRuntime } from "./core/runtime.js";
74
78
  export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./core/sensitive-path-policy.js";
75
79
  export { createFsWriteGatePolicy } from "./core/fs-write-gate-policy.js";
76
80
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
77
- export { DEFAULT_SUBAGENT_TOOL_NAME, SESSION_BG_DEFAULT_TIMEOUT_SEC } from "./agents/subagent.js";
81
+ export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
78
82
  export { renderTaskNotificationXml, taskNotificationDedupKey, SystemInjectionQueue, } from "./core/task-notification.js";
79
83
  export { TaskRegistry, defaultTaskRegistry, createTaskOutputTool, createTaskStopTool, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccessWorkflowRun, DURABLE_AGENT_HANDLE_RE, } from "./core/task-registry.js";
80
84
  export { InMemoryMailboxStore } from "./core/mailbox-store.js";
@@ -162,7 +166,7 @@ export { MemoryRosterStore, FileRosterStore } from "./agents/roster-store.js";
162
166
  export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, } from "./config/catalog.js";
163
167
  export { normalizeAgentName } from "./core/task-registry.js";
164
168
  export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM, TEAMMATE_TASK_LIST_ADDENDUM } from "./prompts/coordinator.js";
165
- export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, FORK_DEFAULT_MAX_TURNS, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, } from "./agents/subagent.js";
169
+ export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, } from "./agents/subagent.js";
166
170
  export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
167
171
  export { createSendMessageTool, SEND_MESSAGE_TOOL_NAME } from "./agents/send-message-tool.js";
168
172
  export { createAgentTranscriptTool, AGENT_TRANSCRIPT_TOOL_NAME, } from "./agents/agent-transcript-tool.js";
@@ -148,16 +148,12 @@ export async function runGoal(runner, spec) {
148
148
  if (result.status === "blocked")
149
149
  return mk("blocked", iteration, { result });
150
150
  if (result.status === "failed") {
151
- if (result.errorCode === "limit.max_turns") {
151
+ if (result.errorCode !== undefined && result.errorCode.startsWith("limits.max_")) {
152
152
  lastFeedback = TIMEOUT_FEEDBACK;
153
153
  continue;
154
154
  }
155
155
  return mk("failed", iteration, { result, errorCode: result.errorCode });
156
156
  }
157
- if (result.status === "timeout") {
158
- lastFeedback = TIMEOUT_FEEDBACK;
159
- continue;
160
- }
161
157
  const gate1 = hasOutputSchema ? result.structuredOutput !== undefined : doneRef.declared === true;
162
158
  if (!gate1) {
163
159
  lastFeedback = NOT_DECLARED_FEEDBACK;
@@ -38,7 +38,7 @@ export interface WorkflowLimits {
38
38
  maxScriptChars?: number;
39
39
  maxAgents?: number;
40
40
  totalTimeoutMs?: number;
41
- perAgentTimeoutSec?: number;
41
+ perAgentMaxWalltimeMs?: number;
42
42
  childMaxCostUsd?: number;
43
43
  childMaxTokens?: number;
44
44
  childMaxTurns?: number;