pi-agent-flow 2.2.13 → 2.2.15

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 (254) hide show
  1. package/README.md +12 -0
  2. package/dist/batch/apply-patch.d.ts +2 -1
  3. package/dist/batch/apply-patch.d.ts.map +1 -1
  4. package/dist/batch/batch-bash.d.ts.map +1 -1
  5. package/dist/batch/batch-bash.js +9 -43
  6. package/dist/batch/batch-bash.js.map +1 -1
  7. package/dist/batch/constants.d.ts +9 -1
  8. package/dist/batch/constants.d.ts.map +1 -1
  9. package/dist/batch/constants.js +7 -0
  10. package/dist/batch/constants.js.map +1 -1
  11. package/dist/batch/execute.d.ts +1 -13
  12. package/dist/batch/execute.d.ts.map +1 -1
  13. package/dist/batch/execute.js +87 -28
  14. package/dist/batch/execute.js.map +1 -1
  15. package/dist/batch/index.d.ts.map +1 -1
  16. package/dist/batch/index.js +16 -14
  17. package/dist/batch/index.js.map +1 -1
  18. package/dist/batch/render.d.ts.map +1 -1
  19. package/dist/batch/render.js.map +1 -1
  20. package/dist/batch/summary.d.ts +0 -6
  21. package/dist/batch/summary.d.ts.map +1 -1
  22. package/dist/batch/summary.js +3 -3
  23. package/dist/batch/summary.js.map +1 -1
  24. package/dist/batch/symbols.d.ts.map +1 -1
  25. package/dist/batch/symbols.js +3 -1
  26. package/dist/batch/symbols.js.map +1 -1
  27. package/dist/batch/truncate-output.d.ts +31 -0
  28. package/dist/batch/truncate-output.d.ts.map +1 -0
  29. package/dist/batch/truncate-output.js +120 -0
  30. package/dist/batch/truncate-output.js.map +1 -0
  31. package/dist/config/config.d.ts +2 -1
  32. package/dist/config/config.d.ts.map +1 -1
  33. package/dist/config/config.js +10 -24
  34. package/dist/config/config.js.map +1 -1
  35. package/dist/config/models.d.ts.map +1 -1
  36. package/dist/config/models.js +7 -5
  37. package/dist/config/models.js.map +1 -1
  38. package/dist/config/paths.d.ts +3 -0
  39. package/dist/config/paths.d.ts.map +1 -0
  40. package/dist/config/paths.js +9 -0
  41. package/dist/config/paths.js.map +1 -0
  42. package/dist/config/resolver-helpers.d.ts +44 -0
  43. package/dist/config/resolver-helpers.d.ts.map +1 -0
  44. package/dist/config/resolver-helpers.js +135 -0
  45. package/dist/config/resolver-helpers.js.map +1 -0
  46. package/dist/config/settings-resolver.d.ts +0 -6
  47. package/dist/config/settings-resolver.d.ts.map +1 -1
  48. package/dist/config/settings-resolver.js +27 -256
  49. package/dist/config/settings-resolver.js.map +1 -1
  50. package/dist/core2/snapshot.d.ts +0 -2
  51. package/dist/core2/snapshot.d.ts.map +1 -1
  52. package/dist/core2/snapshot.js +98 -24
  53. package/dist/core2/snapshot.js.map +1 -1
  54. package/dist/flow/agents.d.ts +1 -1
  55. package/dist/flow/agents.d.ts.map +1 -1
  56. package/dist/flow/agents.js +18 -9
  57. package/dist/flow/agents.js.map +1 -1
  58. package/dist/flow/audit-formatters.d.ts +20 -0
  59. package/dist/flow/audit-formatters.d.ts.map +1 -0
  60. package/dist/flow/audit-formatters.js +123 -0
  61. package/dist/flow/audit-formatters.js.map +1 -0
  62. package/dist/flow/complexity.d.ts +3 -2
  63. package/dist/flow/complexity.d.ts.map +1 -1
  64. package/dist/flow/complexity.js +1 -1
  65. package/dist/flow/complexity.js.map +1 -1
  66. package/dist/flow/continuation.d.ts.map +1 -1
  67. package/dist/flow/continuation.js +6 -4
  68. package/dist/flow/continuation.js.map +1 -1
  69. package/dist/flow/cycle-guard.d.ts +20 -0
  70. package/dist/flow/cycle-guard.d.ts.map +1 -0
  71. package/dist/flow/cycle-guard.js +56 -0
  72. package/dist/flow/cycle-guard.js.map +1 -0
  73. package/dist/flow/depth.d.ts +0 -1
  74. package/dist/flow/depth.d.ts.map +1 -1
  75. package/dist/flow/depth.js +3 -2
  76. package/dist/flow/depth.js.map +1 -1
  77. package/dist/flow/dump-io.d.ts +15 -0
  78. package/dist/flow/dump-io.d.ts.map +1 -0
  79. package/dist/flow/dump-io.js +169 -0
  80. package/dist/flow/dump-io.js.map +1 -0
  81. package/dist/flow/execute-single.d.ts +8 -0
  82. package/dist/flow/execute-single.d.ts.map +1 -0
  83. package/dist/flow/execute-single.js +132 -0
  84. package/dist/flow/execute-single.js.map +1 -0
  85. package/dist/flow/executor.d.ts +3 -62
  86. package/dist/flow/executor.d.ts.map +1 -1
  87. package/dist/flow/executor.js +36 -342
  88. package/dist/flow/executor.js.map +1 -1
  89. package/dist/flow/flow-args.d.ts +14 -0
  90. package/dist/flow/flow-args.d.ts.map +1 -0
  91. package/dist/flow/flow-args.js +119 -0
  92. package/dist/flow/flow-args.js.map +1 -0
  93. package/dist/flow/flow-live.d.ts +18 -0
  94. package/dist/flow/flow-live.d.ts.map +1 -0
  95. package/dist/flow/flow-live.js +46 -0
  96. package/dist/flow/flow-live.js.map +1 -0
  97. package/dist/flow/process-lifecycle.d.ts +28 -0
  98. package/dist/flow/process-lifecycle.d.ts.map +1 -0
  99. package/dist/flow/process-lifecycle.js +114 -0
  100. package/dist/flow/process-lifecycle.js.map +1 -0
  101. package/dist/flow/runner.d.ts +4 -54
  102. package/dist/flow/runner.d.ts.map +1 -1
  103. package/dist/flow/runner.js +55 -517
  104. package/dist/flow/runner.js.map +1 -1
  105. package/dist/flow/settings-command.d.ts +2 -24
  106. package/dist/flow/settings-command.d.ts.map +1 -1
  107. package/dist/flow/settings-command.js +14 -716
  108. package/dist/flow/settings-command.js.map +1 -1
  109. package/dist/flow/settings-handler.d.ts +9 -0
  110. package/dist/flow/settings-handler.d.ts.map +1 -0
  111. package/dist/flow/settings-handler.js +377 -0
  112. package/dist/flow/settings-handler.js.map +1 -0
  113. package/dist/flow/settings-items.d.ts +42 -0
  114. package/dist/flow/settings-items.d.ts.map +1 -0
  115. package/dist/flow/settings-items.js +380 -0
  116. package/dist/flow/settings-items.js.map +1 -0
  117. package/dist/flow/spawn-utils.d.ts +17 -0
  118. package/dist/flow/spawn-utils.d.ts.map +1 -0
  119. package/dist/flow/spawn-utils.js +40 -0
  120. package/dist/flow/spawn-utils.js.map +1 -0
  121. package/dist/flow/store.d.ts.map +1 -1
  122. package/dist/flow/store.js +2 -8
  123. package/dist/flow/store.js.map +1 -1
  124. package/dist/flow/transition.d.ts +0 -1
  125. package/dist/flow/transition.d.ts.map +1 -1
  126. package/dist/flow/transition.js +0 -3
  127. package/dist/flow/transition.js.map +1 -1
  128. package/dist/index.d.ts +3 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +94 -57
  131. package/dist/index.js.map +1 -1
  132. package/dist/io/atomic-write.d.ts +10 -0
  133. package/dist/io/atomic-write.d.ts.map +1 -0
  134. package/dist/io/atomic-write.js +30 -0
  135. package/dist/io/atomic-write.js.map +1 -0
  136. package/dist/notify/notify.d.ts.map +1 -1
  137. package/dist/notify/notify.js +1 -4
  138. package/dist/notify/notify.js.map +1 -1
  139. package/dist/snapshot/cli-args.d.ts +1 -2
  140. package/dist/snapshot/cli-args.d.ts.map +1 -1
  141. package/dist/snapshot/runner-events.d.ts +10 -0
  142. package/dist/snapshot/runner-events.d.ts.map +1 -1
  143. package/dist/snapshot/runner-events.js +112 -30
  144. package/dist/snapshot/runner-events.js.map +1 -1
  145. package/dist/snapshot/structured-output.d.ts.map +1 -1
  146. package/dist/snapshot/structured-output.js +3 -1
  147. package/dist/snapshot/structured-output.js.map +1 -1
  148. package/dist/snapshot/trace-output.d.ts.map +1 -1
  149. package/dist/snapshot/trace-output.js +8 -4
  150. package/dist/snapshot/trace-output.js.map +1 -1
  151. package/dist/steering/sliding-prompt.d.ts.map +1 -1
  152. package/dist/steering/sliding-prompt.js +12 -15
  153. package/dist/steering/sliding-prompt.js.map +1 -1
  154. package/dist/steering/tool-utils.d.ts +3 -3
  155. package/dist/steering/tool-utils.d.ts.map +1 -1
  156. package/dist/steering/tool-utils.js +3 -3
  157. package/dist/steering/tool-utils.js.map +1 -1
  158. package/dist/tools/ask-user.js.map +1 -1
  159. package/dist/tools/timed-bash.d.ts.map +1 -1
  160. package/dist/tools/timed-bash.js +8 -3
  161. package/dist/tools/timed-bash.js.map +1 -1
  162. package/dist/tools/trace.d.ts +0 -1
  163. package/dist/tools/trace.d.ts.map +1 -1
  164. package/dist/tools/trace.js +79 -62
  165. package/dist/tools/trace.js.map +1 -1
  166. package/dist/tools/web-ops.d.ts +0 -49
  167. package/dist/tools/web-ops.d.ts.map +1 -1
  168. package/dist/tools/web-ops.js +9 -9
  169. package/dist/tools/web-ops.js.map +1 -1
  170. package/dist/tui/body-render.d.ts +31 -0
  171. package/dist/tui/body-render.d.ts.map +1 -0
  172. package/dist/tui/body-render.js +589 -0
  173. package/dist/tui/body-render.js.map +1 -0
  174. package/dist/tui/context-display.d.ts +18 -0
  175. package/dist/tui/context-display.d.ts.map +1 -0
  176. package/dist/tui/context-display.js +29 -0
  177. package/dist/tui/context-display.js.map +1 -0
  178. package/dist/tui/flow-colors.d.ts +6 -1
  179. package/dist/tui/flow-colors.d.ts.map +1 -1
  180. package/dist/tui/flow-colors.js +1 -0
  181. package/dist/tui/flow-colors.js.map +1 -1
  182. package/dist/tui/flow-live-state.d.ts +36 -0
  183. package/dist/tui/flow-live-state.d.ts.map +1 -0
  184. package/dist/tui/flow-live-state.js +53 -0
  185. package/dist/tui/flow-live-state.js.map +1 -0
  186. package/dist/tui/grouping.d.ts +27 -0
  187. package/dist/tui/grouping.d.ts.map +1 -0
  188. package/dist/tui/grouping.js +191 -0
  189. package/dist/tui/grouping.js.map +1 -0
  190. package/dist/tui/header.d.ts +25 -0
  191. package/dist/tui/header.d.ts.map +1 -0
  192. package/dist/tui/header.js +95 -0
  193. package/dist/tui/header.js.map +1 -0
  194. package/dist/tui/render-utils.d.ts +1 -0
  195. package/dist/tui/render-utils.d.ts.map +1 -1
  196. package/dist/tui/render-utils.js +4 -5
  197. package/dist/tui/render-utils.js.map +1 -1
  198. package/dist/tui/render.d.ts +19 -33
  199. package/dist/tui/render.d.ts.map +1 -1
  200. package/dist/tui/render.js +112 -1014
  201. package/dist/tui/render.js.map +1 -1
  202. package/dist/tui/scramble/animation-status.d.ts +5 -0
  203. package/dist/tui/scramble/animation-status.d.ts.map +1 -0
  204. package/dist/tui/scramble/animation-status.js +93 -0
  205. package/dist/tui/scramble/animation-status.js.map +1 -0
  206. package/dist/tui/scramble/constants.d.ts +0 -4
  207. package/dist/tui/scramble/constants.d.ts.map +1 -1
  208. package/dist/tui/scramble/constants.js +3 -3
  209. package/dist/tui/scramble/constants.js.map +1 -1
  210. package/dist/tui/scramble/dynamic-text.d.ts +10 -0
  211. package/dist/tui/scramble/dynamic-text.d.ts.map +1 -0
  212. package/dist/tui/scramble/dynamic-text.js +19 -0
  213. package/dist/tui/scramble/dynamic-text.js.map +1 -0
  214. package/dist/tui/scramble/index.d.ts +8 -2
  215. package/dist/tui/scramble/index.d.ts.map +1 -1
  216. package/dist/tui/scramble/index.js +8 -1
  217. package/dist/tui/scramble/index.js.map +1 -1
  218. package/dist/tui/scramble/lifecycle.d.ts +4 -0
  219. package/dist/tui/scramble/lifecycle.d.ts.map +1 -0
  220. package/dist/tui/scramble/lifecycle.js +75 -0
  221. package/dist/tui/scramble/lifecycle.js.map +1 -0
  222. package/dist/tui/scramble/line-state.d.ts +5 -0
  223. package/dist/tui/scramble/line-state.d.ts.map +1 -0
  224. package/dist/tui/scramble/line-state.js +99 -0
  225. package/dist/tui/scramble/line-state.js.map +1 -0
  226. package/dist/tui/scramble/manager.d.ts +3 -14
  227. package/dist/tui/scramble/manager.d.ts.map +1 -1
  228. package/dist/tui/scramble/manager.js +22 -405
  229. package/dist/tui/scramble/manager.js.map +1 -1
  230. package/dist/tui/scramble/singleton.d.ts +3 -0
  231. package/dist/tui/scramble/singleton.d.ts.map +1 -0
  232. package/dist/tui/scramble/singleton.js +3 -0
  233. package/dist/tui/scramble/singleton.js.map +1 -0
  234. package/dist/tui/scramble/timer.d.ts +6 -0
  235. package/dist/tui/scramble/timer.d.ts.map +1 -0
  236. package/dist/tui/scramble/timer.js +28 -0
  237. package/dist/tui/scramble/timer.js.map +1 -0
  238. package/dist/tui/scramble/utils.d.ts +0 -2
  239. package/dist/tui/scramble/utils.d.ts.map +1 -1
  240. package/dist/tui/scramble/utils.js +0 -9
  241. package/dist/tui/scramble/utils.js.map +1 -1
  242. package/dist/tui/scramble/value-flash.d.ts +6 -0
  243. package/dist/tui/scramble/value-flash.d.ts.map +1 -0
  244. package/dist/tui/scramble/value-flash.js +141 -0
  245. package/dist/tui/scramble/value-flash.js.map +1 -0
  246. package/dist/tui/traces.d.ts +13 -0
  247. package/dist/tui/traces.d.ts.map +1 -0
  248. package/dist/tui/traces.js +97 -0
  249. package/dist/tui/traces.js.map +1 -0
  250. package/dist/types/ui.d.ts +0 -4
  251. package/dist/types/ui.d.ts.map +1 -1
  252. package/dist/types/ui.js +1 -30
  253. package/dist/types/ui.js.map +1 -1
  254. package/package.json +5 -1
@@ -5,43 +5,24 @@
5
5
  * project-flow confirmation, parallel execution with failover, caching,
6
6
  * and telemetry.
7
7
  */
8
- import { isFlowSuccess, isFlowError, isFlowComplete, emptyFlowUsage } from "../types/flow.js";
9
- // ~6 KB limit to keep grouped audit intent under typical prompt budget while preserving enough context for meaningful audit
10
- const MAX_AUDIT_OUTPUT_SLICE = 6000;
11
- import { mapFlowConcurrent, runFlow } from "./runner.js";
8
+ import { isFlowSuccess, isFlowError, emptyFlowUsage } from "../types/flow.js";
9
+ import { mapFlowConcurrent } from "./runner.js";
12
10
  import { getFlowSummaryText } from "../snapshot/runner-events.js";
13
- import { normalizeFlowModeName, resolveFlowModelCandidates, resolveModelContextWindow, selectFlowModelStrategy } from "../config/config.js";
14
- import { getComplexityTimeoutMs, resolveComplexity, getImpliedAuditLoop } from "./complexity.js";
11
+ import { normalizeFlowModeName, selectFlowModelStrategy } from "../config/config.js";
12
+ import { getImpliedAuditLoop } from "./complexity.js";
15
13
  import { setFlowComplete } from "../notify/notify-state.js";
16
14
  import { setLiveText, clearLiveText } from '../tui/scramble/index.js';
15
+ import { publishFlowLiveText, publishFlowLiveTextAtIndex } from './flow-live.js';
17
16
  import { logWarn } from '../config/log.js';
18
17
  import { markFlowCompleted } from '../flow/index.js';
19
- /**
20
- * Shallow-merge helper: copies audit-loop metadata fields from `source`
21
- * onto `target` without mutating the target's identity reference.
22
- * Used whenever a fresh SingleResult overwrites a slot that may already
23
- * carry ping-pong or parent-type metadata.
24
- */
25
- export function preserveMetadata(target, source) {
26
- if (source?.pingPongMeta) {
27
- target.pingPongMeta = source.pingPongMeta;
28
- }
29
- if (source?.auditParentType) {
30
- target.auditParentType = source.auditParentType;
31
- }
32
- if (source?.auditLoopGroupId !== undefined) {
33
- target.auditLoopGroupId = source.auditLoopGroupId;
34
- }
35
- }
18
+ import { preserveMetadata, getFlowCycleViolations, createGhostResult, } from "./cycle-guard.js";
19
+ import { resolveAuditModel, buildReworkIntent, buildGroupAuditIntent, } from "./audit-formatters.js";
20
+ import { executeSingleFlow } from "./execute-single.js";
21
+ export { preserveMetadata, createGhostResult, shouldFailover } from "./cycle-guard.js";
22
+ export { buildReworkIntent, buildGroupAuditIntent, formatPriorAuditHistory, formatPriorBuildOutputs } from "./audit-formatters.js";
36
23
  // ---------------------------------------------------------------------------
37
24
  // Helpers
38
25
  // ---------------------------------------------------------------------------
39
- function getFlowCycleViolations(requestedNames, ancestorFlowStack) {
40
- if (requestedNames.size === 0 || ancestorFlowStack.length === 0)
41
- return [];
42
- const stackSet = new Set(ancestorFlowStack);
43
- return Array.from(requestedNames).filter((name) => stackSet.has(name));
44
- }
45
26
  function getRequestedProjectFlows(flows, requestedNames) {
46
27
  return Array.from(requestedNames)
47
28
  .map((name) => flows.find((f) => f.name === name.toLowerCase()))
@@ -61,274 +42,6 @@ async function confirmProjectFlowsIfNeeded(projectFlows, projectFlowsDir, hasUI,
61
42
  blocked: `Blocked: project-local flow confirmation required in non-UI mode.\nFlows: ${names}\nRe-run with confirmProjectFlows: false if trusted.`,
62
43
  };
63
44
  }
64
- function shouldFailover(result) {
65
- if (result.stopReason === "aborted")
66
- return false;
67
- const text = `${result.errorMessage ?? ""}\n${result.stderr ?? ""}`.toLowerCase();
68
- if (!text.trim())
69
- return false;
70
- if (text.includes("permission") || text.includes("invalid tool") || text.includes("bad settings")) {
71
- return false;
72
- }
73
- if (result.exitCode > 0)
74
- return true;
75
- // Some child runs log HTTP 400 / "Param Incorrect" to stderr while exiting 0
76
- // without completing a turn — treat as retryable for model failover.
77
- if (!isFlowComplete(result) && (text.includes("400") && text.includes("param"))) {
78
- return true;
79
- }
80
- return false;
81
- }
82
- export function createGhostResult(type, intent, aim, model, maxContextTokens) {
83
- return {
84
- type,
85
- agentSource: "unknown",
86
- intent,
87
- aim,
88
- exitCode: -1,
89
- messages: [],
90
- stderr: "",
91
- usage: emptyFlowUsage(),
92
- ...(model ? { model } : {}),
93
- ...(maxContextTokens !== undefined ? { maxContextTokens } : {}),
94
- };
95
- }
96
- export function resolveAuditModel(flows, tierOverrideResolver, strategy, fallbackModel) {
97
- const auditFlow = flows.find((f) => f.name === "audit");
98
- const tier = auditFlow?.tier ?? "flash";
99
- const { candidates } = resolveFlowModelCandidates({
100
- tier,
101
- flowModel: auditFlow?.model,
102
- cliTierOverride: tierOverrideResolver(tier),
103
- strategy,
104
- fallbackModel,
105
- });
106
- const model = candidates[0];
107
- const maxContextTokens = resolveModelContextWindow(model);
108
- return { model, maxContextTokens };
109
- }
110
- export function buildReworkIntent(originalIntent, buildAim, acceptance, auditFeedback, cycleHistory) {
111
- const parts = [
112
- `## Original Intent`,
113
- originalIntent,
114
- ``,
115
- `## Build Aim`,
116
- buildAim,
117
- ``,
118
- ];
119
- if (acceptance) {
120
- parts.push(`## Acceptance Criteria`, acceptance, ``);
121
- }
122
- parts.push(`## Audit Feedback`, auditFeedback, ``);
123
- if (cycleHistory && cycleHistory.length > 0) {
124
- // Show all prior build outputs (deep-loop: every cycle, not just latest)
125
- const buildOutputs = formatPriorBuildOutputs(cycleHistory);
126
- if (buildOutputs) {
127
- parts.push(buildOutputs, ``);
128
- }
129
- // Show all prior audit verdicts/feedbacks
130
- const auditHistory = formatPriorAuditHistory(cycleHistory);
131
- if (auditHistory) {
132
- parts.push(auditHistory, ``);
133
- }
134
- }
135
- parts.push(`Fix the above issues, preserving the Original Intent and incorporating all prior cycle feedback.`);
136
- return parts.join("\n");
137
- }
138
- async function executeSingleFlow(deps, item, allResults, resultIndex, toolCallId, emitProgress, selectedFlowModelConfig) {
139
- const { flows, currentDepth, maxDepth, ancestorFlowStack, preventCycles, toolOptimize, structuredOutput, cwd, defaultComplexity, signal, makeDetails, tierOverrideResolver, fallbackModel, forkSessionSnapshotJsonl, onFlowMetrics, goalContext, } = deps;
140
- const normalizedType = item.type.toLowerCase();
141
- const complexity = resolveComplexity(item.complexity, defaultComplexity);
142
- const lookupName = normalizedType;
143
- const targetFlow = flows.find((f) => f.name === lookupName);
144
- const effectiveMaxDepth = targetFlow?.maxDepth !== undefined ? targetFlow.maxDepth : maxDepth;
145
- const shouldInheritContext = targetFlow?.inheritContext !== false;
146
- const tier = targetFlow?.tier ?? "flash";
147
- const { candidates } = resolveFlowModelCandidates({
148
- tier,
149
- flowModel: targetFlow?.model,
150
- cliTierOverride: tierOverrideResolver(tier),
151
- strategy: selectedFlowModelConfig.strategy,
152
- fallbackModel,
153
- });
154
- const attemptModels = candidates.length > 0 ? candidates : [undefined];
155
- const attemptedModels = [];
156
- let result = allResults[resultIndex];
157
- const flowStart = Date.now();
158
- for (let attempt = 0; attempt < attemptModels.length; attempt++) {
159
- const candidateModel = attemptModels[attempt];
160
- if (candidateModel)
161
- attemptedModels.push(candidateModel);
162
- const attemptStartMs = Date.now();
163
- const attemptTimeoutMs = getComplexityTimeoutMs(complexity);
164
- const maxContextTokens = resolveModelContextWindow(candidateModel);
165
- const previous = allResults[resultIndex];
166
- allResults[resultIndex] = {
167
- type: normalizedType,
168
- agentSource: targetFlow?.source ?? "unknown",
169
- intent: item.intent,
170
- aim: item.aim,
171
- exitCode: -1,
172
- messages: [],
173
- stderr: "",
174
- usage: emptyFlowUsage(),
175
- model: candidateModel,
176
- startedAtMs: attemptStartMs,
177
- deadlineAtMs: attemptStartMs + attemptTimeoutMs,
178
- ...(maxContextTokens !== undefined ? { maxContextTokens } : {}),
179
- };
180
- preserveMetadata(allResults[resultIndex], previous);
181
- emitProgress();
182
- result = await runFlow({
183
- cwd,
184
- flows,
185
- flowName: lookupName,
186
- intent: item.intent,
187
- aim: item.aim,
188
- acceptance: item.acceptance,
189
- taskCwd: item.cwd,
190
- forkSessionSnapshotJsonl: shouldInheritContext ? forkSessionSnapshotJsonl : null,
191
- parentDepth: currentDepth,
192
- parentFlowStack: ancestorFlowStack,
193
- maxDepth: effectiveMaxDepth,
194
- preventCycles,
195
- toolOptimize,
196
- structuredOutput,
197
- complexity,
198
- model: candidateModel,
199
- maxContextTokens,
200
- goalContext,
201
- debugMode: deps.debugMode,
202
- tools: item._childTools,
203
- preDispatchResults: item.preDispatchResults,
204
- signal,
205
- onUpdate: (partial) => {
206
- if (partial.details?.results[0]) {
207
- const previous = allResults[resultIndex];
208
- allResults[resultIndex] = partial.details.results[0];
209
- preserveMetadata(allResults[resultIndex], previous);
210
- const flowText = partial.content?.[0]?.text;
211
- if (flowText !== undefined) {
212
- setLiveText(`${toolCallId || 'collapsed'}#${resultIndex}`, flowText);
213
- setLiveText(`collapsed#${resultIndex}`, flowText);
214
- }
215
- emitProgress(partial.content?.[0]?.text);
216
- }
217
- },
218
- makeDetails,
219
- });
220
- const previous2 = allResults[resultIndex];
221
- allResults[resultIndex] = result;
222
- preserveMetadata(allResults[resultIndex], previous2);
223
- emitProgress();
224
- if (isFlowSuccess(result) || signal?.aborted)
225
- break;
226
- if (attempt < attemptModels.length - 1 && shouldFailover(result)) {
227
- continue;
228
- }
229
- break;
230
- }
231
- if (result && !isFlowSuccess(result) && attemptedModels.length > 1) {
232
- const summary = `Model failover attempts: ${attemptedModels.join(" -> ")}`;
233
- const baseStderr = result.stderr.trim();
234
- result.stderr = baseStderr ? `${baseStderr}\n\n${summary}` : summary;
235
- const previous3 = allResults[resultIndex];
236
- allResults[resultIndex] = result;
237
- preserveMetadata(allResults[resultIndex], previous3);
238
- emitProgress();
239
- }
240
- if (onFlowMetrics) {
241
- const flowDuration = Date.now() - flowStart;
242
- onFlowMetrics({
243
- type: normalizedType,
244
- durationMs: flowDuration,
245
- exitCode: result.exitCode,
246
- success: isFlowSuccess(result),
247
- model: result.model,
248
- failoverCount: Math.max(0, attemptedModels.length - 1),
249
- usage: result.usage,
250
- source: result.agentSource,
251
- depth: currentDepth + 1,
252
- });
253
- }
254
- return result;
255
- }
256
- export function formatPriorAuditHistory(entries) {
257
- if (entries.length === 0)
258
- return "";
259
- const lines = entries.map((e) => {
260
- const parts = [
261
- `**Cycle ${e.cycle + 1}**`,
262
- `- Verdict: ${e.verdict}`,
263
- ];
264
- if (e.feedback) {
265
- parts.push(`- Feedback: ${e.feedback.slice(0, 2000)}`);
266
- }
267
- if (e.buildFeedbacks && e.buildFeedbacks.length > 0) {
268
- parts.push(`- Per-Build Feedback:`);
269
- e.buildFeedbacks.forEach((fb, i) => {
270
- if (fb) {
271
- parts.push(` - Build ${i + 1}: ${fb.slice(0, 1500)}`);
272
- }
273
- else {
274
- parts.push(` - Build ${i + 1}: pass`);
275
- }
276
- });
277
- }
278
- return parts.join("\n");
279
- });
280
- return `## Prior Audit History\n\n${lines.join("\n\n")}`;
281
- }
282
- export function formatPriorBuildOutputs(entries) {
283
- if (entries.length === 0)
284
- return "";
285
- const lines = entries.map((e) => {
286
- const parts = [`**Cycle ${e.cycle + 1}**`];
287
- if (e.buildOutputs.length > 0) {
288
- parts.push(`- Build Outputs:`);
289
- e.buildOutputs.forEach((bo, i) => {
290
- parts.push(` - Build ${i + 1}: ${bo.slice(0, 3000)}`);
291
- });
292
- }
293
- return parts.join("\n");
294
- });
295
- return `## Prior Build Outputs\n\n${lines.join("\n\n")}`;
296
- }
297
- export function buildGroupAuditIntent(builds, cycleHistory) {
298
- const sections = builds.map((b, i) => {
299
- const section = [
300
- `### Build ${i + 1}`,
301
- ``,
302
- `## Build Aim`,
303
- b.aim,
304
- ``,
305
- ];
306
- if (b.acceptance) {
307
- section.push(`## Acceptance Criteria`, b.acceptance, ``);
308
- }
309
- if (b.intent) {
310
- section.push(`## Build Intent`, b.intent, ``);
311
- }
312
- section.push(`## Build Output`, b.output.slice(0, MAX_AUDIT_OUTPUT_SLICE));
313
- return section.join("\n");
314
- });
315
- const parts = [
316
- ...sections,
317
- ``,
318
- ];
319
- if (cycleHistory && cycleHistory.length > 0) {
320
- const auditHistory = formatPriorAuditHistory(cycleHistory);
321
- if (auditHistory) {
322
- parts.push(auditHistory, ``);
323
- }
324
- const buildOutputs = formatPriorBuildOutputs(cycleHistory);
325
- if (buildOutputs) {
326
- parts.push(buildOutputs, ``);
327
- }
328
- }
329
- parts.push(`Check for: security issues, correctness, completeness, edge cases, and any overlooked requirements per build. For each build, indicate whether it passes or needs rework with specific actionable feedback.`);
330
- return parts.join("\n\n");
331
- }
332
45
  async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitProgress, selectedFlowModelConfig) {
333
46
  const { items, auditLoop, buildIndices, auditIndex } = group;
334
47
  const maxCycles = (auditLoop ?? 0) + 1;
@@ -336,8 +49,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
336
49
  const verdictHistory = [];
337
50
  const cycleHistory = [];
338
51
  const auditFeedbacks = new Array(items.length).fill(null);
339
- // Initialize all slots (re-creates ghosts; must stamp auditLoopGroupId
340
- // because executeFlows pre-allocation gets overwritten here).
341
52
  for (let i = 0; i < items.length; i++) {
342
53
  allResults[buildIndices[i]] = createGhostResult(items[i].type, items[i].intent, items[i].aim);
343
54
  allResults[buildIndices[i]].status = "running";
@@ -352,7 +63,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
352
63
  const key = toolCallId || 'collapsed';
353
64
  const buildResults = new Array(items.length);
354
65
  while (cycle < maxCycles) {
355
- // ─── Phase A: Run all builds in parallel ───
356
66
  for (let i = 0; i < items.length; i++) {
357
67
  allResults[buildIndices[i]].status = "running";
358
68
  allResults[buildIndices[i]].exitCode = -1;
@@ -366,7 +76,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
366
76
  setLiveText(`${key}#${auditIndex}`, "[awaiting...]");
367
77
  setLiveText(`collapsed#${auditIndex}`, "[awaiting...]");
368
78
  emitProgress();
369
- // Run all builds in parallel
370
79
  const buildPromises = items.map((item, i) => {
371
80
  const buildInput = cycle > 0
372
81
  ? buildReworkIntent(item.intent, item.aim, item.acceptance, auditFeedbacks[i] ?? "No issues found.", cycleHistory)
@@ -385,7 +94,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
385
94
  allResults[buildIndices[i]].deadlineAtMs = undefined;
386
95
  }
387
96
  emitProgress();
388
- // Check if any build failed
389
97
  const anyBuildFailed = buildResults.some(r => !isFlowSuccess(r));
390
98
  if (anyBuildFailed) {
391
99
  const { model: skipAuditModel, maxContextTokens: skipAuditMaxCtx } = resolveAuditModel(deps.flows, deps.tierOverrideResolver, selectedFlowModelConfig.strategy, deps.fallbackModel);
@@ -400,7 +108,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
400
108
  emitProgress();
401
109
  break;
402
110
  }
403
- // ─── Phase B: Run ONE audit that reviews all builds ───
404
111
  for (let i = 0; i < items.length; i++) {
405
112
  allResults[buildIndices[i]].status = "awaiting";
406
113
  clearLiveText(`${key}#${buildIndices[i]}`);
@@ -429,7 +136,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
429
136
  const auditResult = await executeSingleFlow(deps, auditItem, allResults, auditIndex, toolCallId, emitProgress, selectedFlowModelConfig);
430
137
  auditResult.auditParentType = items[0].type;
431
138
  allResults[auditIndex] = auditResult;
432
- // Parse per-build verdicts
433
139
  const perBuildVerdicts = auditResult.structuredOutput?.builds;
434
140
  const topLevelVerdict = auditResult.structuredOutput?.verdict ?? "pass";
435
141
  const topLevelFeedback = auditResult.structuredOutput?.feedback;
@@ -447,7 +153,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
447
153
  }
448
154
  }
449
155
  else {
450
- // Fallback: top-level verdict applies to all builds
451
156
  if (topLevelVerdict === "rework") {
452
157
  for (let i = 0; i < items.length; i++) {
453
158
  auditFeedbacks[i] = topLevelFeedback ?? "Fix issues found in audit.";
@@ -480,12 +185,10 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
480
185
  break;
481
186
  }
482
187
  if (cycle + 1 >= maxCycles) {
483
- break; // Loop exhausted
188
+ break;
484
189
  }
485
190
  cycle++;
486
- // Continue loop — builds needing rework will re-run
487
191
  }
488
- // Finalize: set real exit codes
489
192
  for (let i = 0; i < items.length; i++) {
490
193
  allResults[buildIndices[i]].exitCode = isFlowSuccess(buildResults[i]) ? 0 : (buildResults[i].exitCode > 0 ? buildResults[i].exitCode : 1);
491
194
  allResults[buildIndices[i]].status = isFlowSuccess(buildResults[i]) ? "done" : "error";
@@ -497,7 +200,6 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
497
200
  allResults[auditIndex].exitCode = isFlowSuccess(allResults[auditIndex]) ? 0 : (allResults[auditIndex].exitCode > 0 ? allResults[auditIndex].exitCode : 1);
498
201
  allResults[auditIndex].status = "done";
499
202
  }
500
- // Populate pingPongMeta on each build result
501
203
  for (let i = 0; i < items.length; i++) {
502
204
  allResults[buildIndices[i]].pingPongMeta = {
503
205
  cycles: cycle + 1,
@@ -505,20 +207,22 @@ async function executeGroupedPingPong(deps, group, allResults, toolCallId, emitP
505
207
  finalVerdict: allResults[auditIndex].structuredOutput?.verdict ?? (allResults[auditIndex].status === "skipped" ? "fail" : "pass"),
506
208
  };
507
209
  }
210
+ if (allResults[auditIndex].status !== "skipped") {
211
+ allResults[auditIndex].pingPongMeta = {
212
+ cycles: cycle + 1,
213
+ verdicts: verdictHistory,
214
+ finalVerdict: allResults[auditIndex].structuredOutput?.verdict ?? "pass",
215
+ };
216
+ }
508
217
  emitProgress();
509
218
  return buildResults;
510
219
  }
511
220
  // ---------------------------------------------------------------------------
512
221
  // FlowExecutor
513
222
  // ---------------------------------------------------------------------------
514
- /**
515
- * Execute a set of flow tasks with full orchestration: cycle detection,
516
- * project confirmation, parallel execution with model failover, and telemetry.
517
- */
518
223
  export async function executeFlows(deps, params, toolCallId, auditLoop) {
519
224
  const { flows, currentDepth, maxDepth, ancestorFlowStack, preventCycles, toolOptimize, structuredOutput, cwd, loadedFlowModelConfigs, maxConcurrency, defaultComplexity, signal, onUpdate, makeDetails, getFlag, tierOverrideResolver, fallbackModel, forkSessionSnapshotJsonl, projectFlowsDir, hasUI, uiConfirm, onFlowMetrics, confirmProjectFlows, goalContext, } = deps;
520
225
  const requested = new Set(params.map((f) => f.type.toLowerCase()));
521
- // Cycle check
522
226
  if (preventCycles) {
523
227
  const violations = getFlowCycleViolations(requested, ancestorFlowStack);
524
228
  if (violations.length > 0) {
@@ -533,7 +237,6 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
533
237
  };
534
238
  }
535
239
  }
536
- // Project flow confirmation
537
240
  const projectFlows = getRequestedProjectFlows(flows, requested);
538
241
  if (projectFlows.length > 0 && confirmProjectFlows !== false) {
539
242
  const { ok, blocked } = await confirmProjectFlowsIfNeeded(projectFlows, projectFlowsDir, hasUI, uiConfirm);
@@ -545,18 +248,15 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
545
248
  };
546
249
  }
547
250
  }
548
- // Resolve model strategy
549
251
  const cliFlowMode = normalizeFlowModeName(getFlag("flow-mode"));
550
252
  const cliFlowModelConfig = normalizeFlowModeName(getFlag("flow-model-config"));
551
253
  if (cliFlowMode !== undefined && cliFlowModelConfig !== undefined && cliFlowMode !== cliFlowModelConfig) {
552
254
  logWarn(`[pi-agent-flow] Both --flow-mode "${cliFlowMode}" and --flow-model-config "${cliFlowModelConfig}" were provided. Using --flow-mode.`);
553
255
  }
554
256
  const selectedFlowModelConfig = selectFlowModelStrategy(loadedFlowModelConfigs.configs, cliFlowMode ?? cliFlowModelConfig ?? loadedFlowModelConfigs.selectedName);
555
- // Partition params into regular and grouped ping-pong flows
556
257
  const regularParams = [];
557
258
  const regularIndices = [];
558
259
  const groups = [];
559
- // Compute effective audit loop per build = max(explicit override, complexity-implied)
560
260
  const effectiveAuditLoops = params.map((p) => {
561
261
  if (p.type.toLowerCase() === "build") {
562
262
  return Math.max(auditLoop ?? 0, getImpliedAuditLoop(p.complexity));
@@ -583,8 +283,8 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
583
283
  items: [params[i]],
584
284
  auditLoop: effectiveAuditLoops[i],
585
285
  buildIndices: [buildIndex],
586
- auditIndex: -1, // placeholder; assigned after all builds
587
- groupId: -1, // placeholder; set after auditIndex is assigned
286
+ auditIndex: -1,
287
+ groupId: -1,
588
288
  };
589
289
  groups.push(buildGroup);
590
290
  }
@@ -593,17 +293,14 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
593
293
  regularIndices.push(nextIndex);
594
294
  regularParams.push(params[i]);
595
295
  nextIndex++;
596
- // Non-build param breaks contiguity — reset so later builds start a new group
597
296
  buildGroup = undefined;
598
297
  }
599
298
  }
600
- // Assign audit indices after all builds are allocated
601
299
  let groupCounter = 0;
602
300
  for (const group of groups) {
603
301
  group.auditIndex = nextIndex++;
604
302
  group.groupId = groupCounter++;
605
303
  }
606
- // Pre-allocate results array
607
304
  const allResults = new Array(nextIndex);
608
305
  for (let i = 0; i < regularParams.length; i++) {
609
306
  const idx = regularIndices[i];
@@ -633,7 +330,6 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
633
330
  allResults[group.auditIndex].auditParentType = "build";
634
331
  allResults[group.auditIndex].auditLoopGroupId = group.groupId;
635
332
  }
636
- // Streaming progress
637
333
  let lastEmittedSignature;
638
334
  const emitProgress = (streamingText) => {
639
335
  const activeStreamingText = allResults
@@ -642,18 +338,24 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
642
338
  .filter((text) => Boolean(text))
643
339
  .at(-1);
644
340
  const text = streamingText ?? activeStreamingText ?? "";
645
- // Update live text store FIRST — always
646
- const key = toolCallId || 'collapsed';
647
- setLiveText(key, text);
648
- setLiveText('collapsed', text);
649
- for (let i = 0; i < allResults.length; i++) {
650
- const r = allResults[i];
651
- if (r.streamingText) {
652
- setLiveText(`${key}#${i}`, r.streamingText);
653
- setLiveText(`collapsed#${i}`, r.streamingText);
341
+ if (toolCallId) {
342
+ publishFlowLiveText(toolCallId, text);
343
+ for (let i = 0; i < allResults.length; i++) {
344
+ const r = allResults[i];
345
+ if (r.streamingText) {
346
+ publishFlowLiveTextAtIndex(toolCallId, i, r.streamingText);
347
+ }
348
+ }
349
+ }
350
+ else {
351
+ setLiveText("collapsed", text);
352
+ for (let i = 0; i < allResults.length; i++) {
353
+ const r = allResults[i];
354
+ if (r.streamingText) {
355
+ setLiveText(`collapsed#${i}`, r.streamingText);
356
+ }
654
357
  }
655
358
  }
656
- // Now check onUpdate for host callback
657
359
  if (!onUpdate)
658
360
  return;
659
361
  const signature = text +
@@ -678,15 +380,12 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
678
380
  }
679
381
  catch (err) {
680
382
  if (err instanceof Error && err.message.includes("outside active run")) {
681
- // Agent listener invoked from async callback (child stdout handler)
682
- // after the active run context ended. Safe to drop this update.
683
383
  return;
684
384
  }
685
385
  throw err;
686
386
  }
687
387
  };
688
388
  emitProgress();
689
- // Execute all flows
690
389
  const executionStart = Date.now();
691
390
  const regularPromise = regularParams.length > 0
692
391
  ? mapFlowConcurrent(regularParams, maxConcurrency, async (item, localIndex) => {
@@ -697,19 +396,14 @@ export async function executeFlows(deps, params, toolCallId, auditLoop) {
697
396
  const groupPromises = groups.map((group) => executeGroupedPingPong(deps, group, allResults, toolCallId, emitProgress, selectedFlowModelConfig));
698
397
  await Promise.all([regularPromise, ...groupPromises]);
699
398
  const results = [...allResults];
700
- // Record last flow completion for dynamic notifications
701
399
  const lastResult = results[results.length - 1];
702
400
  if (lastResult) {
703
401
  setFlowComplete(lastResult.type, lastResult.acceptance, results.length - 1, results.length);
704
402
  }
705
- // Mark flow completion for the continuation hold — gives the user
706
- // time to read the result before the next flow auto-spawns.
707
403
  markFlowCompleted(deps.sessionManager.getSessionId());
708
- // Goal continuation callback
709
404
  if (deps.goalContinuationCallback) {
710
405
  await deps.goalContinuationCallback(results);
711
406
  }
712
- // Build tool result
713
407
  const successCount = results.filter((r) => isFlowSuccess(r)).length;
714
408
  const flowReports = results.map((r) => {
715
409
  const output = getFlowSummaryText(r);