@selesai/code 0.8.6 → 0.8.8

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 (234) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.js +11 -0
  4. package/dist/cli/args.test.d.ts +1 -0
  5. package/dist/cli/args.test.js +24 -0
  6. package/dist/core/agent-session.d.ts +4 -1
  7. package/dist/core/agent-session.js +18 -7
  8. package/dist/core/experimental.d.ts +4 -0
  9. package/dist/core/experimental.js +4 -0
  10. package/dist/core/extensions/types.d.ts +6 -0
  11. package/dist/core/keybindings.d.ts +24 -0
  12. package/dist/core/model-config.d.ts +5 -0
  13. package/dist/core/model-config.js +1 -0
  14. package/dist/core/project-trust.js +2 -2
  15. package/dist/core/provider-composer.js +17 -4
  16. package/dist/core/sdk.d.ts +5 -3
  17. package/dist/core/sdk.js +2 -1
  18. package/dist/core/session-manager.js +2 -2
  19. package/dist/core/settings-manager.d.ts +8 -0
  20. package/dist/core/settings-manager.js +15 -0
  21. package/dist/core/system-prompt.js +3 -9
  22. package/dist/core/system-prompt.test.js +6 -0
  23. package/dist/core/tools/bash.js +2 -0
  24. package/dist/core/tools/edit.js +2 -0
  25. package/dist/core/tools/find.js +1 -1
  26. package/dist/core/tools/grep.js +1 -1
  27. package/dist/core/tools/index.d.ts +1 -0
  28. package/dist/core/tools/index.js +1 -0
  29. package/dist/core/tools/read.js +2 -0
  30. package/dist/core/tools/schema-prune.d.ts +16 -0
  31. package/dist/core/tools/schema-prune.js +39 -0
  32. package/dist/core/tools/schema-prune.test.d.ts +1 -0
  33. package/dist/core/tools/schema-prune.test.js +111 -0
  34. package/dist/core/tools/write.js +2 -0
  35. package/dist/defaults/settings.json +1 -0
  36. package/dist/extensions/model-prompt-injector/config.json +10 -0
  37. package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
  38. package/dist/extensions/model-prompt-injector/index.ts +151 -0
  39. package/dist/extensions/package.json +1 -0
  40. package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
  41. package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
  42. package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
  43. package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
  44. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  45. package/dist/extensions/pi-subagents/agents/worker.md +1 -1
  46. package/dist/extensions/pi-subagents/docs/configuration.md +78 -19
  47. package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
  48. package/dist/extensions/pi-subagents/docs/missions.md +5 -3
  49. package/dist/extensions/pi-subagents/docs/models.md +1 -1
  50. package/dist/extensions/pi-subagents/docs/observability.md +42 -2
  51. package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
  52. package/dist/extensions/pi-subagents/docs/workflows.md +5 -5
  53. package/dist/extensions/pi-subagents/install.mjs +2 -2
  54. package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
  55. package/dist/extensions/pi-subagents/package.json +1 -1
  56. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
  57. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
  58. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +15 -14
  59. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
  60. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
  61. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  62. package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
  63. package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
  64. package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
  65. package/dist/extensions/pi-subagents/src/extension/config.ts +53 -0
  66. package/dist/extensions/pi-subagents/src/extension/index.ts +67 -13
  67. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
  68. package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
  69. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
  70. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
  71. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
  72. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
  73. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
  74. package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
  75. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
  76. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
  77. package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
  78. package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
  79. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
  80. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
  81. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
  82. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +5 -0
  83. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
  84. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
  85. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +8 -3
  86. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
  87. package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
  88. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
  89. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
  90. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +187 -41
  91. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
  92. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
  93. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +30 -24
  94. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +101 -4
  95. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
  96. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
  97. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
  98. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
  99. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
  100. package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
  101. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
  102. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
  103. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
  104. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +333 -45
  105. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
  106. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
  107. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
  108. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
  109. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
  110. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
  111. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
  112. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
  113. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
  114. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
  115. package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
  116. package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
  117. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
  118. package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
  119. package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
  120. package/dist/extensions/pi-subagents/src/shared/types.ts +50 -4
  121. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
  122. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +128 -16
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
  127. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
  128. package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
  129. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
  130. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
  131. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
  132. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
  133. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
  134. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
  135. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
  136. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
  137. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  138. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
  139. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
  140. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
  141. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +395 -98
  142. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
  143. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
  144. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
  145. package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
  146. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
  147. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
  148. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
  149. package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
  150. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
  151. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
  152. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
  153. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
  154. package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
  155. package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
  156. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
  157. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
  158. package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
  159. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
  160. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +69 -0
  161. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
  162. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
  163. package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
  164. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  165. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
  166. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
  167. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
  168. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
  169. package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
  170. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
  171. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
  172. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
  173. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
  175. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
  176. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
  177. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
  178. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
  179. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
  180. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
  181. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
  182. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
  183. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
  184. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
  185. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
  186. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
  187. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
  188. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
  189. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
  190. package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
  191. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
  192. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
  193. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
  194. package/dist/extensions/question/index.ts +21 -6
  195. package/dist/extensions/question/question-list.ts +7 -1
  196. package/dist/extensions/question/row-layout.ts +3 -0
  197. package/dist/extensions/question/tests/exp.test.ts +70 -0
  198. package/dist/extensions/question/tests/exp2.test.ts +59 -0
  199. package/dist/extensions/question/tests/exp3.test.ts +47 -0
  200. package/dist/extensions/question/tests/helpers.test.ts +7 -0
  201. package/dist/extensions/question/tests/question-list.test.ts +140 -0
  202. package/dist/extensions/question/tests/row-layout.test.ts +13 -0
  203. package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
  204. package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
  205. package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
  206. package/dist/extensions/tokenin-onboarding.ts +1 -1
  207. package/dist/index.d.ts +1 -1
  208. package/dist/main.js +4 -0
  209. package/dist/modes/interactive/components/model-selector.js +2 -1
  210. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  211. package/dist/modes/interactive/components/settings-selector.js +10 -0
  212. package/dist/modes/interactive/components/tool-execution.js +10 -1
  213. package/dist/modes/interactive/interactive-mode.d.ts +8 -2
  214. package/dist/modes/interactive/interactive-mode.js +81 -25
  215. package/dist/modes/interactive/model-catalog-refresh.d.ts +6 -0
  216. package/dist/modes/interactive/model-catalog-refresh.js +33 -0
  217. package/dist/modes/interactive/theme/dark.json +2 -0
  218. package/dist/modes/interactive/theme/light.json +2 -0
  219. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  220. package/dist/modes/interactive/theme/theme-controller.js +25 -11
  221. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  222. package/dist/modes/interactive/theme/theme.d.ts +5 -3
  223. package/dist/modes/interactive/theme/theme.js +12 -2
  224. package/dist/skills/pi-subagents/SKILL.md +1 -1
  225. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
  226. package/dist/skills/pi-subagents/references/execution-controls.md +15 -14
  227. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
  228. package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
  229. package/dist/utils/abort.d.ts +4 -0
  230. package/dist/utils/abort.js +47 -0
  231. package/dist/utils/tools-manager.d.ts +5 -1
  232. package/dist/utils/tools-manager.js +12 -21
  233. package/docs/settings.md +6 -0
  234. package/package.json +6 -6
@@ -162,6 +162,8 @@ interface ParallelChainRunInput {
162
162
  nestedRoute?: NestedRouteInfo;
163
163
  timeoutMs?: number;
164
164
  deadlineAt?: number;
165
+ callToolTimeoutMs?: number;
166
+ configToolTimeoutMs?: number;
165
167
  turnBudget?: ResolvedTurnBudget;
166
168
  usageBudget?: UsageBudgetConfig;
167
169
  onDetachedExit?: (index: number, result: SingleResult) => void;
@@ -436,6 +438,8 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
436
438
  onEffectivePrompt: input.foregroundControl ? (prompt) => updateLiveEffectivePrompt(input.foregroundControl!, childIndex, prompt) : undefined,
437
439
  timeoutMs: input.timeoutMs,
438
440
  deadlineAt: input.deadlineAt,
441
+ toolTimeoutMs: input.callToolTimeoutMs,
442
+ configToolTimeoutMs: input.configToolTimeoutMs,
439
443
  turnBudget: input.turnBudget,
440
444
  onDetachedExit: (result) => {
441
445
  try {
@@ -548,6 +552,12 @@ interface ChainExecutionParams {
548
552
  toolBudget?: ResolvedToolBudget;
549
553
  usageBudget?: UsageBudgetConfig;
550
554
  configToolBudget?: ToolBudgetConfig;
555
+ /** Optional per-call hard toolTimeoutMs override (highest precedence). */
556
+ callToolTimeoutMs?: number;
557
+ /** Global config.toolTimeoutMs (third precedence, after agent frontmatter). */
558
+ configToolTimeoutMs?: number;
559
+ /** SELESAI_SUBAGENT_TOOL_TIMEOUT_MS override (lowest precedence). */
560
+ toolTimeoutMsEnv?: string | undefined;
551
561
  permissions?: PermissionConfig;
552
562
  /** Global cap on simultaneously-running tasks within this chain. Defaults to DEFAULT_GLOBAL_CONCURRENCY_LIMIT. */
553
563
  globalConcurrencyLimit?: number;
@@ -881,6 +891,8 @@ ${step.message}` : ""}` }],
881
891
  maxSubagentDepth: params.maxSubagentDepth,
882
892
  timeoutMs: params.timeoutMs,
883
893
  deadlineAt,
894
+ callToolTimeoutMs: params.callToolTimeoutMs,
895
+ configToolTimeoutMs: params.configToolTimeoutMs,
884
896
  turnBudget: params.turnBudget,
885
897
  usageBudget: params.usageBudget,
886
898
  onDetachedExit,
@@ -1156,6 +1168,8 @@ ${step.message}` : ""}` }],
1156
1168
  maxSubagentDepth: params.maxSubagentDepth,
1157
1169
  timeoutMs: params.timeoutMs,
1158
1170
  deadlineAt,
1171
+ callToolTimeoutMs: params.callToolTimeoutMs,
1172
+ configToolTimeoutMs: params.configToolTimeoutMs,
1159
1173
  turnBudget: params.turnBudget,
1160
1174
  usageBudget: params.usageBudget,
1161
1175
  onDetachedExit,
@@ -1440,6 +1454,8 @@ ${step.message}` : ""}` }],
1440
1454
  onEffectivePrompt: foregroundControl ? (prompt) => updateLiveEffectivePrompt(foregroundControl, childIndex, prompt) : undefined,
1441
1455
  timeoutMs: params.timeoutMs,
1442
1456
  deadlineAt,
1457
+ toolTimeoutMs: params.callToolTimeoutMs,
1458
+ configToolTimeoutMs: params.configToolTimeoutMs,
1443
1459
  turnBudget: params.turnBudget,
1444
1460
  onDetachedExit: (result) => {
1445
1461
  try {
@@ -38,6 +38,7 @@ import {
38
38
  buildControlEvent,
39
39
  claimControlNotification,
40
40
  deriveActivityState,
41
+ shouldEmitOpenToolAttention,
41
42
  shouldNotifyControlEvent,
42
43
  } from "../shared/subagent-control.ts";
43
44
  import {
@@ -53,10 +54,12 @@ import {
53
54
  } from "../../shared/utils.ts";
54
55
  import { buildSkillInjection, resolveSkillsWithFallback } from "../../agents/skills.ts";
55
56
  import { buildAgentMemoryInjection } from "../../agents/agent-memory.ts";
57
+ import { effectiveToolTimeoutMs, formatToolTimeoutMessage, resolveToolTimeoutMs, toolTimeoutCallKey, toolTimeoutFromEnv } from "../shared/tool-timeout.ts";
56
58
  import { evaluateCompletionMutationGuard } from "../shared/completion-guard.ts";
57
59
  import { arbitrateCompletionGuardRescue } from "../shared/llm-intent-arbiter.ts";
58
60
  import { getPiSpawnCommand } from "../shared/pi-spawn.ts";
59
61
  import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
62
+ import { createOrcaProgressTab, type OrcaProgressTab } from "../shared/orca-progress-tabs.ts";
60
63
  import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
61
64
  import { resolvePermissionRules } from "../shared/permissions.ts";
62
65
  import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan, type SubagentTaskDelivery } from "../shared/pi-args.ts";
@@ -76,6 +79,7 @@ import {
76
79
  } from "../shared/model-fallback.ts";
77
80
  import {
78
81
  SUBAGENT_STARTUP_RETRY_DELAYS_MS,
82
+ formatSubagentExtensionConflictError,
79
83
  formatSubagentStartupRetryExhaustedError,
80
84
  formatSubagentStartupRetryNote,
81
85
  isRetryableSubagentStartupFailure,
@@ -304,6 +308,7 @@ async function runSingleAttempt(
304
308
  outputSnapshot?: SingleOutputSnapshot;
305
309
  originalTask?: string;
306
310
  taskDelivery?: SubagentTaskDelivery;
311
+ orcaProgressTab?: OrcaProgressTab;
307
312
  },
308
313
  ): Promise<SingleResult> {
309
314
  const effectiveThinking = options.thinkingOverride ?? agent.thinking;
@@ -672,6 +677,7 @@ async function runSingleAttempt(
672
677
  clearWatchdogTailTimer();
673
678
  clearStdioGuard();
674
679
  clearTimeoutTimers();
680
+ clearAllToolTimeouts();
675
681
  clearTurnBudgetTimers();
676
682
  if (protocolHardKillTimer) {
677
683
  clearTimeout(protocolHardKillTimer);
@@ -696,6 +702,64 @@ async function runSingleAttempt(
696
702
 
697
703
  let activeLongRunningNotified = false;
698
704
  let pendingToolResult: { tool: string; path?: string; mutates: boolean; startedAt?: number } | undefined;
705
+ type ActiveToolCall = { key: string; tool: string; args: string; startedAt: number; path?: string };
706
+ let activeToolSequence = 0;
707
+ const activeToolCalls = new Map<string, ActiveToolCall>();
708
+ const activeToolKeysByName = new Map<string, string[]>();
709
+ const latestActiveToolCall = (): ActiveToolCall | undefined => [...activeToolCalls.values()].sort((left, right) => right.startedAt - left.startedAt)[0];
710
+ const refreshCurrentTool = (): void => {
711
+ const active = latestActiveToolCall();
712
+ if (!active) {
713
+ progress.currentTool = undefined;
714
+ progress.currentToolArgs = undefined;
715
+ progress.currentToolStartedAt = undefined;
716
+ progress.currentPath = undefined;
717
+ return;
718
+ }
719
+ progress.currentTool = active.tool;
720
+ progress.currentToolArgs = active.args;
721
+ progress.currentToolStartedAt = active.startedAt;
722
+ progress.currentPath = active.path;
723
+ };
724
+ const recordActiveToolCall = (event: { toolCallId?: unknown; toolName: string }, args: Record<string, unknown>, now: number): ActiveToolCall => {
725
+ const key = toolTimeoutCallKey(event, ++activeToolSequence);
726
+ const path = resolveCurrentPath(event.toolName, args);
727
+ const active: ActiveToolCall = {
728
+ key,
729
+ tool: event.toolName,
730
+ args: extractToolArgsPreview(args),
731
+ startedAt: now,
732
+ ...(path !== undefined ? { path } : {}),
733
+ };
734
+ activeToolCalls.set(key, active);
735
+ const keys = activeToolKeysByName.get(active.tool) ?? [];
736
+ keys.push(key);
737
+ activeToolKeysByName.set(active.tool, keys);
738
+ refreshCurrentTool();
739
+ return active;
740
+ };
741
+ const removeActiveToolCallKey = (key: string): ActiveToolCall | undefined => {
742
+ const active = activeToolCalls.get(key);
743
+ if (!active) return undefined;
744
+ activeToolCalls.delete(key);
745
+ const keys = activeToolKeysByName.get(active.tool)?.filter((candidate) => candidate !== key) ?? [];
746
+ if (keys.length > 0) activeToolKeysByName.set(active.tool, keys);
747
+ else activeToolKeysByName.delete(active.tool);
748
+ return active;
749
+ };
750
+ const removeActiveToolCall = (event: { toolCallId?: unknown; toolName?: unknown }): ActiveToolCall | undefined => {
751
+ const key = typeof event.toolCallId === "string" && event.toolCallId.length > 0
752
+ ? `id:${event.toolCallId}`
753
+ : typeof event.toolName === "string"
754
+ ? activeToolKeysByName.get(event.toolName)?.[0]
755
+ : activeToolCalls.size === 1
756
+ ? [...activeToolCalls.keys()][0]
757
+ : undefined;
758
+ return key ? removeActiveToolCallKey(key) : undefined;
759
+ };
760
+ const openToolAttentionTarget = (now: number): ActiveToolCall | undefined => [...activeToolCalls.values()]
761
+ .filter((active) => shouldEmitOpenToolAttention({ config: controlConfig, currentTool: active.tool, currentToolStartedAt: active.startedAt, now }))
762
+ .sort((left, right) => left.startedAt - right.startedAt)[0];
699
763
  const mutatingFailures = createMutatingFailureState();
700
764
  const mutatingFailureWindowMs = 5 * 60_000;
701
765
  const currentToolDurationMs = (now: number) => progress.currentToolStartedAt ? Math.max(0, now - progress.currentToolStartedAt) : undefined;
@@ -813,6 +877,17 @@ async function runSingleAttempt(
813
877
  if (idleState === "needs_attention") {
814
878
  return progress.activityState === "needs_attention" ? false : emitNeedsAttention(now);
815
879
  }
880
+ const toolAttentionTarget = progress.activityState !== "needs_attention" ? openToolAttentionTarget(now) : undefined;
881
+ if (toolAttentionTarget) {
882
+ const durationMs = Math.max(0, now - toolAttentionTarget.startedAt);
883
+ return emitNeedsAttention(now, {
884
+ message: `${agent.name} has had tool '${toolAttentionTarget.tool}' open for ${Math.floor(durationMs / 1000)}s`,
885
+ reason: "tool_open_threshold",
886
+ currentTool: toolAttentionTarget.tool,
887
+ currentPath: toolAttentionTarget.path,
888
+ currentToolDurationMs: durationMs,
889
+ });
890
+ }
816
891
  const activeReason = nextLongRunningTrigger(controlConfig, {
817
892
  startedAt: startTime,
818
893
  now,
@@ -850,16 +925,18 @@ async function runSingleAttempt(
850
925
  const processLine = (line: string) => {
851
926
  if (!line.trim()) return;
852
927
  jsonlWriter.writeLine(line);
853
- let evt: { type?: string; message?: Message; toolName?: string; args?: unknown; willRetry?: unknown };
928
+ let evt: { type?: string; message?: Message; toolName?: string; toolCallId?: string; args?: unknown; willRetry?: unknown };
854
929
  try {
855
- evt = JSON.parse(line) as { type?: string; message?: Message; toolName?: string; args?: unknown; willRetry?: unknown };
930
+ evt = JSON.parse(line) as { type?: string; message?: Message; toolName?: string; toolCallId?: string; args?: unknown; willRetry?: unknown };
856
931
  } catch {
857
932
  rawStdoutTail.push(`${line}\n`);
858
933
  shared.transcriptWriter?.writeStdoutLine(line);
934
+ shared.orcaProgressTab?.append(`${line}\n`);
859
935
  // Non-JSON stdout lines are expected; only structured events are parsed.
860
936
  return;
861
937
  }
862
938
  shared.transcriptWriter?.writeChildEvent(evt);
939
+ shared.orcaProgressTab?.event(evt);
863
940
  if (evt.type === "agent_settled") agentSettledReceived = true;
864
941
  applyChildLifecycle(projectChildLifecycle(evt));
865
942
 
@@ -894,6 +971,8 @@ async function runSingleAttempt(
894
971
  const toolArgs = evt.args && typeof evt.args === "object" && !Array.isArray(evt.args)
895
972
  ? evt.args as Record<string, unknown>
896
973
  : {};
974
+ const activeTool = evt.toolName !== undefined ? recordActiveToolCall(evt as { toolCallId?: unknown; toolName: string }, toolArgs, now) : undefined;
975
+ if (evt.toolName !== undefined) armToolTimeout(evt as { toolCallId?: unknown; toolName: string });
897
976
  if (options.structuredOutput && evt.toolName === "structured_output") {
898
977
  structuredOutputToolInvoked = true;
899
978
  structuredOutputMessageStartIndex = result.messages?.length ?? 0;
@@ -905,28 +984,23 @@ async function runSingleAttempt(
905
984
  if (options.toolBudget) {
906
985
  result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount);
907
986
  }
908
- progress.currentTool = evt.toolName;
909
- progress.currentToolArgs = extractToolArgsPreview(toolArgs);
910
- progress.currentToolStartedAt = now;
911
- progress.currentPath = resolveCurrentPath(evt.toolName, toolArgs);
912
987
  const mutates = isMutatingTool(evt.toolName, toolArgs);
913
988
  observedMutationAttempt = observedMutationAttempt || mutates;
914
- pendingToolResult = { tool: evt.toolName ?? "tool", path: progress.currentPath, mutates, startedAt: now };
989
+ pendingToolResult = { tool: evt.toolName ?? "tool", path: activeTool?.path, mutates, startedAt: now };
915
990
  fireUpdate();
916
991
  }
917
992
 
918
993
  if (evt.type === "tool_execution_end") {
919
- if (progress.currentTool) {
994
+ clearActiveToolTimeout(evt);
995
+ const endedTool = removeActiveToolCall(evt);
996
+ if (endedTool) {
920
997
  progress.recentTools.push({
921
- tool: progress.currentTool,
922
- args: progress.currentToolArgs || "",
998
+ tool: endedTool.tool,
999
+ args: endedTool.args,
923
1000
  endMs: now,
924
1001
  });
925
1002
  }
926
- progress.currentTool = undefined;
927
- progress.currentToolArgs = undefined;
928
- progress.currentToolStartedAt = undefined;
929
- progress.currentPath = undefined;
1003
+ refreshCurrentTool();
930
1004
  fireUpdate();
931
1005
  }
932
1006
 
@@ -1024,6 +1098,7 @@ async function runSingleAttempt(
1024
1098
  timeoutTimer = setTimeout(() => {
1025
1099
  if (processClosed || lifecycleFinished || interruptedByControl) return;
1026
1100
  result.timedOut = true;
1101
+ clearAllToolTimeouts();
1027
1102
  result.error = attemptTimeout.message;
1028
1103
  result.finalOutput = attemptTimeout.message;
1029
1104
  progress.status = "failed";
@@ -1045,6 +1120,81 @@ async function runSingleAttempt(
1045
1120
  timeoutTimer.unref?.();
1046
1121
  }
1047
1122
 
1123
+ let toolTimeoutSequence = 0;
1124
+ const activeToolTimeouts = new Map<string, { toolName: string; timer: ReturnType<typeof setTimeout> }>();
1125
+ const activeToolTimeoutKeysByName = new Map<string, string[]>();
1126
+ let toolTimeoutTerminationTimer: ReturnType<typeof setTimeout> | undefined;
1127
+ let toolTimeoutHardKillTimer: ReturnType<typeof setTimeout> | undefined;
1128
+ const removeToolTimeoutKey = (key: string): void => {
1129
+ const active = activeToolTimeouts.get(key);
1130
+ if (!active) return;
1131
+ clearTimeout(active.timer);
1132
+ activeToolTimeouts.delete(key);
1133
+ const keys = activeToolTimeoutKeysByName.get(active.toolName)?.filter((candidate) => candidate !== key) ?? [];
1134
+ if (keys.length > 0) activeToolTimeoutKeysByName.set(active.toolName, keys);
1135
+ else activeToolTimeoutKeysByName.delete(active.toolName);
1136
+ };
1137
+ const clearActiveToolTimeout = (event: { toolCallId?: unknown; toolName?: unknown }): void => {
1138
+ const key = typeof event.toolCallId === "string" && event.toolCallId.length > 0
1139
+ ? `id:${event.toolCallId}`
1140
+ : typeof event.toolName === "string"
1141
+ ? activeToolTimeoutKeysByName.get(event.toolName)?.[0]
1142
+ : activeToolTimeouts.size === 1
1143
+ ? [...activeToolTimeouts.keys()][0]
1144
+ : undefined;
1145
+ if (key) removeToolTimeoutKey(key);
1146
+ };
1147
+ const clearAllToolTimeouts = (): void => {
1148
+ for (const key of [...activeToolTimeouts.keys()]) removeToolTimeoutKey(key);
1149
+ if (toolTimeoutTerminationTimer) {
1150
+ clearTimeout(toolTimeoutTerminationTimer);
1151
+ toolTimeoutTerminationTimer = undefined;
1152
+ }
1153
+ if (toolTimeoutHardKillTimer) {
1154
+ clearTimeout(toolTimeoutHardKillTimer);
1155
+ toolTimeoutHardKillTimer = undefined;
1156
+ }
1157
+ };
1158
+ const terminateForToolTimeout = (message: string): void => {
1159
+ if (processClosed || lifecycleFinished || interruptedByControl) return;
1160
+ result.timedOut = true;
1161
+ result.error = message;
1162
+ result.finalOutput = message;
1163
+ progress.status = "failed";
1164
+ progress.error = message;
1165
+ progress.durationMs = Date.now() - startTime;
1166
+ fireUpdate();
1167
+ trySignalChild(proc, "SIGINT");
1168
+ toolTimeoutTerminationTimer = setTimeout(() => {
1169
+ if (processClosed || lifecycleFinished) return;
1170
+ trySignalChild(proc, "SIGTERM");
1171
+ }, 1000);
1172
+ toolTimeoutTerminationTimer.unref?.();
1173
+ toolTimeoutHardKillTimer = setTimeout(() => {
1174
+ if (processClosed || lifecycleFinished) return;
1175
+ trySignalChild(proc, "SIGKILL");
1176
+ }, 4000);
1177
+ toolTimeoutHardKillTimer.unref?.();
1178
+ };
1179
+ const armToolTimeout = (event: { toolCallId?: unknown; toolName: string }): void => {
1180
+ const timeoutForTool = effectiveToolTimeoutMs(event.toolName, options.toolTimeoutMs);
1181
+ if (timeoutForTool === undefined) return;
1182
+ const elapsed = Date.now() - startTime;
1183
+ const runRemaining = attemptTimeout ? Math.max(0, attemptTimeout.remainingMs - elapsed) : undefined;
1184
+ if (runRemaining !== undefined && timeoutForTool >= runRemaining) return;
1185
+ const key = toolTimeoutCallKey(event, ++toolTimeoutSequence);
1186
+ const toolName = event.toolName;
1187
+ const timer = setTimeout(() => {
1188
+ removeToolTimeoutKey(key);
1189
+ terminateForToolTimeout(formatToolTimeoutMessage(toolName, timeoutForTool));
1190
+ }, timeoutForTool);
1191
+ timer.unref?.();
1192
+ activeToolTimeouts.set(key, { toolName, timer });
1193
+ const keys = activeToolTimeoutKeysByName.get(toolName) ?? [];
1194
+ keys.push(key);
1195
+ activeToolTimeoutKeysByName.set(toolName, keys);
1196
+ };
1197
+
1048
1198
  const stderrTail = createBoundedByteTail();
1049
1199
  const failProtocol = (limit: ProtocolOutputLimit): void => {
1050
1200
  if (result.protocolError) return;
@@ -1079,6 +1229,7 @@ async function runSingleAttempt(
1079
1229
  proc.stderr.on("data", (chunk: Buffer) => {
1080
1230
  stderrTail.push(chunk);
1081
1231
  stderrReader.push(chunk);
1232
+ shared.orcaProgressTab?.append(chunk.toString("utf-8"));
1082
1233
  });
1083
1234
  proc.on("exit", () => {
1084
1235
  childExited = true;
@@ -1158,6 +1309,7 @@ async function runSingleAttempt(
1158
1309
  if (result.timedOut) return;
1159
1310
  interruptedByControl = true;
1160
1311
  clearTimeoutTimers();
1312
+ clearAllToolTimeouts();
1161
1313
  progress.status = "running";
1162
1314
  progress.durationMs = Date.now() - startTime;
1163
1315
  result.interrupted = true;
@@ -1203,6 +1355,10 @@ async function runSingleAttempt(
1203
1355
  };
1204
1356
  return result;
1205
1357
  }
1358
+ result.error = formatSubagentExtensionConflictError(result.error, {
1359
+ agent: agent.name,
1360
+ ambientExtensionsEnabled: !launchResolvedExtensions.disableAmbientExtensions,
1361
+ });
1206
1362
  if (result.error && result.exitCode === 0) {
1207
1363
  result.exitCode = 1;
1208
1364
  }
@@ -1380,7 +1536,7 @@ async function runSingleAttempt(
1380
1536
  /**
1381
1537
  * Run a subagent synchronously (blocking until complete)
1382
1538
  */
1383
- async function runSyncCompletion(
1539
+ async function runSyncCompletionInner(
1384
1540
  runtimeCwd: string,
1385
1541
  agents: AgentConfig[],
1386
1542
  agentName: string,
@@ -1429,6 +1585,24 @@ async function runSyncCompletion(
1429
1585
  error: acceptanceErrors.join(" "),
1430
1586
  }, options.context));
1431
1587
  }
1588
+ const toolTimeout = resolveToolTimeoutMs({
1589
+ callValue: options.toolTimeoutMs,
1590
+ agentValue: agent.defaultToolTimeoutMs,
1591
+ configValue: options.configToolTimeoutMs,
1592
+ envValue: toolTimeoutFromEnv(),
1593
+ });
1594
+ if (toolTimeout.error) {
1595
+ return redactResultPrompt(withRunContext({
1596
+ index: options.index ?? 0,
1597
+ agent: agentName,
1598
+ task,
1599
+ exitCode: 1,
1600
+ messages: [],
1601
+ usage: emptyUsage(),
1602
+ error: toolTimeout.error,
1603
+ }, options.context));
1604
+ }
1605
+ options = { ...options, toolTimeoutMs: toolTimeout.toolTimeoutMs };
1432
1606
  const outputModeValidationError = validateFileOnlyOutputMode(options.outputMode, options.outputPath, `Single run (${agentName})`);
1433
1607
  if (outputModeValidationError) {
1434
1608
  return redactResultPrompt(withRunContext({
@@ -1533,6 +1707,14 @@ async function runSyncCompletion(
1533
1707
  }
1534
1708
  }
1535
1709
 
1710
+ const orcaProgressTab = createOrcaProgressTab({
1711
+ cwd: options.cwd ?? runtimeCwd,
1712
+ runId: options.runId,
1713
+ agent: agentName,
1714
+ index: options.index ?? 0,
1715
+ });
1716
+ if (orcaProgressTab) options.onOrcaProgressTabCreated?.(orcaProgressTab);
1717
+
1536
1718
  const persistResultMetadata = (target: SingleResult): void => {
1537
1719
  persistSingleResultMetadata({
1538
1720
  metadataPath: artifactPathsResult?.metadataPath,
@@ -1588,6 +1770,7 @@ async function runSyncCompletion(
1588
1770
  outputSnapshot,
1589
1771
  originalTask: task,
1590
1772
  taskDelivery: taskDeliveryOverride,
1773
+ orcaProgressTab,
1591
1774
  });
1592
1775
  lastResult = result;
1593
1776
  if (startupAttemptIndex === 0) {
@@ -1855,6 +2038,27 @@ async function runSyncCompletion(
1855
2038
  return result;
1856
2039
  }
1857
2040
 
2041
+ async function runSyncCompletion(
2042
+ runtimeCwd: string,
2043
+ agents: AgentConfig[],
2044
+ agentName: string,
2045
+ task: string,
2046
+ options: RunSyncOptions,
2047
+ ): Promise<SingleResult> {
2048
+ let orcaProgressTab: OrcaProgressTab | undefined;
2049
+ try {
2050
+ const result = await runSyncCompletionInner(runtimeCwd, agents, agentName, task, {
2051
+ ...options,
2052
+ onOrcaProgressTabCreated: (tab) => { orcaProgressTab = tab; },
2053
+ });
2054
+ orcaProgressTab?.finish(result.stopped ? "stopped" : result.exitCode === 0 && !result.error ? "completed" : "failed", result.sessionFile);
2055
+ return result;
2056
+ } catch (error) {
2057
+ orcaProgressTab?.finish("failed");
2058
+ throw error;
2059
+ }
2060
+ }
2061
+
1858
2062
  /**
1859
2063
  * Runs the authoritative completion pipeline independently from the foreground
1860
2064
  * receipt. Detachment is same-runtime only: it does not adopt or daemonize work.
@@ -1,7 +1,8 @@
1
1
  import { Agent, type StreamFn, type ThinkingLevel } from "@earendil-works/pi-agent-core";
2
2
  import { 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
+ import { agentStreamOptions } from "../../shared/agent-stream-options.ts";
5
6
  import type { ForegroundRunControl } from "../../shared/types.ts";
6
7
  export type PromptAuditView = "authored" | "runtime" | "effective";
7
8
 
@@ -42,7 +43,7 @@ function finalAssistantText(agent: Agent): string {
42
43
  return "";
43
44
  }
44
45
 
45
- async function resolveRewriteAuth(ctx: ExtensionContext, model: RegistryModel): Promise<{ apiKey?: string; headers?: Record<string, string>; env?: Record<string, string> }> {
46
+ async function resolveRewriteAuth(ctx: ExtensionContext, model: RegistryModel): Promise<{ apiKey?: string; headers?: ProviderHeaders; env?: Record<string, string> }> {
46
47
  const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
47
48
  if (auth.ok === false) throw new Error(`Prompt redo model auth failed for ${fullModelId(model)}: ${auth.error}`);
48
49
  return {
@@ -91,7 +92,7 @@ export async function rewritePromptWithGuidance(input: {
91
92
  tools: [],
92
93
  },
93
94
  convertToLlm,
94
- streamFn,
95
+ ...agentStreamOptions(streamFn),
95
96
  getApiKey: (providerName) => providerName === model.provider ? auth.apiKey : undefined,
96
97
  toolExecution: "sequential",
97
98
  });