@selesai/code 0.8.6 → 0.8.7

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 (192) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/core/agent-session.js +13 -1
  3. package/dist/core/extensions/types.d.ts +2 -0
  4. package/dist/core/provider-composer.js +17 -4
  5. package/dist/core/settings-manager.d.ts +2 -0
  6. package/dist/core/settings-manager.js +3 -0
  7. package/dist/core/system-prompt.js +2 -8
  8. package/dist/core/system-prompt.test.js +6 -0
  9. package/dist/core/tools/index.d.ts +1 -0
  10. package/dist/core/tools/index.js +1 -0
  11. package/dist/core/tools/schema-prune.d.ts +16 -0
  12. package/dist/core/tools/schema-prune.js +39 -0
  13. package/dist/core/tools/schema-prune.test.d.ts +1 -0
  14. package/dist/core/tools/schema-prune.test.js +111 -0
  15. package/dist/defaults/settings.json +1 -0
  16. package/dist/extensions/model-prompt-injector/config.json +10 -0
  17. package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
  18. package/dist/extensions/model-prompt-injector/index.ts +151 -0
  19. package/dist/extensions/package.json +1 -0
  20. package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
  21. package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
  22. package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
  23. package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
  24. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  25. package/dist/extensions/pi-subagents/agents/worker.md +1 -1
  26. package/dist/extensions/pi-subagents/docs/configuration.md +78 -19
  27. package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
  28. package/dist/extensions/pi-subagents/docs/missions.md +5 -3
  29. package/dist/extensions/pi-subagents/docs/models.md +1 -1
  30. package/dist/extensions/pi-subagents/docs/observability.md +42 -2
  31. package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
  32. package/dist/extensions/pi-subagents/docs/workflows.md +5 -5
  33. package/dist/extensions/pi-subagents/install.mjs +2 -2
  34. package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
  35. package/dist/extensions/pi-subagents/package.json +1 -1
  36. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
  37. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
  38. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +15 -14
  39. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
  40. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
  41. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  42. package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
  43. package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
  44. package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
  45. package/dist/extensions/pi-subagents/src/extension/config.ts +53 -0
  46. package/dist/extensions/pi-subagents/src/extension/index.ts +67 -13
  47. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
  48. package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
  49. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
  50. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
  51. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
  52. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
  53. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
  54. package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
  55. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
  56. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
  57. package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
  58. package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
  59. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
  60. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
  61. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
  62. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +5 -0
  63. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
  64. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
  65. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +8 -3
  66. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
  67. package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
  68. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
  69. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
  70. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +205 -41
  71. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
  72. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
  73. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +30 -24
  74. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +101 -4
  75. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
  76. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
  77. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
  78. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
  79. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
  80. package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
  81. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
  82. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
  83. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
  84. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +333 -45
  85. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
  86. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
  88. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
  89. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
  90. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
  92. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
  95. package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
  96. package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
  97. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
  98. package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
  99. package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
  100. package/dist/extensions/pi-subagents/src/shared/types.ts +50 -4
  101. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
  102. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
  103. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
  104. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
  105. package/dist/extensions/pi-subagents/src/tui/fleet.ts +128 -16
  106. package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
  107. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
  108. package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
  109. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
  110. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
  111. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
  112. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
  113. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
  114. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
  115. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
  116. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
  117. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  118. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
  119. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
  120. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
  121. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +369 -98
  122. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
  123. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
  124. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
  125. package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
  126. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
  127. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
  128. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
  129. package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
  130. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
  131. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
  132. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
  133. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
  134. package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
  135. package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
  136. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
  137. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
  138. package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
  139. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
  140. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +69 -0
  141. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
  142. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
  143. package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
  144. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  145. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
  146. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
  147. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
  148. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
  149. package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
  150. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
  151. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
  152. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
  153. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
  154. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
  155. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
  156. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
  157. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
  158. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
  159. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
  160. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
  161. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
  162. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
  163. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
  164. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
  165. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
  166. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
  167. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
  168. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
  169. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
  170. package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
  171. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
  172. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
  173. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
  174. package/dist/extensions/question/index.ts +21 -6
  175. package/dist/extensions/question/question-list.ts +7 -1
  176. package/dist/extensions/question/row-layout.ts +3 -0
  177. package/dist/extensions/question/tests/exp.test.ts +70 -0
  178. package/dist/extensions/question/tests/exp2.test.ts +59 -0
  179. package/dist/extensions/question/tests/exp3.test.ts +47 -0
  180. package/dist/extensions/question/tests/helpers.test.ts +7 -0
  181. package/dist/extensions/question/tests/question-list.test.ts +140 -0
  182. package/dist/extensions/question/tests/row-layout.test.ts +13 -0
  183. package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
  184. package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
  185. package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
  186. package/dist/skills/pi-subagents/SKILL.md +1 -1
  187. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
  188. package/dist/skills/pi-subagents/references/execution-controls.md +15 -14
  189. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
  190. package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
  191. package/docs/settings.md +6 -0
  192. package/package.json +3 -3
@@ -15,6 +15,7 @@ import {
15
15
  type NestedRunSummary,
16
16
  type NestedStepSummary,
17
17
  type WorkflowNodeStatus,
18
+ type MainWindowRendererConfig,
18
19
  MAX_WIDGET_JOBS,
19
20
  POLL_INTERVAL_MS,
20
21
  WIDGET_KEY,
@@ -27,9 +28,42 @@ import { formatNestedAggregate } from "../runs/shared/nested-render.ts";
27
28
  import { aggregateStepStatus, formatActivityLabel, formatAgentRunningLabel, formatParallelOutcome } from "../shared/status-format.ts";
28
29
  import { contextModeBadge, contextModePrefix } from "../runs/shared/context-mode.ts";
29
30
  import { buildWorkflowChatProgressRows, type WorkflowChatProgressRow } from "../workflows/chat-progress.ts";
31
+ import { encodeAsyncStatusSnapshotWidget } from "../runs/background/async-status-snapshot.ts";
30
32
 
31
33
  type Theme = ExtensionContext["ui"]["theme"];
32
34
 
35
+ interface MainWindowRenderLayout {
36
+ horizontalSpacing: number;
37
+ compactResultMaxLines?: number;
38
+ }
39
+
40
+ function resolveMainWindowRenderLayout(config?: MainWindowRendererConfig): MainWindowRenderLayout {
41
+ return {
42
+ horizontalSpacing: config?.horizontalSpacing ?? 2,
43
+ ...(config?.compactResultMaxLines !== undefined ? { compactResultMaxLines: config.compactResultMaxLines } : {}),
44
+ };
45
+ }
46
+
47
+ function mainWindowIndent(layout: MainWindowRenderLayout, level: number): string {
48
+ return " ".repeat(Math.max(0, layout.horizontalSpacing * level));
49
+ }
50
+
51
+ function capCompactMainWindowResult(component: Component, layout: MainWindowRenderLayout, theme: Theme, enabled: boolean): Component {
52
+ const maxLines = layout.compactResultMaxLines;
53
+ if (!enabled || maxLines === undefined) return component;
54
+ const capped = new Container();
55
+ capped.render = (width: number): string[] => {
56
+ const lines = component.render(width);
57
+ if (lines.length <= maxLines) return lines;
58
+ const visibleRows = maxLines === 1 ? 1 : maxLines - 1;
59
+ const hiddenCount = lines.length - visibleRows;
60
+ const hint = theme.fg("accent", `… ${hiddenCount} rows hidden · ${liveDetailKeyText()} expands`);
61
+ if (maxLines === 1) return [truncLine(`${lines[0] ?? ""} ${hint}`, width)];
62
+ return [...lines.slice(0, visibleRows), truncLine(hint, width)];
63
+ };
64
+ return capped;
65
+ }
66
+
33
67
  function liveDetailKeyText(): string {
34
68
  return keyText("app.tools.expand");
35
69
  }
@@ -38,6 +72,22 @@ function liveDetailHintText(): string {
38
72
  return `Press ${liveDetailKeyText()} for live detail`;
39
73
  }
40
74
 
75
+ function foregroundSingleHintText(shortcut?: string): string {
76
+ if (!shortcut) return liveDetailHintText();
77
+ const label = shortcut
78
+ .split("+")
79
+ .map((part) => {
80
+ const normalized = part.trim().toLowerCase();
81
+ if (normalized === "ctrl") return "Ctrl";
82
+ if (normalized === "alt") return "Alt";
83
+ if (normalized === "shift") return "Shift";
84
+ if (normalized === "super") return "Super";
85
+ return normalized.length === 1 ? normalized.toUpperCase() : part.trim();
86
+ })
87
+ .join("+");
88
+ return `${liveDetailHintText()} · ${label} to run in background`;
89
+ }
90
+
41
91
  function getTermWidth(): number {
42
92
  return process.stdout.columns || 120;
43
93
  }
@@ -308,7 +358,7 @@ function visibleWorkflowRows(rows: WorkflowChatProgressRow[]): { rows: WorkflowC
308
358
  selected.add(row.key);
309
359
  };
310
360
  for (const row of [...rows].reverse()) {
311
- if (row.state === "failed") add(row);
361
+ if (row.state === "failed" || row.state === "detached") add(row);
312
362
  }
313
363
  for (const row of [...rows].reverse()) add(row);
314
364
  return {
@@ -1552,10 +1602,21 @@ export function renderWidget(ctx: ExtensionContext, jobs: AsyncJobState[]): void
1552
1602
  return;
1553
1603
  }
1554
1604
  if (!ctx.hasUI) return;
1605
+ if ((ctx as { mode?: string }).mode === "rpc") {
1606
+ ctx.ui.setWidget(WIDGET_KEY, encodeAsyncStatusSnapshotWidget(jobs));
1607
+ return;
1608
+ }
1555
1609
  ctx.ui.setWidget(WIDGET_KEY, buildWidgetComponent(jobs, ctx.ui.getToolsExpanded?.() ?? false));
1556
1610
  }
1557
1611
 
1558
- function renderSingleCompact(d: Details, r: Details["results"][number], theme: Theme, frame?: number): Component {
1612
+ function renderSingleCompact(
1613
+ d: Details,
1614
+ r: Details["results"][number],
1615
+ theme: Theme,
1616
+ layout: MainWindowRenderLayout,
1617
+ frame?: number,
1618
+ foregroundDetachShortcut?: string,
1619
+ ): Component {
1559
1620
  const output = r.truncation?.text || getSingleResultOutput(r);
1560
1621
  const progress = r.progress || r.progressSummary;
1561
1622
  const isRunning = isResultRunning(r);
@@ -1566,40 +1627,43 @@ function renderSingleCompact(d: Details, r: Details["results"][number], theme: T
1566
1627
  ]);
1567
1628
  const c = new Container();
1568
1629
  const width = getTermWidth() - 4;
1630
+ const detailIndent = mainWindowIndent(layout, 1);
1631
+ const continuationIndent = mainWindowIndent(layout, 2) + (layout.horizontalSpacing > 0 ? " " : "");
1569
1632
  const modelDisplay = modelThinkingBadge(theme, r.model ?? r.progress?.model, r.thinking ?? r.progress?.thinking);
1570
1633
  c.addChild(new Text(truncLine(`${resultGlyph(r, output, theme, isRunning, undefined, frame)} ${theme.fg("toolTitle", theme.bold(r.agent))}${modelDisplay}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
1571
1634
 
1572
1635
  if (isRunning && r.progress) {
1573
1636
  const progressSnapshotNow = snapshotNowForProgress(r.progress);
1574
1637
  const activity = compactCurrentActivity(r.progress);
1575
- c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${activity}`), width), 0, 0));
1638
+ c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}⎿ ${activity}`), width), 0, 0));
1576
1639
  const liveStatus = buildLiveStatusLine(r.progress, progressSnapshotNow);
1577
- if (liveStatus && liveStatus !== activity) c.addChild(new Text(truncLine(theme.fg("dim", ` ${liveStatus}`), width), 0, 0));
1640
+ if (liveStatus && liveStatus !== activity) c.addChild(new Text(truncLine(theme.fg("dim", `${continuationIndent}${liveStatus}`), width), 0, 0));
1578
1641
  for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, progressSnapshotNow)) {
1579
- c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1642
+ c.addChild(new Text(truncLine(`${detailIndent}${nestedLine}`, width), 0, 0));
1580
1643
  }
1581
- c.addChild(new Text(truncLine(theme.fg("accent", ` ${liveDetailHintText()}`), width), 0, 0));
1582
- if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1644
+ c.addChild(new Text(truncLine(theme.fg("accent", `${detailIndent}${foregroundSingleHintText(foregroundDetachShortcut)}`), width), 0, 0));
1645
+ if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1583
1646
  return c;
1584
1647
  }
1585
1648
 
1586
1649
  for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, r.progress?.lastActivityAt)) {
1587
- c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1650
+ c.addChild(new Text(truncLine(`${detailIndent}${nestedLine}`, width), 0, 0));
1588
1651
  }
1589
- c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
1652
+ c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
1590
1653
  const preview = firstOutputLine(output);
1591
1654
  if (preview && r.exitCode === 0 && !hasEmptyTextOutputWithoutOutputTarget(r.task, output)) {
1592
- c.addChild(new Text(truncLine(theme.fg("dim", ` ${preview}`), width), 0, 0));
1655
+ c.addChild(new Text(truncLine(theme.fg("dim", `${continuationIndent}${preview}`), width), 0, 0));
1593
1656
  }
1594
- if (r.sessionFile) c.addChild(new Text(truncLine(theme.fg("dim", ` session: ${shortenPath(r.sessionFile)}`), width), 0, 0));
1595
- if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1596
- if (r.truncation?.artifactPath) c.addChild(new Text(truncLine(theme.fg("dim", ` full output: ${shortenPath(r.truncation.artifactPath)}`), width), 0, 0));
1657
+ if (r.sessionFile) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}session: ${shortenPath(r.sessionFile)}`), width), 0, 0));
1658
+ if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1659
+ if (r.truncation?.artifactPath) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}full output: ${shortenPath(r.truncation.artifactPath)}`), width), 0, 0));
1597
1660
  return c;
1598
1661
  }
1599
1662
 
1600
1663
  function workflowRowGlyph(row: WorkflowChatProgressRow, theme: Theme, frame?: number): string {
1601
1664
  if (row.state === "running") return theme.fg("accent", runningGlyph(frame));
1602
1665
  if (row.state === "complete") return theme.fg("success", "✓");
1666
+ if (row.state === "detached" || row.state === "stopped") return theme.fg("warning", "■");
1603
1667
  return theme.fg("error", "✗");
1604
1668
  }
1605
1669
 
@@ -1607,47 +1671,50 @@ function workflowRowStateLabel(row: WorkflowChatProgressRow, theme: Theme): stri
1607
1671
  const label = (row.state === "complete" ? "complete" : row.state).padEnd(8);
1608
1672
  if (row.state === "running") return theme.fg("accent", label);
1609
1673
  if (row.state === "complete") return theme.fg("success", label);
1674
+ if (row.state === "detached" || row.state === "stopped") return theme.fg("warning", label);
1610
1675
  return theme.fg("error", label);
1611
1676
  }
1612
1677
 
1613
- function workflowOverallState(rows: WorkflowChatProgressRow[], hasTerminalValue: boolean, isError?: boolean): "running" | "complete" | "failed" {
1678
+ function workflowOverallState(rows: WorkflowChatProgressRow[], hasTerminalValue: boolean, isError?: boolean): "running" | "complete" | "failed" | "paused" {
1614
1679
  if (isError || rows.some((row) => row.state === "failed")) return "failed";
1680
+ if (rows.some((row) => row.state === "detached")) return "paused";
1615
1681
  if ((rows.length > 0 && rows.every((row) => row.state === "complete")) || hasTerminalValue) return "complete";
1616
1682
  return "running";
1617
1683
  }
1618
1684
 
1619
- function renderWorkflowChatProgress(d: Details, result: AgentToolResult<Details>, theme: Theme, frame?: number): Component {
1685
+ function renderWorkflowChatProgress(d: Details, result: AgentToolResult<Details>, theme: Theme, layout: MainWindowRenderLayout, frame?: number): Component {
1620
1686
  const workflow = d.workflow;
1621
1687
  const rows = workflow ? buildWorkflowChatProgressRows(workflow.trace) : [];
1622
1688
  const state = workflowOverallState(rows, workflow?.value !== undefined, result.isError);
1623
- const glyph = state === "running" ? theme.fg("accent", runningGlyph(frame)) : state === "complete" ? theme.fg("success", "✓") : theme.fg("error", "✗");
1689
+ const glyph = state === "running" ? theme.fg("accent", runningGlyph(frame)) : state === "complete" ? theme.fg("success", "✓") : state === "paused" ? theme.fg("warning", "■") : theme.fg("error", "✗");
1624
1690
  const width = getTermWidth() - 4;
1625
1691
  const runId = d.runId ? d.runId.slice(0, 12) : "workflow";
1626
1692
  const repoLabel = d.chatProgress?.repoLabel ?? (d.chatProgress?.repoRelation === "same" ? "same repo" : "other repo");
1627
1693
  const phase = rows.find((row) => row.state === "running" && row.phase)?.phase ?? [...rows].reverse().find((row) => row.phase)?.phase;
1628
1694
  const c = new Container();
1695
+ const rowIndent = mainWindowIndent(layout, 1);
1629
1696
  c.addChild(new Text(truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold("workflow"))} ${runId} ${theme.fg("dim", "·")} ${d.chatProgress?.repoRelation === "same" ? "same repo" : "other repo"} ${theme.fg("dim", "·")} ${state}`, width), 0, 0));
1630
- c.addChild(new Text(truncLine(theme.fg("dim", ` Repo ${repoLabel}`), width), 0, 0));
1631
- if (phase) c.addChild(new Text(truncLine(theme.fg("dim", ` Phase ${phase}`), width), 0, 0));
1697
+ c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}Repo ${repoLabel}`), width), 0, 0));
1698
+ if (phase) c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}Phase ${phase}`), width), 0, 0));
1632
1699
  if (rows.length === 0) {
1633
- c.addChild(new Text(truncLine(theme.fg("dim", " ◦ waiting for workflow child launches"), width), 0, 0));
1700
+ c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}◦ waiting for workflow child launches`), width), 0, 0));
1634
1701
  return c;
1635
1702
  }
1636
1703
  const visible = visibleWorkflowRows(rows);
1637
- if (visible.hiddenRows > 0) c.addChild(new Text(truncLine(theme.fg("dim", ` … ${visible.hiddenRows} older workflow rows hidden`), width), 0, 0));
1704
+ if (visible.hiddenRows > 0) c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}… ${visible.hiddenRows} older workflow rows hidden`), width), 0, 0));
1638
1705
  for (const row of visible.rows) {
1639
1706
  const status = workflowRowStateLabel(row, theme);
1640
1707
  const label = row.label && row.label !== row.key ? ` ${oneLine(row.label)}` : "";
1641
1708
  const duration = row.durationMs !== undefined ? ` ${theme.fg("dim", `· ${formatDuration(row.durationMs)}`)}` : "";
1642
1709
  const run = row.runId ? ` ${theme.fg("dim", `[${row.runId.slice(0, 8)}]`)}` : "";
1643
- const error = row.error ? ` ${theme.fg("error", `· ${compactWorkflowError(row.error)}`)}` : "";
1644
- c.addChild(new Text(truncLine(` ${workflowRowGlyph(row, theme, frame)} ${status} ${theme.bold(row.key)}${label}${run}${duration}${error}`, width), 0, 0));
1710
+ const error = row.error ? ` ${theme.fg(row.state === "detached" ? "warning" : "error", `· ${compactWorkflowError(row.error)}`)}` : "";
1711
+ c.addChild(new Text(truncLine(`${rowIndent}${workflowRowGlyph(row, theme, frame)} ${status} ${theme.bold(row.key)}${label}${run}${duration}${error}`, width), 0, 0));
1645
1712
  }
1646
- if (workflow?.emits.length) c.addChild(new Text(truncLine(theme.fg("dim", ` Emits ${workflow.emits.length}`), width), 0, 0));
1713
+ if (workflow?.emits.length) c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}Emits ${workflow.emits.length}`), width), 0, 0));
1647
1714
  return c;
1648
1715
  }
1649
1716
 
1650
- function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component {
1717
+ function renderMultiCompact(d: Details, theme: Theme, layout: MainWindowRenderLayout, frame?: number): Component {
1651
1718
  const hasRunning = detailsHaveRunningResult(d);
1652
1719
  const detached = d.results.some((r) => r.detached)
1653
1720
  || workflowGraphHasStatus(d, ["detached"]);
@@ -1687,6 +1754,9 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1687
1754
  const contextBadge = contextModeBadge(theme, d.context);
1688
1755
  const c = new Container();
1689
1756
  const width = getTermWidth() - 4;
1757
+ const rowIndent = mainWindowIndent(layout, 1);
1758
+ const detailIndent = mainWindowIndent(layout, 2);
1759
+ const continuationIndent = mainWindowIndent(layout, 3) + (layout.horizontalSpacing > 0 ? " " : "");
1690
1760
  c.addChild(new Text(truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold(d.mode))}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
1691
1761
 
1692
1762
  const useResultsDirectly = multiLabel.hasParallelInChain || !d.chainAgents?.length;
@@ -1704,8 +1774,8 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1704
1774
  if (entry.kind === "placeholder") {
1705
1775
  const glyph = widgetStepGlyph(entry.status as AsyncJobStep["status"], theme);
1706
1776
  const statusLabel = widgetStepStatus(entry.status as AsyncJobStep["status"], theme);
1707
- c.addChild(new Text(truncLine(` ${glyph} ${entry.stepLabel}: ${themeBold(theme, entry.agentName)} ${theme.fg("dim", "·")} ${statusLabel}`, width), 0, 0));
1708
- if (entry.error) c.addChild(new Text(truncLine(theme.fg("error", ` ⎿ Error: ${entry.error}`), width), 0, 0));
1777
+ c.addChild(new Text(truncLine(`${rowIndent}${glyph} ${entry.stepLabel}: ${themeBold(theme, entry.agentName)} ${theme.fg("dim", "·")} ${statusLabel}`, width), 0, 0));
1778
+ if (entry.error) c.addChild(new Text(truncLine(theme.fg("error", `${detailIndent}⎿ Error: ${entry.error}`), width), 0, 0));
1709
1779
  continue;
1710
1780
  }
1711
1781
  const i = entry.resultIndex;
@@ -1714,7 +1784,7 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1714
1784
  const agentName = entry.agentName;
1715
1785
  if (!r) {
1716
1786
  const pendingLabel = entry.rowLabel ?? `${itemTitle} ${rowNumber}`;
1717
- c.addChild(new Text(truncLine(theme.fg("dim", ` ◦ ${pendingLabel}: ${agentName} · pending`), width), 0, 0));
1787
+ c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}◦ ${pendingLabel}: ${agentName} · pending`), width), 0, 0));
1718
1788
  continue;
1719
1789
  }
1720
1790
  const output = getSingleResultOutput(r);
@@ -1730,28 +1800,28 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1730
1800
  const rowProgressModel = rProg && "status" in rProg ? rProg : undefined;
1731
1801
  const rowModelDisplay = modelThinkingBadge(theme, r.model ?? rowProgressModel?.model, r.thinking ?? rowProgressModel?.thinking);
1732
1802
  const line = `${glyph} ${stepLabel}: ${themeBold(theme, agentName)}${contextModeBadge(theme, r.context)}${rowModelDisplay}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}${pendingLabel}`;
1733
- c.addChild(new Text(truncLine(` ${line}`, width), 0, 0));
1803
+ c.addChild(new Text(truncLine(`${rowIndent}${line}`, width), 0, 0));
1734
1804
  if (rRunning && rProg && "status" in rProg) {
1735
1805
  const liveProgress = rProg as AgentProgress;
1736
1806
  const activity = compactCurrentActivity(liveProgress);
1737
- c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${activity}`), width), 0, 0));
1807
+ c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}⎿ ${activity}`), width), 0, 0));
1738
1808
  for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, snapshotNowForProgress(liveProgress))) {
1739
- c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1809
+ c.addChild(new Text(truncLine(`${detailIndent}${nestedLine}`, width), 0, 0));
1740
1810
  }
1741
- c.addChild(new Text(truncLine(theme.fg("accent", ` ${liveDetailHintText()}`), width), 0, 0));
1811
+ c.addChild(new Text(truncLine(theme.fg("accent", `${detailIndent}${liveDetailHintText()}`), width), 0, 0));
1742
1812
  } else if (!rPending && (r.exitCode !== 0 || r.interrupted || r.detached || hasEmptyTextOutputWithoutOutputTarget(r.task, output))) {
1743
- c.addChild(new Text(truncLine(theme.fg(r.exitCode !== 0 ? "error" : "dim", ` ⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
1813
+ c.addChild(new Text(truncLine(theme.fg(r.exitCode !== 0 ? "error" : "dim", `${detailIndent}⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
1744
1814
  }
1745
1815
  if (!rRunning && !rPending) {
1746
1816
  for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, r.progress?.lastActivityAt)) {
1747
- c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1817
+ c.addChild(new Text(truncLine(`${detailIndent}${nestedLine}`, width), 0, 0));
1748
1818
  }
1749
1819
  }
1750
1820
  const outputTarget = extractOutputTarget(r.task);
1751
- if (outputTarget) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${outputTarget}`), width), 0, 0));
1752
- if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1821
+ if (outputTarget) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}output: ${outputTarget}`), width), 0, 0));
1822
+ if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1753
1823
  }
1754
- if (d.artifacts) c.addChild(new Text(truncLine(theme.fg("dim", ` artifacts: ${shortenPath(d.artifacts.dir)}`), width), 0, 0));
1824
+ if (d.artifacts) c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}artifacts: ${shortenPath(d.artifacts.dir)}`), width), 0, 0));
1755
1825
  return c;
1756
1826
  }
1757
1827
 
@@ -1802,22 +1872,29 @@ export function renderSubagentResult(
1802
1872
  options: { expanded: boolean },
1803
1873
  theme: Theme,
1804
1874
  frame?: number,
1875
+ rendererConfig?: MainWindowRendererConfig,
1876
+ foregroundDetachShortcut?: string,
1805
1877
  ): Component {
1878
+ const layout = resolveMainWindowRenderLayout(rendererConfig);
1879
+ const compact = (component: Component): Component => capCompactMainWindowResult(component, layout, theme, !options.expanded);
1806
1880
  const d = result.details;
1807
- if (d?.mode === "workflow" && d.chatProgress?.mode === "live-card" && !result.isError && d.workflow?.value === undefined) return renderWorkflowChatProgress(d, result, theme, frame);
1881
+ if (d?.mode === "workflow" && d.chatProgress?.mode === "live-card" && !result.isError && d.workflow?.value === undefined) {
1882
+ return compact(renderWorkflowChatProgress(d, result, theme, options.expanded ? resolveMainWindowRenderLayout() : layout, frame));
1883
+ }
1808
1884
  if (!d || !d.results.length) {
1809
1885
  const t = result.content[0];
1810
1886
  const text = t?.type === "text" ? t.text : "(no output)";
1811
1887
  const contextPrefix = contextModePrefix(theme, d?.context);
1812
1888
  const width = getTermWidth() - 4;
1813
- if (!text.includes("\n")) return new Text(truncLine(`${contextPrefix}${text}`, width), 0, 0);
1889
+ if (!text.includes("\n")) return compact(new Text(truncLine(`${contextPrefix}${text}`, width), 0, 0));
1814
1890
  if (d && !options.expanded && !result.isError) {
1815
1891
  const lines = text.split(/\r?\n/);
1816
1892
  const firstNonEmptyLine = lines.find((line) => line.trim())?.trim() || "(no output)";
1817
1893
  const c = new Container();
1894
+ const detailIndent = mainWindowIndent(layout, 1);
1818
1895
  c.addChild(new Text(truncLine(`${contextPrefix}${firstNonEmptyLine} · ${lines.length} lines`, width), 0, 0));
1819
- c.addChild(new Text(truncLine(theme.fg("accent", ` Press ${liveDetailKeyText()} for full output`), width), 0, 0));
1820
- return c;
1896
+ c.addChild(new Text(truncLine(theme.fg("accent", `${detailIndent}Press ${liveDetailKeyText()} for full output`), width), 0, 0));
1897
+ return compact(c);
1821
1898
  }
1822
1899
  const c = new Container();
1823
1900
  const wrapped = wrapPlainText(`${contextPrefix}${text}`, width);
@@ -1830,8 +1907,9 @@ export function renderSubagentResult(
1830
1907
 
1831
1908
  if (d.mode === "single" && d.results.length === 1) {
1832
1909
  const r = d.results[0];
1833
- if (!r) return renderMultiCompact(d, theme, frame);
1834
- if (!expanded) return renderSingleCompact(d, r, theme, frame);
1910
+ const detachableShortcut = d.asyncId || d.background ? undefined : foregroundDetachShortcut;
1911
+ if (!r) return compact(renderMultiCompact(d, theme, layout, frame));
1912
+ if (!expanded) return compact(renderSingleCompact(d, r, theme, layout, frame, detachableShortcut));
1835
1913
  const isRunning = isResultRunning(r);
1836
1914
  const contextBadge = contextModeBadge(theme, r.context ?? d.context);
1837
1915
  const output = r.truncation?.text || getSingleResultOutput(r);
@@ -1871,7 +1949,7 @@ export function renderSubagentResult(
1871
1949
  if (liveStatusLine) {
1872
1950
  c.addChild(new Text(fit(theme.fg("accent", liveStatusLine)), 0, 0));
1873
1951
  }
1874
- c.addChild(new Text(fit(theme.fg("accent", liveDetailHintText())), 0, 0));
1952
+ c.addChild(new Text(fit(theme.fg("accent", foregroundSingleHintText(detachableShortcut))), 0, 0));
1875
1953
  if (r.artifactPaths) {
1876
1954
  c.addChild(new Text(fit(theme.fg("dim", `Artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
1877
1955
  }
@@ -1924,7 +2002,7 @@ export function renderSubagentResult(
1924
2002
  return c;
1925
2003
  }
1926
2004
 
1927
- if (!expanded) return renderMultiCompact(d, theme, frame);
2005
+ if (!expanded) return compact(renderMultiCompact(d, theme, layout, frame));
1928
2006
 
1929
2007
  const hasRunning = detailsHaveRunningResult(d);
1930
2008
  const detached = d.results.some((r) => r.detached)
@@ -3,6 +3,7 @@ import { convertToLlm, type ExtensionContext } from "@selesai/code";
3
3
  import { streamSimple } from "@earendil-works/pi-ai/compat";
4
4
  import { Type, type Static } from "typebox";
5
5
  import { appendPermissionAudit, permissionArgsPreview } from "../runs/shared/permissions.ts";
6
+ import { agentStreamOptions } from "../shared/agent-stream-options.ts";
6
7
  import { decodeChildWatchdogConfig } from "./child-status.ts";
7
8
  import { childResolvedConfig } from "./register-child.ts";
8
9
  import { resolveWatchdogReviewModel } from "./review.ts";
@@ -112,7 +113,7 @@ export function createWatchdogPermissionArbiter(options: WatchdogPermissionArbit
112
113
  tools: [tool],
113
114
  },
114
115
  convertToLlm,
115
- streamFn,
116
+ ...agentStreamOptions(streamFn),
116
117
  getApiKey: (providerName) => providerName === selection.model.provider ? auth.apiKey : undefined,
117
118
  beforeToolCall: async ({ toolCall }) => toolCall.name === tool.name ? undefined : { block: true, reason: `Permission arbiter tool '${toolCall.name}' is not allowed.` },
118
119
  toolExecution: "sequential",
@@ -1,9 +1,10 @@
1
1
  import { Agent, type AgentTool, type StreamFn, type ThinkingLevel } from "@earendil-works/pi-agent-core";
2
2
  import { createReadOnlyTools, convertToLlm, type ExtensionContext } from "@selesai/code";
3
3
  import { streamSimple } from "@earendil-works/pi-ai/compat";
4
- import type { Model } from "@earendil-works/pi-ai";
4
+ import type { Model, ProviderHeaders } from "@earendil-works/pi-ai";
5
5
  import { Type, type Static } from "typebox";
6
6
  import { resolveModelCandidate } from "../runs/shared/model-fallback.ts";
7
+ import { agentStreamOptions } from "../shared/agent-stream-options.ts";
7
8
  import { resolveEffectiveThinking, splitKnownThinkingSuffix, THINKING_LEVELS, toModelInfo } from "../shared/model-info.ts";
8
9
  import type { WatchdogReviewFunction, WatchdogReviewRequest } from "./runtime.ts";
9
10
  import {
@@ -36,7 +37,7 @@ type RegistryModel = Model<any>;
36
37
 
37
38
  interface WatchdogReviewAuth {
38
39
  apiKey?: string;
39
- headers?: Record<string, string>;
40
+ headers?: ProviderHeaders;
40
41
  env?: Record<string, string>;
41
42
  }
42
43
 
@@ -280,7 +281,7 @@ export function createMainWatchdogReview(provider: WatchdogContextProvider, opti
280
281
  tools,
281
282
  },
282
283
  convertToLlm,
283
- streamFn,
284
+ ...agentStreamOptions(streamFn),
284
285
  getApiKey: (providerName) => providerName === selection.model.provider ? auth.apiKey : undefined,
285
286
  beforeToolCall: async ({ toolCall }) => WATCHDOG_ALLOWED_TOOL_NAMES.has(toolCall.name)
286
287
  ? undefined
@@ -96,7 +96,7 @@ export function resolveWorkflowChatProgress(input: ResolveWorkflowChatProgressIn
96
96
 
97
97
  export interface WorkflowChatProgressRow {
98
98
  key: string;
99
- state: "running" | "complete" | "failed";
99
+ state: "running" | "complete" | "failed" | "detached" | "stopped";
100
100
  label?: string;
101
101
  phase?: string;
102
102
  runId?: string;
@@ -123,7 +123,15 @@ export function buildWorkflowChatProgressRows(trace: NonNullable<Details["workfl
123
123
  continue;
124
124
  }
125
125
  const next: WorkflowChatProgressRow = existing ?? { key: entry.key, state: "running" };
126
- next.state = entry.state === "completed" ? "complete" : entry.state === "failed" ? "failed" : "running";
126
+ next.state = entry.state === "completed"
127
+ ? "complete"
128
+ : entry.state === "failed"
129
+ ? "failed"
130
+ : entry.state === "detached"
131
+ ? "detached"
132
+ : entry.state === "stopped"
133
+ ? "stopped"
134
+ : "running";
127
135
  const label = cleanLabel(entry.label);
128
136
  const phase = cleanLabel(entry.phase);
129
137
  if (label) next.label = label;