@within-7/minto 0.4.0 → 0.4.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 (391) hide show
  1. package/dist/Tool.js +7 -0
  2. package/dist/Tool.js.map +2 -2
  3. package/dist/commands/agents/AgentsCommand.js +1 -1
  4. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  5. package/dist/commands/agents/constants.js +2 -2
  6. package/dist/commands/agents/constants.js.map +2 -2
  7. package/dist/commands/clear.js +4 -3
  8. package/dist/commands/clear.js.map +2 -2
  9. package/dist/commands/compact.js +2 -2
  10. package/dist/commands/compact.js.map +1 -1
  11. package/dist/commands/context.js +3 -1
  12. package/dist/commands/context.js.map +2 -2
  13. package/dist/commands/login.js +128 -0
  14. package/dist/commands/login.js.map +7 -0
  15. package/dist/commands/memory.js +33 -82
  16. package/dist/commands/memory.js.map +2 -2
  17. package/dist/commands/quit.js +3 -1
  18. package/dist/commands/quit.js.map +2 -2
  19. package/dist/commands/resume.js +39 -239
  20. package/dist/commands/resume.js.map +2 -2
  21. package/dist/commands/tasks.js +1 -1
  22. package/dist/commands/tasks.js.map +2 -2
  23. package/dist/commands/terminalSetup.js +6 -2
  24. package/dist/commands/terminalSetup.js.map +2 -2
  25. package/dist/commands.js +2 -0
  26. package/dist/commands.js.map +2 -2
  27. package/dist/components/AgentDetailView.js +126 -0
  28. package/dist/components/AgentDetailView.js.map +7 -0
  29. package/dist/components/AgentThinkingBlock.js +1 -1
  30. package/dist/components/AgentThinkingBlock.js.map +2 -2
  31. package/dist/components/AgentViewBanner.js +22 -0
  32. package/dist/components/AgentViewBanner.js.map +7 -0
  33. package/dist/components/HeaderBar.js +1 -1
  34. package/dist/components/HeaderBar.js.map +2 -2
  35. package/dist/components/Help.js +8 -1
  36. package/dist/components/Help.js.map +2 -2
  37. package/dist/components/HotkeyHelpPanel.js +26 -8
  38. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  39. package/dist/components/IdleNotificationBar.js +10 -0
  40. package/dist/components/IdleNotificationBar.js.map +7 -0
  41. package/dist/components/ModelSelector/ModelSelector.js +55 -20
  42. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  43. package/dist/components/PromptInput.js +186 -115
  44. package/dist/components/PromptInput.js.map +2 -2
  45. package/dist/components/RewindPanel.js +272 -0
  46. package/dist/components/RewindPanel.js.map +7 -0
  47. package/dist/components/Spinner.js +10 -21
  48. package/dist/components/Spinner.js.map +2 -2
  49. package/dist/components/StreamingTextPreview.js +29 -0
  50. package/dist/components/StreamingTextPreview.js.map +7 -0
  51. package/dist/components/SubagentBlock.js +3 -2
  52. package/dist/components/SubagentBlock.js.map +2 -2
  53. package/dist/components/SubagentProgress.js +4 -4
  54. package/dist/components/SubagentProgress.js.map +2 -2
  55. package/dist/components/TabbedListView/SearchInput.js +1 -1
  56. package/dist/components/TabbedListView/SearchInput.js.map +2 -2
  57. package/dist/components/TabbedListView/TabbedListView.js +87 -41
  58. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  59. package/dist/components/TaskCard.js +4 -4
  60. package/dist/components/TaskCard.js.map +2 -2
  61. package/dist/components/TeamMemberPanel.js +107 -0
  62. package/dist/components/TeamMemberPanel.js.map +7 -0
  63. package/dist/components/ThinkingSelector.js +84 -0
  64. package/dist/components/ThinkingSelector.js.map +7 -0
  65. package/dist/components/TitledDivider.js +26 -0
  66. package/dist/components/TitledDivider.js.map +7 -0
  67. package/dist/components/TodoPanel.js +31 -30
  68. package/dist/components/TodoPanel.js.map +2 -2
  69. package/dist/components/TokenWarning.js +28 -7
  70. package/dist/components/TokenWarning.js.map +2 -2
  71. package/dist/components/messages/AssistantTextMessage.js +5 -2
  72. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  73. package/dist/components/messages/AssistantToolUseMessage.js +9 -1
  74. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  75. package/dist/components/messages/DefaultToolResultFallback.js +11 -0
  76. package/dist/components/messages/DefaultToolResultFallback.js.map +7 -0
  77. package/dist/components/messages/ParallelTasksGroupView.js +14 -6
  78. package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
  79. package/dist/components/messages/TaskInModuleView.js +27 -27
  80. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  81. package/dist/components/messages/UserGuidanceMessage.js +26 -0
  82. package/dist/components/messages/UserGuidanceMessage.js.map +7 -0
  83. package/dist/components/messages/UserPromptMessage.js +2 -1
  84. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  85. package/dist/components/messages/UserTeamNotificationMessage.js +91 -0
  86. package/dist/components/messages/UserTeamNotificationMessage.js.map +7 -0
  87. package/dist/components/messages/UserTextMessage.js +8 -0
  88. package/dist/components/messages/UserTextMessage.js.map +2 -2
  89. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +4 -2
  90. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +2 -2
  91. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +18 -1
  92. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +2 -2
  93. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +12 -1
  94. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  95. package/dist/components/permissions/PermissionRequest.js +4 -0
  96. package/dist/components/permissions/PermissionRequest.js.map +2 -2
  97. package/dist/components/permissions/PlanApprovalRequest.js +164 -0
  98. package/dist/components/permissions/PlanApprovalRequest.js.map +7 -0
  99. package/dist/constants/agentTeams.js +17 -0
  100. package/dist/constants/agentTeams.js.map +7 -0
  101. package/dist/constants/macros.js +2 -1
  102. package/dist/constants/macros.js.map +2 -2
  103. package/dist/constants/prompts/agentPrompt.js +1 -0
  104. package/dist/constants/prompts/agentPrompt.js.map +2 -2
  105. package/dist/constants/prompts/autoMemory.js +39 -0
  106. package/dist/constants/prompts/autoMemory.js.map +7 -0
  107. package/dist/constants/prompts/codeConventions.js +1 -13
  108. package/dist/constants/prompts/codeConventions.js.map +2 -2
  109. package/dist/constants/prompts/doingTasks.js +21 -2
  110. package/dist/constants/prompts/doingTasks.js.map +2 -2
  111. package/dist/constants/prompts/envInfo.js +6 -7
  112. package/dist/constants/prompts/envInfo.js.map +2 -2
  113. package/dist/constants/prompts/index.js +27 -5
  114. package/dist/constants/prompts/index.js.map +2 -2
  115. package/dist/constants/prompts/taskManagement.js +2 -43
  116. package/dist/constants/prompts/taskManagement.js.map +2 -2
  117. package/dist/constants/prompts/teamOverlays.js +50 -0
  118. package/dist/constants/prompts/teamOverlays.js.map +7 -0
  119. package/dist/constants/prompts/toneAndStyle.js +4 -29
  120. package/dist/constants/prompts/toneAndStyle.js.map +2 -2
  121. package/dist/constants/prompts/toolUsagePolicy.js +7 -22
  122. package/dist/constants/prompts/toolUsagePolicy.js.map +2 -2
  123. package/dist/constants/toolInputExamples.js +2 -2
  124. package/dist/constants/toolInputExamples.js.map +2 -2
  125. package/dist/context.js +39 -6
  126. package/dist/context.js.map +2 -2
  127. package/dist/core/backupManager.js +1 -1
  128. package/dist/core/backupManager.js.map +2 -2
  129. package/dist/core/permissions/rules/planModeRule.js +1 -1
  130. package/dist/core/permissions/rules/planModeRule.js.map +1 -1
  131. package/dist/core/permissions/rules/safeModeRule.js +1 -1
  132. package/dist/core/permissions/rules/safeModeRule.js.map +1 -1
  133. package/dist/engine/AgentEngine.js +902 -0
  134. package/dist/engine/AgentEngine.js.map +7 -0
  135. package/dist/engine/EngineRegistry.js +89 -0
  136. package/dist/engine/EngineRegistry.js.map +7 -0
  137. package/dist/engine/foregroundAdapter.js +191 -0
  138. package/dist/engine/foregroundAdapter.js.map +7 -0
  139. package/dist/engine/index.js +15 -0
  140. package/dist/engine/index.js.map +7 -0
  141. package/dist/engine/types.js +1 -0
  142. package/dist/engine/types.js.map +7 -0
  143. package/dist/entrypoints/cli.js +410 -79
  144. package/dist/entrypoints/cli.js.map +3 -3
  145. package/dist/hooks/useAgentEngine.js +129 -0
  146. package/dist/hooks/useAgentEngine.js.map +7 -0
  147. package/dist/hooks/useAgentTokenStats.js +0 -16
  148. package/dist/hooks/useAgentTokenStats.js.map +2 -2
  149. package/dist/hooks/useCanUseTool.js +47 -2
  150. package/dist/hooks/useCanUseTool.js.map +2 -2
  151. package/dist/hooks/useDeferredLoading.js +4 -1
  152. package/dist/hooks/useDeferredLoading.js.map +2 -2
  153. package/dist/hooks/useIdleNotifications.js +66 -0
  154. package/dist/hooks/useIdleNotifications.js.map +7 -0
  155. package/dist/hooks/useSessionTracking.js +9 -7
  156. package/dist/hooks/useSessionTracking.js.map +2 -2
  157. package/dist/hooks/useTeamMembers.js +51 -0
  158. package/dist/hooks/useTeamMembers.js.map +7 -0
  159. package/dist/i18n/locales/en.js +77 -12
  160. package/dist/i18n/locales/en.js.map +2 -2
  161. package/dist/i18n/locales/zh-CN.js +77 -12
  162. package/dist/i18n/locales/zh-CN.js.map +2 -2
  163. package/dist/i18n/types.js.map +1 -1
  164. package/dist/messages.js.map +2 -2
  165. package/dist/permissions.js +113 -7
  166. package/dist/permissions.js.map +2 -2
  167. package/dist/query.js +135 -37
  168. package/dist/query.js.map +2 -2
  169. package/dist/screens/REPL.js +504 -361
  170. package/dist/screens/REPL.js.map +3 -3
  171. package/dist/screens/ResumeConversation.js +199 -14
  172. package/dist/screens/ResumeConversation.js.map +2 -2
  173. package/dist/services/adapters/base.js.map +1 -1
  174. package/dist/services/agentTeams/backends/headless.js +108 -0
  175. package/dist/services/agentTeams/backends/headless.js.map +7 -0
  176. package/dist/services/agentTeams/backends/inProcess.js +102 -0
  177. package/dist/services/agentTeams/backends/inProcess.js.map +7 -0
  178. package/dist/services/agentTeams/backends/resolver.js +18 -0
  179. package/dist/services/agentTeams/backends/resolver.js.map +7 -0
  180. package/dist/services/agentTeams/backends/tmux.js +168 -0
  181. package/dist/services/agentTeams/backends/tmux.js.map +7 -0
  182. package/dist/services/agentTeams/backends/types.js +1 -0
  183. package/dist/services/agentTeams/backends/types.js.map +7 -0
  184. package/dist/services/agentTeams/heartbeat.js +88 -0
  185. package/dist/services/agentTeams/heartbeat.js.map +7 -0
  186. package/dist/services/agentTeams/index.js +42 -2
  187. package/dist/services/agentTeams/index.js.map +2 -2
  188. package/dist/services/agentTeams/injectionChannel.js +105 -0
  189. package/dist/services/agentTeams/injectionChannel.js.map +7 -0
  190. package/dist/services/agentTeams/mailbox.js +410 -30
  191. package/dist/services/agentTeams/mailbox.js.map +2 -2
  192. package/dist/services/agentTeams/messageFormatter.js +80 -0
  193. package/dist/services/agentTeams/messageFormatter.js.map +7 -0
  194. package/dist/services/agentTeams/permissionDelegation.js +71 -0
  195. package/dist/services/agentTeams/permissionDelegation.js.map +7 -0
  196. package/dist/services/agentTeams/teamEvents.js +45 -0
  197. package/dist/services/agentTeams/teamEvents.js.map +7 -0
  198. package/dist/services/agentTeams/teamManager.js +251 -34
  199. package/dist/services/agentTeams/teamManager.js.map +2 -2
  200. package/dist/services/agentTeams/teamTaskStore.js +290 -61
  201. package/dist/services/agentTeams/teamTaskStore.js.map +2 -2
  202. package/dist/services/agentTeams/teammateSpawner.js +99 -18
  203. package/dist/services/agentTeams/teammateSpawner.js.map +2 -2
  204. package/dist/services/hookExecutor.js +51 -8
  205. package/dist/services/hookExecutor.js.map +2 -2
  206. package/dist/services/llm/anthropicProvider.js +56 -59
  207. package/dist/services/llm/anthropicProvider.js.map +2 -2
  208. package/dist/services/llm/dispatch.js +24 -5
  209. package/dist/services/llm/dispatch.js.map +2 -2
  210. package/dist/services/llm/openaiProvider.js +115 -136
  211. package/dist/services/llm/openaiProvider.js.map +3 -3
  212. package/dist/services/llm/types.js +89 -15
  213. package/dist/services/llm/types.js.map +2 -2
  214. package/dist/services/mcpClient.js +80 -4
  215. package/dist/services/mcpClient.js.map +2 -2
  216. package/dist/services/mintoAuth.js +299 -0
  217. package/dist/services/mintoAuth.js.map +7 -0
  218. package/dist/services/oauth.js +3 -3
  219. package/dist/services/oauth.js.map +2 -2
  220. package/dist/services/openai.js +91 -20
  221. package/dist/services/openai.js.map +2 -2
  222. package/dist/services/plugins/pluginRuntime.js +11 -5
  223. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  224. package/dist/services/plugins/pluginValidation.js +4 -2
  225. package/dist/services/plugins/pluginValidation.js.map +2 -2
  226. package/dist/services/sandbox/sandboxController.js +11 -3
  227. package/dist/services/sandbox/sandboxController.js.map +2 -2
  228. package/dist/services/sessionMemoryInjector.js +77 -0
  229. package/dist/services/sessionMemoryInjector.js.map +7 -0
  230. package/dist/services/systemReminder.js +130 -8
  231. package/dist/services/systemReminder.js.map +2 -2
  232. package/dist/services/taskStore.js +199 -8
  233. package/dist/services/taskStore.js.map +3 -3
  234. package/dist/services/topicDetector.js +169 -0
  235. package/dist/services/topicDetector.js.map +7 -0
  236. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +0 -13
  237. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  238. package/dist/tools/BashTool/BashTool.js +51 -28
  239. package/dist/tools/BashTool/BashTool.js.map +2 -2
  240. package/dist/tools/BashTool/prompt.js +95 -118
  241. package/dist/tools/BashTool/prompt.js.map +2 -2
  242. package/dist/tools/BashTool/utils.js +39 -1
  243. package/dist/tools/BashTool/utils.js.map +2 -2
  244. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js +121 -0
  245. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js.map +7 -0
  246. package/dist/tools/EnterWorktreeTool/prompt.js +22 -0
  247. package/dist/tools/EnterWorktreeTool/prompt.js.map +7 -0
  248. package/dist/tools/FileEditTool/FileEditTool.js +9 -4
  249. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  250. package/dist/tools/FileEditTool/prompt.js +3 -7
  251. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  252. package/dist/tools/FileReadTool/FileReadTool.js +125 -3
  253. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  254. package/dist/tools/FileReadTool/prompt.js +1 -2
  255. package/dist/tools/FileReadTool/prompt.js.map +2 -2
  256. package/dist/tools/FileWriteTool/prompt.js +3 -5
  257. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  258. package/dist/tools/GlobTool/GlobTool.js +3 -2
  259. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  260. package/dist/tools/GrepTool/GrepTool.js +16 -5
  261. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  262. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
  263. package/dist/tools/MCPSearchTool/MCPSearchTool.js +172 -0
  264. package/dist/tools/MCPSearchTool/MCPSearchTool.js.map +7 -0
  265. package/dist/tools/MCPSearchTool/prompt.js +77 -0
  266. package/dist/tools/MCPSearchTool/prompt.js.map +7 -0
  267. package/dist/tools/MultiEditTool/prompt.js +4 -7
  268. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  269. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +12 -8
  270. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  271. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +54 -1
  272. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  273. package/dist/tools/PlanModeTool/prompt.js +23 -74
  274. package/dist/tools/PlanModeTool/prompt.js.map +2 -2
  275. package/dist/tools/SendMessageTool/SendMessageTool.js +341 -0
  276. package/dist/tools/SendMessageTool/SendMessageTool.js.map +7 -0
  277. package/dist/tools/SendMessageTool/prompt.js +44 -0
  278. package/dist/tools/SendMessageTool/prompt.js.map +7 -0
  279. package/dist/tools/TaskCreateTool/prompt.js +15 -4
  280. package/dist/tools/TaskCreateTool/prompt.js.map +2 -2
  281. package/dist/tools/TaskListTool/prompt.js +18 -3
  282. package/dist/tools/TaskListTool/prompt.js.map +2 -2
  283. package/dist/tools/TaskOutputTool/prompt.js +4 -3
  284. package/dist/tools/TaskOutputTool/prompt.js.map +2 -2
  285. package/dist/tools/TaskTool/TaskTool.js +762 -98
  286. package/dist/tools/TaskTool/TaskTool.js.map +3 -3
  287. package/dist/tools/TaskTool/constants.js +8 -2
  288. package/dist/tools/TaskTool/constants.js.map +2 -2
  289. package/dist/tools/TaskTool/prompt.js +74 -70
  290. package/dist/tools/TaskTool/prompt.js.map +2 -2
  291. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +15 -1
  292. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +2 -2
  293. package/dist/tools/TeamCreateTool/TeamCreateTool.js +129 -0
  294. package/dist/tools/TeamCreateTool/TeamCreateTool.js.map +7 -0
  295. package/dist/tools/TeamCreateTool/prompt.js +58 -0
  296. package/dist/tools/TeamCreateTool/prompt.js.map +7 -0
  297. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js +151 -0
  298. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js.map +7 -0
  299. package/dist/tools/TeamDeleteTool/prompt.js +16 -0
  300. package/dist/tools/TeamDeleteTool/prompt.js.map +7 -0
  301. package/dist/tools/URLFetcherTool/URLFetcherTool.js +106 -15
  302. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  303. package/dist/tools/URLFetcherTool/prompt.js +3 -2
  304. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  305. package/dist/tools/WebSearchTool/WebSearchTool.js +2 -1
  306. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  307. package/dist/tools/WebSearchTool/prompt.js +5 -4
  308. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  309. package/dist/tools.js +100 -20
  310. package/dist/tools.js.map +2 -2
  311. package/dist/types/PermissionMode.js +35 -6
  312. package/dist/types/PermissionMode.js.map +2 -2
  313. package/dist/types/hooks.js +2 -0
  314. package/dist/types/hooks.js.map +2 -2
  315. package/dist/types/plugin.js +2 -0
  316. package/dist/types/plugin.js.map +3 -3
  317. package/dist/utils/CircuitBreaker.js +15 -9
  318. package/dist/utils/CircuitBreaker.js.map +2 -2
  319. package/dist/utils/agentLoader.js +249 -112
  320. package/dist/utils/agentLoader.js.map +2 -2
  321. package/dist/utils/animationManager.js +40 -3
  322. package/dist/utils/animationManager.js.map +2 -2
  323. package/dist/utils/ask.js +7 -6
  324. package/dist/utils/ask.js.map +2 -2
  325. package/dist/utils/atomicWrite.js +23 -0
  326. package/dist/utils/atomicWrite.js.map +7 -0
  327. package/dist/utils/autoCompactCore.js +73 -56
  328. package/dist/utils/autoCompactCore.js.map +2 -2
  329. package/dist/utils/autoMemoryPaths.js +89 -0
  330. package/dist/utils/autoMemoryPaths.js.map +7 -0
  331. package/dist/utils/config.js +63 -38
  332. package/dist/utils/config.js.map +2 -2
  333. package/dist/utils/configSchema.js +13 -8
  334. package/dist/utils/configSchema.js.map +2 -2
  335. package/dist/utils/credentials/index.js +14 -0
  336. package/dist/utils/credentials/index.js.map +2 -2
  337. package/dist/utils/dualPath.js +24 -0
  338. package/dist/utils/dualPath.js.map +7 -0
  339. package/dist/utils/exit.js +66 -7
  340. package/dist/utils/exit.js.map +2 -2
  341. package/dist/utils/externalEditor.js +155 -0
  342. package/dist/utils/externalEditor.js.map +7 -0
  343. package/dist/utils/fileLock.js +67 -0
  344. package/dist/utils/fileLock.js.map +7 -0
  345. package/dist/utils/format.js +24 -14
  346. package/dist/utils/format.js.map +2 -2
  347. package/dist/utils/globalErrorHandler.js +5 -96
  348. package/dist/utils/globalErrorHandler.js.map +3 -3
  349. package/dist/utils/groupHandlers/parallelTasksHandler.js +5 -3
  350. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +2 -2
  351. package/dist/utils/groupHandlers/taskHandler.js +2 -2
  352. package/dist/utils/groupHandlers/taskHandler.js.map +2 -2
  353. package/dist/utils/hookManager.js +64 -6
  354. package/dist/utils/hookManager.js.map +2 -2
  355. package/dist/utils/log.js +6 -2
  356. package/dist/utils/log.js.map +2 -2
  357. package/dist/utils/markdown.js +237 -19
  358. package/dist/utils/markdown.js.map +2 -2
  359. package/dist/utils/messageContextManager.js +18 -5
  360. package/dist/utils/messageContextManager.js.map +2 -2
  361. package/dist/utils/messageGroupManager.js +1 -1
  362. package/dist/utils/messageGroupManager.js.map +2 -2
  363. package/dist/utils/messages.js +104 -46
  364. package/dist/utils/messages.js.map +2 -2
  365. package/dist/utils/model.js +2 -2
  366. package/dist/utils/model.js.map +2 -2
  367. package/dist/utils/pasteCache.js +8 -4
  368. package/dist/utils/pasteCache.js.map +2 -2
  369. package/dist/utils/pluginLoader.js +18 -0
  370. package/dist/utils/pluginLoader.js.map +2 -2
  371. package/dist/utils/secureKeyStorage.js +36 -7
  372. package/dist/utils/secureKeyStorage.js.map +2 -2
  373. package/dist/utils/simpleMode.js +7 -0
  374. package/dist/utils/simpleMode.js.map +7 -0
  375. package/dist/utils/streamingState.js +11 -1
  376. package/dist/utils/streamingState.js.map +2 -2
  377. package/dist/utils/taskDisplayUtils.js +2 -1
  378. package/dist/utils/taskDisplayUtils.js.map +2 -2
  379. package/dist/utils/teamConfig.js +2 -2
  380. package/dist/utils/teamConfig.js.map +2 -2
  381. package/dist/utils/thinking.js +6 -2
  382. package/dist/utils/thinking.js.map +3 -3
  383. package/dist/utils/tokenProgress.js +55 -0
  384. package/dist/utils/tokenProgress.js.map +7 -0
  385. package/dist/utils/toolRiskClassification.js +26 -17
  386. package/dist/utils/toolRiskClassification.js.map +2 -2
  387. package/dist/utils/tooling/toolError.js +12 -0
  388. package/dist/utils/tooling/toolError.js.map +7 -0
  389. package/dist/version.js +2 -2
  390. package/dist/version.js.map +1 -1
  391. package/package.json +10 -8
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/services/mintoAuth.ts"],
4
+ "sourcesContent": ["/**\n * Minto Login Service\n *\n * Single source of truth for the login domain:\n * - Login API call + Zod validation\n * - LiteLLM model discovery + deduplication\n * - Model auto-configuration via ModelManager\n * - Smart model pointer assignment\n *\n * Security: No account info stored locally. Only LiteLLM API key is persisted\n * via the credential store. Login state is inferred from credential presence.\n */\n\nimport { z } from 'zod'\nimport { MACRO } from '@constants/macros'\nimport { setApiKey, getApiKey, deleteApiKey } from '@utils/credentials/index'\nimport { getModelManager, reloadModelManager } from '@utils/model'\nimport type { ModelPointerType } from '@utils/configSchema'\nimport { t } from '@i18n'\nimport * as readline from 'readline'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MintoLoginResponseSchema = z.object({\n user: z.string(),\n profile: z.object({\n userId: z.string(),\n staff: z.string(),\n email: z.string(),\n permission: z.array(z.string()),\n status: z.string(),\n }),\n model: z.object({\n base_url: z.string(),\n api_key: z.string(),\n qwen_asr_api_key: z.string().optional(),\n }),\n})\n\ntype MintoLoginResponse = z.infer<typeof MintoLoginResponseSchema>\n\nconst LiteLLMModelInfoSchema = z.object({\n model_name: z.string(),\n litellm_params: z.record(z.unknown()).optional().default({}),\n model_info: z\n .object({\n id: z.string().optional(),\n key: z.string().optional(),\n max_tokens: z.number().optional(),\n max_input_tokens: z.number().optional(),\n max_output_tokens: z.number().optional(),\n input_cost_per_token: z.number().optional(),\n output_cost_per_token: z.number().optional(),\n litellm_provider: z.string().optional(),\n mode: z.string().optional(),\n })\n .optional()\n .default({}),\n})\n\ntype LiteLLMModelInfo = z.infer<typeof LiteLLMModelInfoSchema>\n\nconst LiteLLMModelListResponseSchema = z.object({\n data: z.array(LiteLLMModelInfoSchema),\n})\n\nexport interface LoginResult {\n user: string\n modelsConfigured: number\n modelNames: string[]\n aiterVoiceConfigured?: boolean\n}\n\n// \u2500\u2500\u2500 CREDENTIAL_KEY \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst LITELLM_CREDENTIAL_KEY = 'minto-litellm'\n\n// \u2500\u2500\u2500 Core API Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * POST login request to Minto auth API.\n * Returns parsed + validated response.\n */\nexport async function mintoLogin(\n user: string,\n password: string,\n): Promise<MintoLoginResponse> {\n const url = MACRO.LOGIN_API_URL\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ user, password }),\n })\n\n if (res.status === 401 || res.status === 403) {\n throw new Error(t('commands.login.invalidCredentials'))\n }\n if (!res.ok) {\n throw new Error(\n `${t('commands.login.failed')}: HTTP ${res.status} ${res.statusText}`,\n )\n }\n\n const json = await res.json()\n return MintoLoginResponseSchema.parse(json)\n}\n\n/**\n * Fetch available models from LiteLLM /model/info endpoint.\n */\nexport async function fetchLiteLLMModels(\n baseUrl: string,\n apiKey: string,\n): Promise<LiteLLMModelInfo[]> {\n // Normalize base URL \u2014 strip trailing slash\n const base = baseUrl.replace(/\\/+$/, '')\n const url = `${base}/model/info`\n\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n })\n\n if (!res.ok) {\n throw new Error(\n `${t('commands.login.fetchModelsFailed')}: HTTP ${res.status}`,\n )\n }\n\n const json = await res.json()\n const parsed = LiteLLMModelListResponseSchema.parse(json)\n return parsed.data\n}\n\n/**\n * Deduplicate LiteLLM models by base model name.\n * Strips provider/ prefix (e.g., \"openai/gpt-4o\" \u2192 \"gpt-4o\").\n * Keeps the first occurrence per base name.\n */\nexport function deduplicateLiteLLMModels(\n models: LiteLLMModelInfo[],\n): LiteLLMModelInfo[] {\n const seen = new Map<string, LiteLLMModelInfo>()\n\n for (const model of models) {\n const baseName = getBaseModelName(model.model_name)\n if (!seen.has(baseName)) {\n seen.set(baseName, model)\n }\n }\n\n return [...seen.values()]\n}\n\n/**\n * Strip provider prefix from model name.\n * \"openai/gpt-4o\" \u2192 \"gpt-4o\", \"claude-sonnet-4\" \u2192 \"claude-sonnet-4\"\n */\nfunction getBaseModelName(modelName: string): string {\n const slashIdx = modelName.indexOf('/')\n return slashIdx >= 0 ? modelName.slice(slashIdx + 1) : modelName\n}\n\n/**\n * Sort models by total cost (input + output cost per token), cheapest first.\n * Models without pricing info are treated as free (cost = 0).\n */\nexport function sortModelsByCost(\n models: LiteLLMModelInfo[],\n): LiteLLMModelInfo[] {\n return [...models].sort((a, b) => {\n const costA =\n (a.model_info?.input_cost_per_token ?? 0) +\n (a.model_info?.output_cost_per_token ?? 0)\n const costB =\n (b.model_info?.input_cost_per_token ?? 0) +\n (b.model_info?.output_cost_per_token ?? 0)\n return costA - costB\n })\n}\n\n/**\n * Heuristic model pointer assignment.\n * Matches model names to roles based on known patterns.\n * Main model prioritizes cost-effective models (glm-5, qwen-3.5-plus).\n */\nexport function assignModelPointers(\n modelNames: string[],\n): Record<ModelPointerType, string> {\n const find = (...patterns: string[]): string | null => {\n for (const pattern of patterns) {\n const match = modelNames.find(n =>\n n.toLowerCase().includes(pattern.toLowerCase()),\n )\n if (match) return match\n }\n return null\n }\n\n const fallback = modelNames[0] ?? ''\n\n const main =\n find('glm-5', 'qwen-3.5-plus', 'claude-sonnet', 'gpt-4o') ?? fallback\n const task = find('claude-sonnet', 'gpt-4o-mini', 'glm-5') ?? main\n const reasoning = find('o3', 'o1', 'deepseek-r1') ?? main\n const quick = find('gpt-4o-mini', 'claude-haiku', 'qwen-3.5-plus') ?? task\n const compact = quick\n\n return { main, task, reasoning, quick, compact }\n}\n\n// \u2500\u2500\u2500 AiTer Voice Input Configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Configure AiTer voice input when running in AiTer environment.\n * Uses `aiter settings set voiceInput` CLI command.\n */\nasync function configureAiterVoiceInput(\n qwenAsrApiKey: string,\n): Promise<boolean> {\n if (process.env.AITER_TERMINAL !== '1') return false\n\n const { execFile } = await import('child_process')\n const { promisify } = await import('util')\n const execFileAsync = promisify(execFile)\n\n const voiceInputConfig = JSON.stringify({\n enabled: true,\n provider: 'qwen-asr',\n qwenApiKey: qwenAsrApiKey,\n qwenRegion: 'cn',\n })\n\n try {\n await execFileAsync('aiter', [\n 'settings',\n 'set',\n 'voiceInput',\n voiceInputConfig,\n ])\n return true\n } catch {\n return false\n }\n}\n\n// \u2500\u2500\u2500 Full Login Flow \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Complete login flow:\n * 1. Authenticate via login API\n * 2. Verify account active\n * 3. Store API key securely\n * 4. Clear previously login-configured models (by baseURL match)\n * 5. Fetch + deduplicate LiteLLM models\n * 6. Add model profiles via ModelManager\n * 7. Assign model pointers\n */\nexport async function performLogin(\n user: string,\n password: string,\n onProgress?: (phase: string) => void,\n): Promise<LoginResult> {\n // Phase 1: Login\n onProgress?.(t('commands.login.loggingIn'))\n const loginResponse = await mintoLogin(user, password)\n\n // Phase 2: Check account active\n if (loginResponse.profile.status !== 'active') {\n throw new Error(t('commands.login.inactive'))\n }\n\n // Phase 3: Store API key securely (not account info)\n await setApiKey(LITELLM_CREDENTIAL_KEY, loginResponse.model.api_key)\n\n // Phase 4: Clear previous login-configured models (baseURL match)\n onProgress?.(t('commands.login.configuringModels'))\n const mm = getModelManager()\n const existingModels = mm.getAllConfiguredModels()\n const loginBaseURL = loginResponse.model.base_url.replace(/\\/+$/, '')\n\n for (const model of existingModels) {\n if (model.baseURL && model.baseURL.replace(/\\/+$/, '') === loginBaseURL) {\n mm.removeModel(model.modelName)\n }\n }\n\n // Phase 5: Fetch models from LiteLLM\n onProgress?.(t('commands.login.fetchingModels'))\n let litellmModels: LiteLLMModelInfo[]\n try {\n litellmModels = await fetchLiteLLMModels(\n loginResponse.model.base_url,\n loginResponse.model.api_key,\n )\n } catch (err) {\n // Partial success: logged in but model fetch failed\n return {\n user: loginResponse.user,\n modelsConfigured: 0,\n modelNames: [],\n }\n }\n\n // Phase 6: Deduplicate, sort by cost (cheapest first), and add models\n const deduplicated = sortModelsByCost(deduplicateLiteLLMModels(litellmModels))\n const configuredNames: string[] = []\n\n for (const model of deduplicated) {\n const baseName = getBaseModelName(model.model_name)\n const maxOutputTokens = model.model_info?.max_output_tokens ?? 4096\n const maxInputTokens = model.model_info?.max_input_tokens ?? 128000\n\n try {\n await mm.addModel({\n name: baseName,\n provider: 'custom-openai',\n modelName: baseName,\n baseURL: loginBaseURL,\n apiKey: `encrypted:${LITELLM_CREDENTIAL_KEY}`,\n maxTokens: maxOutputTokens,\n contextLength: maxInputTokens,\n })\n configuredNames.push(baseName)\n } catch {\n // Skip duplicate \u2014 defensive, shouldn't happen after cleanup\n }\n }\n\n // Phase 7: Assign model pointers\n if (configuredNames.length > 0) {\n const pointers = assignModelPointers(configuredNames)\n for (const [pointer, modelName] of Object.entries(pointers)) {\n try {\n mm.setPointer(pointer as ModelPointerType, modelName)\n } catch {\n // Skip if model not found (shouldn't happen)\n }\n }\n }\n\n reloadModelManager()\n\n // Phase 8: Configure AiTer voice input if in AiTer environment\n let aiterVoiceConfigured = false\n if (loginResponse.model.qwen_asr_api_key) {\n aiterVoiceConfigured = await configureAiterVoiceInput(\n loginResponse.model.qwen_asr_api_key,\n )\n }\n\n return {\n user: loginResponse.user,\n modelsConfigured: configuredNames.length,\n modelNames: configuredNames,\n aiterVoiceConfigured,\n }\n}\n\n// \u2500\u2500\u2500 Login Status Check \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Check if user is logged in (has stored LiteLLM credential).\n */\nexport async function isLoggedIn(): Promise<boolean> {\n const key = await getApiKey(LITELLM_CREDENTIAL_KEY)\n return key !== null\n}\n\n/**\n * Logout: remove stored credential.\n */\nexport async function logout(): Promise<void> {\n await deleteApiKey(LITELLM_CREDENTIAL_KEY)\n}\n\n// \u2500\u2500\u2500 CLI Handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Handle `minto login` CLI command.\n * Uses readline for interactive input when user/password not provided.\n */\nexport async function handleLoginCLI(\n user?: string,\n password?: string,\n): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n\n const ask = (prompt: string): Promise<string> =>\n new Promise(resolve => rl.question(prompt, resolve))\n\n const askPassword = (prompt: string): Promise<string> =>\n new Promise(resolve => {\n // Mask password input\n process.stdout.write(prompt)\n const stdin = process.stdin\n const wasRaw = stdin.isRaw\n if (stdin.setRawMode) stdin.setRawMode(true)\n stdin.resume()\n\n let pwd = ''\n const onData = (ch: Buffer) => {\n const c = ch.toString('utf8')\n if (c === '\\n' || c === '\\r') {\n if (stdin.setRawMode) stdin.setRawMode(wasRaw ?? false)\n stdin.removeListener('data', onData)\n process.stdout.write('\\n')\n resolve(pwd)\n } else if (c === '\\u0003') {\n // Ctrl-C\n process.exit(1)\n } else if (c === '\\u007f' || c === '\\b') {\n // Backspace\n if (pwd.length > 0) {\n pwd = pwd.slice(0, -1)\n process.stdout.write('\\b \\b')\n }\n } else {\n pwd += c\n process.stdout.write('*')\n }\n }\n stdin.on('data', onData)\n })\n\n try {\n if (!user) {\n user = await ask('Username: ')\n }\n if (!password) {\n password = await askPassword('Password: ')\n }\n\n rl.close()\n\n console.log(`\\n${t('commands.login.loggingIn')}...`)\n\n const result = await performLogin(user, password, phase => {\n console.log(` ${phase}...`)\n })\n\n console.log(`\\n\u2713 ${t('commands.login.success')}`)\n console.log(` User: ${result.user}`)\n console.log(\n ` ${t('commands.login.modelsConfigured')}: ${result.modelsConfigured}`,\n )\n if (result.modelNames.length > 0) {\n console.log(` Models: ${result.modelNames.join(', ')}`)\n }\n if (result.aiterVoiceConfigured) {\n console.log(` AiTer voice input: configured`)\n }\n } catch (err) {\n rl.close()\n console.error(\n `\\n\u2717 ${t('commands.login.failed')}: ${err instanceof Error ? err.message : String(err)}`,\n )\n process.exit(1)\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -6,7 +6,7 @@ import { openBrowser } from "../utils/browser.js";
6
6
  import { logError } from "../utils/log.js";
7
7
  import { resetAnthropicClient } from "./claude.js";
8
8
  import {
9
- getGlobalConfig,
9
+ getMutableGlobalConfig,
10
10
  saveGlobalConfig,
11
11
  normalizeApiKeyForConfig
12
12
  } from "../utils/config.js";
@@ -78,7 +78,7 @@ class OAuthService {
78
78
  emailAddress: account.email_address,
79
79
  organizationUuid: organization?.uuid
80
80
  };
81
- const config = getGlobalConfig();
81
+ const config = getMutableGlobalConfig();
82
82
  config.oauthAccount = accountInfo;
83
83
  saveGlobalConfig(config);
84
84
  }
@@ -222,7 +222,7 @@ async function createAndStoreApiKey(accessToken) {
222
222
  }
223
223
  if (createApiKeyResp.ok && apiKeyData && apiKeyData.raw_key) {
224
224
  const apiKey = apiKeyData.raw_key;
225
- const config = getGlobalConfig();
225
+ const config = getMutableGlobalConfig();
226
226
  if (!config.customApiKeyResponses) {
227
227
  config.customApiKeyResponses = { approved: [], rejected: [] };
228
228
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/services/oauth.ts"],
4
- "sourcesContent": ["import * as crypto from 'crypto'\nimport * as http from 'http'\nimport { IncomingMessage, ServerResponse } from 'http'\nimport * as url from 'url'\n\nimport { OAUTH_CONFIG } from '@constants/oauth'\nimport { openBrowser } from '@utils/browser'\nimport { logError } from '@utils/log'\nimport { resetAnthropicClient } from './claude'\nimport {\n AccountInfo,\n getGlobalConfig,\n saveGlobalConfig,\n normalizeApiKeyForConfig,\n} from '@utils/config'\n\n// Base64URL encoding function (RFC 4648)\nfunction base64URLEncode(buffer: Buffer): string {\n return buffer\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n}\n\nfunction generateCodeVerifier(): string {\n return base64URLEncode(crypto.randomBytes(32))\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n return base64URLEncode(Buffer.from(digest))\n}\n\ntype OAuthTokenExchangeResponse = {\n access_token: string\n account?: {\n uuid: string\n email_address: string\n }\n organization?: {\n uuid: string\n name: string\n }\n}\n\nexport type OAuthResult = {\n accessToken: string\n}\n\nexport class OAuthService {\n private server: http.Server | null = null\n private codeVerifier: string\n private expectedState: string | null = null\n private pendingCodePromise: {\n resolve: (result: {\n authorizationCode: string\n useManualRedirect: boolean\n }) => void\n reject: (err: Error) => void\n } | null = null\n\n constructor() {\n this.codeVerifier = generateCodeVerifier()\n }\n\n private generateAuthUrls(\n codeChallenge: string,\n state: string,\n ): { autoUrl: string; manualUrl: string } {\n function makeUrl(isManual: boolean): string {\n const authUrl = new URL(OAUTH_CONFIG.AUTHORIZE_URL)\n authUrl.searchParams.append('client_id', OAUTH_CONFIG.CLIENT_ID)\n authUrl.searchParams.append('response_type', 'code')\n authUrl.searchParams.append(\n 'redirect_uri',\n isManual\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n )\n authUrl.searchParams.append('scope', OAUTH_CONFIG.SCOPES.join(' '))\n authUrl.searchParams.append('code_challenge', codeChallenge)\n authUrl.searchParams.append('code_challenge_method', 'S256')\n authUrl.searchParams.append('state', state)\n return authUrl.toString()\n }\n\n return {\n autoUrl: makeUrl(false),\n manualUrl: makeUrl(true),\n }\n }\n\n async startOAuthFlow(\n authURLHandler: (url: string) => Promise<void>,\n ): Promise<OAuthResult> {\n const codeChallenge = await generateCodeChallenge(this.codeVerifier)\n const state = base64URLEncode(crypto.randomBytes(32))\n this.expectedState = state\n const { autoUrl, manualUrl } = this.generateAuthUrls(codeChallenge, state)\n\n const onReady = async () => {\n await authURLHandler(manualUrl)\n await openBrowser(autoUrl)\n }\n\n const { authorizationCode, useManualRedirect } = await new Promise<{\n authorizationCode: string\n useManualRedirect: boolean\n }>((resolve, reject) => {\n this.pendingCodePromise = { resolve, reject }\n this.startLocalServer(state, onReady)\n })\n\n // Exchange code for tokens\n const {\n access_token: accessToken,\n account,\n organization,\n } = await this.exchangeCodeForTokens(\n authorizationCode,\n state,\n useManualRedirect,\n )\n\n // Store account info\n if (account) {\n const accountInfo: AccountInfo = {\n accountUuid: account.uuid,\n emailAddress: account.email_address,\n organizationUuid: organization?.uuid,\n }\n const config = getGlobalConfig()\n config.oauthAccount = accountInfo\n saveGlobalConfig(config)\n }\n\n return { accessToken }\n }\n\n private startLocalServer(state: string, onReady?: () => void): void {\n if (this.server) {\n this.closeServer()\n }\n this.server = http.createServer(\n (req: IncomingMessage, res: ServerResponse) => {\n const parsedUrl = url.parse(req.url || '', true)\n\n if (parsedUrl.pathname === '/callback') {\n const authorizationCode = parsedUrl.query.code as string\n const returnedState = parsedUrl.query.state as string\n\n if (!authorizationCode) {\n res.writeHead(400)\n res.end('Authorization code not found')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('No authorization code received'),\n )\n }\n return\n }\n\n if (returnedState !== state) {\n res.writeHead(400)\n res.end('Invalid state parameter')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n }\n return\n }\n\n res.writeHead(302, {\n Location: OAUTH_CONFIG.SUCCESS_URL,\n })\n res.end()\n\n this.processCallback({\n authorizationCode,\n state,\n useManualRedirect: false,\n })\n } else {\n res.writeHead(404)\n res.end()\n }\n },\n )\n\n this.server.listen(OAUTH_CONFIG.REDIRECT_PORT, async () => {\n onReady?.()\n })\n\n this.server.on('error', (err: Error) => {\n const portError = err as NodeJS.ErrnoException\n if (portError.code === 'EADDRINUSE') {\n const error = new Error(\n `Port ${OAUTH_CONFIG.REDIRECT_PORT} is already in use. Please ensure no other applications are using this port.`,\n )\n logError(error)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(error)\n }\n return\n } else {\n logError(err)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(err)\n }\n return\n }\n })\n }\n\n private async exchangeCodeForTokens(\n authorizationCode: string,\n state: string,\n useManualRedirect: boolean = false,\n ): Promise<OAuthTokenExchangeResponse> {\n const requestBody = {\n grant_type: 'authorization_code',\n code: authorizationCode,\n redirect_uri: useManualRedirect\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n client_id: OAUTH_CONFIG.CLIENT_ID,\n code_verifier: this.codeVerifier,\n state,\n }\n\n const response = await fetch(OAUTH_CONFIG.TOKEN_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n signal: AbortSignal.timeout(30_000),\n })\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.statusText}`)\n }\n\n const data = await response.json()\n return data\n }\n\n processCallback({\n authorizationCode,\n state,\n useManualRedirect,\n }: {\n authorizationCode: string\n state: string\n useManualRedirect: boolean\n }): void {\n this.closeServer()\n\n if (state !== this.expectedState) {\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n this.pendingCodePromise = null\n }\n return\n }\n\n if (this.pendingCodePromise) {\n this.pendingCodePromise.resolve({ authorizationCode, useManualRedirect })\n this.pendingCodePromise = null\n }\n }\n\n private closeServer(): void {\n if (this.server) {\n this.server.close()\n this.server = null\n }\n }\n}\n\nexport async function createAndStoreApiKey(\n accessToken: string,\n): Promise<string | null> {\n try {\n // Call create_api_key endpoint\n const createApiKeyResp = await fetch(OAUTH_CONFIG.API_KEY_URL, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(30_000),\n })\n\n let apiKeyData\n let errorText = ''\n\n try {\n apiKeyData = await createApiKeyResp.json()\n } catch (_e) {\n // If response is not valid JSON, get as text for error logging\n errorText = await createApiKeyResp.text()\n }\n\n if (createApiKeyResp.ok && apiKeyData && apiKeyData.raw_key) {\n const apiKey = apiKeyData.raw_key\n\n // Store in global config\n const config = getGlobalConfig()\n\n // Note: API key is now managed per model profile\n\n // Add to approved list\n if (!config.customApiKeyResponses) {\n config.customApiKeyResponses = { approved: [], rejected: [] }\n }\n if (!config.customApiKeyResponses.approved) {\n config.customApiKeyResponses.approved = []\n }\n\n const normalizedKey = normalizeApiKeyForConfig(apiKey)\n if (!config.customApiKeyResponses.approved.includes(normalizedKey)) {\n config.customApiKeyResponses.approved.push(normalizedKey)\n }\n\n // Save config\n saveGlobalConfig(config)\n\n // Reset the Anthropic client to force creation with new API key\n resetAnthropicClient()\n\n return apiKey\n }\n\n return null\n } catch (error) {\n throw error\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import * as crypto from 'crypto'\nimport * as http from 'http'\nimport { IncomingMessage, ServerResponse } from 'http'\nimport * as url from 'url'\n\nimport { OAUTH_CONFIG } from '@constants/oauth'\nimport { openBrowser } from '@utils/browser'\nimport { logError } from '@utils/log'\nimport { resetAnthropicClient } from './claude'\nimport {\n AccountInfo,\n getMutableGlobalConfig,\n saveGlobalConfig,\n normalizeApiKeyForConfig,\n} from '@utils/config'\n\n// Base64URL encoding function (RFC 4648)\nfunction base64URLEncode(buffer: Buffer): string {\n return buffer\n .toString('base64')\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '')\n}\n\nfunction generateCodeVerifier(): string {\n return base64URLEncode(crypto.randomBytes(32))\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder()\n const data = encoder.encode(verifier)\n const digest = await crypto.subtle.digest('SHA-256', data)\n return base64URLEncode(Buffer.from(digest))\n}\n\ntype OAuthTokenExchangeResponse = {\n access_token: string\n account?: {\n uuid: string\n email_address: string\n }\n organization?: {\n uuid: string\n name: string\n }\n}\n\nexport type OAuthResult = {\n accessToken: string\n}\n\nexport class OAuthService {\n private server: http.Server | null = null\n private codeVerifier: string\n private expectedState: string | null = null\n private pendingCodePromise: {\n resolve: (result: {\n authorizationCode: string\n useManualRedirect: boolean\n }) => void\n reject: (err: Error) => void\n } | null = null\n\n constructor() {\n this.codeVerifier = generateCodeVerifier()\n }\n\n private generateAuthUrls(\n codeChallenge: string,\n state: string,\n ): { autoUrl: string; manualUrl: string } {\n function makeUrl(isManual: boolean): string {\n const authUrl = new URL(OAUTH_CONFIG.AUTHORIZE_URL)\n authUrl.searchParams.append('client_id', OAUTH_CONFIG.CLIENT_ID)\n authUrl.searchParams.append('response_type', 'code')\n authUrl.searchParams.append(\n 'redirect_uri',\n isManual\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n )\n authUrl.searchParams.append('scope', OAUTH_CONFIG.SCOPES.join(' '))\n authUrl.searchParams.append('code_challenge', codeChallenge)\n authUrl.searchParams.append('code_challenge_method', 'S256')\n authUrl.searchParams.append('state', state)\n return authUrl.toString()\n }\n\n return {\n autoUrl: makeUrl(false),\n manualUrl: makeUrl(true),\n }\n }\n\n async startOAuthFlow(\n authURLHandler: (url: string) => Promise<void>,\n ): Promise<OAuthResult> {\n const codeChallenge = await generateCodeChallenge(this.codeVerifier)\n const state = base64URLEncode(crypto.randomBytes(32))\n this.expectedState = state\n const { autoUrl, manualUrl } = this.generateAuthUrls(codeChallenge, state)\n\n const onReady = async () => {\n await authURLHandler(manualUrl)\n await openBrowser(autoUrl)\n }\n\n const { authorizationCode, useManualRedirect } = await new Promise<{\n authorizationCode: string\n useManualRedirect: boolean\n }>((resolve, reject) => {\n this.pendingCodePromise = { resolve, reject }\n this.startLocalServer(state, onReady)\n })\n\n // Exchange code for tokens\n const {\n access_token: accessToken,\n account,\n organization,\n } = await this.exchangeCodeForTokens(\n authorizationCode,\n state,\n useManualRedirect,\n )\n\n // Store account info\n if (account) {\n const accountInfo: AccountInfo = {\n accountUuid: account.uuid,\n emailAddress: account.email_address,\n organizationUuid: organization?.uuid,\n }\n const config = getMutableGlobalConfig()\n config.oauthAccount = accountInfo\n saveGlobalConfig(config)\n }\n\n return { accessToken }\n }\n\n private startLocalServer(state: string, onReady?: () => void): void {\n if (this.server) {\n this.closeServer()\n }\n this.server = http.createServer(\n (req: IncomingMessage, res: ServerResponse) => {\n const parsedUrl = url.parse(req.url || '', true)\n\n if (parsedUrl.pathname === '/callback') {\n const authorizationCode = parsedUrl.query.code as string\n const returnedState = parsedUrl.query.state as string\n\n if (!authorizationCode) {\n res.writeHead(400)\n res.end('Authorization code not found')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('No authorization code received'),\n )\n }\n return\n }\n\n if (returnedState !== state) {\n res.writeHead(400)\n res.end('Invalid state parameter')\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n }\n return\n }\n\n res.writeHead(302, {\n Location: OAUTH_CONFIG.SUCCESS_URL,\n })\n res.end()\n\n this.processCallback({\n authorizationCode,\n state,\n useManualRedirect: false,\n })\n } else {\n res.writeHead(404)\n res.end()\n }\n },\n )\n\n this.server.listen(OAUTH_CONFIG.REDIRECT_PORT, async () => {\n onReady?.()\n })\n\n this.server.on('error', (err: Error) => {\n const portError = err as NodeJS.ErrnoException\n if (portError.code === 'EADDRINUSE') {\n const error = new Error(\n `Port ${OAUTH_CONFIG.REDIRECT_PORT} is already in use. Please ensure no other applications are using this port.`,\n )\n logError(error)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(error)\n }\n return\n } else {\n logError(err)\n this.closeServer()\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(err)\n }\n return\n }\n })\n }\n\n private async exchangeCodeForTokens(\n authorizationCode: string,\n state: string,\n useManualRedirect: boolean = false,\n ): Promise<OAuthTokenExchangeResponse> {\n const requestBody = {\n grant_type: 'authorization_code',\n code: authorizationCode,\n redirect_uri: useManualRedirect\n ? OAUTH_CONFIG.MANUAL_REDIRECT_URL\n : `http://localhost:${OAUTH_CONFIG.REDIRECT_PORT}/callback`,\n client_id: OAUTH_CONFIG.CLIENT_ID,\n code_verifier: this.codeVerifier,\n state,\n }\n\n const response = await fetch(OAUTH_CONFIG.TOKEN_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n signal: AbortSignal.timeout(30_000),\n })\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.statusText}`)\n }\n\n const data = await response.json()\n return data\n }\n\n processCallback({\n authorizationCode,\n state,\n useManualRedirect,\n }: {\n authorizationCode: string\n state: string\n useManualRedirect: boolean\n }): void {\n this.closeServer()\n\n if (state !== this.expectedState) {\n if (this.pendingCodePromise) {\n this.pendingCodePromise.reject(\n new Error('Invalid state parameter'), // Possible CSRF attack\n )\n this.pendingCodePromise = null\n }\n return\n }\n\n if (this.pendingCodePromise) {\n this.pendingCodePromise.resolve({ authorizationCode, useManualRedirect })\n this.pendingCodePromise = null\n }\n }\n\n private closeServer(): void {\n if (this.server) {\n this.server.close()\n this.server = null\n }\n }\n}\n\nexport async function createAndStoreApiKey(\n accessToken: string,\n): Promise<string | null> {\n try {\n // Call create_api_key endpoint\n const createApiKeyResp = await fetch(OAUTH_CONFIG.API_KEY_URL, {\n method: 'POST',\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(30_000),\n })\n\n let apiKeyData\n let errorText = ''\n\n try {\n apiKeyData = await createApiKeyResp.json()\n } catch (_e) {\n // If response is not valid JSON, get as text for error logging\n errorText = await createApiKeyResp.text()\n }\n\n if (createApiKeyResp.ok && apiKeyData && apiKeyData.raw_key) {\n const apiKey = apiKeyData.raw_key\n\n // Store in global config\n const config = getMutableGlobalConfig()\n\n // Note: API key is now managed per model profile\n\n // Add to approved list\n if (!config.customApiKeyResponses) {\n config.customApiKeyResponses = { approved: [], rejected: [] }\n }\n if (!config.customApiKeyResponses.approved) {\n config.customApiKeyResponses.approved = []\n }\n\n const normalizedKey = normalizeApiKeyForConfig(apiKey)\n if (!config.customApiKeyResponses.approved.includes(normalizedKey)) {\n config.customApiKeyResponses.approved.push(normalizedKey)\n }\n\n // Save config\n saveGlobalConfig(config)\n\n // Reset the Anthropic client to force creation with new API key\n resetAnthropicClient()\n\n return apiKey\n }\n\n return null\n } catch (error) {\n throw error\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@ import {
7
7
  logAPIError
8
8
  } from "../utils/debugLogger.js";
9
9
  import { logError } from "../utils/log.js";
10
+ import { setStreamingState } from "../utils/streamingState.js";
10
11
  import {
11
12
  abortableDelay,
12
13
  getRetryDelay as sharedGetRetryDelay
@@ -16,6 +17,11 @@ import {
16
17
  } from "../utils/userFriendlyError.js";
17
18
  import { isOpenAICompatibleProvider } from "../constants/providers.js";
18
19
  import { getEffectiveCapabilities } from "../constants/providerRegistry.js";
20
+ import { resolveApiKey } from "../utils/config.js";
21
+ async function resolveModelApiKey(modelProfile) {
22
+ if (!modelProfile?.apiKey) return "";
23
+ return await resolveApiKey(modelProfile) ?? modelProfile.apiKey;
24
+ }
19
25
  function getRetryDelay(attempt) {
20
26
  return sharedGetRetryDelay(attempt);
21
27
  }
@@ -26,6 +32,7 @@ var ModelErrorType = /* @__PURE__ */ ((ModelErrorType2) => {
26
32
  ModelErrorType2["StreamOptions"] = "stream_options";
27
33
  ModelErrorType2["Citations"] = "citations";
28
34
  ModelErrorType2["RateLimit"] = "rate_limit";
35
+ ModelErrorType2["UnsupportedParam"] = "unsupported_param";
29
36
  return ModelErrorType2;
30
37
  })(ModelErrorType || {});
31
38
  function getModelErrorKey(baseURL, model, type) {
@@ -136,6 +143,20 @@ ${description}
136
143
  delete opts.stream_options;
137
144
  }
138
145
  },
146
+ {
147
+ type: "unsupported_param" /* UnsupportedParam */,
148
+ detect: (errMsg) => {
149
+ const lower = errMsg.toLowerCase();
150
+ return lower.includes("unsupported") && lower.includes("reasoning_effort") || lower.includes("does not support") && lower.includes("reasoning_effort");
151
+ },
152
+ fix: async (opts) => {
153
+ debugLogger.info("OPENAI_FIX", {
154
+ action: "remove_reasoning_effort",
155
+ model: opts.model
156
+ });
157
+ delete opts.reasoning_effort;
158
+ }
159
+ },
139
160
  {
140
161
  type: "citations" /* Citations */,
141
162
  detect: (errMsg) => errMsg.includes("Extra inputs are not permitted") && errMsg.includes("citations"),
@@ -311,6 +332,15 @@ async function applyModelErrorFixes(opts, baseURL) {
311
332
  }
312
333
  }
313
334
  }
335
+ const API_FETCH_TIMEOUT_MS = parseInt(
336
+ process.env.API_TIMEOUT_MS || String(120 * 1e3),
337
+ 10
338
+ );
339
+ function withFetchTimeout(signal) {
340
+ const timeoutSignal = AbortSignal.timeout(API_FETCH_TIMEOUT_MS);
341
+ if (!signal) return timeoutSignal;
342
+ return AbortSignal.any([signal, timeoutSignal]);
343
+ }
314
344
  async function tryWithEndpointFallback(baseURL, opts, headers, provider, proxy, signal) {
315
345
  const endpointsToTry = [];
316
346
  if (provider === "minimax") {
@@ -319,6 +349,7 @@ async function tryWithEndpointFallback(baseURL, opts, headers, provider, proxy,
319
349
  endpointsToTry.push("/chat/completions");
320
350
  }
321
351
  let lastError = null;
352
+ const fetchSignal = withFetchTimeout(signal);
322
353
  for (const endpoint of endpointsToTry) {
323
354
  try {
324
355
  const response = await fetch(`${baseURL}${endpoint}`, {
@@ -326,8 +357,7 @@ async function tryWithEndpointFallback(baseURL, opts, headers, provider, proxy,
326
357
  headers,
327
358
  body: JSON.stringify(opts.stream ? { ...opts, stream: true } : opts),
328
359
  dispatcher: proxy,
329
- signal
330
- // 🔧 Connect AbortSignal to fetch call
360
+ signal: fetchSignal
331
361
  });
332
362
  if (response.ok) {
333
363
  return { response, endpoint };
@@ -355,13 +385,13 @@ async function tryWithEndpointFallback(baseURL, opts, headers, provider, proxy,
355
385
  }
356
386
  throw lastError || new Error("All endpoints failed");
357
387
  }
358
- async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAttempts = 10, signal) {
388
+ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAttempts = 5, signal) {
359
389
  if (attempt >= maxAttempts) {
360
390
  throw new Error("Max attempts reached");
361
391
  }
362
392
  const provider = modelProfile?.provider || "anthropic";
363
393
  const baseURL = modelProfile?.baseURL;
364
- const apiKey = modelProfile?.apiKey;
394
+ const apiKey = await resolveModelApiKey(modelProfile);
365
395
  const proxy = getGlobalConfig().proxy ? new ProxyAgent(getGlobalConfig().proxy) : void 0;
366
396
  const headers = {
367
397
  "Content-Type": "application/json"
@@ -381,7 +411,7 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
381
411
  model: opts.model,
382
412
  provider,
383
413
  apiKeyConfigured: !!apiKey,
384
- apiKeyPrefix: apiKey ? apiKey.substring(0, 8) : null,
414
+ apiKeyPrefix: apiKey ? apiKey.substring(0, 4) + "..." : null,
385
415
  maxTokens: opts.max_tokens,
386
416
  temperature: opts.temperature,
387
417
  messageCount: opts.messages?.length || 0,
@@ -391,6 +421,17 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
391
421
  modelProfileName: modelProfile?.name
392
422
  });
393
423
  opts.messages = opts.messages.map((msg) => {
424
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
425
+ const filtered = msg.content.filter(
426
+ (block) => block.type !== "thinking" && block.type !== "redacted_thinking"
427
+ );
428
+ if (filtered.length !== msg.content.length) {
429
+ return {
430
+ ...msg,
431
+ content: filtered.length > 0 ? filtered : [{ type: "text", text: "" }]
432
+ };
433
+ }
434
+ }
394
435
  if (msg.role === "tool") {
395
436
  if (Array.isArray(msg.content)) {
396
437
  return {
@@ -433,8 +474,7 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
433
474
  headers,
434
475
  body: JSON.stringify({ ...opts, stream: true }),
435
476
  dispatcher: proxy,
436
- signal
437
- // 🔧 CRITICAL FIX: Connect AbortSignal to fetch call
477
+ signal: withFetchTimeout(signal)
438
478
  });
439
479
  }
440
480
  if (!response2.ok) {
@@ -502,6 +542,13 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
502
542
  });
503
543
  }
504
544
  const delayMs = getRetryDelay(attempt);
545
+ setStreamingState({
546
+ phase: "retrying",
547
+ retryCount: attempt + 1,
548
+ maxRetries: maxAttempts,
549
+ errorName: `HTTP ${response2.status}`,
550
+ retryDelayMs: delayMs
551
+ });
505
552
  debugLogger.warn("API_RETRY", {
506
553
  status: response2.status,
507
554
  delayMs,
@@ -546,8 +593,7 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
546
593
  headers,
547
594
  body: JSON.stringify(opts),
548
595
  dispatcher: proxy,
549
- signal
550
- // 🔧 CRITICAL FIX: Connect AbortSignal to non-streaming fetch call
596
+ signal: withFetchTimeout(signal)
551
597
  });
552
598
  }
553
599
  if (!response.ok) {
@@ -592,6 +638,13 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
592
638
  debugLogger.warn("OPENAI_PARSE_ERROR", { status: response.status });
593
639
  }
594
640
  const delayMs = getRetryDelay(attempt);
641
+ setStreamingState({
642
+ phase: "retrying",
643
+ retryCount: attempt + 1,
644
+ maxRetries: maxAttempts,
645
+ errorName: `HTTP ${response.status}`,
646
+ retryDelayMs: delayMs
647
+ });
595
648
  debugLogger.warn("API_RETRY", {
596
649
  status: response.status,
597
650
  delayMs,
@@ -626,6 +679,13 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
626
679
  throw new Error("Request cancelled by user");
627
680
  }
628
681
  const delayMs = getRetryDelay(attempt);
682
+ setStreamingState({
683
+ phase: "retrying",
684
+ retryCount: attempt + 1,
685
+ maxRetries: maxAttempts,
686
+ errorName: error instanceof Error ? error.message.slice(0, 30) : "network error",
687
+ retryDelayMs: delayMs
688
+ });
629
689
  debugLogger.warn("API_RETRY", {
630
690
  error: "network_error",
631
691
  delayMs,
@@ -656,6 +716,10 @@ async function getCompletionWithProfile(modelProfile, opts, attempt = 0, maxAtte
656
716
  });
657
717
  }
658
718
  }
719
+ const STREAM_IDLE_TIMEOUT_MS = parseInt(
720
+ process.env.STREAM_IDLE_TIMEOUT_MS || String(120 * 1e3),
721
+ 10
722
+ );
659
723
  function createStreamProcessor(stream, signal) {
660
724
  if (!stream) {
661
725
  throw new Error("Stream is null or undefined");
@@ -671,7 +735,22 @@ function createStreamProcessor(stream, signal) {
671
735
  }
672
736
  let readResult;
673
737
  try {
674
- readResult = await reader.read();
738
+ readResult = await Promise.race([
739
+ reader.read(),
740
+ new Promise((_, reject) => {
741
+ const timer = setTimeout(
742
+ () => reject(
743
+ new Error(
744
+ `Stream idle timeout: no data received for ${STREAM_IDLE_TIMEOUT_MS / 1e3}s`
745
+ )
746
+ ),
747
+ STREAM_IDLE_TIMEOUT_MS
748
+ );
749
+ signal?.addEventListener("abort", () => clearTimeout(timer), {
750
+ once: true
751
+ });
752
+ })
753
+ ]);
675
754
  } catch (e) {
676
755
  if (signal?.aborted) {
677
756
  break;
@@ -742,7 +821,7 @@ function streamCompletion(stream, signal) {
742
821
  }
743
822
  async function callGPT5ResponsesAPI(modelProfile, opts, signal) {
744
823
  const baseURL = modelProfile?.baseURL || "https://api.openai.com/v1";
745
- const apiKey = modelProfile?.apiKey;
824
+ const apiKey = await resolveModelApiKey(modelProfile);
746
825
  const proxy = getGlobalConfig().proxy ? new ProxyAgent(getGlobalConfig().proxy) : void 0;
747
826
  const headers = {
748
827
  "Content-Type": "application/json",
@@ -792,14 +871,6 @@ async function callGPT5ResponsesAPI(modelProfile, opts, signal) {
792
871
  // Balanced for most coding tasks
793
872
  };
794
873
  }
795
- if (!responsesParams.instructions) {
796
- responsesParams.instructions = `You are an expert programmer working in a terminal-based coding environment. Follow these guidelines:
797
- - Provide clear, concise code solutions
798
- - Use proper error handling and validation
799
- - Follow coding best practices and patterns
800
- - Explain complex logic when necessary
801
- - Focus on maintainable, readable code`;
802
- }
803
874
  }
804
875
  try {
805
876
  const response = await fetch(`${baseURL}/responses`, {
@@ -883,7 +954,7 @@ ${mainContent}`;
883
954
  }
884
955
  };
885
956
  }
886
- async function getGPT5CompletionWithProfile(modelProfile, opts, attempt = 0, maxAttempts = 10, signal) {
957
+ async function getGPT5CompletionWithProfile(modelProfile, opts, attempt = 0, maxAttempts = 5, signal) {
887
958
  const features = getModelFeatures(opts.model);
888
959
  const isOfficialOpenAI = !modelProfile.baseURL || modelProfile.baseURL.includes("api.openai.com");
889
960
  if (features.supportsResponsesAPI && !opts.stream && isOfficialOpenAI) {