@qduc/term2 0.7.0 → 0.7.2

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 (509) hide show
  1. package/dist/agent.d.ts +0 -1
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +28 -8
  4. package/dist/agent.js.map +1 -1
  5. package/dist/app.d.ts +3 -3
  6. package/dist/app.d.ts.map +1 -1
  7. package/dist/app.js +161 -75
  8. package/dist/app.js.map +1 -1
  9. package/dist/app.large-uncached-warning.test.js.map +1 -1
  10. package/dist/cli.integration.test.d.ts +2 -0
  11. package/dist/cli.integration.test.d.ts.map +1 -0
  12. package/dist/cli.integration.test.js +142 -0
  13. package/dist/cli.integration.test.js.map +1 -0
  14. package/dist/cli.js +47 -12
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/auto-approve-command.d.ts +10 -0
  17. package/dist/commands/auto-approve-command.d.ts.map +1 -0
  18. package/dist/commands/auto-approve-command.js +40 -0
  19. package/dist/commands/auto-approve-command.js.map +1 -0
  20. package/dist/commands/clear-command.d.ts +3 -0
  21. package/dist/commands/clear-command.d.ts.map +1 -0
  22. package/dist/commands/clear-command.js +12 -0
  23. package/dist/commands/clear-command.js.map +1 -0
  24. package/dist/commands/copy-command.d.ts +10 -0
  25. package/dist/commands/copy-command.d.ts.map +1 -0
  26. package/dist/commands/copy-command.js +25 -0
  27. package/dist/commands/copy-command.js.map +1 -0
  28. package/dist/commands/effort-command.d.ts +11 -0
  29. package/dist/commands/effort-command.d.ts.map +1 -0
  30. package/dist/commands/effort-command.js +34 -0
  31. package/dist/commands/effort-command.js.map +1 -0
  32. package/dist/commands/guarded-settings-command.d.ts +14 -0
  33. package/dist/commands/guarded-settings-command.d.ts.map +1 -0
  34. package/dist/commands/guarded-settings-command.js +23 -0
  35. package/dist/commands/guarded-settings-command.js.map +1 -0
  36. package/dist/commands/handoff-command.d.ts +10 -0
  37. package/dist/commands/handoff-command.d.ts.map +1 -0
  38. package/dist/commands/handoff-command.js +17 -0
  39. package/dist/commands/handoff-command.js.map +1 -0
  40. package/dist/commands/mode-commands.d.ts +32 -0
  41. package/dist/commands/mode-commands.d.ts.map +1 -0
  42. package/dist/commands/mode-commands.js +64 -0
  43. package/dist/commands/mode-commands.js.map +1 -0
  44. package/dist/commands/model-command.d.ts +11 -0
  45. package/dist/commands/model-command.d.ts.map +1 -0
  46. package/dist/commands/model-command.js +35 -0
  47. package/dist/commands/model-command.js.map +1 -0
  48. package/dist/commands/quit-command.d.ts +3 -0
  49. package/dist/commands/quit-command.d.ts.map +1 -0
  50. package/dist/commands/quit-command.js +10 -0
  51. package/dist/commands/quit-command.js.map +1 -0
  52. package/dist/commands/retry-command.d.ts +19 -0
  53. package/dist/commands/retry-command.d.ts.map +1 -0
  54. package/dist/commands/retry-command.js +30 -0
  55. package/dist/commands/retry-command.js.map +1 -0
  56. package/dist/commands/undo-command.d.ts +15 -0
  57. package/dist/commands/undo-command.d.ts.map +1 -0
  58. package/dist/commands/undo-command.js +28 -0
  59. package/dist/commands/undo-command.js.map +1 -0
  60. package/dist/commands/usage-command.d.ts +3 -0
  61. package/dist/commands/usage-command.d.ts.map +1 -0
  62. package/dist/commands/usage-command.js +11 -0
  63. package/dist/commands/usage-command.js.map +1 -0
  64. package/dist/components/BottomArea.d.ts +7 -0
  65. package/dist/components/BottomArea.d.ts.map +1 -1
  66. package/dist/components/BottomArea.js +15 -6
  67. package/dist/components/BottomArea.js.map +1 -1
  68. package/dist/components/BottomArea.test.js +36 -4
  69. package/dist/components/BottomArea.test.js.map +1 -1
  70. package/dist/components/Common/MenuContainer.d.ts +1 -3
  71. package/dist/components/Common/MenuContainer.d.ts.map +1 -1
  72. package/dist/components/Common/MenuContainer.js +1 -13
  73. package/dist/components/Common/MenuContainer.js.map +1 -1
  74. package/dist/components/Input/input-width.d.ts +2 -1
  75. package/dist/components/Input/input-width.d.ts.map +1 -1
  76. package/dist/components/Input/input-width.js +6 -2
  77. package/dist/components/Input/input-width.js.map +1 -1
  78. package/dist/components/InputBox.d.ts +2 -0
  79. package/dist/components/InputBox.d.ts.map +1 -1
  80. package/dist/components/InputBox.js +21 -7
  81. package/dist/components/InputBox.js.map +1 -1
  82. package/dist/components/InputBox.test.js +44 -0
  83. package/dist/components/InputBox.test.js.map +1 -1
  84. package/dist/components/LargeUncachedConfirmationPrompt.d.ts +9 -0
  85. package/dist/components/LargeUncachedConfirmationPrompt.d.ts.map +1 -0
  86. package/dist/components/LargeUncachedConfirmationPrompt.js +44 -0
  87. package/dist/components/LargeUncachedConfirmationPrompt.js.map +1 -0
  88. package/dist/components/LargeUncachedConfirmationPrompt.test.d.ts +2 -0
  89. package/dist/components/LargeUncachedConfirmationPrompt.test.d.ts.map +1 -0
  90. package/dist/components/LargeUncachedConfirmationPrompt.test.js +47 -0
  91. package/dist/components/LargeUncachedConfirmationPrompt.test.js.map +1 -0
  92. package/dist/components/MessageList.d.ts +9 -0
  93. package/dist/components/MessageList.d.ts.map +1 -1
  94. package/dist/components/MessageList.js +29 -3
  95. package/dist/components/MessageList.js.map +1 -1
  96. package/dist/components/MessageList.test.js +28 -1
  97. package/dist/components/MessageList.test.js.map +1 -1
  98. package/dist/components/ModelSelectionMenu.d.ts.map +1 -1
  99. package/dist/components/ModelSelectionMenu.js +1 -4
  100. package/dist/components/ModelSelectionMenu.js.map +1 -1
  101. package/dist/components/PathSelectionMenu.d.ts.map +1 -1
  102. package/dist/components/PathSelectionMenu.js +1 -7
  103. package/dist/components/PathSelectionMenu.js.map +1 -1
  104. package/dist/components/SettingsSelectionMenu.d.ts.map +1 -1
  105. package/dist/components/SettingsSelectionMenu.js +1 -12
  106. package/dist/components/SettingsSelectionMenu.js.map +1 -1
  107. package/dist/components/SettingsValueSelectionMenu.d.ts.map +1 -1
  108. package/dist/components/SettingsValueSelectionMenu.js +1 -8
  109. package/dist/components/SettingsValueSelectionMenu.js.map +1 -1
  110. package/dist/components/StatusBar.d.ts +4 -0
  111. package/dist/components/StatusBar.d.ts.map +1 -1
  112. package/dist/components/StatusBar.js +25 -6
  113. package/dist/components/StatusBar.js.map +1 -1
  114. package/dist/components/StatusBar.test.js +23 -0
  115. package/dist/components/StatusBar.test.js.map +1 -1
  116. package/dist/components/UndoSelectionMenu.d.ts.map +1 -1
  117. package/dist/components/UndoSelectionMenu.js +1 -1
  118. package/dist/components/UndoSelectionMenu.js.map +1 -1
  119. package/dist/context/InputContext.d.ts +5 -0
  120. package/dist/context/InputContext.d.ts.map +1 -1
  121. package/dist/context/InputContext.images.test.d.ts +2 -0
  122. package/dist/context/InputContext.images.test.d.ts.map +1 -0
  123. package/dist/context/InputContext.images.test.js +56 -0
  124. package/dist/context/InputContext.images.test.js.map +1 -0
  125. package/dist/context/InputContext.js +3 -2
  126. package/dist/context/InputContext.js.map +1 -1
  127. package/dist/contracts/conversation.d.ts +3 -0
  128. package/dist/contracts/conversation.d.ts.map +1 -1
  129. package/dist/hooks/use-app-commands.d.ts +11 -32
  130. package/dist/hooks/use-app-commands.d.ts.map +1 -1
  131. package/dist/hooks/use-app-commands.js +64 -369
  132. package/dist/hooks/use-app-commands.js.map +1 -1
  133. package/dist/hooks/use-app-commands.test.js +24 -15
  134. package/dist/hooks/use-app-commands.test.js.map +1 -1
  135. package/dist/hooks/use-conversation.clear.test.js +49 -1
  136. package/dist/hooks/use-conversation.clear.test.js.map +1 -1
  137. package/dist/hooks/use-conversation.d.ts +12 -2
  138. package/dist/hooks/use-conversation.d.ts.map +1 -1
  139. package/dist/hooks/use-conversation.js +29 -25
  140. package/dist/hooks/use-conversation.js.map +1 -1
  141. package/dist/hooks/use-conversation.resume.test.js +26 -3
  142. package/dist/hooks/use-conversation.resume.test.js.map +1 -1
  143. package/dist/hooks/use-mode-handlers.d.ts +4 -1
  144. package/dist/hooks/use-mode-handlers.d.ts.map +1 -1
  145. package/dist/hooks/use-mode-handlers.js +6 -1
  146. package/dist/hooks/use-mode-handlers.js.map +1 -1
  147. package/dist/hooks/use-runtime-settings.d.ts.map +1 -1
  148. package/dist/hooks/use-runtime-settings.js +2 -2
  149. package/dist/hooks/use-runtime-settings.js.map +1 -1
  150. package/dist/hooks/use-runtime-settings.test.js +0 -1
  151. package/dist/hooks/use-runtime-settings.test.js.map +1 -1
  152. package/dist/hooks/use-settings-completion.d.ts.map +1 -1
  153. package/dist/hooks/use-settings-completion.js +8 -1
  154. package/dist/hooks/use-settings-completion.js.map +1 -1
  155. package/dist/hooks/use-settings-completion.test.js +4 -0
  156. package/dist/hooks/use-settings-completion.test.js.map +1 -1
  157. package/dist/hooks/use-slash-commands.d.ts.map +1 -1
  158. package/dist/hooks/use-slash-commands.js +10 -0
  159. package/dist/hooks/use-slash-commands.js.map +1 -1
  160. package/dist/hooks/use-slash-commands.test.js +35 -5
  161. package/dist/hooks/use-slash-commands.test.js.map +1 -1
  162. package/dist/hooks/use-terminal-width.d.ts +2 -1
  163. package/dist/hooks/use-terminal-width.d.ts.map +1 -1
  164. package/dist/hooks/use-terminal-width.js +2 -1
  165. package/dist/hooks/use-terminal-width.js.map +1 -1
  166. package/dist/hooks/use-undo-selection.d.ts.map +1 -1
  167. package/dist/hooks/use-undo-selection.js +3 -1
  168. package/dist/hooks/use-undo-selection.js.map +1 -1
  169. package/dist/lib/openai-agent-client.d.ts.map +1 -1
  170. package/dist/lib/openai-agent-client.flex-tier.test.js +8 -3
  171. package/dist/lib/openai-agent-client.flex-tier.test.js.map +1 -1
  172. package/dist/lib/openai-agent-client.js +50 -24
  173. package/dist/lib/openai-agent-client.js.map +1 -1
  174. package/dist/lib/tool-execution-limiter.d.ts +16 -0
  175. package/dist/lib/tool-execution-limiter.d.ts.map +1 -0
  176. package/dist/lib/tool-execution-limiter.js +112 -0
  177. package/dist/lib/tool-execution-limiter.js.map +1 -0
  178. package/dist/lib/tool-execution-limiter.test.d.ts +2 -0
  179. package/dist/lib/tool-execution-limiter.test.d.ts.map +1 -0
  180. package/dist/lib/tool-execution-limiter.test.js +70 -0
  181. package/dist/lib/tool-execution-limiter.test.js.map +1 -0
  182. package/dist/lib/tool-invoke.test.js +8 -8
  183. package/dist/lib/tool-invoke.test.js.map +1 -1
  184. package/dist/lib/tool-selection-policy.d.ts.map +1 -1
  185. package/dist/lib/tool-selection-policy.js +43 -2
  186. package/dist/lib/tool-selection-policy.js.map +1 -1
  187. package/dist/lib/tool-selection-policy.test.js +39 -0
  188. package/dist/lib/tool-selection-policy.test.js.map +1 -1
  189. package/dist/prompts/gpt-5-modern.md +105 -97
  190. package/dist/prompts/gpt-5.5.md +106 -0
  191. package/dist/prompts/orchestrator.md +2 -5
  192. package/dist/prompts/prompt-profiles.js +1 -1
  193. package/dist/prompts/prompt-profiles.js.map +1 -1
  194. package/dist/prompts/prompt-profiles.ts +1 -1
  195. package/dist/prompts/prompt-selector.test.js +1 -1
  196. package/dist/prompts/prompt-selector.test.js.map +1 -1
  197. package/dist/prompts/prompt-selector.test.ts +1 -1
  198. package/dist/prompts/search-via-shell.d.ts.map +1 -1
  199. package/dist/prompts/search-via-shell.js +0 -1
  200. package/dist/prompts/search-via-shell.js.map +1 -1
  201. package/dist/prompts/search-via-shell.ts +0 -1
  202. package/dist/prompts/shell-auto-approval.d.ts +2 -2
  203. package/dist/prompts/shell-auto-approval.d.ts.map +1 -1
  204. package/dist/prompts/shell-auto-approval.js +6 -6
  205. package/dist/prompts/shell-auto-approval.js.map +1 -1
  206. package/dist/prompts/shell-auto-approval.ts +6 -6
  207. package/dist/prompts/simple-prev.md +55 -0
  208. package/dist/prompts/simple.md +31 -53
  209. package/dist/prompts/subagent-delegation.js +2 -2
  210. package/dist/prompts/subagent-delegation.js.map +1 -1
  211. package/dist/prompts/subagent-delegation.ts +2 -2
  212. package/dist/providers/codex-responses-model.d.ts +5 -3
  213. package/dist/providers/codex-responses-model.d.ts.map +1 -1
  214. package/dist/providers/codex-responses-model.js +76 -20
  215. package/dist/providers/codex-responses-model.js.map +1 -1
  216. package/dist/providers/codex-responses-model.test.js +242 -1
  217. package/dist/providers/codex-responses-model.test.js.map +1 -1
  218. package/dist/providers/codex.provider.d.ts +0 -2
  219. package/dist/providers/codex.provider.d.ts.map +1 -1
  220. package/dist/providers/codex.provider.js +2 -6
  221. package/dist/providers/codex.provider.js.map +1 -1
  222. package/dist/providers/codex.provider.test.js +4 -31
  223. package/dist/providers/codex.provider.test.js.map +1 -1
  224. package/dist/providers/custom-provider-adapter.test.js +3 -3
  225. package/dist/providers/custom-provider-adapter.test.js.map +1 -1
  226. package/dist/providers/fallback-responses-model.d.ts.map +1 -1
  227. package/dist/providers/fallback-responses-model.js +160 -83
  228. package/dist/providers/fallback-responses-model.js.map +1 -1
  229. package/dist/providers/fallback-responses-model.test.js +318 -0
  230. package/dist/providers/fallback-responses-model.test.js.map +1 -1
  231. package/dist/providers/openai-compatible-lazy.d.ts +4 -0
  232. package/dist/providers/openai-compatible-lazy.d.ts.map +1 -0
  233. package/dist/providers/openai-compatible-lazy.js +54 -0
  234. package/dist/providers/openai-compatible-lazy.js.map +1 -0
  235. package/dist/providers/openai-compatible.provider.d.ts +2 -2
  236. package/dist/providers/openai-compatible.provider.d.ts.map +1 -1
  237. package/dist/providers/openai-compatible.provider.js +3 -3
  238. package/dist/providers/openai-compatible.provider.js.map +1 -1
  239. package/dist/providers/openai-compatible.provider.test.js +31 -0
  240. package/dist/providers/openai-compatible.provider.test.js.map +1 -1
  241. package/dist/providers/openai.provider.js +5 -3
  242. package/dist/providers/openai.provider.js.map +1 -1
  243. package/dist/providers/timed-responses-ws-model.d.ts +20 -0
  244. package/dist/providers/timed-responses-ws-model.d.ts.map +1 -0
  245. package/dist/providers/timed-responses-ws-model.js +381 -0
  246. package/dist/providers/timed-responses-ws-model.js.map +1 -0
  247. package/dist/providers/timed-responses-ws-model.test.d.ts +2 -0
  248. package/dist/providers/timed-responses-ws-model.test.d.ts.map +1 -0
  249. package/dist/providers/timed-responses-ws-model.test.js +441 -0
  250. package/dist/providers/timed-responses-ws-model.test.js.map +1 -0
  251. package/dist/providers/timed-ws-connection.d.ts +26 -0
  252. package/dist/providers/timed-ws-connection.d.ts.map +1 -0
  253. package/dist/providers/timed-ws-connection.js +156 -0
  254. package/dist/providers/timed-ws-connection.js.map +1 -0
  255. package/dist/providers/timed-ws-connection.test.d.ts +2 -0
  256. package/dist/providers/timed-ws-connection.test.d.ts.map +1 -0
  257. package/dist/providers/timed-ws-connection.test.js +223 -0
  258. package/dist/providers/timed-ws-connection.test.js.map +1 -0
  259. package/dist/providers/timed-ws-timeouts.d.ts +6 -0
  260. package/dist/providers/timed-ws-timeouts.d.ts.map +1 -0
  261. package/dist/providers/timed-ws-timeouts.js +6 -0
  262. package/dist/providers/timed-ws-timeouts.js.map +1 -0
  263. package/dist/services/command-message-streaming.d.ts.map +1 -1
  264. package/dist/services/command-message-streaming.js +8 -3
  265. package/dist/services/command-message-streaming.js.map +1 -1
  266. package/dist/services/conversation-clear-save.test.js +4 -5
  267. package/dist/services/conversation-clear-save.test.js.map +1 -1
  268. package/dist/services/conversation-events.d.ts +4 -0
  269. package/dist/services/conversation-events.d.ts.map +1 -1
  270. package/dist/services/conversation-history-repair.d.ts.map +1 -1
  271. package/dist/services/conversation-history-repair.js +81 -26
  272. package/dist/services/conversation-history-repair.js.map +1 -1
  273. package/dist/services/conversation-integration.test.js +109 -0
  274. package/dist/services/conversation-integration.test.js.map +1 -1
  275. package/dist/services/conversation-log-events.d.ts +19 -10
  276. package/dist/services/conversation-log-events.d.ts.map +1 -1
  277. package/dist/services/conversation-log-events.js +1 -1
  278. package/dist/services/conversation-log-events.js.map +1 -1
  279. package/dist/services/conversation-log-writer.d.ts.map +1 -1
  280. package/dist/services/conversation-log-writer.js +2 -3
  281. package/dist/services/conversation-log-writer.js.map +1 -1
  282. package/dist/services/conversation-persistence-types.d.ts +32 -0
  283. package/dist/services/conversation-persistence-types.d.ts.map +1 -1
  284. package/dist/services/conversation-persistence.d.ts +7 -1
  285. package/dist/services/conversation-persistence.d.ts.map +1 -1
  286. package/dist/services/conversation-persistence.js +95 -44
  287. package/dist/services/conversation-persistence.js.map +1 -1
  288. package/dist/services/conversation-persistence.test.js +551 -107
  289. package/dist/services/conversation-persistence.test.js.map +1 -1
  290. package/dist/services/conversation-replay.d.ts.map +1 -1
  291. package/dist/services/conversation-replay.js +234 -11
  292. package/dist/services/conversation-replay.js.map +1 -1
  293. package/dist/services/conversation-replay.test.js +426 -31
  294. package/dist/services/conversation-replay.test.js.map +1 -1
  295. package/dist/services/conversation-result-builder.d.ts +2 -0
  296. package/dist/services/conversation-result-builder.d.ts.map +1 -1
  297. package/dist/services/conversation-result-builder.js +4 -0
  298. package/dist/services/conversation-result-builder.js.map +1 -1
  299. package/dist/services/conversation-result-builder.test.js +126 -0
  300. package/dist/services/conversation-result-builder.test.js.map +1 -1
  301. package/dist/services/conversation-retry-policy.d.ts.map +1 -1
  302. package/dist/services/conversation-retry-policy.js +3 -0
  303. package/dist/services/conversation-retry-policy.js.map +1 -1
  304. package/dist/services/conversation-retry-policy.test.js +4 -0
  305. package/dist/services/conversation-retry-policy.test.js.map +1 -1
  306. package/dist/services/conversation-service.d.ts +3 -3
  307. package/dist/services/conversation-service.d.ts.map +1 -1
  308. package/dist/services/conversation-service.js +0 -3
  309. package/dist/services/conversation-service.js.map +1 -1
  310. package/dist/services/conversation-session.d.ts +10 -7
  311. package/dist/services/conversation-session.d.ts.map +1 -1
  312. package/dist/services/conversation-session.js +283 -86
  313. package/dist/services/conversation-session.js.map +1 -1
  314. package/dist/services/conversation-store.d.ts +16 -13
  315. package/dist/services/conversation-store.d.ts.map +1 -1
  316. package/dist/services/conversation-store.js +62 -191
  317. package/dist/services/conversation-store.js.map +1 -1
  318. package/dist/services/conversation-store.merge-modes.test.d.ts +2 -0
  319. package/dist/services/conversation-store.merge-modes.test.d.ts.map +1 -0
  320. package/dist/services/conversation-store.merge-modes.test.js +161 -0
  321. package/dist/services/conversation-store.merge-modes.test.js.map +1 -0
  322. package/dist/services/conversation-store.test.js +157 -294
  323. package/dist/services/conversation-store.test.js.map +1 -1
  324. package/dist/services/conversation-turn-items.d.ts +5 -0
  325. package/dist/services/conversation-turn-items.d.ts.map +1 -0
  326. package/dist/services/conversation-turn-items.js +351 -0
  327. package/dist/services/conversation-turn-items.js.map +1 -0
  328. package/dist/services/conversation-turn-items.test.d.ts +2 -0
  329. package/dist/services/conversation-turn-items.test.d.ts.map +1 -0
  330. package/dist/services/conversation-turn-items.test.js +68 -0
  331. package/dist/services/conversation-turn-items.test.js.map +1 -0
  332. package/dist/services/large-uncached-input-guard.d.ts.map +1 -1
  333. package/dist/services/large-uncached-input-guard.js +4 -3
  334. package/dist/services/large-uncached-input-guard.js.map +1 -1
  335. package/dist/services/large-uncached-input-guard.test.js +22 -0
  336. package/dist/services/large-uncached-input-guard.test.js.map +1 -1
  337. package/dist/services/notification-service.d.ts +22 -0
  338. package/dist/services/notification-service.d.ts.map +1 -0
  339. package/dist/services/notification-service.js +68 -0
  340. package/dist/services/notification-service.js.map +1 -0
  341. package/dist/services/notification-service.test.d.ts +2 -0
  342. package/dist/services/notification-service.test.d.ts.map +1 -0
  343. package/dist/services/notification-service.test.js +78 -0
  344. package/dist/services/notification-service.test.js.map +1 -0
  345. package/dist/services/provider-traffic.d.ts.map +1 -1
  346. package/dist/services/provider-traffic.js +1 -0
  347. package/dist/services/provider-traffic.js.map +1 -1
  348. package/dist/services/provider-traffic.test.js +51 -0
  349. package/dist/services/provider-traffic.test.js.map +1 -1
  350. package/dist/services/settings-schema.d.ts +16 -1
  351. package/dist/services/settings-schema.d.ts.map +1 -1
  352. package/dist/services/settings-schema.js +42 -22
  353. package/dist/services/settings-schema.js.map +1 -1
  354. package/dist/services/settings-schema.test.js +10 -0
  355. package/dist/services/settings-schema.test.js.map +1 -1
  356. package/dist/services/settings-service.js +2 -2
  357. package/dist/services/settings-service.js.map +1 -1
  358. package/dist/services/settings-sources.d.ts.map +1 -1
  359. package/dist/services/settings-sources.js +1 -0
  360. package/dist/services/settings-sources.js.map +1 -1
  361. package/dist/services/settings-sources.test.js +2 -0
  362. package/dist/services/settings-sources.test.js.map +1 -1
  363. package/dist/services/subagents/subagent-manager.d.ts.map +1 -1
  364. package/dist/services/subagents/subagent-manager.js +32 -30
  365. package/dist/services/subagents/subagent-manager.js.map +1 -1
  366. package/dist/services/subagents/subagent-manager.test.js +8 -12
  367. package/dist/services/subagents/subagent-manager.test.js.map +1 -1
  368. package/dist/services/subagents/subagent-session.d.ts +1 -1
  369. package/dist/services/subagents/subagent-session.d.ts.map +1 -1
  370. package/dist/services/subagents/subagent-session.js +2 -2
  371. package/dist/services/subagents/subagent-session.js.map +1 -1
  372. package/dist/services/subagents/subagent-session.test.js +3 -3
  373. package/dist/services/subagents/subagent-session.test.js.map +1 -1
  374. package/dist/services/subagents/types.d.ts +2 -1
  375. package/dist/services/subagents/types.d.ts.map +1 -1
  376. package/dist/services/terminal-result-collector.d.ts.map +1 -1
  377. package/dist/services/terminal-result-collector.js +43 -0
  378. package/dist/services/terminal-result-collector.js.map +1 -1
  379. package/dist/services/terminal-result-collector.test.js +44 -0
  380. package/dist/services/terminal-result-collector.test.js.map +1 -1
  381. package/dist/services/tool-execution-ledger.d.ts +6 -0
  382. package/dist/services/tool-execution-ledger.d.ts.map +1 -1
  383. package/dist/services/tool-execution-ledger.js +90 -25
  384. package/dist/services/tool-execution-ledger.js.map +1 -1
  385. package/dist/services/tool-execution-ledger.test.js +177 -2
  386. package/dist/services/tool-execution-ledger.test.js.map +1 -1
  387. package/dist/tools/apply-patch.d.ts.map +1 -1
  388. package/dist/tools/apply-patch.js +41 -23
  389. package/dist/tools/apply-patch.js.map +1 -1
  390. package/dist/tools/apply-patch.test.js +6 -6
  391. package/dist/tools/apply-patch.test.js.map +1 -1
  392. package/dist/tools/code-context.js +1 -1
  393. package/dist/tools/code-context.js.map +1 -1
  394. package/dist/tools/code-context.test.js +278 -0
  395. package/dist/tools/code-context.test.js.map +1 -1
  396. package/dist/tools/edit-healing.d.ts.map +1 -1
  397. package/dist/tools/edit-healing.js +9 -3
  398. package/dist/tools/edit-healing.js.map +1 -1
  399. package/dist/tools/language-providers.d.ts.map +1 -1
  400. package/dist/tools/language-providers.js +379 -0
  401. package/dist/tools/language-providers.js.map +1 -1
  402. package/dist/tools/languages/cpp.d.ts +8 -0
  403. package/dist/tools/languages/cpp.d.ts.map +1 -0
  404. package/dist/tools/languages/cpp.js +306 -0
  405. package/dist/tools/languages/cpp.js.map +1 -0
  406. package/dist/tools/languages/csharp.d.ts +5 -0
  407. package/dist/tools/languages/csharp.d.ts.map +1 -0
  408. package/dist/tools/languages/csharp.js +225 -0
  409. package/dist/tools/languages/csharp.js.map +1 -0
  410. package/dist/tools/languages/go.d.ts +7 -0
  411. package/dist/tools/languages/go.d.ts.map +1 -0
  412. package/dist/tools/languages/go.js +223 -0
  413. package/dist/tools/languages/go.js.map +1 -0
  414. package/dist/tools/languages/index.d.ts +6 -0
  415. package/dist/tools/languages/index.d.ts.map +1 -0
  416. package/dist/tools/languages/index.js +32 -0
  417. package/dist/tools/languages/index.js.map +1 -0
  418. package/dist/tools/languages/java.d.ts +5 -0
  419. package/dist/tools/languages/java.d.ts.map +1 -0
  420. package/dist/tools/languages/java.js +183 -0
  421. package/dist/tools/languages/java.js.map +1 -0
  422. package/dist/tools/languages/json.d.ts +3 -0
  423. package/dist/tools/languages/json.d.ts.map +1 -0
  424. package/dist/tools/languages/json.js +40 -0
  425. package/dist/tools/languages/json.js.map +1 -0
  426. package/dist/tools/languages/php.d.ts +8 -0
  427. package/dist/tools/languages/php.d.ts.map +1 -0
  428. package/dist/tools/languages/php.js +139 -0
  429. package/dist/tools/languages/php.js.map +1 -0
  430. package/dist/tools/languages/python.d.ts +7 -0
  431. package/dist/tools/languages/python.d.ts.map +1 -0
  432. package/dist/tools/languages/python.js +189 -0
  433. package/dist/tools/languages/python.js.map +1 -0
  434. package/dist/tools/languages/ruby.d.ts +8 -0
  435. package/dist/tools/languages/ruby.d.ts.map +1 -0
  436. package/dist/tools/languages/ruby.js +94 -0
  437. package/dist/tools/languages/ruby.js.map +1 -0
  438. package/dist/tools/languages/rust.d.ts +7 -0
  439. package/dist/tools/languages/rust.d.ts.map +1 -0
  440. package/dist/tools/languages/rust.js +186 -0
  441. package/dist/tools/languages/rust.js.map +1 -0
  442. package/dist/tools/languages/types.d.ts +39 -0
  443. package/dist/tools/languages/types.d.ts.map +1 -0
  444. package/dist/tools/languages/types.js +2 -0
  445. package/dist/tools/languages/types.js.map +1 -0
  446. package/dist/tools/languages/typescript.d.ts +4 -0
  447. package/dist/tools/languages/typescript.d.ts.map +1 -0
  448. package/dist/tools/languages/typescript.js +94 -0
  449. package/dist/tools/languages/typescript.js.map +1 -0
  450. package/dist/tools/languages/utils.d.ts +14 -0
  451. package/dist/tools/languages/utils.d.ts.map +1 -0
  452. package/dist/tools/languages/utils.js +73 -0
  453. package/dist/tools/languages/utils.js.map +1 -0
  454. package/dist/tools/run-subagent.d.ts +0 -1
  455. package/dist/tools/run-subagent.d.ts.map +1 -1
  456. package/dist/tools/run-subagent.js +1 -8
  457. package/dist/tools/run-subagent.js.map +1 -1
  458. package/dist/tools/run-subagent.test.js +0 -18
  459. package/dist/tools/run-subagent.test.js.map +1 -1
  460. package/dist/tools/shell.d.ts.map +1 -1
  461. package/dist/tools/shell.js +13 -1
  462. package/dist/tools/shell.js.map +1 -1
  463. package/dist/tools/web-fetch.d.ts.map +1 -1
  464. package/dist/tools/web-fetch.js +1 -1
  465. package/dist/tools/web-fetch.js.map +1 -1
  466. package/dist/utils/clipboard.d.ts +8 -0
  467. package/dist/utils/clipboard.d.ts.map +1 -1
  468. package/dist/utils/clipboard.js +50 -4
  469. package/dist/utils/clipboard.js.map +1 -1
  470. package/dist/utils/clipboard.test.js +152 -2
  471. package/dist/utils/clipboard.test.js.map +1 -1
  472. package/dist/utils/conversation-event-handler.d.ts.map +1 -1
  473. package/dist/utils/conversation-event-handler.js +3 -0
  474. package/dist/utils/conversation-event-handler.js.map +1 -1
  475. package/dist/utils/conversation-event-handler.test.js +13 -0
  476. package/dist/utils/conversation-event-handler.test.js.map +1 -1
  477. package/dist/utils/extract-command-messages.d.ts.map +1 -1
  478. package/dist/utils/extract-command-messages.js +8 -4
  479. package/dist/utils/extract-command-messages.js.map +1 -1
  480. package/dist/utils/message-utils.d.ts +7 -0
  481. package/dist/utils/message-utils.d.ts.map +1 -0
  482. package/dist/utils/message-utils.js +31 -0
  483. package/dist/utils/message-utils.js.map +1 -0
  484. package/dist/utils/resume-list.d.ts +15 -0
  485. package/dist/utils/resume-list.d.ts.map +1 -0
  486. package/dist/utils/resume-list.js +68 -0
  487. package/dist/utils/resume-list.js.map +1 -0
  488. package/dist/utils/resume-list.test.d.ts +2 -0
  489. package/dist/utils/resume-list.test.d.ts.map +1 -0
  490. package/dist/utils/resume-list.test.js +89 -0
  491. package/dist/utils/resume-list.test.js.map +1 -0
  492. package/dist/utils/settings-command.d.ts.map +1 -1
  493. package/dist/utils/settings-command.js +11 -0
  494. package/dist/utils/settings-command.js.map +1 -1
  495. package/dist/utils/token-usage.d.ts +3 -1
  496. package/dist/utils/token-usage.d.ts.map +1 -1
  497. package/dist/utils/token-usage.js +4 -2
  498. package/dist/utils/token-usage.js.map +1 -1
  499. package/dist/utils/tty-osc.d.ts +27 -0
  500. package/dist/utils/tty-osc.d.ts.map +1 -0
  501. package/dist/utils/tty-osc.js +66 -0
  502. package/dist/utils/tty-osc.js.map +1 -0
  503. package/dist/utils/tty-osc.test.d.ts +2 -0
  504. package/dist/utils/tty-osc.test.d.ts.map +1 -0
  505. package/dist/utils/tty-osc.test.js +130 -0
  506. package/dist/utils/tty-osc.test.js.map +1 -0
  507. package/package.json +3 -3
  508. package/readme.md +24 -9
  509. package/dist/app.large-uncached-warning.test.js +0 -15
@@ -3,7 +3,7 @@ import { decideRetry, isTransientRetryableError, MAX_HALLUCINATION_RETRIES, MAX_
3
3
  import { getProvider } from '../providers/index.js';
4
4
  import { ApprovalState } from './approval-state.js';
5
5
  import { collectTerminalResult } from './terminal-result-collector.js';
6
- import { getMethod } from './interruption-info.js';
6
+ import { getMethod, getCallIdFromObject } from './interruption-info.js';
7
7
  import { createStreamAccumulator, processStreamEvents } from './stream-event-processor.js';
8
8
  import { ShellAutoApprovalResolver } from './shell-auto-approval-resolver.js';
9
9
  import { ApprovalFlowCoordinator } from './approval-flow-coordinator.js';
@@ -11,29 +11,8 @@ import { buildConversationResult, toTerminalEvent } from './conversation-result-
11
11
  import { normalizeUserTurn } from '../types/user-turn.js';
12
12
  import { collectDuplicateToolCallResultPairs, InputSurgeGuard } from './input-surge-guard.js';
13
13
  import { LargeUncachedInputGuard } from './large-uncached-input-guard.js';
14
- import { reconcileHistoryWithToolLedger, ToolExecutionLedger, } from './tool-execution-ledger.js';
14
+ import { reconcileHistoryWithToolLedger, ToolExecutionLedger, callIdOf, toolNameOf, outputOf, } from './tool-execution-ledger.js';
15
15
  import { describeError } from '../utils/error-helpers.js';
16
- const asRecordLocal = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : null;
17
- const rawItemLocal = (item) => {
18
- const rec = asRecordLocal(item);
19
- if (!rec)
20
- return null;
21
- return asRecordLocal(rec.rawItem) ?? rec;
22
- };
23
- const callIdOfLocal = (item) => {
24
- const raw = rawItemLocal(item);
25
- const cid = raw?.callId ?? raw?.call_id ?? raw?.tool_call_id ?? raw?.toolCallId ?? raw?.id;
26
- return typeof cid === 'string' && cid ? cid : null;
27
- };
28
- const toolNameOfLocal = (item) => {
29
- const raw = rawItemLocal(item);
30
- const name = raw?.name ?? asRecordLocal(item)?.name;
31
- return typeof name === 'string' && name ? name : 'unknown';
32
- };
33
- const outputOfLocal = (item) => {
34
- const raw = rawItemLocal(item);
35
- return raw?.output ?? asRecordLocal(item)?.output;
36
- };
37
16
  const supportsConversationChaining = (providerId) => {
38
17
  const providerDef = getProvider(providerId);
39
18
  return providerDef?.capabilities?.supportsConversationChaining ?? false;
@@ -85,8 +64,12 @@ export class ConversationSession {
85
64
  largeUncachedInputGuard = new LargeUncachedInputGuard();
86
65
  toolLedger = new ToolExecutionLedger();
87
66
  generation = 0;
67
+ #inputSurgeKind = 'delta';
68
+ currentPersistedTurnItems = [];
69
+ currentReasoningBuffer = '';
70
+ currentAssistantTextBuffer = '';
71
+ currentDisplayUsage;
88
72
  settingsService;
89
- pendingModeNotice = null;
90
73
  logSink = null;
91
74
  constructor(id, { agentClient, deps, sessionStartedAt, }) {
92
75
  this.id = id;
@@ -154,28 +137,11 @@ export class ConversationSession {
154
137
  #buildOutgoingInput(turn, { includeTurn }) {
155
138
  const provider = this.#getProviderForGuard() ?? 'openai';
156
139
  const supportsChaining = supportsConversationChaining(provider);
157
- const history = this.conversationStore.getHistory();
140
+ const history = this.#getCanonicalHistory();
158
141
  const outgoingHistory = includeTurn ? [...history, this.#makeUserInputItem(turn)] : history;
159
142
  const useChaining = supportsChaining && (!!this.previousResponseId || outgoingHistory.length <= 1);
160
- const notice = this.pendingModeNotice;
161
143
  const latestInput = outgoingHistory[outgoingHistory.length - 1] ?? turn.text;
162
144
  const chainedInput = turn.images?.length ? latestInput : turn.text;
163
- if (notice) {
164
- if (useChaining) {
165
- const userItem = typeof chainedInput === 'string' ? { role: 'user', type: 'message', content: chainedInput } : chainedInput;
166
- const noticeItem = { role: 'system', type: 'message', content: notice };
167
- return {
168
- streamInput: [noticeItem, userItem],
169
- inputSurgeKind: 'delta',
170
- };
171
- }
172
- const noticeItem = { role: 'user', type: 'message', content: notice };
173
- return {
174
- streamInput: [...outgoingHistory, noticeItem],
175
- inputSurgeKind: 'full_history',
176
- modeNoticeToPersist: notice,
177
- };
178
- }
179
145
  return {
180
146
  streamInput: useChaining ? (typeof chainedInput === 'string' ? chainedInput : [chainedInput]) : outgoingHistory,
181
147
  inputSurgeKind: useChaining ? 'delta' : 'full_history',
@@ -224,6 +190,8 @@ export class ConversationSession {
224
190
  this.shellAutoApproval.clearCache();
225
191
  this.inputSurgeGuard.reset();
226
192
  this.largeUncachedInputGuard.reset();
193
+ this.#inputSurgeKind = 'delta';
194
+ this.#resetPersistedTurnState();
227
195
  const clearConversations = getMethod(this.agentClient, 'clearConversations');
228
196
  clearConversations?.call(this.agentClient);
229
197
  }
@@ -237,9 +205,12 @@ export class ConversationSession {
237
205
  this.approvalState.consumeAborted();
238
206
  this.toolCallArgumentsById.clear();
239
207
  this.emittedToolStartedCallIds.clear();
208
+ this.toolLedger = new ToolExecutionLedger();
240
209
  this.shellAutoApproval.clearCache();
241
210
  this.inputSurgeGuard.reset();
242
211
  this.largeUncachedInputGuard.markUndoOrRewind();
212
+ this.#inputSurgeKind = 'delta';
213
+ this.#resetPersistedTurnState();
243
214
  this.#log({ type: 'undo', removedUserTurns: 1, snapshot: this.getCurrentSnapshot() });
244
215
  return removed;
245
216
  }
@@ -256,9 +227,12 @@ export class ConversationSession {
256
227
  this.approvalState.consumeAborted();
257
228
  this.toolCallArgumentsById.clear();
258
229
  this.emittedToolStartedCallIds.clear();
230
+ this.toolLedger = new ToolExecutionLedger();
259
231
  this.shellAutoApproval.clearCache();
260
232
  this.inputSurgeGuard.reset();
261
233
  this.largeUncachedInputGuard.markUndoOrRewind();
234
+ this.#inputSurgeKind = 'delta';
235
+ this.#resetPersistedTurnState();
262
236
  this.#log({ type: 'undo', removedUserTurns: n, snapshot: this.getCurrentSnapshot() });
263
237
  return removed;
264
238
  }
@@ -305,13 +279,70 @@ export class ConversationSession {
305
279
  : this.settingsService?.get('agent.provider');
306
280
  const model = this.settingsService?.get('agent.model');
307
281
  return {
308
- history: this.conversationStore.getHistory(),
282
+ history: this.#getCanonicalHistory(),
309
283
  previousResponseId: this.previousResponseId,
310
284
  toolLedger: this.toolLedger.export(),
311
285
  ...(model ? { model } : {}),
312
286
  ...(provider ? { provider } : {}),
313
287
  };
314
288
  }
289
+ #getCurrentAssistantTurnState() {
290
+ const getProvider = getMethod(this.agentClient, 'getProvider');
291
+ const provider = getProvider
292
+ ? getProvider.call(this.agentClient)
293
+ : this.settingsService?.get('agent.provider');
294
+ const model = this.settingsService?.get('agent.model');
295
+ return {
296
+ previousResponseId: this.previousResponseId,
297
+ ...(model ? { model } : {}),
298
+ ...(provider ? { provider } : {}),
299
+ };
300
+ }
301
+ #flushReasoningItem() {
302
+ if (this.currentReasoningBuffer) {
303
+ this.currentPersistedTurnItems.push({
304
+ type: 'reasoning',
305
+ text: this.currentReasoningBuffer,
306
+ });
307
+ this.currentReasoningBuffer = '';
308
+ }
309
+ }
310
+ #flushAssistantTextItem() {
311
+ if (this.currentAssistantTextBuffer) {
312
+ this.currentPersistedTurnItems.push({
313
+ type: 'assistant_text',
314
+ text: this.currentAssistantTextBuffer,
315
+ });
316
+ this.currentAssistantTextBuffer = '';
317
+ }
318
+ }
319
+ #recordToolCallItem(callId, toolName, args) {
320
+ this.#flushReasoningItem();
321
+ this.#flushAssistantTextItem();
322
+ this.currentPersistedTurnItems.push({
323
+ type: 'tool_call',
324
+ callId,
325
+ toolName,
326
+ arguments: args,
327
+ });
328
+ }
329
+ #recordToolResultItem(callId, toolName, status, output) {
330
+ this.#flushReasoningItem();
331
+ this.#flushAssistantTextItem();
332
+ this.currentPersistedTurnItems.push({
333
+ type: 'tool_result',
334
+ callId,
335
+ toolName,
336
+ status,
337
+ output,
338
+ });
339
+ }
340
+ #resetPersistedTurnState() {
341
+ this.currentPersistedTurnItems = [];
342
+ this.currentReasoningBuffer = '';
343
+ this.currentAssistantTextBuffer = '';
344
+ this.currentDisplayUsage = undefined;
345
+ }
315
346
  #log(event) {
316
347
  if (!this.logSink)
317
348
  return;
@@ -330,7 +361,23 @@ export class ConversationSession {
330
361
  if (!this.logSink)
331
362
  return;
332
363
  switch (event.type) {
364
+ case 'usage_update':
365
+ this.currentDisplayUsage = event.usage;
366
+ return;
367
+ case 'text_delta':
368
+ if (this.currentReasoningBuffer) {
369
+ this.#flushReasoningItem();
370
+ }
371
+ this.currentAssistantTextBuffer += event.delta;
372
+ return;
373
+ case 'reasoning_delta':
374
+ if (this.currentAssistantTextBuffer) {
375
+ this.#flushAssistantTextItem();
376
+ }
377
+ this.currentReasoningBuffer += event.delta;
378
+ return;
333
379
  case 'tool_started':
380
+ this.#recordToolCallItem(event.toolCallId, event.toolName, event.arguments);
334
381
  this.#log({
335
382
  type: 'tool_started',
336
383
  toolCallId: event.toolCallId,
@@ -340,6 +387,11 @@ export class ConversationSession {
340
387
  return;
341
388
  case 'command_message':
342
389
  this.#log({ type: 'command_message', message: event.message });
390
+ if (event.message.callId &&
391
+ event.message.toolName &&
392
+ (event.message.status === 'completed' || event.message.status === 'failed')) {
393
+ this.#recordToolResultItem(event.message.callId, event.message.toolName, event.message.status === 'failed' ? 'failed' : 'completed', event.message.output);
394
+ }
343
395
  return;
344
396
  case 'approval_required':
345
397
  this.#log({
@@ -364,24 +416,45 @@ export class ConversationSession {
364
416
  this.#log({ type: 'subagent_completed', result: event.result });
365
417
  return;
366
418
  case 'error':
367
- this.#log({ type: 'error', message: event.message, ...(event.kind ? { kind: event.kind } : {}) });
419
+ this.#log({
420
+ type: 'error',
421
+ message: event.message,
422
+ ...(event.kind ? { kind: event.kind } : {}),
423
+ ...(event.stack ? { stack: event.stack } : {}),
424
+ });
368
425
  return;
369
426
  case 'final': {
370
- const snapshot = this.getCurrentSnapshot();
371
- this.#log({
372
- type: 'assistant_final',
373
- message: {
374
- id: `bot-${snapshot.history.length}-${Date.now()}`,
375
- sender: 'bot',
376
- status: 'finalized',
427
+ const turnState = this.#getCurrentAssistantTurnState();
428
+ const toolLedger = this.toolLedger.export();
429
+ this.#flushReasoningItem();
430
+ this.#flushAssistantTextItem();
431
+ const turnItemsToLog = event.turnItems ? [...event.turnItems] : [...this.currentPersistedTurnItems];
432
+ if (event.finalText && !turnItemsToLog.some((item) => item.type === 'assistant_text')) {
433
+ turnItemsToLog.push({
434
+ type: 'assistant_text',
377
435
  text: event.finalText,
378
- ...(event.reasoningText ? { reasoningText: event.reasoningText } : {}),
379
- },
380
- finalText: event.finalText,
381
- ...(event.reasoningText ? { reasoningText: event.reasoningText } : {}),
436
+ });
437
+ }
438
+ // Invariant check: if transcript contains tool_result, matching call IDs exist in the live tool ledger.
439
+ for (const item of turnItemsToLog) {
440
+ if (item.type === 'tool_result') {
441
+ const exists = toolLedger.some((t) => t.callId === item.callId);
442
+ if (!exists) {
443
+ this.logger.warn(`Invariant violation: tool_result callId ${item.callId} not found in toolLedger`);
444
+ }
445
+ }
446
+ }
447
+ const turn = {
448
+ items: turnItemsToLog,
449
+ };
450
+ this.#log({
451
+ type: 'assistant_turn',
452
+ turn,
382
453
  ...(event.usage ? { usage: event.usage } : {}),
383
- snapshot,
454
+ ...(this.currentDisplayUsage ? { displayUsage: this.currentDisplayUsage } : {}),
455
+ state: turnState,
384
456
  });
457
+ this.#resetPersistedTurnState();
385
458
  return;
386
459
  }
387
460
  default:
@@ -398,9 +471,13 @@ export class ConversationSession {
398
471
  this.emittedToolStartedCallIds.add(event.toolCallId);
399
472
  return event;
400
473
  }
474
+ #getCanonicalHistory() {
475
+ return reconcileHistoryWithToolLedger(this.conversationStore.getHistory(), this.toolLedger.export())
476
+ .history;
477
+ }
401
478
  exportState() {
402
479
  return {
403
- history: this.conversationStore.getHistory(),
480
+ history: this.#getCanonicalHistory(),
404
481
  previousResponseId: this.previousResponseId,
405
482
  toolLedger: this.toolLedger.export(),
406
483
  };
@@ -433,21 +510,28 @@ export class ConversationSession {
433
510
  addShellContext(historyText) {
434
511
  this.conversationStore.addShellContext(historyText);
435
512
  }
436
- queueModeNotice(text) {
437
- this.pendingModeNotice = text;
438
- }
439
513
  /**
440
514
  * Abort the current running operation
441
515
  */
442
516
  abort() {
443
- this.approvalFlow.abort();
517
+ const pending = this.approvalFlow.getPending();
518
+ const callId = pending ? getCallIdFromObject(pending.interruption) : undefined;
519
+ if (this.approvalFlow.abort()) {
520
+ this.toolLedger.recordAbortedApproval('Tool execution was not approved.', 'Tool execution was not approved.', callId);
521
+ }
444
522
  }
445
523
  /**
446
524
  * Phase 4: stream conversation events as an async iterator.
447
525
  *
448
526
  * This is the transport-friendly primitive that can later be bridged to SSE/WebSockets.
449
527
  */
450
- async *run(input, { hallucinationRetryCount = 0, flexServiceTierFallbackCount = 0, skipUserMessage = false, } = {}) {
528
+ async *run(input, { skipUserMessage = false, flexServiceTierFallbackCount = 0, hallucinationRetryCount = 0, transientRetryCount = 0, } = {}) {
529
+ if (!skipUserMessage ||
530
+ hallucinationRetryCount > 0 ||
531
+ flexServiceTierFallbackCount > 0 ||
532
+ transientRetryCount > 0) {
533
+ this.#resetPersistedTurnState();
534
+ }
451
535
  const gen = this.generation;
452
536
  let stream = null;
453
537
  const turn = normalizeUserTurn(input);
@@ -504,15 +588,15 @@ export class ConversationSession {
504
588
  onFunctionCallItem: (item) => this.toolLedger.recordFunctionCall(item),
505
589
  onFunctionResultItem: (item) => {
506
590
  this.toolLedger.recordFunctionResult(item);
507
- const cid = callIdOfLocal(item);
591
+ const cid = callIdOf(item);
508
592
  if (cid && this.logSink) {
509
593
  const entry = this.toolLedger.export().find((e) => e.callId === cid);
510
594
  this.#log({
511
595
  type: 'tool_result',
512
596
  callId: cid,
513
- toolName: entry?.toolName ?? toolNameOfLocal(item),
597
+ toolName: entry?.toolName ?? toolNameOf(item),
514
598
  status: entry?.status === 'failed' || entry?.status === 'aborted' ? entry.status : 'completed',
515
- output: entry?.output ?? outputOfLocal(item),
599
+ output: entry?.output ?? outputOf(item),
516
600
  ...(entry?.historyItems ? { historyItems: entry.historyItems } : {}),
517
601
  });
518
602
  }
@@ -530,7 +614,16 @@ export class ConversationSession {
530
614
  source: 'abortResolution',
531
615
  stream: continuedStream,
532
616
  });
533
- this.conversationStore.updateFromResult(continuedStream);
617
+ const s = continuedStream;
618
+ const terminal = !continuedStream.interruptions || continuedStream.interruptions.length === 0;
619
+ if (terminal) {
620
+ if (this.#inputSurgeKind === 'delta') {
621
+ this.conversationStore.appendOutput(s.output);
622
+ }
623
+ else {
624
+ this.conversationStore.replaceHistory(s.history);
625
+ }
626
+ }
534
627
  }
535
628
  // Check if another interruption occurred
536
629
  if (continuedStream.interruptions && continuedStream.interruptions.length > 0) {
@@ -563,22 +656,10 @@ export class ConversationSession {
563
656
  // resync (fresh start with just the current message). After undo the chain
564
657
  // is severed (previousResponseId = null) while prior turns remain in the
565
658
  // local store, so we fall back to full-history mode to re-establish context.
566
- const { streamInput, inputSurgeKind, modeNoticeToPersist } = this.#buildOutgoingInput(turn, {
659
+ const { streamInput, inputSurgeKind } = this.#buildOutgoingInput(turn, {
567
660
  includeTurn: false,
568
661
  });
569
- if (this.pendingModeNotice) {
570
- this.pendingModeNotice = null;
571
- }
572
- if (modeNoticeToPersist) {
573
- // Persist the notice at the tail (append-only) rather than splicing
574
- // it before the last user turn or sending it as a one-shot item.
575
- // Mid-history insertion adds a stray ephemeral cache breakpoint (see
576
- // addCacheControlToLastTwoMessages) and a transient item makes
577
- // consecutive requests diverge at the tail — both break the
578
- // Claude/Qwen prompt cache. Appending keeps the cached prefix
579
- // byte-identical and only growing.
580
- this.conversationStore.addModeNotice(modeNoticeToPersist);
581
- }
662
+ this.#inputSurgeKind = inputSurgeKind;
582
663
  const surgeDecision = this.inputSurgeGuard.inspect(streamInput, { kind: inputSurgeKind });
583
664
  if (surgeDecision.action === 'block') {
584
665
  let droppedUserMessage;
@@ -628,7 +709,16 @@ export class ConversationSession {
628
709
  source: 'startStream',
629
710
  stream,
630
711
  });
631
- this.conversationStore.updateFromResult(stream);
712
+ const s = stream;
713
+ const terminal = !stream.interruptions || stream.interruptions.length === 0;
714
+ if (terminal) {
715
+ if (inputSurgeKind === 'delta') {
716
+ this.conversationStore.appendOutput(s.output);
717
+ }
718
+ else {
719
+ this.conversationStore.replaceHistory(s.history);
720
+ }
721
+ }
632
722
  }
633
723
  const resolvedResult = yield* this.#buildAndResolve(stream, acc.finalOutput || undefined, acc.reasoningOutput || undefined, acc.emittedCommandIds, acc.latestUsage);
634
724
  if (inputSurgeKind === 'delta') {
@@ -649,6 +739,14 @@ export class ConversationSession {
649
739
  mode: this.#getTrafficMode(),
650
740
  });
651
741
  if (resolvedResult.type === 'approval_required') {
742
+ if (resolvedResult.approval.callId) {
743
+ this.toolLedger.recordFunctionCall({
744
+ type: 'function_call',
745
+ callId: resolvedResult.approval.callId,
746
+ name: resolvedResult.approval.toolName,
747
+ arguments: resolvedResult.approval.argumentsText,
748
+ });
749
+ }
652
750
  this.logger.debug('Tool approval required', {
653
751
  eventType: 'approval.required',
654
752
  category: 'approval',
@@ -694,6 +792,56 @@ export class ConversationSession {
694
792
  });
695
793
  return;
696
794
  }
795
+ if (isTransientRetryableError(error) && transientRetryCount < MAX_TRANSIENT_RETRIES) {
796
+ const attempt = transientRetryCount + 1;
797
+ const delay = Math.min(500 * Math.pow(2, attempt - 1), 30000);
798
+ this.logger.warn('Transient upstream error detected, retrying turn', {
799
+ eventType: 'retry.transient',
800
+ category: 'retry',
801
+ phase: 'retry',
802
+ retryType: 'upstream',
803
+ retryAttempt: attempt,
804
+ attempt,
805
+ maxRetries: MAX_TRANSIENT_RETRIES,
806
+ sessionId: this.id,
807
+ traceId: this.logger.getCorrelationId(),
808
+ errorMessage: error instanceof Error ? error.message : String(error),
809
+ delayMs: delay,
810
+ });
811
+ yield {
812
+ type: 'retry',
813
+ toolName: 'turn',
814
+ attempt,
815
+ maxRetries: MAX_TRANSIENT_RETRIES,
816
+ errorMessage: error instanceof Error ? error.message : String(error),
817
+ retryType: 'upstream',
818
+ };
819
+ if (!this.#isCurrentGeneration(gen))
820
+ return;
821
+ if (stream) {
822
+ const provider = this.#getProviderForGuard() ?? 'openai';
823
+ const supportsChaining = supportsConversationChaining(provider);
824
+ if (supportsChaining) {
825
+ this.toolLedger.import(ledgerSnapshot);
826
+ }
827
+ else {
828
+ this.toolLedger.markOpenCallsAborted(error instanceof Error ? error.message : String(error));
829
+ const reconciled = reconcileHistoryWithToolLedger(this.conversationStore.getHistory(), this.toolLedger.export());
830
+ if (reconciled.addedCompletedPairs > 0) {
831
+ this.conversationStore.replaceHistory(reconciled.history);
832
+ }
833
+ }
834
+ }
835
+ else {
836
+ this.conversationStore.removeLastUserMessage();
837
+ }
838
+ await new Promise((resolve) => setTimeout(resolve, delay));
839
+ yield* this.run(turn, {
840
+ skipUserMessage: Boolean(stream),
841
+ transientRetryCount: attempt,
842
+ });
843
+ return;
844
+ }
697
845
  const decision = decideRetry(error, hallucinationRetryCount, Boolean(stream), streamHistoryLength);
698
846
  if (decision.kind === 'retry') {
699
847
  this.logger.warn('Recoverable model error detected, retrying', {
@@ -734,6 +882,13 @@ export class ConversationSession {
734
882
  }
735
883
  if (stream && this.#isCurrentGeneration(gen)) {
736
884
  this.toolLedger.markOpenCallsAborted(error instanceof Error ? error.message : String(error));
885
+ // Persist completed tool call/result pairs (and the recovery notice) into
886
+ // canonical history so the next user turn doesn't ship a request with two
887
+ // consecutive user messages and no record of the tool activity.
888
+ const reconciled = reconcileHistoryWithToolLedger(this.conversationStore.getHistory(), this.toolLedger.export());
889
+ if (reconciled.addedCompletedPairs > 0 || reconciled.droppedIncompleteCalls > 0) {
890
+ this.conversationStore.replaceHistory(reconciled.history);
891
+ }
737
892
  const recoverySummary = this.toolLedger.getRecoverySummary();
738
893
  if (recoverySummary) {
739
894
  yield {
@@ -747,6 +902,7 @@ export class ConversationSession {
747
902
  yield {
748
903
  type: 'error',
749
904
  message: describeError(error),
905
+ ...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
750
906
  ...(droppedUserMessage ? { droppedUserMessage } : {}),
751
907
  };
752
908
  this.logger.error('Conversation stream error', {
@@ -756,6 +912,7 @@ export class ConversationSession {
756
912
  sessionId: this.id,
757
913
  traceId: this.logger.getCorrelationId(),
758
914
  errorMessage: describeError(error),
915
+ stack: error instanceof Error ? error.stack : undefined,
759
916
  });
760
917
  throw error;
761
918
  }
@@ -771,6 +928,14 @@ export class ConversationSession {
771
928
  if (!plan) {
772
929
  return;
773
930
  }
931
+ if (answer !== 'y') {
932
+ const interruption = plan.pendingApprovalContext.interruption;
933
+ const callId = getCallIdFromObject(interruption);
934
+ const output = rejectionReason
935
+ ? `Tool execution was not approved. User's reason: ${rejectionReason}`
936
+ : 'Tool execution was not approved.';
937
+ this.toolLedger.recordAbortedApproval(output, output, callId);
938
+ }
774
939
  const { pendingApprovalContext: { state, toolCallArgumentsById, emittedCommandIds: previouslyEmittedIds }, toolStartedEvent, removeInterceptor, } = plan;
775
940
  if (toolStartedEvent) {
776
941
  const filtered = this.#dedupeToolStarted(toolStartedEvent);
@@ -800,15 +965,15 @@ export class ConversationSession {
800
965
  onFunctionCallItem: (item) => this.toolLedger.recordFunctionCall(item),
801
966
  onFunctionResultItem: (item) => {
802
967
  this.toolLedger.recordFunctionResult(item);
803
- const cid = callIdOfLocal(item);
968
+ const cid = callIdOf(item);
804
969
  if (cid && this.logSink) {
805
970
  const entry = this.toolLedger.export().find((e) => e.callId === cid);
806
971
  this.#log({
807
972
  type: 'tool_result',
808
973
  callId: cid,
809
- toolName: entry?.toolName ?? toolNameOfLocal(item),
974
+ toolName: entry?.toolName ?? toolNameOf(item),
810
975
  status: entry?.status === 'failed' || entry?.status === 'aborted' ? entry.status : 'completed',
811
- output: entry?.output ?? outputOfLocal(item),
976
+ output: entry?.output ?? outputOf(item),
812
977
  ...(entry?.historyItems ? { historyItems: entry.historyItems } : {}),
813
978
  });
814
979
  }
@@ -826,13 +991,30 @@ export class ConversationSession {
826
991
  source: 'continueRunStream',
827
992
  stream,
828
993
  });
829
- this.conversationStore.updateFromResult(stream);
994
+ const s = stream;
995
+ const terminal = !stream.interruptions || stream.interruptions.length === 0;
996
+ if (terminal) {
997
+ if (this.#inputSurgeKind === 'delta') {
998
+ this.conversationStore.appendOutput(s.output);
999
+ }
1000
+ else {
1001
+ this.conversationStore.replaceHistory(s.history);
1002
+ }
1003
+ }
830
1004
  }
831
1005
  // Merge previously emitted command IDs with newly emitted ones
832
1006
  // This prevents duplicates when result.history contains commands from the initial stream
833
1007
  const allEmittedIds = new Set([...previouslyEmittedIds, ...acc.emittedCommandIds]);
834
1008
  const resolvedResult = yield* this.#buildAndResolve(stream, acc.finalOutput || undefined, acc.reasoningOutput || undefined, allEmittedIds, acc.latestUsage);
835
1009
  if (resolvedResult.type === 'approval_required') {
1010
+ if (resolvedResult.approval.callId) {
1011
+ this.toolLedger.recordFunctionCall({
1012
+ type: 'function_call',
1013
+ callId: resolvedResult.approval.callId,
1014
+ name: resolvedResult.approval.toolName,
1015
+ arguments: resolvedResult.approval.argumentsText,
1016
+ });
1017
+ }
836
1018
  this.logger.debug('Tool approval required', {
837
1019
  eventType: 'approval.required',
838
1020
  category: 'approval',
@@ -879,9 +1061,19 @@ export class ConversationSession {
879
1061
  }
880
1062
  }
881
1063
  catch (error) {
1064
+ this.logger.error('Conversation stream error during continuation', {
1065
+ eventType: 'stream.failed',
1066
+ category: 'stream',
1067
+ phase: 'abort',
1068
+ sessionId: this.id,
1069
+ traceId: this.logger.getCorrelationId(),
1070
+ errorMessage: describeError(error),
1071
+ stack: error instanceof Error ? error.stack : undefined,
1072
+ });
882
1073
  yield {
883
1074
  type: 'error',
884
1075
  message: describeError(error),
1076
+ ...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
885
1077
  };
886
1078
  throw error;
887
1079
  }
@@ -981,6 +1173,7 @@ export class ConversationSession {
981
1173
  emittedCommandIds,
982
1174
  usage,
983
1175
  toolCallArgumentsById: this.toolCallArgumentsById,
1176
+ turnItems: this.currentPersistedTurnItems,
984
1177
  }, {
985
1178
  approvalFlow: this.approvalFlow,
986
1179
  shellAutoApproval: this.shellAutoApproval,
@@ -996,6 +1189,7 @@ export class ConversationSession {
996
1189
  let continuationApprovalUsage;
997
1190
  const commandMessages = [];
998
1191
  let approvalRequiredResult;
1192
+ let continuationTurnItems;
999
1193
  for await (const event of this['continue']({ answer: 'y' })) {
1000
1194
  if (event.type === 'approval_required') {
1001
1195
  continuationApprovalUsage = event.usage;
@@ -1024,7 +1218,9 @@ export class ConversationSession {
1024
1218
  if (event.commandMessages) {
1025
1219
  commandMessages.push(...event.commandMessages);
1026
1220
  }
1027
- yield event;
1221
+ if (event.turnItems) {
1222
+ continuationTurnItems = event.turnItems;
1223
+ }
1028
1224
  }
1029
1225
  else {
1030
1226
  yield event;
@@ -1044,6 +1240,7 @@ export class ConversationSession {
1044
1240
  finalText: finalText || 'Done.',
1045
1241
  ...(reasoningText ? { reasoningText } : {}),
1046
1242
  ...(combinedUsage && Object.keys(combinedUsage).length > 0 ? { usage: combinedUsage } : {}),
1243
+ turnItems: continuationTurnItems ?? this.currentPersistedTurnItems,
1047
1244
  };
1048
1245
  }
1049
1246
  }