@bastani/atomic 0.8.29 → 0.8.30-alpha.2

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 (144) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +4 -0
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +4 -0
  5. package/dist/builtin/intercom/package.json +2 -2
  6. package/dist/builtin/mcp/CHANGELOG.md +4 -0
  7. package/dist/builtin/mcp/package.json +3 -3
  8. package/dist/builtin/subagents/CHANGELOG.md +9 -0
  9. package/dist/builtin/subagents/README.md +10 -30
  10. package/dist/builtin/subagents/package.json +4 -4
  11. package/dist/builtin/subagents/skills/subagent/SKILL.md +5 -11
  12. package/dist/builtin/subagents/src/agents/agent-management.ts +0 -5
  13. package/dist/builtin/subagents/src/agents/agent-serializer.ts +7 -3
  14. package/dist/builtin/subagents/src/agents/agents.ts +4 -29
  15. package/dist/builtin/subagents/src/agents/chain-serializer.ts +27 -25
  16. package/dist/builtin/subagents/src/extension/schemas.ts +0 -75
  17. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -29
  18. package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -2
  19. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +134 -239
  20. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +1 -52
  21. package/dist/builtin/subagents/src/runs/foreground/execution.ts +103 -94
  22. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +0 -10
  23. package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +16 -8
  24. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +0 -1
  25. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +0 -3
  26. package/dist/builtin/subagents/src/runs/shared/structured-output.ts +67 -2
  27. package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +6 -20
  28. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -1
  29. package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +2 -6
  30. package/dist/builtin/subagents/src/shared/settings.ts +1 -4
  31. package/dist/builtin/subagents/src/shared/types.ts +1 -156
  32. package/dist/builtin/subagents/src/tui/render.ts +0 -1
  33. package/dist/builtin/web-access/CHANGELOG.md +4 -0
  34. package/dist/builtin/web-access/package.json +2 -2
  35. package/dist/builtin/workflows/CHANGELOG.md +11 -0
  36. package/dist/builtin/workflows/README.md +2 -2
  37. package/dist/builtin/workflows/package.json +2 -2
  38. package/dist/builtin/workflows/src/extension/index.ts +8 -1
  39. package/dist/builtin/workflows/src/extension/wiring.ts +66 -10
  40. package/dist/builtin/workflows/src/runs/foreground/executor.ts +70 -19
  41. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +98 -14
  42. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +0 -1
  43. package/dist/builtin/workflows/src/shared/persistence-restore.ts +4 -0
  44. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  45. package/dist/builtin/workflows/src/shared/store.ts +2 -0
  46. package/dist/config.d.ts.map +1 -1
  47. package/dist/config.js +18 -4
  48. package/dist/config.js.map +1 -1
  49. package/dist/core/agent-session.d.ts +2 -2
  50. package/dist/core/agent-session.d.ts.map +1 -1
  51. package/dist/core/agent-session.js +21 -9
  52. package/dist/core/agent-session.js.map +1 -1
  53. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  54. package/dist/core/compaction/branch-summarization.js +2 -2
  55. package/dist/core/compaction/branch-summarization.js.map +1 -1
  56. package/dist/core/compaction/compaction.d.ts +6 -0
  57. package/dist/core/compaction/compaction.d.ts.map +1 -1
  58. package/dist/core/compaction/compaction.js +2 -0
  59. package/dist/core/compaction/compaction.js.map +1 -1
  60. package/dist/core/compaction/context-compaction.d.ts +43 -16
  61. package/dist/core/compaction/context-compaction.d.ts.map +1 -1
  62. package/dist/core/compaction/context-compaction.js +561 -189
  63. package/dist/core/compaction/context-compaction.js.map +1 -1
  64. package/dist/core/extensions/loader.d.ts +4 -2
  65. package/dist/core/extensions/loader.d.ts.map +1 -1
  66. package/dist/core/extensions/loader.js +11 -7
  67. package/dist/core/extensions/loader.js.map +1 -1
  68. package/dist/core/extensions/types.d.ts +14 -3
  69. package/dist/core/extensions/types.d.ts.map +1 -1
  70. package/dist/core/extensions/types.js.map +1 -1
  71. package/dist/core/model-registry.d.ts.map +1 -1
  72. package/dist/core/model-registry.js +2 -1
  73. package/dist/core/model-registry.js.map +1 -1
  74. package/dist/core/package-manager.d.ts +1 -1
  75. package/dist/core/package-manager.d.ts.map +1 -1
  76. package/dist/core/package-manager.js +52 -18
  77. package/dist/core/package-manager.js.map +1 -1
  78. package/dist/core/resource-loader.d.ts +20 -0
  79. package/dist/core/resource-loader.d.ts.map +1 -1
  80. package/dist/core/resource-loader.js +89 -24
  81. package/dist/core/resource-loader.js.map +1 -1
  82. package/dist/core/session-manager.d.ts +14 -1
  83. package/dist/core/session-manager.d.ts.map +1 -1
  84. package/dist/core/session-manager.js +145 -3
  85. package/dist/core/session-manager.js.map +1 -1
  86. package/dist/core/settings-manager.d.ts +9 -0
  87. package/dist/core/settings-manager.d.ts.map +1 -1
  88. package/dist/core/settings-manager.js +16 -0
  89. package/dist/core/settings-manager.js.map +1 -1
  90. package/dist/core/thinking-blocks.d.ts +7 -0
  91. package/dist/core/thinking-blocks.d.ts.map +1 -0
  92. package/dist/core/thinking-blocks.js +16 -0
  93. package/dist/core/thinking-blocks.js.map +1 -0
  94. package/dist/core/tools/bash.d.ts.map +1 -1
  95. package/dist/core/tools/bash.js +4 -0
  96. package/dist/core/tools/bash.js.map +1 -1
  97. package/dist/index.d.ts +2 -2
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +1 -1
  100. package/dist/index.js.map +1 -1
  101. package/dist/main.d.ts.map +1 -1
  102. package/dist/main.js +30 -0
  103. package/dist/main.js.map +1 -1
  104. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  105. package/dist/modes/interactive/components/tree-selector.js +87 -12
  106. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  107. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  108. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  109. package/dist/modes/interactive/interactive-mode.js +37 -18
  110. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  111. package/dist/modes/interactive/theme/theme.d.ts +24 -1
  112. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  113. package/dist/modes/interactive/theme/theme.js +58 -13
  114. package/dist/modes/interactive/theme/theme.js.map +1 -1
  115. package/dist/utils/child-process.d.ts +9 -4
  116. package/dist/utils/child-process.d.ts.map +1 -1
  117. package/dist/utils/child-process.js +42 -10
  118. package/dist/utils/child-process.js.map +1 -1
  119. package/dist/utils/version-check.d.ts.map +1 -1
  120. package/dist/utils/version-check.js +4 -27
  121. package/dist/utils/version-check.js.map +1 -1
  122. package/docs/compaction.md +470 -51
  123. package/docs/containerization.md +37 -37
  124. package/docs/extensions.md +23 -14
  125. package/docs/models.md +6 -4
  126. package/docs/packages.md +2 -0
  127. package/docs/providers.md +1 -1
  128. package/docs/subagents.md +11 -4
  129. package/docs/workflows.md +4 -2
  130. package/examples/extensions/README.md +2 -2
  131. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  132. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  133. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  134. package/examples/extensions/gondolin/package-lock.json +2 -2
  135. package/examples/extensions/gondolin/package.json +1 -1
  136. package/examples/extensions/question.ts +39 -18
  137. package/examples/extensions/questionnaire.ts +49 -28
  138. package/examples/extensions/sandbox/package-lock.json +2 -2
  139. package/examples/extensions/sandbox/package.json +1 -1
  140. package/examples/extensions/with-deps/package-lock.json +2 -2
  141. package/examples/extensions/with-deps/package.json +1 -1
  142. package/package.json +7 -5
  143. package/dist/builtin/subagents/src/runs/shared/acceptance.ts +0 -612
  144. package/dist/builtin/subagents/src/runs/shared/completion-guard.ts +0 -147
@@ -45,7 +45,14 @@ import {
45
45
  } from "../shared/parallel-utils.ts";
46
46
  import { buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
47
47
  import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
48
- import { createStructuredOutputRuntime, readStructuredOutput } from "../shared/structured-output.ts";
48
+ import {
49
+ STRUCTURED_OUTPUT_MAX_CORRECTIVE_PROMPTS,
50
+ createStructuredOutputRuntime,
51
+ formatStructuredOutputCorrectionPrompt,
52
+ isStructuredOutputContractError,
53
+ latestStructuredOutputToolErrorFromMessages,
54
+ readStructuredOutput,
55
+ } from "../shared/structured-output.ts";
49
56
  import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection } from "../shared/dynamic-fanout.ts";
50
57
  import { nestedSummaryFromAsyncStatus, writeNestedEvent } from "../shared/nested-events.ts";
51
58
  import { formatModelAttemptNote, isRetryableModelFailure, modelFailureMessage } from "../shared/model-fallback.ts";
@@ -56,7 +63,6 @@ import {
56
63
  } from "../shared/final-drain.ts";
57
64
  import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
58
65
  import { detectSubagentError, extractTextFromContent, extractToolArgsPreview, getFinalOutput } from "../../shared/utils.ts";
59
- import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
60
66
  import {
61
67
  createMutatingFailureState,
62
68
  didMutatingToolFail,
@@ -82,7 +88,6 @@ import {
82
88
  import { resolveEffectiveThinking } from "../../shared/model-info.ts";
83
89
  import { writeInitialProgressFile } from "../../shared/settings.ts";
84
90
  import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts";
85
- import { acceptanceFailureMessage, aggregateAcceptanceReport, evaluateAcceptance, formatAcceptancePrompt, stripAcceptanceReport } from "../shared/acceptance.ts";
86
91
 
87
92
  interface SubagentRunConfig {
88
93
  id: string;
@@ -132,7 +137,6 @@ interface StepResult {
132
137
  structuredOutput?: unknown;
133
138
  structuredOutputPath?: string;
134
139
  structuredOutputSchemaPath?: string;
135
- acceptance?: import("../../shared/types.ts").AcceptanceLedger;
136
140
  }
137
141
 
138
142
  const ASYNC_INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === "win32" ? "SIGBREAK" : "SIGUSR2";
@@ -234,7 +238,6 @@ interface RunPiStreamingResult {
234
238
  error?: string;
235
239
  finalOutput: string;
236
240
  interrupted?: boolean;
237
- observedMutationAttempt?: boolean;
238
241
  modelFailureSignal?: unknown;
239
242
  }
240
243
 
@@ -278,7 +281,6 @@ function runPiStreaming(
278
281
  let assistantError: string | undefined;
279
282
  let assistantFailureSignal: unknown;
280
283
  let interrupted = false;
281
- let observedMutationAttempt = false;
282
284
  const rawStdoutLines: string[] = [];
283
285
 
284
286
  const writeOutputLine = (line: string) => {
@@ -324,7 +326,6 @@ function runPiStreaming(
324
326
  onChildEvent?.(event);
325
327
 
326
328
  if (event.type === "tool_execution_start" && event.toolName) {
327
- observedMutationAttempt = observedMutationAttempt || isMutatingTool(event.toolName, event.args);
328
329
  const toolArgs = extractToolArgsPreview(event.args ?? {});
329
330
  writeOutputLine(toolArgs ? `${event.toolName}: ${toolArgs}` : event.toolName);
330
331
  return;
@@ -462,7 +463,6 @@ function runPiStreaming(
462
463
  error: interrupted || forcedDrainAfterFinalSuccess ? undefined : finalError,
463
464
  finalOutput,
464
465
  interrupted,
465
- observedMutationAttempt,
466
466
  ...(assistantFailureSignal !== undefined && finalError === assistantError
467
467
  ? { modelFailureSignal: assistantFailureSignal }
468
468
  : {}),
@@ -486,7 +486,6 @@ function runPiStreaming(
486
486
  model,
487
487
  error: finalError,
488
488
  finalOutput,
489
- observedMutationAttempt,
490
489
  ...(assistantFailureSignal !== undefined && finalError === assistantError
491
490
  ? { modelFailureSignal: assistantFailureSignal }
492
491
  : {}),
@@ -643,11 +642,9 @@ async function runSingleStep(
643
642
  interrupted?: boolean;
644
643
  sessionFile?: string;
645
644
  intercomTarget?: string;
646
- completionGuardTriggered?: boolean;
647
645
  structuredOutput?: unknown;
648
646
  structuredOutputPath?: string;
649
647
  structuredOutputSchemaPath?: string;
650
- acceptance?: import("../../shared/types.ts").AcceptanceLedger;
651
648
  }> {
652
649
  const effectiveStructuredOutput = step.structuredOutput ?? (step.structuredOutputSchema
653
650
  ? createStructuredOutputRuntime(step.structuredOutputSchema, path.join(path.dirname(ctx.outputFile), "structured-output"))
@@ -655,11 +652,6 @@ async function runSingleStep(
655
652
  const placeholderRegex = new RegExp(ctx.placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g");
656
653
  let task = step.task.replace(placeholderRegex, () => ctx.previousOutput);
657
654
  task = resolveOutputReferences(task, ctx.outputs ?? {});
658
- const taskForCompletionGuard = task;
659
- if (step.effectiveAcceptance) {
660
- const acceptancePrompt = formatAcceptancePrompt(step.effectiveAcceptance);
661
- if (acceptancePrompt) task = `${task}\n${acceptancePrompt}`;
662
- }
663
655
  const sessionEnabled = Boolean(step.sessionFile) || ctx.sessionEnabled;
664
656
  const sessionDir = step.sessionFile ? undefined : ctx.sessionDir;
665
657
 
@@ -686,146 +678,150 @@ async function runSingleStep(
686
678
  let finalResult: RunPiStreamingResult | undefined;
687
679
  let finalFastMode: boolean | undefined;
688
680
  let finalOutputSnapshot: SingleOutputSnapshot | undefined;
689
- let completionGuardTriggeredFinal = false;
690
681
 
691
682
  for (let index = 0; index < candidates.length; index++) {
692
683
  const candidate = candidates[index];
693
684
  const attemptFastMode = fastModeForStepAttempt(step, candidate);
694
685
  ctx.onAttemptStart?.({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking), fastMode: attemptFastMode ? true : undefined });
695
- const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
696
- if (effectiveStructuredOutput) {
697
- try {
698
- if (fs.existsSync(effectiveStructuredOutput.outputPath)) fs.unlinkSync(effectiveStructuredOutput.outputPath);
699
- } catch {
700
- // Missing/stale structured-output files are handled after the child exits.
686
+ if (candidate) attemptedModels.push(candidate);
687
+ let nextTask = task;
688
+ let correctiveAttempts = 0;
689
+ let tryNextModel = false;
690
+
691
+ while (true) {
692
+ const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
693
+ if (effectiveStructuredOutput) {
694
+ try {
695
+ if (fs.existsSync(effectiveStructuredOutput.outputPath)) fs.unlinkSync(effectiveStructuredOutput.outputPath);
696
+ } catch {
697
+ // Missing/stale structured-output files are handled after the child exits.
698
+ }
701
699
  }
702
- }
703
- const { args, env, tempDir } = buildPiArgs({
704
- baseArgs: ["--mode", "json", "-p"],
705
- task,
706
- sessionEnabled,
707
- sessionDir,
708
- sessionFile: step.sessionFile,
709
- model: candidate,
710
- inheritProjectContext: step.inheritProjectContext,
711
- inheritSkills: step.inheritSkills,
712
- tools: step.tools,
713
- extensions: step.extensions,
714
- systemPrompt: step.systemPrompt,
715
- systemPromptMode: step.systemPromptMode,
716
- mcpDirectTools: step.mcpDirectTools,
717
- cwd: step.cwd ?? ctx.cwd,
718
- promptFileStem: step.agent,
719
- intercomSessionName: ctx.childIntercomTarget,
720
- orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
721
- runId: ctx.id,
722
- childAgentName: step.agent,
723
- childIndex: ctx.flatIndex,
724
- parentEventSink: ctx.nestedRoute?.eventSink,
725
- parentControlInbox: ctx.nestedRoute?.controlInbox,
726
- parentRootRunId: ctx.nestedRoute?.rootRunId,
727
- parentCapabilityToken: ctx.nestedRoute?.capabilityToken,
728
- codexFastModeSettings: step.codexFastModeSettings,
729
- codexFastModeScope: step.codexFastModeScope,
730
- structuredOutput: effectiveStructuredOutput,
731
- });
732
- const run = await runPiStreaming(
733
- args,
734
- step.cwd ?? ctx.cwd,
735
- ctx.outputFile,
736
- env,
737
- ctx.piPackageRoot,
738
- ctx.piArgv1,
739
- step.maxSubagentDepth,
740
- step.workflowStageSubagentGuard ?? ctx.workflowStageSubagentGuard,
741
- { eventsPath, runId: ctx.id, stepIndex: ctx.flatIndex, agent: step.agent },
742
- ctx.registerInterrupt,
743
- ctx.onChildEvent,
744
- );
745
- cleanupTempDir(tempDir);
746
-
747
- const hiddenError = run.exitCode === 0 && !run.error ? detectSubagentError(run.messages) : null;
748
- let structuredOutput: unknown;
749
- let structuredError: string | undefined;
750
- if (effectiveStructuredOutput && run.exitCode === 0 && !run.error && !hiddenError?.hasError) {
751
- const structured = readStructuredOutput(effectiveStructuredOutput);
752
- if (structured.error) structuredError = structured.error;
753
- else structuredOutput = structured.value;
754
- }
755
- const completionGuard = run.exitCode === 0 && !run.error && !hiddenError?.hasError && step.completionGuard !== false
756
- ? evaluateCompletionMutationGuard({
757
- agent: step.agent,
758
- task: taskForCompletionGuard,
759
- messages: run.messages,
700
+ const { args, env, tempDir } = buildPiArgs({
701
+ baseArgs: ["--mode", "json", "-p"],
702
+ task: nextTask,
703
+ sessionEnabled,
704
+ sessionDir,
705
+ sessionFile: step.sessionFile,
706
+ model: candidate,
707
+ inheritProjectContext: step.inheritProjectContext,
708
+ inheritSkills: step.inheritSkills,
760
709
  tools: step.tools,
710
+ extensions: step.extensions,
711
+ systemPrompt: step.systemPrompt,
712
+ systemPromptMode: step.systemPromptMode,
761
713
  mcpDirectTools: step.mcpDirectTools,
762
- })
763
- : undefined;
764
- const completionGuardTriggered = completionGuard?.triggered === true && !run.observedMutationAttempt;
765
- const completionGuardError = completionGuardTriggered
766
- ? "Subagent completed without making edits for an implementation task.\nIt appears to have returned planning or scratchpad output instead of applying changes."
767
- : undefined;
768
- const effectiveExitCode = completionGuardTriggered
769
- ? 1
770
- : structuredError
714
+ cwd: step.cwd ?? ctx.cwd,
715
+ promptFileStem: step.agent,
716
+ intercomSessionName: ctx.childIntercomTarget,
717
+ orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
718
+ runId: ctx.id,
719
+ childAgentName: step.agent,
720
+ childIndex: ctx.flatIndex,
721
+ parentEventSink: ctx.nestedRoute?.eventSink,
722
+ parentControlInbox: ctx.nestedRoute?.controlInbox,
723
+ parentRootRunId: ctx.nestedRoute?.rootRunId,
724
+ parentCapabilityToken: ctx.nestedRoute?.capabilityToken,
725
+ codexFastModeSettings: step.codexFastModeSettings,
726
+ codexFastModeScope: step.codexFastModeScope,
727
+ structuredOutput: effectiveStructuredOutput,
728
+ });
729
+ const run = await runPiStreaming(
730
+ args,
731
+ step.cwd ?? ctx.cwd,
732
+ ctx.outputFile,
733
+ env,
734
+ ctx.piPackageRoot,
735
+ ctx.piArgv1,
736
+ step.maxSubagentDepth,
737
+ step.workflowStageSubagentGuard ?? ctx.workflowStageSubagentGuard,
738
+ { eventsPath, runId: ctx.id, stepIndex: ctx.flatIndex, agent: step.agent },
739
+ ctx.registerInterrupt,
740
+ ctx.onChildEvent,
741
+ );
742
+ cleanupTempDir(tempDir);
743
+
744
+ const hiddenError = run.exitCode === 0 && !run.error ? detectSubagentError(run.messages) : null;
745
+ let structuredOutput: unknown;
746
+ let structuredError: string | undefined;
747
+ if (effectiveStructuredOutput && run.exitCode === 0 && !run.error && !hiddenError?.hasError) {
748
+ const structured = readStructuredOutput(effectiveStructuredOutput);
749
+ if (structured.error) structuredError = structured.error;
750
+ else structuredOutput = structured.value;
751
+ }
752
+ const structuredContractError = structuredError
753
+ ? latestStructuredOutputToolErrorFromMessages(run.messages) ?? structuredError
754
+ : undefined;
755
+ const effectiveExitCode = structuredContractError
771
756
  ? 1
772
757
  : hiddenError?.hasError
773
758
  ? (hiddenError.exitCode ?? 1)
774
759
  : run.error && run.exitCode === 0
775
760
  ? 1
776
761
  : run.exitCode;
777
- const error = completionGuardError
778
- ?? structuredError
779
- ?? (hiddenError?.hasError
780
- ? hiddenError.details
781
- ? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
782
- : `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
783
- : run.error || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
784
- const attemptModel = candidate ?? run.model ?? step.model ?? "default";
785
- const attempt: ModelAttempt = {
786
- model: attemptModel,
787
- reasoningLevel: resolveEffectiveThinking(attemptModel, step.thinking),
788
- success: effectiveExitCode === 0 && !error,
789
- exitCode: effectiveExitCode,
790
- error,
791
- usage: run.usage,
792
- };
793
- modelAttempts.push(attempt);
794
- if (candidate) attemptedModels.push(candidate);
795
- completionGuardTriggeredFinal = completionGuardTriggered;
796
- finalFastMode = attemptFastMode;
797
- finalOutputSnapshot = outputSnapshot;
798
- finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput } as RunPiStreamingResult & { structuredOutput?: unknown };
799
- if (attempt.success) break;
800
- const retrySignal = run.modelFailureSignal ?? error;
801
- if (
802
- !completionGuardTriggered
803
- && structuredError === undefined
804
- && hiddenError?.hasError !== true
805
- && isRetryableModelFailure(retrySignal)
806
- && index < candidates.length - 1
807
- ) {
808
- pendingAttemptNotes.push(formatModelAttemptNote(attempt, candidates[index + 1]));
809
- continue;
762
+ const error = structuredContractError
763
+ ?? (hiddenError?.hasError
764
+ ? hiddenError.details
765
+ ? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
766
+ : `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
767
+ : run.error || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
768
+ const attemptModel = candidate ?? run.model ?? step.model ?? "default";
769
+ const attempt: ModelAttempt = {
770
+ model: attemptModel,
771
+ reasoningLevel: resolveEffectiveThinking(attemptModel, step.thinking),
772
+ success: effectiveExitCode === 0 && !error,
773
+ exitCode: effectiveExitCode,
774
+ error,
775
+ usage: run.usage,
776
+ };
777
+ modelAttempts.push(attempt);
778
+ finalFastMode = attemptFastMode;
779
+ finalOutputSnapshot = outputSnapshot;
780
+ finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput } as RunPiStreamingResult & { structuredOutput?: unknown };
781
+ if (attempt.success) break;
782
+ if (
783
+ effectiveStructuredOutput
784
+ && isStructuredOutputContractError(structuredContractError)
785
+ && correctiveAttempts < STRUCTURED_OUTPUT_MAX_CORRECTIVE_PROMPTS
786
+ ) {
787
+ correctiveAttempts += 1;
788
+ nextTask = formatStructuredOutputCorrectionPrompt({
789
+ originalTask: task,
790
+ error: structuredContractError!,
791
+ attempt: correctiveAttempts,
792
+ });
793
+ continue;
794
+ }
795
+ const retrySignal = run.modelFailureSignal ?? error;
796
+ if (
797
+ structuredContractError === undefined
798
+ && hiddenError?.hasError !== true
799
+ && isRetryableModelFailure(retrySignal)
800
+ && index < candidates.length - 1
801
+ ) {
802
+ pendingAttemptNotes.push(formatModelAttemptNote(attempt, candidates[index + 1]));
803
+ tryNextModel = true;
804
+ break;
805
+ }
806
+ attemptNotes.push(...pendingAttemptNotes);
807
+ break;
810
808
  }
811
- attemptNotes.push(...pendingAttemptNotes);
812
- break;
809
+ if (!tryNextModel) break;
813
810
  }
814
811
 
815
812
  const rawOutput = finalResult?.finalOutput ?? "";
816
- const outputForPersistence = stripAcceptanceReport(rawOutput);
813
+ const outputForPersistence = rawOutput;
817
814
  const resolvedOutput = step.outputPath && finalResult?.exitCode === 0
818
815
  ? resolveSingleOutput(step.outputPath, outputForPersistence, finalOutputSnapshot)
819
816
  : { fullOutput: outputForPersistence };
820
817
  const output = resolvedOutput.fullOutput;
821
818
  const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, output) : undefined;
822
819
  let outputForSummary = output;
823
- if (attemptNotes.length > 0) {
824
- outputForSummary = `${attemptNotes.join("\n")}\n\n${outputForSummary}`.trim();
825
- }
826
- const outputForAcceptance = rawOutput;
827
- const finalizedOutput = finalizeSingleOutput({
828
- fullOutput: outputForSummary,
820
+ if (attemptNotes.length > 0) {
821
+ outputForSummary = `${attemptNotes.join("\n")}\n\n${outputForSummary}`.trim();
822
+ }
823
+ const finalizedOutput = finalizeSingleOutput({
824
+ fullOutput: outputForSummary,
829
825
  outputPath: step.outputPath,
830
826
  outputMode: step.outputMode,
831
827
  exitCode: finalResult?.exitCode ?? 1,
@@ -834,19 +830,8 @@ async function runSingleStep(
834
830
  saveError: resolvedOutput.saveError,
835
831
  });
836
832
  outputForSummary = finalizedOutput.displayOutput;
837
- const acceptance = step.effectiveAcceptance
838
- ? await evaluateAcceptance({
839
- acceptance: step.effectiveAcceptance,
840
- output: outputForAcceptance,
841
- cwd: step.cwd ?? ctx.cwd,
842
- })
843
- : undefined;
844
- const acceptanceFailure = acceptance ? acceptanceFailureMessage(acceptance) : undefined;
845
- const acceptanceCanFailRun = acceptanceFailure && acceptance?.explicit && (finalResult?.exitCode ?? 1) === 0 && !finalResult?.interrupted;
846
- const effectiveFinalExitCode = acceptanceCanFailRun ? 1 : finalResult?.exitCode ?? 1;
847
- const effectiveFinalError = acceptanceCanFailRun
848
- ? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
849
- : finalResult?.error;
833
+ const effectiveFinalExitCode = finalResult?.exitCode ?? 1;
834
+ const effectiveFinalError = finalResult?.error;
850
835
 
851
836
  if (artifactPaths && ctx.artifactConfig?.enabled !== false) {
852
837
  if (ctx.artifactConfig?.includeOutput !== false) {
@@ -885,11 +870,9 @@ async function runSingleStep(
885
870
  modelAttempts,
886
871
  artifactPaths,
887
872
  interrupted: finalResult?.interrupted,
888
- completionGuardTriggered: completionGuardTriggeredFinal,
889
873
  structuredOutput: (finalResult as (RunPiStreamingResult & { structuredOutput?: unknown }) | undefined)?.structuredOutput,
890
874
  structuredOutputPath: effectiveStructuredOutput?.outputPath,
891
875
  structuredOutputSchemaPath: effectiveStructuredOutput?.schemaPath,
892
- acceptance,
893
876
  };
894
877
  }
895
878
 
@@ -1159,7 +1142,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1159
1142
  if (step) {
1160
1143
  node.status = normalize(step.status);
1161
1144
  node.error = step.error;
1162
- node.acceptanceStatus = step.acceptance?.status;
1163
1145
  }
1164
1146
  if (statusPayload.currentStep === node.flatIndex) graph.currentNodeId = node.id;
1165
1147
  }
@@ -1180,12 +1162,11 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1180
1162
  writeAtomicJson(statusPath, statusPayload);
1181
1163
  emitNestedSelfEvent(statusPayload.state === "running" || statusPayload.state === "queued" ? "subagent.nested.updated" : "subagent.nested.completed");
1182
1164
  };
1183
- const markDynamicGraphGroup = (stepIndex: number, status: "completed" | "failed" | "running", error?: string, acceptance?: import("../../shared/types.ts").AcceptanceLedger): void => {
1165
+ const markDynamicGraphGroup = (stepIndex: number, status: "completed" | "failed" | "running", error?: string): void => {
1184
1166
  const groupNode = statusPayload.workflowGraph?.nodes.find((node) => node.id === `step-${stepIndex}`);
1185
1167
  if (!groupNode) return;
1186
1168
  groupNode.status = status;
1187
1169
  groupNode.error = error;
1188
- groupNode.acceptanceStatus = acceptance?.status ?? groupNode.acceptanceStatus;
1189
1170
  };
1190
1171
 
1191
1172
  const stepOutputActivityAt = (index: number): number => {
@@ -1346,7 +1327,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1346
1327
  resetMutatingFailureState(mutatingFailureStates[flatIndex]!);
1347
1328
  }
1348
1329
  } else if (event.type === "message_end" && event.message?.role === "assistant") {
1349
- appendRecentStepOutput(step, stripAcceptanceReport(extractTextFromContent(event.message.content)).split("\n").slice(-10));
1330
+ appendRecentStepOutput(step, extractTextFromContent(event.message.content).split("\n").slice(-10));
1350
1331
  step.turnCount = (step.turnCount ?? 0) + 1;
1351
1332
  const usage = event.message.usage;
1352
1333
  if (usage) {
@@ -1523,36 +1504,9 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1523
1504
  placeholder.durationMs = 0;
1524
1505
  }
1525
1506
  previousOutput = "Dynamic fanout produced 0 results.";
1526
- const groupAcceptance = step.effectiveAcceptance?.explicit
1527
- ? await evaluateAcceptance({
1528
- acceptance: step.effectiveAcceptance,
1529
- output: "",
1530
- report: aggregateAcceptanceReport({
1531
- results: [],
1532
- notes: "Dynamic fanout produced 0 results.",
1533
- }),
1534
- cwd,
1535
- })
1536
- : undefined;
1537
- if (placeholder && groupAcceptance) placeholder.acceptance = groupAcceptance;
1538
- const groupAcceptanceFailure = groupAcceptance ? acceptanceFailureMessage(groupAcceptance) : undefined;
1539
- if (groupAcceptanceFailure) {
1540
- statusPayload.state = "failed";
1541
- statusPayload.error = groupAcceptanceFailure;
1542
- if (placeholder) {
1543
- placeholder.status = "failed";
1544
- placeholder.error = groupAcceptanceFailure;
1545
- placeholder.exitCode = 1;
1546
- }
1547
- markDynamicGraphGroup(stepIndex, "failed", groupAcceptanceFailure, groupAcceptance);
1548
- statusPayload.lastUpdate = now;
1549
- writeStatusPayload();
1550
- results.push({ agent: step.parallel.agent, output: groupAcceptanceFailure, error: groupAcceptanceFailure, success: false, exitCode: 1, acceptance: groupAcceptance });
1551
- break;
1552
- }
1553
1507
  flatIndex++;
1554
1508
  statusPayload.lastUpdate = now;
1555
- markDynamicGraphGroup(stepIndex, "completed", undefined, groupAcceptance);
1509
+ markDynamicGraphGroup(stepIndex, "completed");
1556
1510
  writeStatusPayload();
1557
1511
  continue;
1558
1512
  }
@@ -1683,7 +1637,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1683
1637
  statusPayload.steps[fi].structuredOutput = singleResult.structuredOutput;
1684
1638
  statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
1685
1639
  statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
1686
- statusPayload.steps[fi].acceptance = singleResult.acceptance;
1687
1640
  statusPayload.lastUpdate = taskEndTime;
1688
1641
  writeStatusPayload();
1689
1642
  appendJsonl(eventsPath, JSON.stringify({
@@ -1713,7 +1666,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1713
1666
  structuredOutput: pr.structuredOutput,
1714
1667
  structuredOutputPath: pr.structuredOutputPath,
1715
1668
  structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
1716
- acceptance: pr.acceptance,
1717
1669
  });
1718
1670
  }
1719
1671
  const collection = collectDynamicResults(step as Parameters<typeof collectDynamicResults>[0], materialized.items, parallelResults);
@@ -1728,31 +1680,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1728
1680
  stepIndex,
1729
1681
  };
1730
1682
  statusPayload.outputs = outputs;
1731
- const groupAcceptance = step.effectiveAcceptance
1732
- ? await evaluateAcceptance({
1733
- acceptance: step.effectiveAcceptance,
1734
- output: "",
1735
- report: aggregateAcceptanceReport({
1736
- results: parallelResults,
1737
- notes: `Dynamic fanout collected ${collection.length} result(s) into ${step.collect.as}.`,
1738
- }),
1739
- cwd,
1740
- })
1741
- : undefined;
1742
- const groupAcceptanceFailure = groupAcceptance ? acceptanceFailureMessage(groupAcceptance) : undefined;
1743
- markDynamicGraphGroup(stepIndex, groupAcceptanceFailure ? "failed" : "completed", groupAcceptanceFailure, groupAcceptance);
1744
- if (groupAcceptanceFailure) {
1745
- results.push({
1746
- agent: step.parallel.agent,
1747
- output: groupAcceptanceFailure,
1748
- error: groupAcceptanceFailure,
1749
- success: false,
1750
- exitCode: 1,
1751
- structuredOutput: collection,
1752
- acceptance: groupAcceptance,
1753
- });
1754
- statusPayload.error = groupAcceptanceFailure;
1755
- }
1683
+ markDynamicGraphGroup(stepIndex, "completed");
1756
1684
  } catch (error) {
1757
1685
  const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
1758
1686
  results.push({ agent: step.parallel.agent, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection });
@@ -1938,7 +1866,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1938
1866
  statusPayload.steps[fi].structuredOutput = singleResult.structuredOutput;
1939
1867
  statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
1940
1868
  statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
1941
- statusPayload.steps[fi].acceptance = singleResult.acceptance;
1942
1869
  statusPayload.lastUpdate = taskEndTime;
1943
1870
  writeStatusPayload();
1944
1871
 
@@ -1947,20 +1874,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
1947
1874
  ts: taskEndTime, runId: id, stepIndex: fi, agent: task.agent,
1948
1875
  exitCode: singleResult.exitCode, durationMs: taskDuration,
1949
1876
  }));
1950
- if (singleResult.completionGuardTriggered) {
1951
- const event = buildControlEvent({
1952
- from: statusPayload.steps[fi].activityState,
1953
- to: "needs_attention",
1954
- runId: id,
1955
- agent: task.agent,
1956
- index: fi,
1957
- ts: taskEndTime,
1958
- message: `${task.agent} completed without making edits for an implementation task`,
1959
- reason: "completion_guard",
1960
- });
1961
- appendControlEvent(event);
1962
- }
1963
-
1964
1877
  if (singleResult.exitCode !== 0 && failFast) aborted = true;
1965
1878
  return { ...singleResult, skipped: false };
1966
1879
  },
@@ -2004,7 +1917,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2004
1917
  structuredOutput: pr.structuredOutput,
2005
1918
  structuredOutputPath: pr.structuredOutputPath,
2006
1919
  structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
2007
- acceptance: pr.acceptance,
2008
1920
  });
2009
1921
  }
2010
1922
  for (let t = 0; t < group.parallel.length; t++) {
@@ -2108,7 +2020,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2108
2020
  structuredOutput: singleResult.structuredOutput,
2109
2021
  structuredOutputPath: singleResult.structuredOutputPath,
2110
2022
  structuredOutputSchemaPath: singleResult.structuredOutputSchemaPath,
2111
- acceptance: singleResult.acceptance,
2112
2023
  });
2113
2024
  if (seqStep.outputName) {
2114
2025
  outputs[seqStep.outputName] = outputEntryFromAsyncResult({
@@ -2154,7 +2065,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2154
2065
  statusPayload.steps[flatIndex].structuredOutput = singleResult.structuredOutput;
2155
2066
  statusPayload.steps[flatIndex].structuredOutputPath = singleResult.structuredOutputPath;
2156
2067
  statusPayload.steps[flatIndex].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
2157
- statusPayload.steps[flatIndex].acceptance = singleResult.acceptance;
2158
2068
  if (stepTokens) {
2159
2069
  statusPayload.steps[flatIndex].tokens = stepTokens;
2160
2070
  statusPayload.totalTokens = { ...previousCumulativeTokens };
@@ -2172,20 +2082,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2172
2082
  durationMs: stepEndTime - stepStartTime,
2173
2083
  tokens: stepTokens,
2174
2084
  }));
2175
- if (singleResult.completionGuardTriggered) {
2176
- const event = buildControlEvent({
2177
- from: statusPayload.steps[flatIndex].activityState,
2178
- to: "needs_attention",
2179
- runId: id,
2180
- agent: seqStep.agent,
2181
- index: flatIndex,
2182
- ts: stepEndTime,
2183
- message: `${seqStep.agent} completed without making edits for an implementation task`,
2184
- reason: "completion_guard",
2185
- });
2186
- appendControlEvent(event);
2187
- }
2188
-
2189
2085
  flatIndex++;
2190
2086
  if (singleResult.exitCode !== 0) {
2191
2087
  break;
@@ -2317,7 +2213,6 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2317
2213
  structuredOutput: r.structuredOutput,
2318
2214
  structuredOutputPath: r.structuredOutputPath,
2319
2215
  structuredOutputSchemaPath: r.structuredOutputSchemaPath,
2320
- acceptance: r.acceptance,
2321
2216
  })),
2322
2217
  outputs,
2323
2218
  workflowGraph: statusPayload.workflowGraph,