@yeshwanthyk/coding-agent 0.3.0 → 0.3.3

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 (379) hide show
  1. package/README.md +8 -6
  2. package/dist/adapters/acp/index.d.ts +10 -0
  3. package/dist/adapters/acp/index.d.ts.map +1 -0
  4. package/dist/adapters/acp/index.js +250 -0
  5. package/dist/adapters/acp/index.js.map +1 -0
  6. package/dist/adapters/acp/protocol.d.ts +171 -0
  7. package/dist/adapters/acp/protocol.d.ts.map +1 -0
  8. package/dist/adapters/acp/protocol.js +25 -0
  9. package/dist/adapters/acp/protocol.js.map +1 -0
  10. package/dist/adapters/acp/session.d.ts +33 -0
  11. package/dist/adapters/acp/session.d.ts.map +1 -0
  12. package/dist/adapters/acp/session.js +216 -0
  13. package/dist/adapters/acp/session.js.map +1 -0
  14. package/dist/adapters/acp/updates.d.ts +17 -0
  15. package/dist/adapters/acp/updates.d.ts.map +1 -0
  16. package/dist/adapters/acp/updates.js +62 -0
  17. package/dist/adapters/acp/updates.js.map +1 -0
  18. package/dist/adapters/cli/headless.d.ts +7 -0
  19. package/dist/adapters/cli/headless.d.ts.map +1 -0
  20. package/dist/adapters/cli/headless.js +93 -0
  21. package/dist/adapters/cli/headless.js.map +1 -0
  22. package/dist/adapters/cli/validate.d.ts +3 -0
  23. package/dist/adapters/cli/validate.d.ts.map +1 -0
  24. package/dist/adapters/cli/validate.js +40 -0
  25. package/dist/adapters/cli/validate.js.map +1 -0
  26. package/dist/adapters/tui/app.d.ts +8 -0
  27. package/dist/adapters/tui/app.d.ts.map +1 -0
  28. package/dist/adapters/tui/app.jsx +25 -0
  29. package/dist/adapters/tui/app.jsx.map +1 -0
  30. package/dist/agent-events.d.ts +63 -0
  31. package/dist/agent-events.d.ts.map +1 -0
  32. package/dist/agent-events.js +510 -0
  33. package/dist/agent-events.js.map +1 -0
  34. package/dist/args.d.ts +18 -0
  35. package/dist/args.d.ts.map +1 -0
  36. package/dist/args.js +87 -0
  37. package/dist/args.js.map +1 -0
  38. package/dist/autocomplete-commands.d.ts +26 -0
  39. package/dist/autocomplete-commands.d.ts.map +1 -0
  40. package/dist/autocomplete-commands.js +82 -0
  41. package/dist/autocomplete-commands.js.map +1 -0
  42. package/dist/commands.d.ts +10 -0
  43. package/dist/commands.d.ts.map +1 -0
  44. package/dist/commands.js +17 -0
  45. package/dist/commands.js.map +1 -0
  46. package/dist/compact-handler.d.ts +42 -0
  47. package/dist/compact-handler.d.ts.map +1 -0
  48. package/dist/compact-handler.js +211 -0
  49. package/dist/compact-handler.js.map +1 -0
  50. package/dist/components/Footer.d.ts +9 -0
  51. package/dist/components/Footer.d.ts.map +1 -0
  52. package/dist/components/Footer.jsx +36 -0
  53. package/dist/components/Footer.jsx.map +1 -0
  54. package/dist/components/Header.d.ts +23 -0
  55. package/dist/components/Header.d.ts.map +1 -0
  56. package/dist/components/Header.jsx +174 -0
  57. package/dist/components/Header.jsx.map +1 -0
  58. package/dist/components/MessageList.d.ts +19 -0
  59. package/dist/components/MessageList.d.ts.map +1 -0
  60. package/dist/components/MessageList.jsx +237 -0
  61. package/dist/components/MessageList.jsx.map +1 -0
  62. package/dist/config.d.ts +2 -0
  63. package/dist/config.d.ts.map +1 -0
  64. package/dist/config.js +2 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/domain/commands/builtin/clear.d.ts +3 -0
  67. package/dist/domain/commands/builtin/clear.d.ts.map +1 -0
  68. package/dist/domain/commands/builtin/clear.js +13 -0
  69. package/dist/domain/commands/builtin/clear.js.map +1 -0
  70. package/dist/domain/commands/builtin/compact.d.ts +3 -0
  71. package/dist/domain/commands/builtin/compact.d.ts.map +1 -0
  72. package/dist/domain/commands/builtin/compact.js +84 -0
  73. package/dist/domain/commands/builtin/compact.js.map +1 -0
  74. package/dist/domain/commands/builtin/conceal.d.ts +3 -0
  75. package/dist/domain/commands/builtin/conceal.d.ts.map +1 -0
  76. package/dist/domain/commands/builtin/conceal.js +8 -0
  77. package/dist/domain/commands/builtin/conceal.js.map +1 -0
  78. package/dist/domain/commands/builtin/diffwrap.d.ts +3 -0
  79. package/dist/domain/commands/builtin/diffwrap.d.ts.map +1 -0
  80. package/dist/domain/commands/builtin/diffwrap.js +8 -0
  81. package/dist/domain/commands/builtin/diffwrap.js.map +1 -0
  82. package/dist/domain/commands/builtin/editor.d.ts +3 -0
  83. package/dist/domain/commands/builtin/editor.d.ts.map +1 -0
  84. package/dist/domain/commands/builtin/editor.js +22 -0
  85. package/dist/domain/commands/builtin/editor.js.map +1 -0
  86. package/dist/domain/commands/builtin/exit.d.ts +3 -0
  87. package/dist/domain/commands/builtin/exit.d.ts.map +1 -0
  88. package/dist/domain/commands/builtin/exit.js +14 -0
  89. package/dist/domain/commands/builtin/exit.js.map +1 -0
  90. package/dist/domain/commands/builtin/followup.d.ts +3 -0
  91. package/dist/domain/commands/builtin/followup.d.ts.map +1 -0
  92. package/dist/domain/commands/builtin/followup.js +20 -0
  93. package/dist/domain/commands/builtin/followup.js.map +1 -0
  94. package/dist/domain/commands/builtin/index.d.ts +2 -0
  95. package/dist/domain/commands/builtin/index.d.ts.map +1 -0
  96. package/dist/domain/commands/builtin/index.js +29 -0
  97. package/dist/domain/commands/builtin/index.js.map +1 -0
  98. package/dist/domain/commands/builtin/login.d.ts +3 -0
  99. package/dist/domain/commands/builtin/login.d.ts.map +1 -0
  100. package/dist/domain/commands/builtin/login.js +92 -0
  101. package/dist/domain/commands/builtin/login.js.map +1 -0
  102. package/dist/domain/commands/builtin/model.d.ts +3 -0
  103. package/dist/domain/commands/builtin/model.d.ts.map +1 -0
  104. package/dist/domain/commands/builtin/model.js +53 -0
  105. package/dist/domain/commands/builtin/model.js.map +1 -0
  106. package/dist/domain/commands/builtin/status.d.ts +3 -0
  107. package/dist/domain/commands/builtin/status.d.ts.map +1 -0
  108. package/dist/domain/commands/builtin/status.js +30 -0
  109. package/dist/domain/commands/builtin/status.js.map +1 -0
  110. package/dist/domain/commands/builtin/steer.d.ts +3 -0
  111. package/dist/domain/commands/builtin/steer.d.ts.map +1 -0
  112. package/dist/domain/commands/builtin/steer.js +20 -0
  113. package/dist/domain/commands/builtin/steer.js.map +1 -0
  114. package/dist/domain/commands/builtin/theme.d.ts +3 -0
  115. package/dist/domain/commands/builtin/theme.d.ts.map +1 -0
  116. package/dist/domain/commands/builtin/theme.js +19 -0
  117. package/dist/domain/commands/builtin/theme.js.map +1 -0
  118. package/dist/domain/commands/builtin/thinking.d.ts +3 -0
  119. package/dist/domain/commands/builtin/thinking.d.ts.map +1 -0
  120. package/dist/domain/commands/builtin/thinking.js +16 -0
  121. package/dist/domain/commands/builtin/thinking.js.map +1 -0
  122. package/dist/domain/commands/helpers.d.ts +7 -0
  123. package/dist/domain/commands/helpers.d.ts.map +1 -0
  124. package/dist/domain/commands/helpers.js +34 -0
  125. package/dist/domain/commands/helpers.js.map +1 -0
  126. package/dist/domain/commands/registry.d.ts +10 -0
  127. package/dist/domain/commands/registry.d.ts.map +1 -0
  128. package/dist/domain/commands/registry.js +36 -0
  129. package/dist/domain/commands/registry.js.map +1 -0
  130. package/dist/domain/commands/types.d.ts +62 -0
  131. package/dist/domain/commands/types.d.ts.map +1 -0
  132. package/dist/domain/commands/types.js +2 -0
  133. package/dist/domain/commands/types.js.map +1 -0
  134. package/dist/domain/messaging/content.d.ts +37 -0
  135. package/dist/domain/messaging/content.d.ts.map +1 -0
  136. package/dist/domain/messaging/content.js +103 -0
  137. package/dist/domain/messaging/content.js.map +1 -0
  138. package/dist/editor.d.ts +26 -0
  139. package/dist/editor.d.ts.map +1 -0
  140. package/dist/editor.js +81 -0
  141. package/dist/editor.js.map +1 -0
  142. package/dist/extensibility/schema.d.ts +2 -0
  143. package/dist/extensibility/schema.d.ts.map +1 -0
  144. package/{src/extensibility/schema.ts → dist/extensibility/schema.js} +2 -1
  145. package/dist/extensibility/schema.js.map +1 -0
  146. package/dist/extensibility/validation.d.ts +2 -0
  147. package/dist/extensibility/validation.d.ts.map +1 -0
  148. package/{src/extensibility/validation.ts → dist/extensibility/validation.js} +2 -1
  149. package/dist/extensibility/validation.js.map +1 -0
  150. package/dist/hooks/index.d.ts +2 -0
  151. package/dist/hooks/index.d.ts.map +1 -0
  152. package/dist/hooks/index.js +2 -0
  153. package/dist/hooks/index.js.map +1 -0
  154. package/dist/hooks/useAgentEvents.d.ts +8 -0
  155. package/dist/hooks/useAgentEvents.d.ts.map +1 -0
  156. package/dist/hooks/useAgentEvents.js +22 -0
  157. package/dist/hooks/useAgentEvents.js.map +1 -0
  158. package/dist/hooks/useEditorBridge.d.ts +20 -0
  159. package/dist/hooks/useEditorBridge.d.ts.map +1 -0
  160. package/dist/hooks/useEditorBridge.js +80 -0
  161. package/dist/hooks/useEditorBridge.js.map +1 -0
  162. package/dist/hooks/useGitStatus.d.ts +2 -0
  163. package/dist/hooks/useGitStatus.d.ts.map +1 -0
  164. package/dist/hooks/useGitStatus.js +26 -0
  165. package/dist/hooks/useGitStatus.js.map +1 -0
  166. package/dist/hooks/usePromptQueue.d.ts +2 -0
  167. package/dist/hooks/usePromptQueue.d.ts.map +1 -0
  168. package/dist/hooks/usePromptQueue.js +2 -0
  169. package/dist/hooks/usePromptQueue.js.map +1 -0
  170. package/dist/hooks/useSessionController.d.ts +2 -0
  171. package/dist/hooks/useSessionController.d.ts.map +1 -0
  172. package/dist/hooks/useSessionController.js +2 -0
  173. package/dist/hooks/useSessionController.js.map +1 -0
  174. package/dist/hooks/useSpinner.d.ts +4 -0
  175. package/dist/hooks/useSpinner.d.ts.map +1 -0
  176. package/dist/hooks/useSpinner.js +25 -0
  177. package/dist/hooks/useSpinner.js.map +1 -0
  178. package/dist/hooks/useToastManager.d.ts +6 -0
  179. package/dist/hooks/useToastManager.d.ts.map +1 -0
  180. package/dist/hooks/useToastManager.js +22 -0
  181. package/dist/hooks/useToastManager.js.map +1 -0
  182. package/dist/index.d.ts +3 -0
  183. package/dist/index.d.ts.map +1 -0
  184. package/dist/index.js +156 -0
  185. package/dist/index.js.map +1 -0
  186. package/dist/keyboard-handler.d.ts +30 -0
  187. package/dist/keyboard-handler.d.ts.map +1 -0
  188. package/dist/keyboard-handler.js +96 -0
  189. package/dist/keyboard-handler.js.map +1 -0
  190. package/dist/profiler.d.ts +2 -0
  191. package/dist/profiler.d.ts.map +1 -0
  192. package/dist/profiler.js +41 -0
  193. package/dist/profiler.js.map +1 -0
  194. package/dist/runtime/context.d.ts +8 -0
  195. package/dist/runtime/context.d.ts.map +1 -0
  196. package/dist/runtime/context.jsx +11 -0
  197. package/dist/runtime/context.jsx.map +1 -0
  198. package/dist/runtime/factory.d.ts +12 -0
  199. package/dist/runtime/factory.d.ts.map +1 -0
  200. package/dist/runtime/factory.js +37 -0
  201. package/dist/runtime/factory.js.map +1 -0
  202. package/dist/runtime/git/git-info.d.ts +3 -0
  203. package/dist/runtime/git/git-info.d.ts.map +1 -0
  204. package/dist/runtime/git/git-info.js +29 -0
  205. package/dist/runtime/git/git-info.js.map +1 -0
  206. package/dist/runtime/session/session-controller.d.ts +48 -0
  207. package/dist/runtime/session/session-controller.d.ts.map +1 -0
  208. package/dist/runtime/session/session-controller.js +159 -0
  209. package/dist/runtime/session/session-controller.js.map +1 -0
  210. package/dist/session-manager.d.ts +2 -0
  211. package/dist/session-manager.d.ts.map +1 -0
  212. package/dist/session-manager.js +2 -0
  213. package/dist/session-manager.js.map +1 -0
  214. package/dist/session-picker.d.ts +6 -0
  215. package/dist/session-picker.d.ts.map +1 -0
  216. package/dist/session-picker.jsx +96 -0
  217. package/dist/session-picker.jsx.map +1 -0
  218. package/dist/shell-runner.d.ts +21 -0
  219. package/dist/shell-runner.d.ts.map +1 -0
  220. package/dist/shell-runner.js +106 -0
  221. package/dist/shell-runner.js.map +1 -0
  222. package/dist/syntax-highlighting.d.ts +4 -0
  223. package/dist/syntax-highlighting.d.ts.map +1 -0
  224. package/dist/syntax-highlighting.js +108 -0
  225. package/dist/syntax-highlighting.js.map +1 -0
  226. package/dist/theme-names.d.ts +7 -0
  227. package/dist/theme-names.d.ts.map +1 -0
  228. package/dist/theme-names.js +38 -0
  229. package/dist/theme-names.js.map +1 -0
  230. package/dist/tool-ui-contracts.d.ts +30 -0
  231. package/dist/tool-ui-contracts.d.ts.map +1 -0
  232. package/dist/tool-ui-contracts.js +53 -0
  233. package/dist/tool-ui-contracts.js.map +1 -0
  234. package/dist/tui-open-rendering.d.ts +37 -0
  235. package/dist/tui-open-rendering.d.ts.map +1 -0
  236. package/dist/tui-open-rendering.jsx +462 -0
  237. package/dist/tui-open-rendering.jsx.map +1 -0
  238. package/dist/types.d.ts +117 -0
  239. package/dist/types.d.ts.map +1 -0
  240. package/dist/types.js +4 -0
  241. package/dist/types.js.map +1 -0
  242. package/dist/ui/app-shell/TuiApp.d.ts +6 -0
  243. package/dist/ui/app-shell/TuiApp.d.ts.map +1 -0
  244. package/dist/ui/app-shell/TuiApp.jsx +480 -0
  245. package/dist/ui/app-shell/TuiApp.jsx.map +1 -0
  246. package/dist/ui/clipboard/osc52.d.ts +2 -0
  247. package/dist/ui/clipboard/osc52.d.ts.map +1 -0
  248. package/dist/ui/clipboard/osc52.js +19 -0
  249. package/dist/ui/clipboard/osc52.js.map +1 -0
  250. package/dist/ui/components/modals/ConfirmModal.d.ts +8 -0
  251. package/dist/ui/components/modals/ConfirmModal.d.ts.map +1 -0
  252. package/dist/ui/components/modals/ConfirmModal.jsx +39 -0
  253. package/dist/ui/components/modals/ConfirmModal.jsx.map +1 -0
  254. package/dist/ui/components/modals/EditorModal.d.ts +8 -0
  255. package/dist/ui/components/modals/EditorModal.d.ts.map +1 -0
  256. package/dist/ui/components/modals/EditorModal.jsx +23 -0
  257. package/dist/ui/components/modals/EditorModal.jsx.map +1 -0
  258. package/dist/ui/components/modals/InputModal.d.ts +8 -0
  259. package/dist/ui/components/modals/InputModal.d.ts.map +1 -0
  260. package/dist/ui/components/modals/InputModal.jsx +15 -0
  261. package/dist/ui/components/modals/InputModal.jsx.map +1 -0
  262. package/dist/ui/components/modals/ModalContainer.d.ts +8 -0
  263. package/dist/ui/components/modals/ModalContainer.d.ts.map +1 -0
  264. package/dist/ui/components/modals/ModalContainer.jsx +34 -0
  265. package/dist/ui/components/modals/ModalContainer.jsx.map +1 -0
  266. package/dist/ui/components/modals/SelectModal.d.ts +8 -0
  267. package/dist/ui/components/modals/SelectModal.d.ts.map +1 -0
  268. package/dist/ui/components/modals/SelectModal.jsx +32 -0
  269. package/dist/ui/components/modals/SelectModal.jsx.map +1 -0
  270. package/{src/ui/components/modals/index.ts → dist/ui/components/modals/index.d.ts} +5 -4
  271. package/dist/ui/components/modals/index.d.ts.map +1 -0
  272. package/dist/ui/components/modals/index.js +5 -0
  273. package/dist/ui/components/modals/index.js.map +1 -0
  274. package/dist/ui/features/composer/Composer.d.ts +16 -0
  275. package/dist/ui/features/composer/Composer.d.ts.map +1 -0
  276. package/dist/ui/features/composer/Composer.jsx +39 -0
  277. package/dist/ui/features/composer/Composer.jsx.map +1 -0
  278. package/dist/ui/features/composer/SlashCommandHandler.d.ts +14 -0
  279. package/dist/ui/features/composer/SlashCommandHandler.d.ts.map +1 -0
  280. package/dist/ui/features/composer/SlashCommandHandler.js +43 -0
  281. package/dist/ui/features/composer/SlashCommandHandler.js.map +1 -0
  282. package/dist/ui/features/composer/keyboard.d.ts +3 -0
  283. package/dist/ui/features/composer/keyboard.d.ts.map +1 -0
  284. package/dist/ui/features/composer/keyboard.js +3 -0
  285. package/dist/ui/features/composer/keyboard.js.map +1 -0
  286. package/dist/ui/features/main-view/MainView.d.ts +52 -0
  287. package/dist/ui/features/main-view/MainView.d.ts.map +1 -0
  288. package/dist/ui/features/main-view/MainView.jsx +269 -0
  289. package/dist/ui/features/main-view/MainView.jsx.map +1 -0
  290. package/dist/ui/features/message-pane/MessagePane.d.ts +15 -0
  291. package/dist/ui/features/message-pane/MessagePane.d.ts.map +1 -0
  292. package/dist/ui/features/message-pane/MessagePane.jsx +7 -0
  293. package/dist/ui/features/message-pane/MessagePane.jsx.map +1 -0
  294. package/dist/ui/hooks/useModals.d.ts +35 -0
  295. package/dist/ui/hooks/useModals.d.ts.map +1 -0
  296. package/dist/ui/hooks/useModals.js +36 -0
  297. package/dist/ui/hooks/useModals.js.map +1 -0
  298. package/dist/ui/state/app-store.d.ts +42 -0
  299. package/dist/ui/state/app-store.d.ts.map +1 -0
  300. package/dist/ui/state/app-store.js +28 -0
  301. package/dist/ui/state/app-store.js.map +1 -0
  302. package/dist/utils.d.ts +3 -0
  303. package/dist/utils.d.ts.map +1 -0
  304. package/dist/utils.js +3 -0
  305. package/dist/utils.js.map +1 -0
  306. package/package.json +20 -7
  307. package/src/adapters/acp/index.ts +0 -305
  308. package/src/adapters/acp/protocol.ts +0 -191
  309. package/src/adapters/acp/session.ts +0 -289
  310. package/src/adapters/acp/updates.ts +0 -96
  311. package/src/adapters/cli/headless.ts +0 -112
  312. package/src/adapters/cli/validate.ts +0 -50
  313. package/src/adapters/tui/app.tsx +0 -39
  314. package/src/agent-events.ts +0 -671
  315. package/src/args.ts +0 -102
  316. package/src/autocomplete-commands.ts +0 -102
  317. package/src/commands.ts +0 -23
  318. package/src/compact-handler.ts +0 -272
  319. package/src/components/Footer.tsx +0 -49
  320. package/src/components/Header.tsx +0 -218
  321. package/src/components/MessageList.tsx +0 -380
  322. package/src/config.ts +0 -1
  323. package/src/domain/commands/builtin/clear.ts +0 -14
  324. package/src/domain/commands/builtin/compact.ts +0 -96
  325. package/src/domain/commands/builtin/conceal.ts +0 -9
  326. package/src/domain/commands/builtin/diffwrap.ts +0 -9
  327. package/src/domain/commands/builtin/editor.ts +0 -24
  328. package/src/domain/commands/builtin/exit.ts +0 -14
  329. package/src/domain/commands/builtin/followup.ts +0 -24
  330. package/src/domain/commands/builtin/index.ts +0 -29
  331. package/src/domain/commands/builtin/login.ts +0 -118
  332. package/src/domain/commands/builtin/model.ts +0 -66
  333. package/src/domain/commands/builtin/status.ts +0 -32
  334. package/src/domain/commands/builtin/steer.ts +0 -24
  335. package/src/domain/commands/builtin/theme.ts +0 -23
  336. package/src/domain/commands/builtin/thinking.ts +0 -16
  337. package/src/domain/commands/helpers.ts +0 -41
  338. package/src/domain/commands/registry.ts +0 -42
  339. package/src/domain/commands/types.ts +0 -69
  340. package/src/domain/messaging/content.ts +0 -117
  341. package/src/editor.ts +0 -103
  342. package/src/hooks/index.ts +0 -1
  343. package/src/hooks/useAgentEvents.ts +0 -28
  344. package/src/hooks/useEditorBridge.ts +0 -101
  345. package/src/hooks/useGitStatus.ts +0 -28
  346. package/src/hooks/usePromptQueue.ts +0 -7
  347. package/src/hooks/useSessionController.ts +0 -5
  348. package/src/hooks/useSpinner.ts +0 -28
  349. package/src/hooks/useToastManager.ts +0 -26
  350. package/src/index.ts +0 -188
  351. package/src/keyboard-handler.ts +0 -134
  352. package/src/profiler.ts +0 -40
  353. package/src/runtime/context.tsx +0 -16
  354. package/src/runtime/factory.ts +0 -63
  355. package/src/runtime/git/git-info.ts +0 -25
  356. package/src/runtime/session/session-controller.ts +0 -208
  357. package/src/session-manager.ts +0 -1
  358. package/src/session-picker.tsx +0 -134
  359. package/src/shell-runner.ts +0 -134
  360. package/src/syntax-highlighting.ts +0 -114
  361. package/src/theme-names.ts +0 -37
  362. package/src/tool-ui-contracts.ts +0 -77
  363. package/src/tui-open-rendering.tsx +0 -565
  364. package/src/types.ts +0 -89
  365. package/src/ui/app-shell/TuiApp.tsx +0 -586
  366. package/src/ui/clipboard/osc52.ts +0 -18
  367. package/src/ui/components/modals/ConfirmModal.tsx +0 -52
  368. package/src/ui/components/modals/EditorModal.tsx +0 -39
  369. package/src/ui/components/modals/InputModal.tsx +0 -30
  370. package/src/ui/components/modals/ModalContainer.tsx +0 -67
  371. package/src/ui/components/modals/SelectModal.tsx +0 -48
  372. package/src/ui/features/composer/Composer.tsx +0 -73
  373. package/src/ui/features/composer/SlashCommandHandler.ts +0 -58
  374. package/src/ui/features/composer/keyboard.ts +0 -3
  375. package/src/ui/features/main-view/MainView.tsx +0 -367
  376. package/src/ui/features/message-pane/MessagePane.tsx +0 -34
  377. package/src/ui/hooks/useModals.ts +0 -74
  378. package/src/ui/state/app-store.ts +0 -67
  379. package/src/utils.ts +0 -14
@@ -1,671 +0,0 @@
1
- /**
2
- * Agent event handler for TUI application
3
- */
4
-
5
- import { batch } from "solid-js"
6
- import { profile } from "./profiler.js"
7
- import type { AgentEvent, AppMessage } from "@yeshwanthyk/agent-core"
8
- import type { AgentToolResult, AssistantMessage, ToolResultMessage } from "@yeshwanthyk/ai"
9
- import type { Theme } from "@yeshwanthyk/open-tui"
10
- import type { JSX } from "solid-js"
11
- import type { SessionManager } from "./session-manager.js"
12
- import type { UIMessage, UIAssistantMessage, ToolBlock, ActivityState, UIContentBlock } from "./types.js"
13
- import {
14
- appendWithCap,
15
- buildThinkingSummary,
16
- extractOrderedBlocks,
17
- extractThinking,
18
- extractText,
19
- getEditDiffText,
20
- getToolText,
21
- } from "@domain/messaging/content.js"
22
- import type { PromptQueue } from "./hooks/usePromptQueue.js"
23
- import type { HookRunner } from "./hooks/index.js"
24
- import type { RenderResultOptions } from "@yeshwanthyk/runtime-effect/extensibility/custom-tools/types.js"
25
-
26
- /** Tool metadata for UI rendering */
27
- export interface ToolMeta {
28
- label: string
29
- source: "builtin" | "custom"
30
- sourcePath?: string
31
- renderCall?: (args: any, theme: Theme) => JSX.Element
32
- renderResult?: (result: AgentToolResult<any>, opts: RenderResultOptions, theme: Theme) => JSX.Element
33
- }
34
-
35
- export interface EventHandlerContext {
36
- // State setters
37
- setMessages: (updater: (prev: UIMessage[]) => UIMessage[]) => void
38
- setToolBlocks: (updater: (prev: ToolBlock[]) => ToolBlock[]) => void
39
- setActivityState: (s: ActivityState) => void
40
- setIsResponding: (v: boolean) => void
41
- setContextTokens: (v: number) => void
42
- setCacheStats: (v: { cacheRead: number; input: number } | null) => void
43
- setRetryStatus: (v: string | null) => void
44
- setTurnCount: (v: number) => void
45
-
46
- // Queue management
47
- promptQueue: PromptQueue
48
-
49
- // Session management
50
- sessionManager: SessionManager
51
-
52
- // Streaming message tracking (mutable ref)
53
- streamingMessageId: { current: string | null }
54
-
55
- // Retry configuration
56
- retryConfig: { enabled: boolean; maxRetries: number; baseDelayMs: number }
57
- retryablePattern: RegExp
58
- retryState: { attempt: number; abortController: AbortController | null }
59
-
60
- // Agent reference for retry logic
61
- agent: {
62
- state: { messages: unknown[] }
63
- replaceMessages: (messages: unknown[]) => void
64
- continue: () => Promise<void>
65
- }
66
-
67
- // Hook runner for lifecycle events (optional for backwards compat)
68
- hookRunner?: HookRunner
69
-
70
- // Tool metadata registry for custom tool rendering
71
- toolByName?: Map<string, ToolMeta>
72
-
73
- // Context window getter for usage calculations
74
- getContextWindow?: () => number
75
- }
76
-
77
- export type AgentEventHandler = ((event: AgentEvent) => void) & { dispose: () => void }
78
-
79
- const UPDATE_THROTTLE_MS = 150 // ~7fps during streaming - smoother perceived text flow
80
- const UPDATE_THROTTLE_SLOW_MS = 180
81
- const UPDATE_THROTTLE_SLOWEST_MS = 220
82
- const TOOL_UPDATE_THROTTLE_MS = 50 // Throttle tool streaming updates
83
- const STREAMING_TAIL_CHARS = 4000
84
-
85
- function computeUpdateThrottleMs(textLength: number): number {
86
- if (textLength > 12000) return UPDATE_THROTTLE_SLOWEST_MS
87
- if (textLength > 6000) return UPDATE_THROTTLE_SLOW_MS
88
- return UPDATE_THROTTLE_MS
89
- }
90
-
91
- /** Incremental extraction cache - avoids re-parsing entire content array each update */
92
- interface ExtractionCache {
93
- // Track processed content length for incremental updates
94
- lastContentLength: number
95
- // Total streaming text length (full content, even if view is tailed)
96
- textLength: number
97
- // Tail of streaming text for display
98
- textTail: string
99
- thinking: { summary: string; preview: string; full: string } | null
100
- contentBlocks: UIContentBlock[]
101
- // For thinking block ID generation
102
- thinkingCounter: number
103
- }
104
-
105
- function createExtractionCache(): ExtractionCache {
106
- return {
107
- lastContentLength: 0,
108
- textLength: 0,
109
- textTail: "",
110
- thinking: null,
111
- contentBlocks: [],
112
- thinkingCounter: 0,
113
- }
114
- }
115
-
116
- function appendStreamingTail(current: string, next: string): string {
117
- if (next.length >= STREAMING_TAIL_CHARS) return next.slice(-STREAMING_TAIL_CHARS)
118
- if (current.length + next.length <= STREAMING_TAIL_CHARS) return current + next
119
- return (current + next).slice(-STREAMING_TAIL_CHARS)
120
- }
121
-
122
- /** Incrementally extract new content blocks, appending to cached results */
123
- function extractIncremental(content: unknown[], cache: ExtractionCache): ExtractionCache {
124
- const len = content.length
125
- if (len === cache.lastContentLength) return cache // No change
126
-
127
- // Process only new blocks
128
- let textLength = cache.textLength
129
- let textTail = cache.textTail
130
- let thinking = cache.thinking
131
- const contentBlocks = cache.contentBlocks
132
- let thinkingCounter = cache.thinkingCounter
133
-
134
- for (let i = cache.lastContentLength; i < len; i++) {
135
- const block = content[i]
136
- if (typeof block !== "object" || block === null) continue
137
- const b = block as Record<string, unknown>
138
-
139
- if (b.type === "text" && typeof b.text === "string") {
140
- textLength += b.text.length
141
- textTail = appendStreamingTail(textTail, b.text)
142
- // Merge with last text block or add new
143
- const lastBlock = contentBlocks[contentBlocks.length - 1]
144
- if (lastBlock?.type === "text") {
145
- lastBlock.text = appendStreamingTail(lastBlock.text, b.text)
146
- } else {
147
- contentBlocks.push({ type: "text", text: appendStreamingTail("", b.text) })
148
- }
149
- } else if (b.type === "thinking" && typeof b.thinking === "string") {
150
- const full = b.thinking
151
- const { summary, preview } = buildThinkingSummary(full)
152
- thinking = { summary, preview, full }
153
- contentBlocks.push({ type: "thinking", id: `thinking-${thinkingCounter++}`, summary, preview, full })
154
- } else if (b.type === "toolCall" && typeof b.id === "string" && typeof b.name === "string") {
155
- contentBlocks.push({
156
- type: "tool",
157
- tool: { id: b.id, name: b.name, args: b.arguments ?? {}, isError: false, isComplete: false },
158
- })
159
- }
160
- }
161
-
162
- return { lastContentLength: len, textLength, textTail, thinking, contentBlocks, thinkingCounter }
163
- }
164
-
165
- export function createAgentEventHandler(ctx: EventHandlerContext): AgentEventHandler {
166
- let pendingUpdate: Extract<AgentEvent, { type: "message_update" }> | null = null
167
- let updateTimeout: ReturnType<typeof setTimeout> | null = null
168
- let disposed = false
169
- let turnIndex = 0
170
-
171
- // Incremental extraction cache - reset on new message
172
- let extractionCache = createExtractionCache()
173
-
174
- // Tool update throttling - track pending updates per tool
175
- const pendingToolUpdates = new Map<string, Extract<AgentEvent, { type: "tool_execution_update" }>>()
176
- let toolUpdateTimeout: ReturnType<typeof setTimeout> | null = null
177
-
178
- const dispose = () => {
179
- disposed = true
180
- pendingUpdate = null
181
- pendingToolUpdates.clear()
182
- extractionCache = createExtractionCache()
183
- if (updateTimeout) clearTimeout(updateTimeout)
184
- if (toolUpdateTimeout) clearTimeout(toolUpdateTimeout)
185
- updateTimeout = null
186
- toolUpdateTimeout = null
187
- }
188
-
189
- // Inline update handler - accesses extractionCache from closure
190
- const handleMessageUpdate = (ev: Extract<AgentEvent, { type: "message_update" }>) =>
191
- profile("stream_message_update", () => {
192
- const content = ev.message.content as unknown[]
193
-
194
- // Use incremental extraction - only processes new blocks
195
- extractionCache = extractIncremental(content, extractionCache)
196
- const { textLength, textTail, thinking, contentBlocks } = extractionCache
197
- updateThrottleMs = computeUpdateThrottleMs(textLength)
198
-
199
- updateStreamingMessage(ctx, (msg) => {
200
- const nextThinking = thinking || msg.thinking
201
- return { ...msg, content: textTail, thinking: nextThinking, contentBlocks }
202
- })
203
-
204
- if (thinking && textLength === 0) ctx.setActivityState("thinking")
205
- })
206
-
207
- const flushPendingUpdate = () => {
208
- if (!pendingUpdate) return
209
- const event = pendingUpdate
210
- pendingUpdate = null
211
- handleMessageUpdate(event)
212
- }
213
-
214
- let updateThrottleMs = UPDATE_THROTTLE_MS
215
-
216
- const scheduleUpdate = () => {
217
- if (updateTimeout) return
218
- updateTimeout = setTimeout(() => {
219
- updateTimeout = null
220
- if (disposed) return
221
- flushPendingUpdate()
222
- }, updateThrottleMs)
223
- }
224
-
225
- const flushToolUpdates = () => {
226
- if (pendingToolUpdates.size === 0) return
227
- for (const event of pendingToolUpdates.values()) {
228
- handleToolUpdateImmediate(event, ctx)
229
- }
230
- pendingToolUpdates.clear()
231
- }
232
-
233
- const scheduleToolUpdate = () => {
234
- if (toolUpdateTimeout) return
235
- toolUpdateTimeout = setTimeout(() => {
236
- toolUpdateTimeout = null
237
- if (disposed) return
238
- flushToolUpdates()
239
- }, TOOL_UPDATE_THROTTLE_MS)
240
- }
241
-
242
- const handler = ((event: AgentEvent) => {
243
- if (disposed) return
244
-
245
- // Emit hook events for agent lifecycle (fire-and-forget)
246
- if (event.type === "agent_start") {
247
- turnIndex = 0
248
- ctx.setTurnCount(0) // Reset turn count for new agent run
249
- extractionCache = createExtractionCache() // Reset for new agent run
250
- void ctx.hookRunner?.emit({
251
- type: "agent.start",
252
- sessionId: ctx.sessionManager.sessionId,
253
- })
254
- }
255
-
256
- if (event.type === "turn_start") {
257
- ctx.setTurnCount(turnIndex + 1) // Update UI with current turn (1-indexed for display)
258
- void ctx.hookRunner?.emit({
259
- type: "turn.start",
260
- sessionId: ctx.sessionManager.sessionId,
261
- turnIndex,
262
- })
263
- }
264
-
265
- if (event.type === "turn_end") {
266
- // Extract usage from message for hook consumption
267
- const msgUsage = event.message as { usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number; cacheReadInputTokens?: number; cacheCreationInputTokens?: number } }
268
- const contextWindow = ctx.getContextWindow?.() ?? 0
269
- const currentTokens = msgUsage.usage?.totalTokens ?? 0
270
-
271
- const tokens = {
272
- input: msgUsage.usage?.inputTokens ?? 0,
273
- output: msgUsage.usage?.outputTokens ?? 0,
274
- cacheRead: msgUsage.usage?.cacheReadInputTokens,
275
- cacheWrite: msgUsage.usage?.cacheCreationInputTokens,
276
- total: currentTokens,
277
- }
278
-
279
- // Update hook runner with token usage for session context
280
- ctx.hookRunner?.updateTokenUsage(tokens, contextWindow)
281
-
282
- void ctx.hookRunner?.emit({
283
- type: "turn.end",
284
- sessionId: ctx.sessionManager.sessionId,
285
- turnIndex,
286
- message: event.message,
287
- toolResults: event.toolResults as ToolResultMessage[],
288
- tokens,
289
- contextLimit: contextWindow,
290
- usage: contextWindow > 0 && currentTokens > 0
291
- ? { current: currentTokens, max: contextWindow, percent: (currentTokens / contextWindow) * 100 }
292
- : undefined,
293
- })
294
- turnIndex++
295
- }
296
-
297
- if (event.type === "message_start") {
298
- handleMessageStart(event, ctx, { current: extractionCache, set: (c) => { extractionCache = c } })
299
- }
300
-
301
- if (event.type === "message_update" && event.message.role === "assistant") {
302
- pendingUpdate = event
303
- scheduleUpdate()
304
- }
305
-
306
- if (event.type === "message_end" && event.message.role === "assistant") {
307
- pendingUpdate = null
308
- handleMessageEnd(event, ctx)
309
- }
310
-
311
- if (event.type === "message_end" && event.message.role === "toolResult") {
312
- // Persist tool results so sessions can be resumed with tool output context.
313
- ctx.sessionManager.appendMessage(event.message as AppMessage)
314
- }
315
-
316
- if (event.type === "tool_execution_start") {
317
- handleToolStart(event, ctx)
318
- }
319
-
320
- if (event.type === "tool_execution_update") {
321
- // Throttle tool updates - coalesce per tool
322
- pendingToolUpdates.set(event.toolCallId, event)
323
- scheduleToolUpdate()
324
- }
325
-
326
- if (event.type === "tool_execution_end") {
327
- // Clear any pending throttled update for this tool
328
- pendingToolUpdates.delete(event.toolCallId)
329
- handleToolEnd(event, ctx)
330
- }
331
-
332
- if (event.type === "turn_end") {
333
- ctx.streamingMessageId.current = null
334
- }
335
-
336
- if (event.type === "agent_end") {
337
- handleAgentEnd(event, ctx)
338
- }
339
- }) as AgentEventHandler
340
-
341
- handler.dispose = dispose
342
- return handler
343
- }
344
-
345
- function updateStreamingMessage(ctx: EventHandlerContext, updater: (msg: UIAssistantMessage) => UIAssistantMessage): void {
346
- const streamingId = ctx.streamingMessageId.current
347
- if (!streamingId) return
348
-
349
- ctx.setMessages((prev) => {
350
- if (prev.length === 0) return prev
351
-
352
- const lastIdx = prev.length - 1
353
- const last = prev[lastIdx]
354
- if (last?.id === streamingId && last.role === "assistant") {
355
- const nextLast = updater(last)
356
- if (nextLast === last) return prev
357
- const next = prev.slice()
358
- next[lastIdx] = nextLast
359
- return next
360
- }
361
-
362
- const idx = prev.findIndex((m) => m.id === streamingId)
363
- if (idx === -1) return prev
364
-
365
- const current = prev[idx]!
366
- if (current.role !== "assistant") return prev
367
- const updated = updater(current)
368
- if (updated === current) return prev
369
-
370
- const next = prev.slice()
371
- next[idx] = updated
372
- return next
373
- })
374
- }
375
-
376
- function handleMessageStart(
377
- event: Extract<AgentEvent, { type: "message_start" }>,
378
- ctx: EventHandlerContext,
379
- cache: { current: ExtractionCache; set: (c: ExtractionCache) => void }
380
- ): void {
381
- // Handle queued user message being processed
382
- if (event.message.role === "user") {
383
- const text = typeof event.message.content === "string"
384
- ? event.message.content
385
- : extractText(event.message.content as unknown[])
386
-
387
- // Only consume from queue if this message matches the queued text
388
- const peeked = ctx.promptQueue.peek()
389
- if (peeked !== undefined && peeked.text === text) {
390
- ctx.promptQueue.shift() // consume the matched message
391
- ctx.sessionManager.appendMessage(event.message as AppMessage)
392
- ctx.setMessages((prev) => appendWithCap(prev, { id: crypto.randomUUID(), role: "user", content: text, timestamp: Date.now() }))
393
- ctx.setActivityState("thinking")
394
- }
395
- }
396
-
397
- // Create streaming assistant message
398
- if (event.message.role === "assistant") {
399
- ctx.streamingMessageId.current = crypto.randomUUID()
400
- cache.current = createExtractionCache() // Reset cache for new message
401
- batch(() => {
402
- ctx.setActivityState("streaming")
403
- ctx.setMessages((prev) => appendWithCap(prev, {
404
- id: ctx.streamingMessageId.current!,
405
- role: "assistant",
406
- content: "",
407
- isStreaming: true,
408
- tools: [],
409
- timestamp: Date.now(),
410
- }))
411
- })
412
- }
413
- }
414
-
415
- function handleMessageEnd(
416
- event: Extract<AgentEvent, { type: "message_end" }>,
417
- ctx: EventHandlerContext
418
- ): void {
419
- const content = event.message.content as unknown[]
420
- const text = extractText(content)
421
- const thinking = extractThinking(content)
422
- const orderedBlocks = extractOrderedBlocks(content)
423
-
424
- // Convert ordered blocks to UIContentBlocks, preserving order
425
- const contentBlocks: UIContentBlock[] = orderedBlocks.map((block) => {
426
- if (block.type === "thinking") {
427
- return { type: "thinking" as const, id: block.id, summary: block.summary, preview: block.preview, full: block.full }
428
- } else if (block.type === "text") {
429
- return { type: "text" as const, text: block.text }
430
- } else {
431
- // toolCall - create a stub tool block (will be updated by handleToolEnd)
432
- return {
433
- type: "tool" as const,
434
- tool: { id: block.id, name: block.name, args: block.args, isError: false, isComplete: false },
435
- }
436
- }
437
- })
438
-
439
- updateStreamingMessage(ctx, (msg) => {
440
- const nextThinking = thinking || msg.thinking
441
- return { ...msg, content: text, thinking: nextThinking, contentBlocks, isStreaming: false }
442
- })
443
-
444
- ctx.streamingMessageId.current = null
445
-
446
- // Save message to session
447
- ctx.sessionManager.appendMessage(event.message as AppMessage)
448
-
449
- // Update usage - context window budget includes input + output for the full request
450
- // totalTokens is already computed by providers as: (uncached_input + cacheRead + cacheWrite) + output
451
- // Only update if totalTokens > 0 to avoid clearing bar on aborted responses
452
- const msg = event.message as { usage?: { totalTokens?: number; cacheRead?: number; input?: number } }
453
- if (msg.usage?.totalTokens) {
454
- ctx.setContextTokens(msg.usage.totalTokens)
455
- }
456
- // Update cache stats for efficiency indicator
457
- if (msg.usage && typeof msg.usage.cacheRead === "number" && typeof msg.usage.input === "number") {
458
- ctx.setCacheStats({ cacheRead: msg.usage.cacheRead, input: msg.usage.input })
459
- }
460
- }
461
-
462
- /** Update a tool in both tools array and contentBlocks */
463
- function updateToolInContentBlocks(
464
- contentBlocks: UIContentBlock[] | undefined,
465
- toolId: string,
466
- updater: (tool: ToolBlock) => ToolBlock
467
- ): UIContentBlock[] | undefined {
468
- if (!contentBlocks) return undefined
469
- for (let i = 0; i < contentBlocks.length; i++) {
470
- const block = contentBlocks[i]
471
- if (block.type !== "tool" || block.tool.id !== toolId) continue
472
- const updated = updater(block.tool)
473
- if (updated === block.tool) return contentBlocks
474
- contentBlocks[i] = { ...block, tool: updated }
475
- return contentBlocks
476
- }
477
- return contentBlocks
478
- }
479
-
480
- function updateToolById(
481
- tools: ToolBlock[],
482
- toolId: string,
483
- updater: (tool: ToolBlock) => ToolBlock
484
- ): ToolBlock[] {
485
- const idx = tools.findIndex((t) => t.id === toolId)
486
- if (idx === -1) return tools
487
- const current = tools[idx]
488
- if (!current) return tools
489
- const updated = updater(current)
490
- if (updated === current) return tools
491
- const next = tools.slice()
492
- next[idx] = updated
493
- return next
494
- }
495
-
496
- function handleToolStart(
497
- event: Extract<AgentEvent, { type: "tool_execution_start" }>,
498
- ctx: EventHandlerContext
499
- ): void {
500
- ctx.setActivityState("tool")
501
-
502
- // Attach tool metadata from registry if available
503
- const meta = ctx.toolByName?.get(event.toolName)
504
-
505
- const newTool: ToolBlock = {
506
- id: event.toolCallId,
507
- name: event.toolName,
508
- args: event.args,
509
- updateSeq: 0,
510
- isError: false,
511
- isComplete: false,
512
- // Attach metadata for custom rendering
513
- label: meta?.label,
514
- source: meta?.source,
515
- sourcePath: meta?.sourcePath,
516
- renderCall: meta?.renderCall,
517
- renderResult: meta?.renderResult,
518
- }
519
-
520
- updateStreamingMessage(ctx, (msg) => ({
521
- ...msg,
522
- tools: [...(msg.tools || []), newTool],
523
- // Update tool in contentBlocks if it exists there (as stub from message_end)
524
- contentBlocks: updateToolInContentBlocks(msg.contentBlocks, event.toolCallId, () => newTool),
525
- }))
526
-
527
- ctx.setToolBlocks((prev) => [...prev, newTool])
528
- }
529
-
530
- function handleToolUpdateImmediate(
531
- event: Extract<AgentEvent, { type: "tool_execution_update" }>,
532
- ctx: EventHandlerContext
533
- ): void {
534
- const toolUpdater = (t: ToolBlock): ToolBlock => ({
535
- ...t,
536
- updateSeq: (t.updateSeq ?? 0) + 1,
537
- output: getToolText(event.partialResult),
538
- result: event.partialResult,
539
- })
540
- const updateTools = (tools: ToolBlock[]) => updateToolById(tools, event.toolCallId, toolUpdater)
541
-
542
- batch(() => {
543
- ctx.setToolBlocks(updateTools)
544
- updateStreamingMessage(ctx, (msg) => ({
545
- ...msg,
546
- tools: updateTools(msg.tools || []),
547
- contentBlocks: updateToolInContentBlocks(msg.contentBlocks, event.toolCallId, toolUpdater),
548
- }))
549
- })
550
- }
551
-
552
- function handleToolEnd(
553
- event: Extract<AgentEvent, { type: "tool_execution_end" }>,
554
- ctx: EventHandlerContext
555
- ): void {
556
- const toolUpdater = (t: ToolBlock): ToolBlock => ({
557
- ...t,
558
- output: getToolText(event.result),
559
- editDiff: getEditDiffText(event.result) || undefined,
560
- isError: event.isError,
561
- isComplete: true,
562
- result: event.result,
563
- })
564
-
565
- const updateTools = (tools: ToolBlock[]) => updateToolById(tools, event.toolCallId, toolUpdater)
566
- ctx.setToolBlocks(updateTools)
567
-
568
- // Update message containing this tool - find by tool ID since streamingMessageId
569
- // may be null if message_end fired before tool_execution_end
570
- ctx.setMessages((prev) => {
571
- const idx = prev.findIndex(
572
- (m) =>
573
- m.role === "assistant" && (
574
- m.tools?.some((t: ToolBlock) => t.id === event.toolCallId) ||
575
- m.contentBlocks?.some((b: UIContentBlock) => b.type === "tool" && b.tool.id === event.toolCallId)
576
- )
577
- )
578
- if (idx === -1) return prev
579
-
580
- const msg = prev[idx]!
581
- if (msg.role !== "assistant") return prev
582
- const updated: UIAssistantMessage = {
583
- ...msg,
584
- tools: updateTools(msg.tools || []),
585
- contentBlocks: updateToolInContentBlocks(msg.contentBlocks, event.toolCallId, toolUpdater),
586
- }
587
- const next = prev.slice()
588
- next[idx] = updated
589
- return next
590
- })
591
- }
592
-
593
- function handleAgentEnd(
594
- event: Extract<AgentEvent, { type: "agent_end" }>,
595
- ctx: EventHandlerContext
596
- ): void {
597
- ctx.streamingMessageId.current = null
598
-
599
- // Emit hook event - aggregate total tokens from all turns
600
- const totalTokens = ctx.hookRunner?.getContext?.()?.session?.getTokenUsage?.() ?? { input: 0, output: 0, total: 0 }
601
- const contextLimit = ctx.getContextWindow?.() ?? 0
602
- void ctx.hookRunner?.emit({
603
- type: "agent.end",
604
- sessionId: ctx.sessionManager.sessionId,
605
- messages: event.messages,
606
- totalTokens,
607
- contextLimit,
608
- })
609
-
610
- // Check for retryable error
611
- const lastMsg = ctx.agent.state.messages[ctx.agent.state.messages.length - 1] as AssistantMessage | undefined
612
- const errorMsg = lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).errorMessage
613
- const isRetryable = errorMsg && ctx.retryablePattern.test(errorMsg)
614
-
615
- if (isRetryable && ctx.retryConfig.enabled && ctx.retryState.attempt < ctx.retryConfig.maxRetries) {
616
- ctx.retryState.attempt++
617
- const delay = ctx.retryConfig.baseDelayMs * Math.pow(2, ctx.retryState.attempt - 1)
618
- ctx.setRetryStatus(`Retrying (${ctx.retryState.attempt}/${ctx.retryConfig.maxRetries}) in ${Math.round(delay / 1000)}s... (esc to cancel)`)
619
-
620
- ctx.retryState.abortController = new AbortController()
621
- const signal = ctx.retryState.abortController.signal
622
-
623
- const sleep = (ms: number) =>
624
- new Promise<void>((resolve, reject) => {
625
- const timeout = setTimeout(resolve, ms)
626
- signal.addEventListener(
627
- "abort",
628
- () => {
629
- clearTimeout(timeout)
630
- reject(new Error("cancelled"))
631
- },
632
- { once: true }
633
- )
634
- })
635
-
636
- sleep(delay)
637
- .then(() => {
638
- if (signal.aborted) return
639
- ctx.setRetryStatus(null)
640
- ctx.retryState.abortController = null
641
- // Remove last error message and retry
642
- ctx.agent.replaceMessages(ctx.agent.state.messages.slice(0, -1))
643
- ctx.setActivityState("thinking")
644
- void ctx.agent.continue().catch((err) => {
645
- ctx.setActivityState("idle")
646
- ctx.setIsResponding(false)
647
- ctx.setMessages((prev) => [
648
- ...prev,
649
- {
650
- id: crypto.randomUUID(),
651
- role: "assistant",
652
- content: `Error: ${err instanceof Error ? err.message : String(err)}`,
653
- },
654
- ])
655
- })
656
- })
657
- .catch(() => {
658
- // Retry cancelled
659
- ctx.setIsResponding(false)
660
- ctx.setActivityState("idle")
661
- })
662
- return
663
- }
664
-
665
- ctx.retryState.attempt = 0
666
- batch(() => {
667
- ctx.setIsResponding(false)
668
- ctx.setActivityState("idle")
669
- ctx.setTurnCount(0) // Reset turn count when agent completes
670
- })
671
- }