turboflux 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -0
  3. package/bin/turboflux.mjs +28 -0
  4. package/dist/cli/brand.d.ts +7 -0
  5. package/dist/cli/brand.js +33 -0
  6. package/dist/cli/brand.js.map +1 -0
  7. package/dist/cli/commands/index.d.ts +4 -0
  8. package/dist/cli/commands/index.js +671 -0
  9. package/dist/cli/commands/index.js.map +1 -0
  10. package/dist/cli/commands/registry.d.ts +24 -0
  11. package/dist/cli/commands/registry.js +124 -0
  12. package/dist/cli/commands/registry.js.map +1 -0
  13. package/dist/cli/commands/types.d.ts +69 -0
  14. package/dist/cli/commands/types.js +2 -0
  15. package/dist/cli/commands/types.js.map +1 -0
  16. package/dist/cli/components/App.d.ts +15 -0
  17. package/dist/cli/components/App.js +1738 -0
  18. package/dist/cli/components/App.js.map +1 -0
  19. package/dist/cli/components/ConversationHistory.d.ts +15 -0
  20. package/dist/cli/components/ConversationHistory.js +92 -0
  21. package/dist/cli/components/ConversationHistory.js.map +1 -0
  22. package/dist/cli/components/TranscriptViewport.d.ts +25 -0
  23. package/dist/cli/components/TranscriptViewport.js +77 -0
  24. package/dist/cli/components/TranscriptViewport.js.map +1 -0
  25. package/dist/cli/components/agentActivityModel.d.ts +24 -0
  26. package/dist/cli/components/agentActivityModel.js +45 -0
  27. package/dist/cli/components/agentActivityModel.js.map +1 -0
  28. package/dist/cli/components/appHelpers.d.ts +34 -0
  29. package/dist/cli/components/appHelpers.js +209 -0
  30. package/dist/cli/components/appHelpers.js.map +1 -0
  31. package/dist/cli/components/design-system/StatusIcon.d.ts +5 -0
  32. package/dist/cli/components/design-system/StatusIcon.js +25 -0
  33. package/dist/cli/components/design-system/StatusIcon.js.map +1 -0
  34. package/dist/cli/components/developerFlowModel.d.ts +36 -0
  35. package/dist/cli/components/developerFlowModel.js +88 -0
  36. package/dist/cli/components/developerFlowModel.js.map +1 -0
  37. package/dist/cli/components/diff/DiffCard.d.ts +16 -0
  38. package/dist/cli/components/diff/DiffCard.js +30 -0
  39. package/dist/cli/components/diff/DiffCard.js.map +1 -0
  40. package/dist/cli/components/diff/DiffHunks.d.ts +11 -0
  41. package/dist/cli/components/diff/DiffHunks.js +58 -0
  42. package/dist/cli/components/diff/DiffHunks.js.map +1 -0
  43. package/dist/cli/components/header/Header.d.ts +13 -0
  44. package/dist/cli/components/header/Header.js +25 -0
  45. package/dist/cli/components/header/Header.js.map +1 -0
  46. package/dist/cli/components/header/Mascot.d.ts +4 -0
  47. package/dist/cli/components/header/Mascot.js +53 -0
  48. package/dist/cli/components/header/Mascot.js.map +1 -0
  49. package/dist/cli/components/header/StatusLine.d.ts +21 -0
  50. package/dist/cli/components/header/StatusLine.js +110 -0
  51. package/dist/cli/components/header/StatusLine.js.map +1 -0
  52. package/dist/cli/components/input/EffortPicker.d.ts +30 -0
  53. package/dist/cli/components/input/EffortPicker.js +126 -0
  54. package/dist/cli/components/input/EffortPicker.js.map +1 -0
  55. package/dist/cli/components/input/ModelPicker.d.ts +15 -0
  56. package/dist/cli/components/input/ModelPicker.js +95 -0
  57. package/dist/cli/components/input/ModelPicker.js.map +1 -0
  58. package/dist/cli/components/input/PromptInput.d.ts +79 -0
  59. package/dist/cli/components/input/PromptInput.js +496 -0
  60. package/dist/cli/components/input/PromptInput.js.map +1 -0
  61. package/dist/cli/components/input/RewindSelector.d.ts +8 -0
  62. package/dist/cli/components/input/RewindSelector.js +45 -0
  63. package/dist/cli/components/input/RewindSelector.js.map +1 -0
  64. package/dist/cli/components/input/pasteState.d.ts +6 -0
  65. package/dist/cli/components/input/pasteState.js +42 -0
  66. package/dist/cli/components/input/pasteState.js.map +1 -0
  67. package/dist/cli/components/input/terminalInputStateMachine.d.ts +29 -0
  68. package/dist/cli/components/input/terminalInputStateMachine.js +67 -0
  69. package/dist/cli/components/input/terminalInputStateMachine.js.map +1 -0
  70. package/dist/cli/components/layout/CockpitRails.d.ts +6 -0
  71. package/dist/cli/components/layout/CockpitRails.js +13 -0
  72. package/dist/cli/components/layout/CockpitRails.js.map +1 -0
  73. package/dist/cli/components/layout/LandingView.d.ts +15 -0
  74. package/dist/cli/components/layout/LandingView.js +12 -0
  75. package/dist/cli/components/layout/LandingView.js.map +1 -0
  76. package/dist/cli/components/layout/SessionSidebar.d.ts +18 -0
  77. package/dist/cli/components/layout/SessionSidebar.js +70 -0
  78. package/dist/cli/components/layout/SessionSidebar.js.map +1 -0
  79. package/dist/cli/components/layout/StartupAnimation.d.ts +14 -0
  80. package/dist/cli/components/layout/StartupAnimation.js +30 -0
  81. package/dist/cli/components/layout/StartupAnimation.js.map +1 -0
  82. package/dist/cli/components/markdown/highlighter.d.ts +1 -0
  83. package/dist/cli/components/markdown/highlighter.js +110 -0
  84. package/dist/cli/components/markdown/highlighter.js.map +1 -0
  85. package/dist/cli/components/markdown/index.d.ts +11 -0
  86. package/dist/cli/components/markdown/index.js +86 -0
  87. package/dist/cli/components/markdown/index.js.map +1 -0
  88. package/dist/cli/components/messages/MessageList.d.ts +16 -0
  89. package/dist/cli/components/messages/MessageList.js +56 -0
  90. package/dist/cli/components/messages/MessageList.js.map +1 -0
  91. package/dist/cli/components/messages/Messages.d.ts +26 -0
  92. package/dist/cli/components/messages/Messages.js +32 -0
  93. package/dist/cli/components/messages/Messages.js.map +1 -0
  94. package/dist/cli/components/messages/ThinkingBlock.d.ts +9 -0
  95. package/dist/cli/components/messages/ThinkingBlock.js +51 -0
  96. package/dist/cli/components/messages/ThinkingBlock.js.map +1 -0
  97. package/dist/cli/components/messages/WindowedMessageList.d.ts +21 -0
  98. package/dist/cli/components/messages/WindowedMessageList.js +44 -0
  99. package/dist/cli/components/messages/WindowedMessageList.js.map +1 -0
  100. package/dist/cli/components/permissions/PermissionDialog.d.ts +23 -0
  101. package/dist/cli/components/permissions/PermissionDialog.js +83 -0
  102. package/dist/cli/components/permissions/PermissionDialog.js.map +1 -0
  103. package/dist/cli/components/spinner/SpinnerGlyph.d.ts +6 -0
  104. package/dist/cli/components/spinner/SpinnerGlyph.js +55 -0
  105. package/dist/cli/components/spinner/SpinnerGlyph.js.map +1 -0
  106. package/dist/cli/components/spinner/constants.d.ts +4 -0
  107. package/dist/cli/components/spinner/constants.js +5 -0
  108. package/dist/cli/components/spinner/constants.js.map +1 -0
  109. package/dist/cli/components/tools/ActiveWorkPanel.d.ts +22 -0
  110. package/dist/cli/components/tools/ActiveWorkPanel.js +70 -0
  111. package/dist/cli/components/tools/ActiveWorkPanel.js.map +1 -0
  112. package/dist/cli/components/tools/AgentActivityLine.d.ts +13 -0
  113. package/dist/cli/components/tools/AgentActivityLine.js +88 -0
  114. package/dist/cli/components/tools/AgentActivityLine.js.map +1 -0
  115. package/dist/cli/components/tools/QueuedPromptList.d.ts +10 -0
  116. package/dist/cli/components/tools/QueuedPromptList.js +26 -0
  117. package/dist/cli/components/tools/QueuedPromptList.js.map +1 -0
  118. package/dist/cli/components/tools/TaskFlowHud.d.ts +15 -0
  119. package/dist/cli/components/tools/TaskFlowHud.js +55 -0
  120. package/dist/cli/components/tools/TaskFlowHud.js.map +1 -0
  121. package/dist/cli/components/tools/TerminalSessionsFooter.d.ts +6 -0
  122. package/dist/cli/components/tools/TerminalSessionsFooter.js +36 -0
  123. package/dist/cli/components/tools/TerminalSessionsFooter.js.map +1 -0
  124. package/dist/cli/components/tools/ToolActivityList.d.ts +11 -0
  125. package/dist/cli/components/tools/ToolActivityList.js +73 -0
  126. package/dist/cli/components/tools/ToolActivityList.js.map +1 -0
  127. package/dist/cli/components/tools/ToolCallTree.d.ts +11 -0
  128. package/dist/cli/components/tools/ToolCallTree.js +14 -0
  129. package/dist/cli/components/tools/ToolCallTree.js.map +1 -0
  130. package/dist/cli/components/tools/toolLifecycleModel.d.ts +16 -0
  131. package/dist/cli/components/tools/toolLifecycleModel.js +30 -0
  132. package/dist/cli/components/tools/toolLifecycleModel.js.map +1 -0
  133. package/dist/cli/components/tools/toolPresentation.d.ts +9 -0
  134. package/dist/cli/components/tools/toolPresentation.js +171 -0
  135. package/dist/cli/components/tools/toolPresentation.js.map +1 -0
  136. package/dist/cli/components/tools/toolTypes.d.ts +16 -0
  137. package/dist/cli/components/tools/toolTypes.js +2 -0
  138. package/dist/cli/components/tools/toolTypes.js.map +1 -0
  139. package/dist/cli/components/transcriptWindowing.d.ts +19 -0
  140. package/dist/cli/components/transcriptWindowing.js +81 -0
  141. package/dist/cli/components/transcriptWindowing.js.map +1 -0
  142. package/dist/cli/config.d.ts +1 -0
  143. package/dist/cli/config.js +2 -0
  144. package/dist/cli/config.js.map +1 -0
  145. package/dist/cli/conversations/journalWriter.d.ts +50 -0
  146. package/dist/cli/conversations/journalWriter.js +191 -0
  147. package/dist/cli/conversations/journalWriter.js.map +1 -0
  148. package/dist/cli/conversations/manager.d.ts +65 -0
  149. package/dist/cli/conversations/manager.js +435 -0
  150. package/dist/cli/conversations/manager.js.map +1 -0
  151. package/dist/cli/conversations/recoveryExport.d.ts +18 -0
  152. package/dist/cli/conversations/recoveryExport.js +39 -0
  153. package/dist/cli/conversations/recoveryExport.js.map +1 -0
  154. package/dist/cli/conversations/recoveryMessages.d.ts +2 -0
  155. package/dist/cli/conversations/recoveryMessages.js +3 -0
  156. package/dist/cli/conversations/recoveryMessages.js.map +1 -0
  157. package/dist/cli/conversations/store.d.ts +14 -0
  158. package/dist/cli/conversations/store.js +603 -0
  159. package/dist/cli/conversations/store.js.map +1 -0
  160. package/dist/cli/conversations/types.d.ts +142 -0
  161. package/dist/cli/conversations/types.js +2 -0
  162. package/dist/cli/conversations/types.js.map +1 -0
  163. package/dist/cli/globalConfiguration.d.ts +13 -0
  164. package/dist/cli/globalConfiguration.js +61 -0
  165. package/dist/cli/globalConfiguration.js.map +1 -0
  166. package/dist/cli/hooks/useMessageCursor.d.ts +16 -0
  167. package/dist/cli/hooks/useMessageCursor.js +75 -0
  168. package/dist/cli/hooks/useMessageCursor.js.map +1 -0
  169. package/dist/cli/hooks/useOverlayStack.d.ts +9 -0
  170. package/dist/cli/hooks/useOverlayStack.js +26 -0
  171. package/dist/cli/hooks/useOverlayStack.js.map +1 -0
  172. package/dist/cli/hooks/useTerminalSize.d.ts +16 -0
  173. package/dist/cli/hooks/useTerminalSize.js +37 -0
  174. package/dist/cli/hooks/useTerminalSize.js.map +1 -0
  175. package/dist/cli/i18n/index.d.ts +15 -0
  176. package/dist/cli/i18n/index.js +32 -0
  177. package/dist/cli/i18n/index.js.map +1 -0
  178. package/dist/cli/i18n/messages.d.ts +1305 -0
  179. package/dist/cli/i18n/messages.js +1305 -0
  180. package/dist/cli/i18n/messages.js.map +1 -0
  181. package/dist/cli/imageAttachments.d.ts +22 -0
  182. package/dist/cli/imageAttachments.js +329 -0
  183. package/dist/cli/imageAttachments.js.map +1 -0
  184. package/dist/cli/index.d.ts +2 -0
  185. package/dist/cli/index.js +146 -0
  186. package/dist/cli/index.js.map +1 -0
  187. package/dist/cli/platform/terminalAttention.d.ts +46 -0
  188. package/dist/cli/platform/terminalAttention.js +152 -0
  189. package/dist/cli/platform/terminalAttention.js.map +1 -0
  190. package/dist/cli/platform/terminalTransparency.d.ts +11 -0
  191. package/dist/cli/platform/terminalTransparency.js +193 -0
  192. package/dist/cli/platform/terminalTransparency.js.map +1 -0
  193. package/dist/cli/repl.d.ts +15 -0
  194. package/dist/cli/repl.js +38 -0
  195. package/dist/cli/repl.js.map +1 -0
  196. package/dist/cli/setup.d.ts +17 -0
  197. package/dist/cli/setup.js +991 -0
  198. package/dist/cli/setup.js.map +1 -0
  199. package/dist/cli/singleShot.d.ts +30 -0
  200. package/dist/cli/singleShot.js +167 -0
  201. package/dist/cli/singleShot.js.map +1 -0
  202. package/dist/cli/state/adaptiveStreamScheduler.d.ts +53 -0
  203. package/dist/cli/state/adaptiveStreamScheduler.js +136 -0
  204. package/dist/cli/state/adaptiveStreamScheduler.js.map +1 -0
  205. package/dist/cli/state/agentFlowController.d.ts +37 -0
  206. package/dist/cli/state/agentFlowController.js +402 -0
  207. package/dist/cli/state/agentFlowController.js.map +1 -0
  208. package/dist/cli/state/approvalPresentationScheduler.d.ts +28 -0
  209. package/dist/cli/state/approvalPresentationScheduler.js +72 -0
  210. package/dist/cli/state/approvalPresentationScheduler.js.map +1 -0
  211. package/dist/cli/state/flowFeatureFlags.d.ts +18 -0
  212. package/dist/cli/state/flowFeatureFlags.js +45 -0
  213. package/dist/cli/state/flowFeatureFlags.js.map +1 -0
  214. package/dist/cli/state/flowReducer.d.ts +120 -0
  215. package/dist/cli/state/flowReducer.js +535 -0
  216. package/dist/cli/state/flowReducer.js.map +1 -0
  217. package/dist/cli/state/flowSelectors.d.ts +45 -0
  218. package/dist/cli/state/flowSelectors.js +144 -0
  219. package/dist/cli/state/flowSelectors.js.map +1 -0
  220. package/dist/cli/state/flowStore.d.ts +19 -0
  221. package/dist/cli/state/flowStore.js +51 -0
  222. package/dist/cli/state/flowStore.js.map +1 -0
  223. package/dist/cli/state/globalCommandActivity.d.ts +25 -0
  224. package/dist/cli/state/globalCommandActivity.js +57 -0
  225. package/dist/cli/state/globalCommandActivity.js.map +1 -0
  226. package/dist/cli/state/goldenTraces.d.ts +2 -0
  227. package/dist/cli/state/goldenTraces.js +15 -0
  228. package/dist/cli/state/goldenTraces.js.map +1 -0
  229. package/dist/cli/state/notificationCoordinator.d.ts +38 -0
  230. package/dist/cli/state/notificationCoordinator.js +101 -0
  231. package/dist/cli/state/notificationCoordinator.js.map +1 -0
  232. package/dist/cli/stateProvider.d.ts +5 -0
  233. package/dist/cli/stateProvider.js +7 -0
  234. package/dist/cli/stateProvider.js.map +1 -0
  235. package/dist/cli/telemetry/localFlowTelemetry.d.ts +42 -0
  236. package/dist/cli/telemetry/localFlowTelemetry.js +131 -0
  237. package/dist/cli/telemetry/localFlowTelemetry.js.map +1 -0
  238. package/dist/cli/telemetry/terminalBaseline.d.ts +93 -0
  239. package/dist/cli/telemetry/terminalBaseline.js +199 -0
  240. package/dist/cli/telemetry/terminalBaseline.js.map +1 -0
  241. package/dist/cli/telemetry/terminalLatencyTracker.d.ts +24 -0
  242. package/dist/cli/telemetry/terminalLatencyTracker.js +59 -0
  243. package/dist/cli/telemetry/terminalLatencyTracker.js.map +1 -0
  244. package/dist/cli/terminalLayout.d.ts +2 -0
  245. package/dist/cli/terminalLayout.js +16 -0
  246. package/dist/cli/terminalLayout.js.map +1 -0
  247. package/dist/cli/terminalMouse.d.ts +10 -0
  248. package/dist/cli/terminalMouse.js +29 -0
  249. package/dist/cli/terminalMouse.js.map +1 -0
  250. package/dist/cli/theme/ThemeProvider.d.ts +9 -0
  251. package/dist/cli/theme/ThemeProvider.js +26 -0
  252. package/dist/cli/theme/ThemeProvider.js.map +1 -0
  253. package/dist/cli/theme/dark.d.ts +2 -0
  254. package/dist/cli/theme/dark.js +27 -0
  255. package/dist/cli/theme/dark.js.map +1 -0
  256. package/dist/cli/theme/index.d.ts +5 -0
  257. package/dist/cli/theme/index.js +5 -0
  258. package/dist/cli/theme/index.js.map +1 -0
  259. package/dist/cli/theme/light.d.ts +2 -0
  260. package/dist/cli/theme/light.js +26 -0
  261. package/dist/cli/theme/light.js.map +1 -0
  262. package/dist/cli/theme/palette.d.ts +7 -0
  263. package/dist/cli/theme/palette.js +8 -0
  264. package/dist/cli/theme/palette.js.map +1 -0
  265. package/dist/cli/theme/resolveColor.d.ts +4 -0
  266. package/dist/cli/theme/resolveColor.js +43 -0
  267. package/dist/cli/theme/resolveColor.js.map +1 -0
  268. package/dist/cli/theme/types.d.ts +27 -0
  269. package/dist/cli/theme/types.js +2 -0
  270. package/dist/cli/theme/types.js.map +1 -0
  271. package/dist/cli/toolExecutor.d.ts +1 -0
  272. package/dist/cli/toolExecutor.js +2 -0
  273. package/dist/cli/toolExecutor.js.map +1 -0
  274. package/dist/core/agentEngine.d.ts +425 -0
  275. package/dist/core/agentEngine.js +5170 -0
  276. package/dist/core/agentEngine.js.map +1 -0
  277. package/dist/core/agents/loader.d.ts +9 -0
  278. package/dist/core/agents/loader.js +144 -0
  279. package/dist/core/agents/loader.js.map +1 -0
  280. package/dist/core/applyPatch.d.ts +24 -0
  281. package/dist/core/applyPatch.js +158 -0
  282. package/dist/core/applyPatch.js.map +1 -0
  283. package/dist/core/cacheMonitor.d.ts +24 -0
  284. package/dist/core/cacheMonitor.js +211 -0
  285. package/dist/core/cacheMonitor.js.map +1 -0
  286. package/dist/core/clientIdentity.d.ts +6 -0
  287. package/dist/core/clientIdentity.js +44 -0
  288. package/dist/core/clientIdentity.js.map +1 -0
  289. package/dist/core/config.d.ts +99 -0
  290. package/dist/core/config.js +715 -0
  291. package/dist/core/config.js.map +1 -0
  292. package/dist/core/contextCompaction.d.ts +20 -0
  293. package/dist/core/contextCompaction.js +158 -0
  294. package/dist/core/contextCompaction.js.map +1 -0
  295. package/dist/core/contextManager.d.ts +44 -0
  296. package/dist/core/contextManager.js +590 -0
  297. package/dist/core/contextManager.js.map +1 -0
  298. package/dist/core/contextPolicy.d.ts +18 -0
  299. package/dist/core/contextPolicy.js +39 -0
  300. package/dist/core/contextPolicy.js.map +1 -0
  301. package/dist/core/credentialStore.d.ts +8 -0
  302. package/dist/core/credentialStore.js +37 -0
  303. package/dist/core/credentialStore.js.map +1 -0
  304. package/dist/core/diffCompute.d.ts +31 -0
  305. package/dist/core/diffCompute.js +116 -0
  306. package/dist/core/diffCompute.js.map +1 -0
  307. package/dist/core/editHelpers.d.ts +8 -0
  308. package/dist/core/editHelpers.js +35 -0
  309. package/dist/core/editHelpers.js.map +1 -0
  310. package/dist/core/fileIO.d.ts +12 -0
  311. package/dist/core/fileIO.js +199 -0
  312. package/dist/core/fileIO.js.map +1 -0
  313. package/dist/core/gitService.d.ts +83 -0
  314. package/dist/core/gitService.js +522 -0
  315. package/dist/core/gitService.js.map +1 -0
  316. package/dist/core/index.d.ts +30 -0
  317. package/dist/core/index.js +19 -0
  318. package/dist/core/index.js.map +1 -0
  319. package/dist/core/mcp/client.d.ts +32 -0
  320. package/dist/core/mcp/client.js +186 -0
  321. package/dist/core/mcp/client.js.map +1 -0
  322. package/dist/core/mcp/settings.d.ts +2 -0
  323. package/dist/core/mcp/settings.js +26 -0
  324. package/dist/core/mcp/settings.js.map +1 -0
  325. package/dist/core/mcp/toolBridge.d.ts +20 -0
  326. package/dist/core/mcp/toolBridge.js +74 -0
  327. package/dist/core/mcp/toolBridge.js.map +1 -0
  328. package/dist/core/mcp/types.d.ts +29 -0
  329. package/dist/core/mcp/types.js +2 -0
  330. package/dist/core/mcp/types.js.map +1 -0
  331. package/dist/core/modelDiscovery.d.ts +14 -0
  332. package/dist/core/modelDiscovery.js +566 -0
  333. package/dist/core/modelDiscovery.js.map +1 -0
  334. package/dist/core/modelProtocol.d.ts +43 -0
  335. package/dist/core/modelProtocol.js +238 -0
  336. package/dist/core/modelProtocol.js.map +1 -0
  337. package/dist/core/modelRegistry.d.ts +56 -0
  338. package/dist/core/modelRegistry.js +308 -0
  339. package/dist/core/modelRegistry.js.map +1 -0
  340. package/dist/core/networkProxy.d.ts +20 -0
  341. package/dist/core/networkProxy.js +145 -0
  342. package/dist/core/networkProxy.js.map +1 -0
  343. package/dist/core/normalizeBaseUrl.d.ts +1 -0
  344. package/dist/core/normalizeBaseUrl.js +9 -0
  345. package/dist/core/normalizeBaseUrl.js.map +1 -0
  346. package/dist/core/pathUtils.d.ts +3 -0
  347. package/dist/core/pathUtils.js +46 -0
  348. package/dist/core/pathUtils.js.map +1 -0
  349. package/dist/core/permissions.d.ts +29 -0
  350. package/dist/core/permissions.js +245 -0
  351. package/dist/core/permissions.js.map +1 -0
  352. package/dist/core/persona/voiceProfile.d.ts +7 -0
  353. package/dist/core/persona/voiceProfile.js +14 -0
  354. package/dist/core/persona/voiceProfile.js.map +1 -0
  355. package/dist/core/profile.d.ts +35 -0
  356. package/dist/core/profile.js +373 -0
  357. package/dist/core/profile.js.map +1 -0
  358. package/dist/core/requestCompatibility.d.ts +13 -0
  359. package/dist/core/requestCompatibility.js +181 -0
  360. package/dist/core/requestCompatibility.js.map +1 -0
  361. package/dist/core/runtime/agentRuntime.d.ts +43 -0
  362. package/dist/core/runtime/agentRuntime.js +137 -0
  363. package/dist/core/runtime/agentRuntime.js.map +1 -0
  364. package/dist/core/runtime/approvalCoordinator.d.ts +36 -0
  365. package/dist/core/runtime/approvalCoordinator.js +113 -0
  366. package/dist/core/runtime/approvalCoordinator.js.map +1 -0
  367. package/dist/core/runtime/capabilityBoundary.d.ts +18 -0
  368. package/dist/core/runtime/capabilityBoundary.js +89 -0
  369. package/dist/core/runtime/capabilityBoundary.js.map +1 -0
  370. package/dist/core/runtime/nodeToolExecutor.d.ts +200 -0
  371. package/dist/core/runtime/nodeToolExecutor.js +2446 -0
  372. package/dist/core/runtime/nodeToolExecutor.js.map +1 -0
  373. package/dist/core/runtime/runtimeLogWriter.d.ts +32 -0
  374. package/dist/core/runtime/runtimeLogWriter.js +129 -0
  375. package/dist/core/runtime/runtimeLogWriter.js.map +1 -0
  376. package/dist/core/runtime/runtimeTaskManager.d.ts +78 -0
  377. package/dist/core/runtime/runtimeTaskManager.js +374 -0
  378. package/dist/core/runtime/runtimeTaskManager.js.map +1 -0
  379. package/dist/core/runtime/sessionRegistry.d.ts +19 -0
  380. package/dist/core/runtime/sessionRegistry.js +41 -0
  381. package/dist/core/runtime/sessionRegistry.js.map +1 -0
  382. package/dist/core/runtime/stateProvider.d.ts +69 -0
  383. package/dist/core/runtime/stateProvider.js +131 -0
  384. package/dist/core/runtime/stateProvider.js.map +1 -0
  385. package/dist/core/runtime/subAgentTaskManager.d.ts +111 -0
  386. package/dist/core/runtime/subAgentTaskManager.js +386 -0
  387. package/dist/core/runtime/subAgentTaskManager.js.map +1 -0
  388. package/dist/core/schemaValidation.d.ts +5 -0
  389. package/dist/core/schemaValidation.js +153 -0
  390. package/dist/core/schemaValidation.js.map +1 -0
  391. package/dist/core/skills/loader.d.ts +7 -0
  392. package/dist/core/skills/loader.js +91 -0
  393. package/dist/core/skills/loader.js.map +1 -0
  394. package/dist/core/skills/runtime.d.ts +19 -0
  395. package/dist/core/skills/runtime.js +61 -0
  396. package/dist/core/skills/runtime.js.map +1 -0
  397. package/dist/core/subAgent.d.ts +50 -0
  398. package/dist/core/subAgent.js +1258 -0
  399. package/dist/core/subAgent.js.map +1 -0
  400. package/dist/core/systemPrompt.d.ts +27 -0
  401. package/dist/core/systemPrompt.js +219 -0
  402. package/dist/core/systemPrompt.js.map +1 -0
  403. package/dist/core/taskManager.d.ts +105 -0
  404. package/dist/core/taskManager.js +617 -0
  405. package/dist/core/taskManager.js.map +1 -0
  406. package/dist/core/tokenCompressor.d.ts +14 -0
  407. package/dist/core/tokenCompressor.js +161 -0
  408. package/dist/core/tokenCompressor.js.map +1 -0
  409. package/dist/core/tokenCounter.d.ts +28 -0
  410. package/dist/core/tokenCounter.js +101 -0
  411. package/dist/core/tokenCounter.js.map +1 -0
  412. package/dist/core/toolDispatcher.d.ts +11 -0
  413. package/dist/core/toolDispatcher.js +38 -0
  414. package/dist/core/toolDispatcher.js.map +1 -0
  415. package/dist/core/toolExecutionLedger.d.ts +9 -0
  416. package/dist/core/toolExecutionLedger.js +84 -0
  417. package/dist/core/toolExecutionLedger.js.map +1 -0
  418. package/dist/core/toolRegistry.d.ts +19 -0
  419. package/dist/core/toolRegistry.js +820 -0
  420. package/dist/core/toolRegistry.js.map +1 -0
  421. package/dist/core/turnStrategy.d.ts +20 -0
  422. package/dist/core/turnStrategy.js +103 -0
  423. package/dist/core/turnStrategy.js.map +1 -0
  424. package/dist/platform/process.d.ts +14 -0
  425. package/dist/platform/process.js +28 -0
  426. package/dist/platform/process.js.map +1 -0
  427. package/dist/platform/runtime.d.ts +8 -0
  428. package/dist/platform/runtime.js +21 -0
  429. package/dist/platform/runtime.js.map +1 -0
  430. package/dist/server/adminPage.d.ts +1 -0
  431. package/dist/server/adminPage.js +755 -0
  432. package/dist/server/adminPage.js.map +1 -0
  433. package/dist/server/index.d.ts +22 -0
  434. package/dist/server/index.js +566 -0
  435. package/dist/server/index.js.map +1 -0
  436. package/dist/shared/agentTypes.d.ts +227 -0
  437. package/dist/shared/agentTypes.js +79 -0
  438. package/dist/shared/agentTypes.js.map +1 -0
  439. package/dist/shared/codeIndexTypes.d.ts +32 -0
  440. package/dist/shared/codeIndexTypes.js +2 -0
  441. package/dist/shared/codeIndexTypes.js.map +1 -0
  442. package/dist/shared/flowEvents.d.ts +192 -0
  443. package/dist/shared/flowEvents.js +37 -0
  444. package/dist/shared/flowEvents.js.map +1 -0
  445. package/dist/shared/memoryTypes.d.ts +100 -0
  446. package/dist/shared/memoryTypes.js +2 -0
  447. package/dist/shared/memoryTypes.js.map +1 -0
  448. package/dist/shared/pluginTypes.d.ts +345 -0
  449. package/dist/shared/pluginTypes.js +2 -0
  450. package/dist/shared/pluginTypes.js.map +1 -0
  451. package/dist/shared/runtimeTaskTypes.d.ts +43 -0
  452. package/dist/shared/runtimeTaskTypes.js +2 -0
  453. package/dist/shared/runtimeTaskTypes.js.map +1 -0
  454. package/dist/shared/skillTypes.d.ts +1 -0
  455. package/dist/shared/skillTypes.js +2 -0
  456. package/dist/shared/skillTypes.js.map +1 -0
  457. package/dist/shared/subAgentTypes.d.ts +99 -0
  458. package/dist/shared/subAgentTypes.js +2 -0
  459. package/dist/shared/subAgentTypes.js.map +1 -0
  460. package/dist/shared/terminalTypes.d.ts +102 -0
  461. package/dist/shared/terminalTypes.js +2 -0
  462. package/dist/shared/terminalTypes.js.map +1 -0
  463. package/dist/shared/toolCallMarkup.d.ts +10 -0
  464. package/dist/shared/toolCallMarkup.js +107 -0
  465. package/dist/shared/toolCallMarkup.js.map +1 -0
  466. package/dist/shared/toolTypes.d.ts +24 -0
  467. package/dist/shared/toolTypes.js +2 -0
  468. package/dist/shared/toolTypes.js.map +1 -0
  469. package/dist/shared/types.d.ts +81 -0
  470. package/dist/shared/types.js +2 -0
  471. package/dist/shared/types.js.map +1 -0
  472. package/dist/state/types.d.ts +69 -0
  473. package/dist/state/types.js +2 -0
  474. package/dist/state/types.js.map +1 -0
  475. package/dist/tools/executor.d.ts +133 -0
  476. package/dist/tools/executor.js +2 -0
  477. package/dist/tools/executor.js.map +1 -0
  478. package/dist/tools/memory/loaders.d.ts +6 -0
  479. package/dist/tools/memory/loaders.js +292 -0
  480. package/dist/tools/memory/loaders.js.map +1 -0
  481. package/dist/tools/memory/sanitizer.d.ts +6 -0
  482. package/dist/tools/memory/sanitizer.js +48 -0
  483. package/dist/tools/memory/sanitizer.js.map +1 -0
  484. package/dist/tools/memory/service.d.ts +24 -0
  485. package/dist/tools/memory/service.js +273 -0
  486. package/dist/tools/memory/service.js.map +1 -0
  487. package/dist/tools/memory/writer.d.ts +17 -0
  488. package/dist/tools/memory/writer.js +192 -0
  489. package/dist/tools/memory/writer.js.map +1 -0
  490. package/package.json +68 -0
@@ -0,0 +1,1258 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { isAbsolute, relative, resolve } from 'path';
3
+ import { createTurboFluxRequestHeaders } from './clientIdentity';
4
+ import { resolveNativeReasoningRequest } from './modelRegistry';
5
+ import { downgradeReasoningEffort, extractUnsupportedRequestParam, isReasoningEffortValueError, removeAnthropicCompatibleRequestParam, removeOpenAICompatibleRequestParam, setOpenAIChatMaxTokens, } from './requestCompatibility';
6
+ import { loadAgentsFromDir } from './agents/loader';
7
+ import { ModelProtocolRequestError, buildModelProtocolUrl, formatProtocolAttempt, formatProtocolFailure, looksLikeResponsesPreferredModel, planModelProtocols, shouldFallbackProtocol, toProtocolAttempt, toResponsesInput, toResponsesTools, } from './modelProtocol';
8
+ const registeredAgents = new Map();
9
+ let workspaceAgents = new Map();
10
+ export function loadDynamicAgents(workspacePath) {
11
+ const loaded = loadAgentsFromDir(workspacePath);
12
+ const nextWorkspaceAgents = new Map();
13
+ for (const agent of loaded) {
14
+ nextWorkspaceAgents.set(agent.id, agent);
15
+ }
16
+ workspaceAgents = nextWorkspaceAgents;
17
+ }
18
+ function resolveWorkspacePath(workspacePath, pathValue) {
19
+ const scopeRoot = resolve(workspacePath);
20
+ const path = String(pathValue || '').trim();
21
+ const candidate = path ? resolve(scopeRoot, path) : scopeRoot;
22
+ const scopeRelative = relative(scopeRoot, candidate);
23
+ if (scopeRelative === '..' || scopeRelative.startsWith('../') || scopeRelative.startsWith('..\\') || isAbsolute(scopeRelative)) {
24
+ throw new Error(`Path escapes the delegated subagent scope: ${path}`);
25
+ }
26
+ return candidate;
27
+ }
28
+ function toWorkspaceRelative(workspacePath, filePath) {
29
+ const rel = isAbsolute(filePath) ? relative(workspacePath, filePath) : filePath;
30
+ return rel.replace(/\\/g, '/').replace(/^[./]+/, '');
31
+ }
32
+ function normalizeCodeSearchHits(value) {
33
+ if (!Array.isArray(value))
34
+ return [];
35
+ return value.filter((item) => item && typeof item === 'object' && typeof item.path === 'string');
36
+ }
37
+ function collectCodeMapEvidence(nodes, workspacePath) {
38
+ const evidence = [];
39
+ const visit = (node) => {
40
+ if (node.path) {
41
+ evidence.push({
42
+ path: toWorkspaceRelative(workspacePath, node.path),
43
+ startLine: node.startLine || node.line || 1,
44
+ endLine: node.endLine || node.line || 1,
45
+ preview: `${node.title}${node.summary ? ` - ${node.summary}` : ''}`,
46
+ reason: 'codemap',
47
+ symbol: node.kind === 'symbol' ? node.title : undefined,
48
+ });
49
+ }
50
+ for (const child of node.children || [])
51
+ visit(child);
52
+ };
53
+ for (const node of nodes)
54
+ visit(node);
55
+ return evidence;
56
+ }
57
+ function formatCodeMapNode(node, lines, depth = 0) {
58
+ const indent = ' '.repeat(depth);
59
+ const loc = node.path ? ` ${node.path}${node.line ? `:${node.line}` : ''}` : '';
60
+ lines.push(`${indent}- ${node.title}${loc}${node.summary ? ` - ${node.summary}` : ''}`);
61
+ for (const child of (node.children || []).slice(0, 12)) {
62
+ formatCodeMapNode(child, lines, depth + 1);
63
+ }
64
+ }
65
+ export function registerAgent(def, skillRuntime) {
66
+ const loaded = def;
67
+ registeredAgents.set(def.id, loaded);
68
+ if (loaded.skills && loaded.skills.length > 0 && skillRuntime) {
69
+ const agentSkills = loaded.skills.map(skillId => ({
70
+ id: skillId,
71
+ name: skillId,
72
+ command: `/${skillId}`,
73
+ description: `Skill registered by agent: ${def.id}`,
74
+ category: 'custom',
75
+ systemPrompt: '',
76
+ source: 'system',
77
+ filePath: `[agent:${def.id}]`,
78
+ rawContent: '',
79
+ }));
80
+ skillRuntime.registerSkills(agentSkills);
81
+ }
82
+ }
83
+ export function getSubAgentDefinition(type) {
84
+ return workspaceAgents.get(type) ?? registeredAgents.get(type);
85
+ }
86
+ export function getAllAgentDefinitions() {
87
+ const map = new Map();
88
+ for (const [id, def] of registeredAgents) {
89
+ map.set(id, def);
90
+ }
91
+ for (const [id, def] of workspaceAgents) {
92
+ map.set(id, def);
93
+ }
94
+ return [...map.values()];
95
+ }
96
+ export function getAvailableAgentTypes() {
97
+ return getAllAgentDefinitions().map(d => d.id);
98
+ }
99
+ export function syncAgentSkills(skillRuntime) {
100
+ for (const definition of getAllAgentDefinitions()) {
101
+ const agent = definition;
102
+ const loaded = agent;
103
+ if (!loaded.skills || loaded.skills.length === 0)
104
+ continue;
105
+ const agentSkills = loaded.skills.map(skillId => ({
106
+ id: skillId,
107
+ name: skillId,
108
+ command: `/${skillId}`,
109
+ description: `Skill registered by agent: ${agent.id}`,
110
+ category: 'custom',
111
+ systemPrompt: '',
112
+ source: 'system',
113
+ filePath: `[agent:${agent.id}]`,
114
+ rawContent: '',
115
+ }));
116
+ skillRuntime.registerSkills(agentSkills);
117
+ }
118
+ }
119
+ function boundToolOutput(tool, content) {
120
+ const limit = tool === 'read_file' ? 12_000 : 8_000;
121
+ if (content.length <= limit)
122
+ return content;
123
+ const head = Math.floor(limit * 0.8);
124
+ const tail = limit - head - 64;
125
+ return `${content.slice(0, head)}\n...[tool output bounded once for stable history]...\n${content.slice(-tail)}`;
126
+ }
127
+ const TRANSIENT_HTTP_STATUSES = new Set([408, 409, 429, 500, 502, 503, 504]);
128
+ const TRANSIENT_RETRY_DELAYS_MS = [300, 900, 1_800];
129
+ const PROTOCOL_CACHE_TTL_MS = 10 * 60_000;
130
+ const PROTOCOL_CACHE_MAX_ENTRIES = 64;
131
+ const protocolCache = new Map();
132
+ function protocolCacheKey(params) {
133
+ const headers = Object.entries(params.customHeaders || {})
134
+ .sort(([left], [right]) => left.localeCompare(right))
135
+ .map(([key, value]) => `${key.toLowerCase()}:${value}`)
136
+ .join('\n');
137
+ return createHash('sha256')
138
+ .update([
139
+ params.baseUrl.replace(/\/+$/, ''),
140
+ params.provider || '',
141
+ params.model,
142
+ params.apiKey,
143
+ headers,
144
+ ].join('\0'))
145
+ .digest('hex');
146
+ }
147
+ function getCachedProtocol(key) {
148
+ const cached = protocolCache.get(key);
149
+ if (!cached)
150
+ return null;
151
+ if (cached.expiresAt <= Date.now()) {
152
+ protocolCache.delete(key);
153
+ return null;
154
+ }
155
+ protocolCache.delete(key);
156
+ protocolCache.set(key, cached);
157
+ return cached.protocol;
158
+ }
159
+ function rememberProtocol(key, protocol) {
160
+ protocolCache.delete(key);
161
+ protocolCache.set(key, { protocol, expiresAt: Date.now() + PROTOCOL_CACHE_TTL_MS });
162
+ while (protocolCache.size > PROTOCOL_CACHE_MAX_ENTRIES) {
163
+ const oldest = protocolCache.keys().next().value;
164
+ if (!oldest)
165
+ break;
166
+ protocolCache.delete(oldest);
167
+ }
168
+ }
169
+ export function __testClearSubAgentProtocolCache() {
170
+ protocolCache.clear();
171
+ }
172
+ const TRANSIENT_NETWORK_CODES = new Set([
173
+ 'ECONNREFUSED',
174
+ 'ECONNRESET',
175
+ 'EPIPE',
176
+ 'EAI_AGAIN',
177
+ 'ENETDOWN',
178
+ 'ENETRESET',
179
+ 'ENETUNREACH',
180
+ 'ETIMEDOUT',
181
+ 'UND_ERR_CONNECT_TIMEOUT',
182
+ 'UND_ERR_HEADERS_TIMEOUT',
183
+ 'UND_ERR_BODY_TIMEOUT',
184
+ 'UND_ERR_SOCKET',
185
+ ]);
186
+ function removeCompatibleRequestParam(protocol, body, headers, param) {
187
+ return protocol === 'anthropic_messages'
188
+ ? removeAnthropicCompatibleRequestParam(body, headers, param)
189
+ : removeOpenAICompatibleRequestParam(body, param);
190
+ }
191
+ async function fetchWithTimeout(url, init, parentSignal, timeoutMs = 120_000) {
192
+ const controller = new AbortController();
193
+ let timedOut = false;
194
+ const abort = () => controller.abort();
195
+ if (parentSignal?.aborted)
196
+ controller.abort();
197
+ else
198
+ parentSignal?.addEventListener('abort', abort, { once: true });
199
+ const timer = setTimeout(() => {
200
+ timedOut = true;
201
+ controller.abort();
202
+ }, timeoutMs);
203
+ try {
204
+ return await fetch(url, { ...init, signal: controller.signal });
205
+ }
206
+ catch (error) {
207
+ if (timedOut && !parentSignal?.aborted) {
208
+ throw new Error(`Model request timed out after ${timeoutMs}ms`);
209
+ }
210
+ throw error;
211
+ }
212
+ finally {
213
+ clearTimeout(timer);
214
+ parentSignal?.removeEventListener('abort', abort);
215
+ }
216
+ }
217
+ function abortableDelay(delayMs, signal) {
218
+ if (delayMs <= 0)
219
+ return Promise.resolve();
220
+ return new Promise((resolve, reject) => {
221
+ const onAbort = () => {
222
+ clearTimeout(timer);
223
+ const error = new Error('Aborted');
224
+ error.name = 'AbortError';
225
+ reject(error);
226
+ };
227
+ const timer = setTimeout(() => {
228
+ signal?.removeEventListener('abort', onAbort);
229
+ resolve();
230
+ }, delayMs);
231
+ if (signal?.aborted)
232
+ onAbort();
233
+ else
234
+ signal?.addEventListener('abort', onAbort, { once: true });
235
+ });
236
+ }
237
+ function errorCode(error) {
238
+ let current = error;
239
+ for (let depth = 0; current && depth < 4; depth += 1) {
240
+ if (typeof current === 'object') {
241
+ const code = current.code;
242
+ if (typeof code === 'string')
243
+ return code;
244
+ current = current.cause;
245
+ continue;
246
+ }
247
+ break;
248
+ }
249
+ return undefined;
250
+ }
251
+ function isTransientNetworkError(error) {
252
+ const code = errorCode(error);
253
+ if (code && TRANSIENT_NETWORK_CODES.has(code))
254
+ return true;
255
+ return error instanceof TypeError && /fetch failed|network|socket/i.test(error.message);
256
+ }
257
+ function retryAfterMs(response) {
258
+ const value = response.headers.get('retry-after')?.trim();
259
+ if (!value)
260
+ return 200;
261
+ const seconds = Number(value);
262
+ if (Number.isFinite(seconds))
263
+ return Math.max(0, Math.min(2_000, seconds * 1_000));
264
+ const at = Date.parse(value);
265
+ return Number.isFinite(at) ? Math.max(0, Math.min(2_000, at - Date.now())) : 200;
266
+ }
267
+ async function fetchWithTransientRetry(url, init, parentSignal, timeoutMs, attemptTimeoutMs, onRetry, maxAttempts = 4) {
268
+ const startedAt = Date.now();
269
+ let lastError;
270
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
271
+ const remainingMs = timeoutMs - (Date.now() - startedAt);
272
+ if (remainingMs < 1) {
273
+ throw lastError || new Error(`Model request timed out after ${timeoutMs}ms`);
274
+ }
275
+ try {
276
+ const response = await fetchWithTimeout(url, init, parentSignal, Math.min(remainingMs, attemptTimeoutMs));
277
+ if (attempt < maxAttempts && TRANSIENT_HTTP_STATUSES.has(response.status)) {
278
+ const requestedDelay = Math.max(retryAfterMs(response), TRANSIENT_RETRY_DELAYS_MS[attempt - 1] || 1_800);
279
+ const remainingAfterResponseMs = timeoutMs - (Date.now() - startedAt);
280
+ const delayMs = Math.min(requestedDelay, Math.max(0, remainingAfterResponseMs - 1));
281
+ if (delayMs <= 0)
282
+ return response;
283
+ onRetry(attempt + 1, delayMs, `API ${response.status}`);
284
+ await response.body?.cancel().catch(() => undefined);
285
+ await abortableDelay(delayMs, parentSignal);
286
+ continue;
287
+ }
288
+ return response;
289
+ }
290
+ catch (error) {
291
+ lastError = error;
292
+ const isAbort = parentSignal?.aborted === true;
293
+ const isTimeout = error instanceof Error && /timed out after \d+ms/i.test(error.message);
294
+ if (attempt === maxAttempts || isAbort || (!isTimeout && !isTransientNetworkError(error)))
295
+ throw error;
296
+ const elapsedMs = Date.now() - startedAt;
297
+ const delayMs = Math.min(TRANSIENT_RETRY_DELAYS_MS[attempt - 1] || 1_800, Math.max(0, timeoutMs - elapsedMs - 1));
298
+ if (delayMs <= 0)
299
+ throw error;
300
+ onRetry(attempt + 1, delayMs, formatSubAgentError(error));
301
+ await abortableDelay(delayMs, parentSignal);
302
+ }
303
+ }
304
+ throw lastError || new Error('Model request failed');
305
+ }
306
+ function toAnthropicMessages(messages, cacheCodemap = false) {
307
+ const source = messages.filter(message => message.role !== 'system');
308
+ const normalized = [];
309
+ for (let index = 0; index < source.length; index += 1) {
310
+ const message = source[index];
311
+ if (message.role === 'assistant' && message.tool_calls?.length) {
312
+ normalized.push({
313
+ role: 'assistant',
314
+ content: [
315
+ ...(message.content ? [{ type: 'text', text: message.content }] : []),
316
+ ...message.tool_calls.map(toolCall => ({
317
+ type: 'tool_use',
318
+ id: toolCall.id,
319
+ name: toolCall.function.name,
320
+ input: JSON.parse(toolCall.function.arguments || '{}'),
321
+ })),
322
+ ],
323
+ });
324
+ continue;
325
+ }
326
+ if (message.role === 'tool') {
327
+ const results = [];
328
+ let nextIndex = index;
329
+ while (nextIndex < source.length && source[nextIndex].role === 'tool') {
330
+ const toolMessage = source[nextIndex];
331
+ results.push({ type: 'tool_result', tool_use_id: toolMessage.tool_call_id, content: toolMessage.content });
332
+ nextIndex += 1;
333
+ }
334
+ normalized.push({
335
+ role: 'user',
336
+ content: results,
337
+ });
338
+ index = nextIndex - 1;
339
+ continue;
340
+ }
341
+ normalized.push(cacheCodemap && message.role === 'user' && message.content.startsWith('Workspace structure:')
342
+ ? { role: message.role, content: [{ type: 'text', text: message.content, cache_control: { type: 'ephemeral' } }] }
343
+ : { role: message.role, content: message.content });
344
+ }
345
+ return normalized;
346
+ }
347
+ function subAgentPromptCacheKey(params) {
348
+ const toolNames = params.tools.map(tool => String(tool.function?.name || '')).join(',');
349
+ const digest = createHash('sha256')
350
+ .update([
351
+ params.definition.id,
352
+ params.definition.systemPrompt,
353
+ params.workspacePath.replace(/\\/g, '/').toLowerCase(),
354
+ params.codemap || '',
355
+ toolNames,
356
+ ].join('\0'))
357
+ .digest('hex')
358
+ .slice(0, 24);
359
+ return `tf:subagent:${params.model}:${params.definition.id}:${digest}`.slice(0, 240);
360
+ }
361
+ export async function runSubAgent(options) {
362
+ const { definition, objective, workspacePath, toolExecutor, apiKey, baseUrl, provider, customHeaders, model, codemap, abortSignal, onEvent, reasoning, modelCapabilities, } = options;
363
+ const requestTimeoutMs = Math.max(1_000, options.requestTimeoutMs ?? 120_000);
364
+ const requestAttemptTimeoutMs = Math.max(1_000, Math.min(requestTimeoutMs, options.requestAttemptTimeoutMs ?? requestTimeoutMs));
365
+ const startedAt = Date.now();
366
+ const emit = (event) => onEvent?.(event);
367
+ const messages = [];
368
+ messages.push({ role: 'system', content: definition.systemPrompt });
369
+ if (codemap) {
370
+ messages.push({ role: 'user', content: `Workspace structure:\n${codemap}` });
371
+ messages.push({ role: 'assistant', content: 'READY' });
372
+ }
373
+ messages.push({
374
+ role: 'user',
375
+ content: options.userPrompt || [
376
+ `Objective: ${objective}`,
377
+ '\nUse the available read-only tools as needed. Return a concise result grounded in the files and line ranges you inspected, and state any remaining uncertainty.',
378
+ ].join('\n'),
379
+ });
380
+ const tools = [
381
+ {
382
+ type: 'function',
383
+ function: {
384
+ name: 'search_content',
385
+ description: 'Grep for a regex pattern across the codebase',
386
+ parameters: {
387
+ type: 'object',
388
+ properties: {
389
+ pattern: { type: 'string' },
390
+ path: { type: 'string' },
391
+ file_pattern: { type: 'string' },
392
+ case_sensitive: { type: 'boolean' },
393
+ offset: { type: 'number' },
394
+ head_limit: { type: 'number' },
395
+ context_before: { type: 'number' },
396
+ context_after: { type: 'number' },
397
+ multiline: { type: 'boolean' },
398
+ file_type: { type: 'string' },
399
+ },
400
+ required: ['pattern'],
401
+ },
402
+ },
403
+ },
404
+ {
405
+ type: 'function',
406
+ function: {
407
+ name: 'read_file',
408
+ description: 'Read a bounded line range without loading the whole file. offset is 1-based.',
409
+ parameters: {
410
+ type: 'object',
411
+ properties: {
412
+ path: { type: 'string' },
413
+ offset: { type: 'number' },
414
+ limit: { type: 'number' },
415
+ },
416
+ required: ['path'],
417
+ },
418
+ },
419
+ },
420
+ {
421
+ type: 'function',
422
+ function: {
423
+ name: 'search_files',
424
+ description: 'Find files by glob pattern',
425
+ parameters: {
426
+ type: 'object',
427
+ properties: {
428
+ pattern: { type: 'string' },
429
+ },
430
+ required: ['pattern'],
431
+ },
432
+ },
433
+ },
434
+ {
435
+ type: 'function',
436
+ function: {
437
+ name: 'search_symbol',
438
+ description: 'Search deterministic source declarations such as functions, classes, interfaces, types, constants, and components',
439
+ parameters: {
440
+ type: 'object',
441
+ properties: {
442
+ query: { type: 'string' },
443
+ path: { type: 'string' },
444
+ symbol_kind: { type: 'string', enum: ['class', 'function', 'interface', 'type', 'enum', 'constant'] },
445
+ },
446
+ required: ['query'],
447
+ },
448
+ },
449
+ },
450
+ {
451
+ type: 'function',
452
+ function: {
453
+ name: 'get_codemap',
454
+ description: 'Generate a compact graph map with typed caller and callee relationships for a feature area or path before drilling into files',
455
+ parameters: {
456
+ type: 'object',
457
+ properties: {
458
+ query: { type: 'string' },
459
+ path: { type: 'string' },
460
+ },
461
+ required: ['query'],
462
+ },
463
+ },
464
+ },
465
+ ];
466
+ const allowedToolNames = options.allowedTools ? new Set(options.allowedTools) : undefined;
467
+ const availableTools = allowedToolNames
468
+ ? tools.filter(tool => allowedToolNames.has(tool.function.name))
469
+ : tools;
470
+ const modelId = model?.trim();
471
+ if (!modelId) {
472
+ const message = `Subagent ${definition.label} requires an active model from the main agent.`;
473
+ emit({ type: 'error', message });
474
+ return { ok: false, finalText: '', evidence: [], turns: 0, elapsedMs: Date.now() - startedAt, truncated: false, error: message };
475
+ }
476
+ let turn = 0;
477
+ const collectedEvidence = [];
478
+ const evidenceKeys = new Set(collectedEvidence.map(evidence => `${evidence.path}:${evidence.startLine}-${evidence.endLine}:${evidence.reason}`));
479
+ const toolResultCache = new Map();
480
+ const activeProtocolCacheKey = protocolCacheKey({ baseUrl, provider, model: modelId, apiKey, customHeaders });
481
+ let resolvedProtocol = getCachedProtocol(activeProtocolCacheKey);
482
+ const turnLimit = definition.maxTurns;
483
+ const effectiveReasoning = definition.thinking === 'disabled'
484
+ ? { enabled: false, effort: 'none' }
485
+ : definition.thinking === 'high' || definition.thinking === 'max'
486
+ ? { ...reasoning, enabled: true, effort: definition.thinking }
487
+ : reasoning;
488
+ const addEvidence = (evidence) => {
489
+ const key = `${evidence.path}:${evidence.startLine}-${evidence.endLine}:${evidence.reason}`;
490
+ if (evidenceKeys.has(key))
491
+ return false;
492
+ evidenceKeys.add(key);
493
+ collectedEvidence.push(evidence);
494
+ return true;
495
+ };
496
+ while (turn < turnLimit) {
497
+ if (abortSignal?.aborted)
498
+ break;
499
+ turn++;
500
+ const turnStartedAt = Date.now();
501
+ let modelElapsedMs = 0;
502
+ let turnInputTokens = 0;
503
+ let turnOutputTokens = 0;
504
+ let turnCacheReadTokens = 0;
505
+ let turnReasoningTokens = 0;
506
+ emit({ type: 'turn_start', turn, maxTurns: turnLimit });
507
+ let messageText = '';
508
+ let responseToolCalls = [];
509
+ let responseToolViolation = '';
510
+ const waitStartedAt = Date.now();
511
+ const requestDeadline = waitStartedAt + requestTimeoutMs;
512
+ emit({ type: 'model_wait', turn, elapsedMs: 0, timeoutMs: requestTimeoutMs });
513
+ const waitTimer = setInterval(() => {
514
+ emit({ type: 'model_wait', turn, elapsedMs: Date.now() - waitStartedAt, timeoutMs: requestTimeoutMs });
515
+ }, 5_000);
516
+ try {
517
+ const providerHint = provider === 'anthropic' ? 'anthropic' : provider === 'openai' ? 'openai' : 'custom';
518
+ const plannedProtocols = planModelProtocols(providerHint, modelId);
519
+ const protocolCandidates = resolvedProtocol
520
+ ? [resolvedProtocol, ...plannedProtocols.filter(protocol => protocol !== resolvedProtocol)]
521
+ : plannedProtocols;
522
+ const protocolAttempts = [];
523
+ let parsedResponse = false;
524
+ for (let protocolIndex = 0; protocolIndex < protocolCandidates.length; protocolIndex += 1) {
525
+ const protocol = protocolCandidates[protocolIndex];
526
+ const url = buildModelProtocolUrl(baseUrl, protocol, provider);
527
+ const activeSystemPrompt = definition.systemPrompt;
528
+ const activeMessages = messages.map(message => ({ ...message }));
529
+ const requestMessages = activeMessages.map(message => ({ ...message }));
530
+ const requestTools = availableTools;
531
+ const requestBody = protocol === 'anthropic_messages'
532
+ ? {
533
+ model: modelId,
534
+ system: [{ type: 'text', text: activeSystemPrompt, cache_control: { type: 'ephemeral' } }],
535
+ messages: toAnthropicMessages(activeMessages, Boolean(codemap)),
536
+ tools: requestTools.map(tool => ({
537
+ name: tool.function.name,
538
+ description: tool.function.description,
539
+ input_schema: tool.function.parameters,
540
+ })),
541
+ temperature: definition.temperature ?? 0,
542
+ max_tokens: definition.maxOutputTokens || 4096,
543
+ }
544
+ : protocol === 'openai_responses'
545
+ ? {
546
+ model: modelId,
547
+ instructions: activeSystemPrompt,
548
+ input: toResponsesInput(requestMessages),
549
+ tools: toResponsesTools(requestTools),
550
+ temperature: definition.temperature ?? 0,
551
+ max_output_tokens: definition.maxOutputTokens || 4096,
552
+ store: false,
553
+ }
554
+ : {
555
+ model: modelId,
556
+ messages: activeMessages,
557
+ tools: requestTools,
558
+ temperature: definition.temperature ?? 0,
559
+ max_tokens: definition.maxOutputTokens || 4096,
560
+ stream: false,
561
+ };
562
+ if (protocol === 'openai_chat') {
563
+ setOpenAIChatMaxTokens(requestBody, definition.maxOutputTokens || 4096, provider, modelId);
564
+ }
565
+ const reasoningRequest = resolveNativeReasoningRequest(modelId, effectiveReasoning, provider, modelCapabilities);
566
+ const reasoningEffort = reasoningRequest?.reasoningEffort ?? reasoningRequest?.outputConfig?.effort;
567
+ if (protocol === 'anthropic_messages') {
568
+ if (reasoningRequest?.thinking)
569
+ requestBody.thinking = reasoningRequest.thinking;
570
+ if (reasoningRequest?.outputConfig)
571
+ requestBody.output_config = reasoningRequest.outputConfig;
572
+ }
573
+ else if (protocol === 'openai_responses') {
574
+ if (reasoningEffort && reasoningEffort !== 'none')
575
+ requestBody.reasoning = { effort: reasoningEffort };
576
+ requestBody.parallel_tool_calls = true;
577
+ }
578
+ else {
579
+ if (reasoningRequest?.thinking)
580
+ requestBody.thinking = reasoningRequest.thinking;
581
+ if (reasoningRequest?.reasoningEffort && reasoningRequest.reasoningEffort !== 'none')
582
+ requestBody.reasoning_effort = reasoningRequest.reasoningEffort;
583
+ if (reasoningRequest?.outputConfig)
584
+ requestBody.output_config = reasoningRequest.outputConfig;
585
+ requestBody.parallel_tool_calls = true;
586
+ }
587
+ if (requestTools.length === 0) {
588
+ delete requestBody.tools;
589
+ delete requestBody.tool_choice;
590
+ delete requestBody.parallel_tool_calls;
591
+ }
592
+ if (protocol !== 'anthropic_messages' && (provider === 'openai' || provider === 'kimi' || looksLikeResponsesPreferredModel(modelId) || /(?:^|[/_.:-])(?:kimi|moonshot)(?:$|[/_.:-])/i.test(modelId))) {
593
+ requestBody.prompt_cache_key = subAgentPromptCacheKey({
594
+ definition,
595
+ model: modelId,
596
+ workspacePath,
597
+ codemap,
598
+ tools: requestTools,
599
+ });
600
+ if (protocol === 'openai_responses' && /gpt-5\.5/i.test(modelId)) {
601
+ requestBody.prompt_cache_retention = '24h';
602
+ }
603
+ }
604
+ if (reasoningRequest?.omitTemperature)
605
+ delete requestBody.temperature;
606
+ const headers = createTurboFluxRequestHeaders(protocol === 'anthropic_messages'
607
+ ? {
608
+ 'Content-Type': 'application/json',
609
+ 'x-api-key': apiKey,
610
+ 'anthropic-version': '2023-06-01',
611
+ ...(provider === 'anthropic' ? {} : { 'Authorization': `Bearer ${apiKey}` }),
612
+ ...customHeaders,
613
+ }
614
+ : { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}`, ...customHeaders });
615
+ let res;
616
+ let errorText = '';
617
+ for (let compatibilityAttempt = 0; compatibilityAttempt < 4; compatibilityAttempt += 1) {
618
+ const remainingRequestMs = requestDeadline - Date.now();
619
+ if (remainingRequestMs <= 0)
620
+ throw new Error(`Model request timed out after ${requestTimeoutMs}ms`);
621
+ res = await fetchWithTransientRetry(url, {
622
+ method: 'POST',
623
+ headers,
624
+ body: JSON.stringify(requestBody),
625
+ }, abortSignal, remainingRequestMs, requestAttemptTimeoutMs, (attempt, delayMs, reason) => {
626
+ emit({ type: 'model_retry', turn, attempt, delayMs, reason });
627
+ }, options.maxTransientAttempts ?? 4);
628
+ if (res.ok)
629
+ break;
630
+ errorText = await res.text();
631
+ if (isReasoningEffortValueError(errorText)) {
632
+ const fallback = downgradeReasoningEffort(requestBody);
633
+ if (fallback) {
634
+ emit({
635
+ type: 'model_retry',
636
+ turn,
637
+ attempt: compatibilityAttempt + 2,
638
+ delayMs: 0,
639
+ reason: `Provider rejected reasoning effort ${fallback.from}; retrying with ${fallback.to}.`,
640
+ });
641
+ continue;
642
+ }
643
+ }
644
+ const unsupportedParam = extractUnsupportedRequestParam(errorText);
645
+ if (compatibilityAttempt >= 3
646
+ || (res.status !== 400 && res.status !== 422)
647
+ || !unsupportedParam
648
+ || !removeCompatibleRequestParam(protocol, requestBody, headers, unsupportedParam))
649
+ break;
650
+ emit({
651
+ type: 'model_retry',
652
+ turn,
653
+ attempt: compatibilityAttempt + 2,
654
+ delayMs: 0,
655
+ reason: `Provider rejected "${unsupportedParam}"; retrying without that optional parameter.`,
656
+ });
657
+ }
658
+ if (!res)
659
+ throw new Error('Model request returned no response');
660
+ if (!res.ok) {
661
+ if (!errorText)
662
+ errorText = await res.text();
663
+ const protocolError = new ModelProtocolRequestError(`HTTP ${res.status}: ${errorText || 'empty response'}`, {
664
+ protocol,
665
+ url,
666
+ status: res.status,
667
+ kind: 'http',
668
+ });
669
+ const attempt = toProtocolAttempt(protocolError);
670
+ protocolAttempts.push(attempt);
671
+ const nextProtocol = protocolCandidates[protocolIndex + 1];
672
+ if (nextProtocol && shouldFallbackProtocol(protocolError)) {
673
+ emit({
674
+ type: 'model_retry',
675
+ turn,
676
+ attempt: protocolIndex + 2,
677
+ delayMs: 0,
678
+ reason: `Protocol fallback: ${formatProtocolAttempt(attempt)} -> ${buildModelProtocolUrl(baseUrl, nextProtocol, provider)}`,
679
+ });
680
+ continue;
681
+ }
682
+ const failure = formatProtocolFailure(protocolAttempts);
683
+ emit({ type: 'error', message: failure });
684
+ return { ok: false, turns: turn, elapsedMs: Date.now() - startedAt, error: failure };
685
+ }
686
+ const response = await res.json();
687
+ const responseUsage = response?.usage || {};
688
+ turnInputTokens = Number(responseUsage.input_tokens ?? responseUsage.prompt_tokens ?? 0) || 0;
689
+ turnOutputTokens = Number(responseUsage.output_tokens ?? responseUsage.completion_tokens ?? 0) || 0;
690
+ turnCacheReadTokens = Number(responseUsage.input_tokens_details?.cached_tokens
691
+ ?? responseUsage.prompt_tokens_details?.cached_tokens
692
+ ?? responseUsage.cache_read_input_tokens
693
+ ?? 0) || 0;
694
+ turnReasoningTokens = Number(responseUsage.output_tokens_details?.reasoning_tokens
695
+ ?? responseUsage.completion_tokens_details?.reasoning_tokens
696
+ ?? 0) || 0;
697
+ if (protocol === 'anthropic_messages') {
698
+ const blocks = Array.isArray(response.content) ? response.content : [];
699
+ messageText = blocks.filter((block) => block.type === 'text').map((block) => block.text || '').join('');
700
+ responseToolCalls = blocks.filter((block) => block.type === 'tool_use').map((block) => ({
701
+ id: block.id,
702
+ function: { name: block.name, arguments: JSON.stringify(block.input || {}) },
703
+ }));
704
+ }
705
+ else if (protocol === 'openai_responses') {
706
+ if (!Array.isArray(response.output)) {
707
+ const message = `Responses endpoint ${url} returned no output array.`;
708
+ emit({ type: 'error', message });
709
+ return { ok: false, turns: turn, elapsedMs: Date.now() - startedAt, error: message };
710
+ }
711
+ messageText = response.output
712
+ .filter((item) => item?.type === 'message' && Array.isArray(item.content))
713
+ .flatMap((item) => item.content)
714
+ .filter((item) => (item?.type === 'output_text' || item?.type === 'refusal') && typeof item.text === 'string')
715
+ .map((item) => item.text)
716
+ .join('');
717
+ responseToolCalls = response.output
718
+ .filter((item) => item?.type === 'function_call' && typeof item.name === 'string')
719
+ .map((item, index) => ({
720
+ id: item.call_id || item.id || `call_${index}`,
721
+ function: { name: item.name, arguments: typeof item.arguments === 'string' ? item.arguments : '{}' },
722
+ }));
723
+ }
724
+ else {
725
+ const choice = response.choices?.[0];
726
+ if (!choice) {
727
+ const message = `Chat Completions endpoint ${url} returned no response choice.`;
728
+ emit({ type: 'error', message });
729
+ return { ok: false, turns: turn, elapsedMs: Date.now() - startedAt, error: message };
730
+ }
731
+ messageText = choice.message?.content || '';
732
+ responseToolCalls = choice.message?.tool_calls || [];
733
+ }
734
+ const offeredToolNames = new Set(requestTools.map(tool => tool.function.name));
735
+ const unexpectedToolNames = Array.from(new Set(responseToolCalls
736
+ .map(call => call.function.name)
737
+ .filter(name => !offeredToolNames.has(name))));
738
+ emit({
739
+ type: 'model_response',
740
+ turn,
741
+ protocol,
742
+ offeredTools: Array.from(offeredToolNames),
743
+ returnedTools: responseToolCalls.map(call => call.function.name),
744
+ });
745
+ if (unexpectedToolNames.length > 0) {
746
+ responseToolViolation = `Subagent provider returned tool(s) not offered for turn ${turn}: ${unexpectedToolNames.join(', ')}. The calls were not executed.`;
747
+ }
748
+ resolvedProtocol = protocol;
749
+ rememberProtocol(activeProtocolCacheKey, protocol);
750
+ parsedResponse = true;
751
+ break;
752
+ }
753
+ if (!parsedResponse) {
754
+ const failure = formatProtocolFailure(protocolAttempts);
755
+ emit({ type: 'error', message: failure });
756
+ return { ok: false, turns: turn, elapsedMs: Date.now() - startedAt, error: failure };
757
+ }
758
+ }
759
+ catch (e) {
760
+ if (e.name === 'AbortError')
761
+ return { ok: false, turns: turn, elapsedMs: Date.now() - startedAt, error: 'Aborted' };
762
+ const detail = formatSubAgentError(e);
763
+ const message = /Model request timed out after \d+ms/i.test(detail)
764
+ ? `Model request timed out after ${requestTimeoutMs}ms`
765
+ : detail;
766
+ emit({ type: 'error', message });
767
+ return { ok: false, turns: turn, elapsedMs: Date.now() - startedAt, error: message };
768
+ }
769
+ finally {
770
+ clearInterval(waitTimer);
771
+ modelElapsedMs = Date.now() - waitStartedAt;
772
+ }
773
+ if (responseToolViolation) {
774
+ emit({ type: 'error', message: responseToolViolation });
775
+ emit({
776
+ type: 'turn_complete',
777
+ turn,
778
+ calls: 0,
779
+ modelElapsedMs,
780
+ toolElapsedMs: 0,
781
+ totalElapsedMs: Date.now() - turnStartedAt,
782
+ inputTokens: turnInputTokens,
783
+ outputTokens: turnOutputTokens,
784
+ cacheReadTokens: turnCacheReadTokens,
785
+ reasoningTokens: turnReasoningTokens,
786
+ });
787
+ return {
788
+ ok: false,
789
+ turns: turn,
790
+ elapsedMs: Date.now() - startedAt,
791
+ evidence: collectedEvidence,
792
+ truncated: true,
793
+ error: responseToolViolation,
794
+ };
795
+ }
796
+ if (responseToolCalls.length === 0) {
797
+ emit({ type: 'final', text: messageText });
798
+ emit({
799
+ type: 'turn_complete',
800
+ turn,
801
+ calls: 0,
802
+ modelElapsedMs,
803
+ toolElapsedMs: 0,
804
+ totalElapsedMs: Date.now() - turnStartedAt,
805
+ inputTokens: turnInputTokens,
806
+ outputTokens: turnOutputTokens,
807
+ cacheReadTokens: turnCacheReadTokens,
808
+ reasoningTokens: turnReasoningTokens,
809
+ });
810
+ return { ok: true, turns: turn, elapsedMs: Date.now() - startedAt, finalText: messageText, evidence: collectedEvidence };
811
+ }
812
+ const toolCalls = responseToolCalls.slice(0, definition.maxParallel);
813
+ messages.push({ role: 'assistant', content: messageText, tool_calls: toolCalls });
814
+ const entries = toolCalls.map(tc => {
815
+ let args = {};
816
+ try {
817
+ args = JSON.parse(tc.function.arguments);
818
+ }
819
+ catch { }
820
+ emit({ type: 'tool_call', tool: tc.function.name, args, turn });
821
+ return { tc, args, signature: toolCallSignature(tc.function.name, args) };
822
+ });
823
+ const toolWaveStartedAt = Date.now();
824
+ const batchedSearchResults = new Map();
825
+ const batchableSearchEntries = entries.filter(entry => entry.tc.function.name === 'search_content'
826
+ && !toolResultCache.has(entry.signature)
827
+ && buildSearchContentBatchRequest(entry.args, workspacePath));
828
+ if (toolExecutor.searchContentBatch && batchableSearchEntries.length >= 2) {
829
+ const requests = batchableSearchEntries
830
+ .map(entry => buildSearchContentBatchRequest(entry.args, workspacePath))
831
+ .filter((request) => Boolean(request));
832
+ try {
833
+ const pages = await toolExecutor.searchContentBatch(requests);
834
+ pages.forEach((page, index) => {
835
+ const entry = batchableSearchEntries[index];
836
+ if (entry)
837
+ batchedSearchResults.set(entry.tc.id, page);
838
+ });
839
+ }
840
+ catch { }
841
+ }
842
+ const results = await Promise.all(entries.map(async (entry) => {
843
+ const toolStartedAt = Date.now();
844
+ const cached = toolResultCache.get(entry.signature);
845
+ if (cached)
846
+ return { entry, result: cached, reused: true, elapsedMs: 0 };
847
+ if (abortSignal?.aborted) {
848
+ return {
849
+ entry,
850
+ result: {
851
+ ok: false,
852
+ output: 'Aborted.',
853
+ summary: `${entry.tc.function.name} aborted`,
854
+ evidence: [],
855
+ },
856
+ reused: false,
857
+ elapsedMs: Date.now() - toolStartedAt,
858
+ };
859
+ }
860
+ try {
861
+ const batchResult = batchedSearchResults.get(entry.tc.id);
862
+ const executionArgs = batchResult ? { ...entry.args, __batch_result: batchResult } : entry.args;
863
+ const result = await executeSubAgentTool(entry.tc.function.name, executionArgs, workspacePath, toolExecutor);
864
+ if (result.ok)
865
+ toolResultCache.set(entry.signature, result);
866
+ return { entry, result, reused: false, elapsedMs: Date.now() - toolStartedAt };
867
+ }
868
+ catch (error) {
869
+ const message = formatSubAgentError(error);
870
+ return {
871
+ entry,
872
+ result: {
873
+ ok: false,
874
+ output: `Tool failed: ${message}`,
875
+ summary: `${entry.tc.function.name} failed: ${message}`,
876
+ evidence: [],
877
+ },
878
+ reused: false,
879
+ elapsedMs: Date.now() - toolStartedAt,
880
+ };
881
+ }
882
+ }));
883
+ for (const { entry, result, reused, elapsedMs } of results) {
884
+ const { tc } = entry;
885
+ emit({
886
+ type: 'tool_result',
887
+ tool: tc.function.name,
888
+ ok: result.ok,
889
+ summary: reused ? `${result.summary} (cached exact repeat)` : result.summary,
890
+ turn,
891
+ elapsedMs,
892
+ operations: reused ? 0 : result.operations ?? 1,
893
+ readOperations: reused ? 0 : result.readOperations ?? 0,
894
+ });
895
+ for (const ev of result.evidence) {
896
+ if (addEvidence(ev)) {
897
+ emit({ type: 'evidence', evidence: ev });
898
+ }
899
+ }
900
+ const stableOutput = boundToolOutput(tc.function.name, result.output);
901
+ messages.push({
902
+ role: 'tool',
903
+ tool_call_id: tc.id,
904
+ content: [reused ? '[Cached exact repeat; no new execution.]' : '', stableOutput].filter(Boolean).join('\n'),
905
+ });
906
+ }
907
+ emit({
908
+ type: 'turn_complete',
909
+ turn,
910
+ calls: results.length,
911
+ modelElapsedMs,
912
+ toolElapsedMs: Date.now() - toolWaveStartedAt,
913
+ totalElapsedMs: Date.now() - turnStartedAt,
914
+ inputTokens: turnInputTokens,
915
+ outputTokens: turnOutputTokens,
916
+ cacheReadTokens: turnCacheReadTokens,
917
+ reasoningTokens: turnReasoningTokens,
918
+ });
919
+ }
920
+ return { ok: true, turns: turn, elapsedMs: Date.now() - startedAt, evidence: collectedEvidence, truncated: turn >= turnLimit };
921
+ }
922
+ function stableToolValue(value) {
923
+ if (Array.isArray(value))
924
+ return value.map(stableToolValue);
925
+ if (!value || typeof value !== 'object')
926
+ return value;
927
+ return Object.fromEntries(Object.entries(value)
928
+ .sort(([left], [right]) => left.localeCompare(right))
929
+ .map(([key, entry]) => [key, stableToolValue(entry)]));
930
+ }
931
+ function toolCallSignature(name, args) {
932
+ return `${name}:${JSON.stringify(stableToolValue(args))}`;
933
+ }
934
+ function buildSearchContentBatchRequest(args, workspacePath) {
935
+ const pattern = String(args.pattern || '').trim();
936
+ if (!pattern)
937
+ return null;
938
+ let basePath;
939
+ try {
940
+ basePath = args.path ? resolveWorkspacePath(workspacePath, args.path) : resolveWorkspacePath(workspacePath, '');
941
+ }
942
+ catch {
943
+ return null;
944
+ }
945
+ return {
946
+ pattern,
947
+ basePath,
948
+ filePattern: args.file_pattern,
949
+ caseInsensitive: args.case_sensitive !== true,
950
+ options: {
951
+ offset: Math.max(0, Math.floor(Number(args.offset) || 0)),
952
+ limit: Math.min(200, Math.max(1, Math.floor(Number(args.head_limit) || 40)) * 4),
953
+ contextBefore: Math.max(0, Math.min(12, Math.floor(Number(args.context_before) || 0))),
954
+ contextAfter: Math.max(0, Math.min(12, Math.floor(Number(args.context_after) || 0))),
955
+ multiline: args.multiline === true,
956
+ fileType: typeof args.file_type === 'string' ? args.file_type : undefined,
957
+ },
958
+ };
959
+ }
960
+ export function __testTraceDefinitionReadLimit(hit) {
961
+ const startLine = hit.startLine || hit.line || 1;
962
+ const endLine = hit.endLine || startLine;
963
+ const structuralDefinition = hit.symbolKind === 'class'
964
+ || hit.symbolKind === 'interface'
965
+ || hit.symbolKind === 'type'
966
+ || hit.symbolKind === 'enum';
967
+ return Math.min(220, Math.max(structuralDefinition ? 160 : 40, endLine - startLine + 24));
968
+ }
969
+ function searchPathPriority(path) {
970
+ const normalized = path.replace(/\\/g, '/').toLowerCase();
971
+ if (/(^|\/)(docs?|examples?|fixtures?|templates?|vendor|generated)(\/|$)/.test(normalized))
972
+ return 2;
973
+ if (/(^|\/)(__tests__|tests?|spec)(\/|$)|\.(?:test|spec)\.[^/]+$/.test(normalized))
974
+ return 1;
975
+ return 0;
976
+ }
977
+ function diversifySearchHits(hits, limit) {
978
+ const buckets = new Map();
979
+ hits.forEach((hit, index) => {
980
+ const path = hit.file.replace(/\\/g, '/');
981
+ const bucket = buckets.get(path);
982
+ if (bucket)
983
+ bucket.hits.push(hit);
984
+ else
985
+ buckets.set(path, { priority: searchPathPriority(path), firstIndex: index, hits: [hit] });
986
+ });
987
+ const orderedBuckets = [...buckets.values()].sort((left, right) => left.priority - right.priority || left.firstIndex - right.firstIndex);
988
+ const selected = [];
989
+ for (let depth = 0; selected.length < limit && orderedBuckets.some(bucket => depth < bucket.hits.length); depth += 1) {
990
+ for (const bucket of orderedBuckets) {
991
+ const hit = bucket.hits[depth];
992
+ if (hit)
993
+ selected.push(hit);
994
+ if (selected.length >= limit)
995
+ break;
996
+ }
997
+ }
998
+ return selected;
999
+ }
1000
+ async function executeSubAgentTool(name, args, workspacePath, executor) {
1001
+ const evidence = [];
1002
+ switch (name) {
1003
+ case 'search_content': {
1004
+ const pattern = String(args.pattern || '').trim();
1005
+ if (!pattern) {
1006
+ return { ok: false, output: 'Search pattern is required.', summary: 'grep failed: missing pattern', evidence };
1007
+ }
1008
+ const basePath = args.path ? resolveWorkspacePath(workspacePath, args.path) : workspacePath;
1009
+ const filePattern = typeof args.file_pattern === 'string' ? args.file_pattern : undefined;
1010
+ const caseInsensitive = args.case_sensitive === true ? false : true;
1011
+ const offset = Math.max(0, Math.floor(Number(args.offset) || 0));
1012
+ const headLimit = Math.max(1, Math.min(200, Math.floor(Number(args.head_limit) || 40)));
1013
+ const contextBefore = Math.max(0, Math.min(12, Math.floor(Number(args.context_before) || 0)));
1014
+ const contextAfter = Math.max(0, Math.min(12, Math.floor(Number(args.context_after) || 0)));
1015
+ const usingPagedSearch = typeof executor.searchContentPage === 'function';
1016
+ const retrievalLimit = Math.min(200, headLimit * 4);
1017
+ let effectivePattern = pattern;
1018
+ let res = args.__batch_result || (usingPagedSearch
1019
+ ? await executor.searchContentPage(pattern, basePath, filePattern, caseInsensitive, {
1020
+ offset,
1021
+ limit: retrievalLimit,
1022
+ contextBefore,
1023
+ contextAfter,
1024
+ multiline: args.multiline === true,
1025
+ fileType: typeof args.file_type === 'string' ? args.file_type : undefined,
1026
+ })
1027
+ : await executor.searchContent(pattern, basePath, filePattern, caseInsensitive));
1028
+ if (!res.success && /regex parse error|invalid regular expression|unclosed (?:group|class)|unterminated/i.test(res.error || '')) {
1029
+ effectivePattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1030
+ res = usingPagedSearch
1031
+ ? await executor.searchContentPage(effectivePattern, basePath, filePattern, caseInsensitive, {
1032
+ offset,
1033
+ limit: retrievalLimit,
1034
+ contextBefore,
1035
+ contextAfter,
1036
+ multiline: false,
1037
+ fileType: typeof args.file_type === 'string' ? args.file_type : undefined,
1038
+ })
1039
+ : await executor.searchContent(effectivePattern, basePath, filePattern, caseInsensitive);
1040
+ }
1041
+ if (!res.success) {
1042
+ const error = res.error || 'unknown search error';
1043
+ return { ok: false, output: `Search failed: ${error}`, summary: `grep "${pattern}" failed: ${error}`, evidence };
1044
+ }
1045
+ const page = usingPagedSearch
1046
+ ? res.data
1047
+ : { hits: Array.isArray(res.data) ? res.data : [], totalMatches: Array.isArray(res.data) ? res.data.length : 0, truncated: false };
1048
+ const pageHits = page.hits || [];
1049
+ if (pageHits.length === 0) {
1050
+ return { ok: true, output: 'No matches found.', summary: `grep "${pattern}" → 0 hits`, evidence };
1051
+ }
1052
+ const hits = diversifySearchHits(pageHits, headLimit);
1053
+ const lines = [];
1054
+ for (const hit of hits) {
1055
+ const relPath = toWorkspaceRelative(workspacePath, hit.file);
1056
+ lines.push(`${relPath}:${hit.line}: ${hit.text}`);
1057
+ if (hit.context)
1058
+ lines.push(hit.context.split('\n').map(line => ` ${line}`).join('\n'));
1059
+ evidence.push({
1060
+ path: relPath,
1061
+ startLine: Math.max(1, hit.line - 2),
1062
+ endLine: hit.line + 2,
1063
+ preview: hit.text,
1064
+ reason: `grep: ${effectivePattern}`,
1065
+ });
1066
+ }
1067
+ if (page.truncated)
1068
+ lines.push(`[More matches available. Continue with offset=${offset + pageHits.length}.]`);
1069
+ return { ok: true, output: lines.join('\n'), summary: `grep "${pattern}" → ${hits.length} hits`, evidence };
1070
+ }
1071
+ case 'read_file': {
1072
+ const requestedPath = String(args.path || '').trim();
1073
+ if (!requestedPath) {
1074
+ return { ok: false, output: 'File path is required.', summary: 'read failed: missing path', evidence };
1075
+ }
1076
+ const offset = Math.max(0, Math.floor(Number(args.offset) || 1) - 1);
1077
+ const limit = Math.max(1, Math.min(400, Math.floor(Number(args.limit) || 80)));
1078
+ const readPath = async (path) => {
1079
+ const filePath = resolveWorkspacePath(workspacePath, path);
1080
+ const rangeResult = executor.readFileRange
1081
+ ? await executor.readFileRange(filePath, offset, limit)
1082
+ : null;
1083
+ return { path, filePath, rangeResult, res: rangeResult || await executor.readFile(filePath) };
1084
+ };
1085
+ let read = await readPath(requestedPath);
1086
+ let recoveryOperations = 0;
1087
+ if (!read.res.success || !read.res.data) {
1088
+ const normalized = requestedPath.replace(/\\/g, '/').replace(/^\.\//, '');
1089
+ const collapsedModule = normalized.replace(/\/(?:__init__|index)(\.[^/.]+)$/i, '$1');
1090
+ if (collapsedModule !== normalized) {
1091
+ const collapsedRead = await readPath(collapsedModule);
1092
+ recoveryOperations += 1;
1093
+ if (collapsedRead.res.success && collapsedRead.res.data)
1094
+ read = collapsedRead;
1095
+ }
1096
+ if (!read.res.success || !read.res.data) {
1097
+ const basename = normalized.split('/').pop() || normalized;
1098
+ const matches = await executor.searchFiles(`**/${basename}`, workspacePath);
1099
+ recoveryOperations += 1;
1100
+ const candidates = matches.success ? matches.data?.matches || [] : [];
1101
+ if (candidates.length === 1)
1102
+ read = await readPath(toWorkspaceRelative(workspacePath, candidates[0]));
1103
+ }
1104
+ }
1105
+ const { rangeResult, res } = read;
1106
+ const relativePath = toWorkspaceRelative(workspacePath, read.filePath);
1107
+ if (!res.success || !res.data) {
1108
+ const error = res.error || 'file not found';
1109
+ return { ok: false, output: `Read failed: ${error}`, summary: `read ${relativePath} failed: ${error}`, evidence };
1110
+ }
1111
+ const rangeData = rangeResult?.data;
1112
+ if (rangeData && !rangeData.content) {
1113
+ return {
1114
+ ok: false,
1115
+ output: `Read failed: ${relativePath} has no content at line ${offset + 1}. Retry with a lower offset or search for the current symbol location.`,
1116
+ summary: `read ${relativePath}:${offset + 1} failed: offset beyond content`,
1117
+ evidence,
1118
+ };
1119
+ }
1120
+ const slice = rangeData
1121
+ ? rangeData.content.split('\n')
1122
+ : String(res.data).split('\n').slice(offset, offset + limit);
1123
+ const preview = slice.slice(0, 10).join('\n');
1124
+ evidence.push({
1125
+ path: relativePath,
1126
+ startLine: offset + 1,
1127
+ endLine: offset + slice.length,
1128
+ preview,
1129
+ content: slice.join('\n').slice(0, 20_000),
1130
+ reason: 'file read',
1131
+ });
1132
+ const outputLines = slice.map((line, index) => `${offset + index + 1} | ${line}`);
1133
+ if (rangeData?.truncated)
1134
+ outputLines.push(`[More lines available. Continue with offset=${offset + slice.length + 1}.]`);
1135
+ const recovered = relativePath.replace(/\\/g, '/').toLowerCase() !== requestedPath.replace(/\\/g, '/').replace(/^\.\//, '').toLowerCase();
1136
+ return {
1137
+ ok: true,
1138
+ output: `${recovered ? `[Resolved requested path ${requestedPath} -> ${relativePath}]\n` : ''}${outputLines.join('\n')}`,
1139
+ summary: `read ${relativePath}:${offset + 1}-${offset + slice.length}${recovered ? ' (resolved missing path)' : ''}`,
1140
+ evidence,
1141
+ operations: 1 + recoveryOperations,
1142
+ readOperations: 1,
1143
+ };
1144
+ }
1145
+ case 'search_files': {
1146
+ const pattern = args.pattern || '**/*.ts';
1147
+ const res = await executor.searchFiles(pattern, workspacePath);
1148
+ if (!res.success) {
1149
+ const error = res.error || 'unknown file search error';
1150
+ return { ok: false, output: `File search failed: ${error}`, summary: `glob "${pattern}" failed: ${error}`, evidence };
1151
+ }
1152
+ if (!res.data?.matches?.length) {
1153
+ return { ok: true, output: 'No files found.', summary: `glob "${pattern}" → 0 files`, evidence };
1154
+ }
1155
+ const matches = res.data.matches.slice(0, 20);
1156
+ const relPaths = matches.map(m => toWorkspaceRelative(workspacePath, m));
1157
+ for (const relPath of relPaths.slice(0, 8)) {
1158
+ evidence.push({
1159
+ path: relPath,
1160
+ startLine: 1,
1161
+ endLine: 1,
1162
+ preview: relPath,
1163
+ reason: `glob: ${pattern}`,
1164
+ });
1165
+ }
1166
+ return { ok: true, output: relPaths.join('\n'), summary: `glob "${pattern}" → ${matches.length} files`, evidence };
1167
+ }
1168
+ case 'search_symbol':
1169
+ case 'search_symbols': {
1170
+ const query = String(args.query || '').trim();
1171
+ if (!query)
1172
+ return { ok: true, output: 'No symbol query provided.', summary: 'symbol search skipped', evidence };
1173
+ const scopedPath = typeof args.path === 'string' && args.path.trim()
1174
+ ? resolveWorkspacePath(workspacePath, args.path)
1175
+ : undefined;
1176
+ const res = await executor.searchCodeSymbols({
1177
+ workspacePath,
1178
+ query,
1179
+ path: scopedPath,
1180
+ kind: typeof args.symbol_kind === 'string' ? args.symbol_kind : undefined,
1181
+ kinds: typeof args.symbol_kind === 'string' ? [args.symbol_kind] : undefined,
1182
+ limit: 20,
1183
+ });
1184
+ const hits = normalizeCodeSearchHits(res.data).slice(0, 15);
1185
+ if (!res.success) {
1186
+ const error = res.error || 'unknown symbol search error';
1187
+ return { ok: false, output: `Symbol search failed: ${error}`, summary: `symbols "${query}" failed: ${error}`, evidence };
1188
+ }
1189
+ if (hits.length === 0) {
1190
+ return { ok: true, output: 'No symbols found.', summary: `symbols "${query}" -> 0 hits`, evidence };
1191
+ }
1192
+ const lines = hits.map(hit => {
1193
+ const relPath = toWorkspaceRelative(workspacePath, hit.path);
1194
+ evidence.push({
1195
+ path: relPath,
1196
+ startLine: hit.startLine || hit.line || 1,
1197
+ endLine: hit.endLine || hit.line || 1,
1198
+ preview: hit.preview || hit.subtitle || hit.title,
1199
+ reason: `symbol: ${query}`,
1200
+ symbol: hit.symbolName || hit.title,
1201
+ });
1202
+ return `${relPath}:${hit.line || hit.startLine || 1}: ${hit.title} (${hit.symbolKind || hit.source}) ${hit.preview || hit.subtitle || ''}`.trim();
1203
+ });
1204
+ return { ok: true, output: lines.join('\n'), summary: `symbols "${query}" -> ${hits.length} hits`, evidence };
1205
+ }
1206
+ case 'get_codemap': {
1207
+ const query = String(args.query || args.path || '').trim();
1208
+ const scopedPath = typeof args.path === 'string' && args.path.trim()
1209
+ ? resolveWorkspacePath(workspacePath, args.path)
1210
+ : undefined;
1211
+ const res = await executor.getCodeMap({
1212
+ workspacePath,
1213
+ query,
1214
+ targetPaths: scopedPath ? [scopedPath] : undefined,
1215
+ path: scopedPath,
1216
+ maxPaths: 8,
1217
+ maxChildrenPerPath: 5,
1218
+ });
1219
+ const map = res.data?.map;
1220
+ const nodes = Array.isArray(map) ? map : map ? [map] : [];
1221
+ if (!res.success) {
1222
+ const error = res.error || 'unknown codemap error';
1223
+ return { ok: false, output: `Codemap failed: ${error}`, summary: `codemap "${query}" failed: ${error}`, evidence };
1224
+ }
1225
+ if (nodes.length === 0) {
1226
+ return { ok: true, output: 'No codemap found.', summary: `codemap "${query}" -> 0 nodes`, evidence };
1227
+ }
1228
+ const lines = [];
1229
+ const nodeEvidence = collectCodeMapEvidence(nodes, workspacePath);
1230
+ for (const ev of nodeEvidence.slice(0, 12))
1231
+ evidence.push(ev);
1232
+ for (const node of nodes)
1233
+ formatCodeMapNode(node, lines);
1234
+ return { ok: true, output: lines.join('\n'), summary: `codemap "${query}" -> ${nodeEvidence.length} anchors`, evidence };
1235
+ }
1236
+ default:
1237
+ return { ok: false, output: `Unknown tool: ${name}`, summary: `unknown tool ${name}`, evidence };
1238
+ }
1239
+ }
1240
+ function formatSubAgentError(error) {
1241
+ if (!(error instanceof Error))
1242
+ return String(error);
1243
+ const metadata = error;
1244
+ const endpoint = metadata.address !== undefined
1245
+ ? `${String(metadata.address)}${metadata.port !== undefined ? `:${String(metadata.port)}` : ''}`
1246
+ : metadata.port !== undefined ? `port ${String(metadata.port)}` : '';
1247
+ const details = [metadata.code, endpoint].filter(value => value !== undefined && value !== '');
1248
+ const suffix = details.length > 0 ? ` [${details.join(' ')}]` : '';
1249
+ if (!error.cause)
1250
+ return `${error.message}${suffix}`;
1251
+ const cause = error.cause instanceof Error
1252
+ ? formatSubAgentError(error.cause)
1253
+ : typeof error.cause === 'object' && error.cause !== null
1254
+ ? formatSubAgentError(Object.assign(new Error(String(error.cause.message || 'request cause')), error.cause))
1255
+ : String(error.cause);
1256
+ return `${error.message}${suffix} (${cause})`;
1257
+ }
1258
+ //# sourceMappingURL=subAgent.js.map