titan-agent 6.5.2 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +180 -53
  2. package/assets/agent-skills/NOTICE-ECC.md +39 -0
  3. package/assets/agent-skills/agent-introspection-debugging/SKILL.md +153 -0
  4. package/assets/agent-skills/continuous-agent-loop/SKILL.md +45 -0
  5. package/assets/agent-skills/continuous-learning/SKILL.md +131 -0
  6. package/assets/agent-skills/continuous-learning/config.json +18 -0
  7. package/assets/agent-skills/continuous-learning/evaluate-session.sh +69 -0
  8. package/assets/agent-skills/production-audit/SKILL.md +206 -0
  9. package/assets/agent-skills/recursive-decision-ledger/SKILL.md +79 -0
  10. package/assets/agent-skills/scientific-thinking-literature-review/SKILL.md +192 -0
  11. package/assets/agent-skills/scientific-thinking-scholar-evaluation/SKILL.md +160 -0
  12. package/assets/agent-skills/verification-loop/SKILL.md +126 -0
  13. package/dist/agent/agent.js +67 -26
  14. package/dist/agent/agent.js.map +1 -1
  15. package/dist/agent/agentLoop.js +6 -2
  16. package/dist/agent/agentLoop.js.map +1 -1
  17. package/dist/agent/autoModeClassifier.js +26 -2
  18. package/dist/agent/autoModeClassifier.js.map +1 -1
  19. package/dist/agent/goalDriver.js +2 -0
  20. package/dist/agent/goalDriver.js.map +1 -1
  21. package/dist/agent/goalSpec.js +229 -0
  22. package/dist/agent/goalSpec.js.map +1 -0
  23. package/dist/agent/heartbeat.js +130 -0
  24. package/dist/agent/heartbeat.js.map +1 -0
  25. package/dist/agent/missionDecompose.js +38 -0
  26. package/dist/agent/missionDecompose.js.map +1 -0
  27. package/dist/agent/muscleMemory.js +291 -0
  28. package/dist/agent/muscleMemory.js.map +1 -0
  29. package/dist/agent/observationWriter.js +56 -0
  30. package/dist/agent/observationWriter.js.map +1 -0
  31. package/dist/agent/promptSectionCaps.js +6 -0
  32. package/dist/agent/promptSectionCaps.js.map +1 -1
  33. package/dist/agent/reminders.js +101 -0
  34. package/dist/agent/reminders.js.map +1 -0
  35. package/dist/agent/systemWidgets.js +41 -0
  36. package/dist/agent/systemWidgets.js.map +1 -0
  37. package/dist/agent/toolRunner.js +24 -0
  38. package/dist/agent/toolRunner.js.map +1 -1
  39. package/dist/agent/toolSearch.js +3 -0
  40. package/dist/agent/toolSearch.js.map +1 -1
  41. package/dist/channels/messenger.js +39 -0
  42. package/dist/channels/messenger.js.map +1 -1
  43. package/dist/config/config.js +7 -0
  44. package/dist/config/config.js.map +1 -1
  45. package/dist/config/schema.js +18 -1
  46. package/dist/config/schema.js.map +1 -1
  47. package/dist/eval/harness.js +13 -3
  48. package/dist/eval/harness.js.map +1 -1
  49. package/dist/gateway/onboarding.js +91 -0
  50. package/dist/gateway/onboarding.js.map +1 -0
  51. package/dist/gateway/routes/skills.js +2 -1
  52. package/dist/gateway/routes/skills.js.map +1 -1
  53. package/dist/gateway/routes/studioRouter.js +88 -0
  54. package/dist/gateway/routes/studioRouter.js.map +1 -0
  55. package/dist/gateway/routes/watchRouter.js +4 -4
  56. package/dist/gateway/routes/watchRouter.js.map +1 -1
  57. package/dist/gateway/server.js +251 -43
  58. package/dist/gateway/server.js.map +1 -1
  59. package/dist/memory/taxonomy.js +117 -0
  60. package/dist/memory/taxonomy.js.map +1 -0
  61. package/dist/providers/modelCapabilities.js +13 -0
  62. package/dist/providers/modelCapabilities.js.map +1 -1
  63. package/dist/providers/ollama.js +8 -2
  64. package/dist/providers/ollama.js.map +1 -1
  65. package/dist/providers/openai.js +1 -1
  66. package/dist/providers/openai.js.map +1 -1
  67. package/dist/providers/openai_compat.js +38 -2
  68. package/dist/providers/openai_compat.js.map +1 -1
  69. package/dist/providers/router.js +14 -0
  70. package/dist/providers/router.js.map +1 -1
  71. package/dist/recipes/runner.js +8 -1
  72. package/dist/recipes/runner.js.map +1 -1
  73. package/dist/recipes/store.js +2 -1
  74. package/dist/recipes/store.js.map +1 -1
  75. package/dist/skills/builtin/codebase_explore.js +214 -0
  76. package/dist/skills/builtin/codebase_explore.js.map +1 -0
  77. package/dist/skills/builtin/config_audit.js +160 -0
  78. package/dist/skills/builtin/config_audit.js.map +1 -0
  79. package/dist/skills/builtin/delegate_agent.js +107 -0
  80. package/dist/skills/builtin/delegate_agent.js.map +1 -0
  81. package/dist/skills/builtin/memory_map.js +38 -0
  82. package/dist/skills/builtin/memory_map.js.map +1 -0
  83. package/dist/skills/builtin/reminders.js +67 -0
  84. package/dist/skills/builtin/reminders.js.map +1 -0
  85. package/dist/skills/builtin/spec.js +139 -0
  86. package/dist/skills/builtin/spec.js.map +1 -0
  87. package/dist/skills/builtin/widget_gallery.js +12 -5
  88. package/dist/skills/builtin/widget_gallery.js.map +1 -1
  89. package/dist/skills/frontmatterLoader.js +7 -1
  90. package/dist/skills/frontmatterLoader.js.map +1 -1
  91. package/dist/skills/registry.js +12 -0
  92. package/dist/skills/registry.js.map +1 -1
  93. package/dist/substrate/traceBus.js.map +1 -1
  94. package/dist/telemetry/traceStore.js +127 -0
  95. package/dist/telemetry/traceStore.js.map +1 -0
  96. package/dist/utils/constants.js +1 -1
  97. package/dist/utils/constants.js.map +1 -1
  98. package/dist/utils/contrast.js +69 -0
  99. package/dist/utils/contrast.js.map +1 -0
  100. package/dist/watch/sessionContext.js +14 -0
  101. package/dist/watch/sessionContext.js.map +1 -0
  102. package/dist/watch/sessionTrace.js +51 -0
  103. package/dist/watch/sessionTrace.js.map +1 -0
  104. package/dist/watch/studioBuffer.js +53 -0
  105. package/dist/watch/studioBuffer.js.map +1 -0
  106. package/package.json +4 -3
  107. package/ui/dist/assets/AboutYouMemory-CZKEOd_O.js +11 -0
  108. package/ui/dist/assets/AuditPanel-Bu71N5Er.js +1 -0
  109. package/ui/dist/assets/{AutonomyPanel-CmaXJV8d.js → AutonomyPanel-DB-39dX4.js} +2 -2
  110. package/ui/dist/assets/{AutopilotPanel-CbohPtXW.js → AutopilotPanel-Cj8oKxWv.js} +1 -1
  111. package/ui/dist/assets/{AutoresearchPanel-DCwiQ2v2.js → AutoresearchPanel-3s8pjm6Z.js} +2 -2
  112. package/ui/dist/assets/BackupPanel-EUQJMJE7.js +1 -0
  113. package/ui/dist/assets/{BrowserPanel-D6UaSxap.js → BrowserPanel-Beo4F5Ar.js} +2 -2
  114. package/ui/dist/assets/Button-MdXmb4_n.js +1 -0
  115. package/ui/dist/assets/CPActivity-B1Se9VVc.js +1 -0
  116. package/ui/dist/assets/CPAgentDetail-BYji6tT8.js +1 -0
  117. package/ui/dist/assets/CPAgents-BSUKucTe.js +1 -0
  118. package/ui/dist/assets/CPApprovals-B4v0em6e.js +1 -0
  119. package/ui/dist/assets/CPCosts-9ikh61Kv.js +1 -0
  120. package/ui/dist/assets/CPDashboard-sOok2T5v.js +1 -0
  121. package/ui/dist/assets/{CPFiles-BO73EZwJ.js → CPFiles-DB2nY5JE.js} +1 -1
  122. package/ui/dist/assets/CPGoals-8Z1yOY8e.js +1 -0
  123. package/ui/dist/assets/CPInbox-Cq6-UY8F.js +11 -0
  124. package/ui/dist/assets/CPIssueDetail-NAGfmJg8.js +1 -0
  125. package/ui/dist/assets/CPIssues-BzX6Rckx.js +1 -0
  126. package/ui/dist/assets/CPLayout-BcRM6QSg.js +2 -0
  127. package/ui/dist/assets/CPOrg-B7DQ4UQP.js +1 -0
  128. package/ui/dist/assets/CPRuns-D-cpPw_M.js +1 -0
  129. package/ui/dist/assets/{CPSocial-Qw5rKy_4.js → CPSocial-DshtmcK0.js} +3 -3
  130. package/ui/dist/assets/CPVoice-DfXRnQVU.js +1 -0
  131. package/ui/dist/assets/{ChannelsPanel-DS21E-Iz.js → ChannelsPanel-BnaTOeyf.js} +1 -1
  132. package/ui/dist/assets/CheckpointsPanel-C62naE4U.js +1 -0
  133. package/ui/dist/assets/CommandPostHub-B_L1CAss.js +24 -0
  134. package/ui/dist/assets/ConfirmDialog-VErHWAbo.js +1 -0
  135. package/ui/dist/assets/CronPanel-BwMrrZ5d.js +1 -0
  136. package/ui/dist/assets/{DataTable-PnhPeDBG.js → DataTable-BCqSUuN7.js} +1 -1
  137. package/ui/dist/assets/{DreamPanel-DIrtlk2K.js → DreamPanel-BNAcCLBB.js} +2 -2
  138. package/ui/dist/assets/EmptyState-D9kQf1PX.js +1 -0
  139. package/ui/dist/assets/{EvalHarnessPanel-uYb_ZEQG.js → EvalHarnessPanel-BaMLdBNm.js} +2 -2
  140. package/ui/dist/assets/EvalPanel-CW-SSjtg.js +1 -0
  141. package/ui/dist/assets/{FileViewer-CVO3TRs3.js → FileViewer-BL00nsd7.js} +1 -1
  142. package/ui/dist/assets/FilesPanel-CeC6YUSd.js +16 -0
  143. package/ui/dist/assets/FleetPanel-EyWF7l3W.js +1 -0
  144. package/ui/dist/assets/{HomelabPanel-BZvN4LPM.js → HomelabPanel-BRfKRYe7.js} +2 -2
  145. package/ui/dist/assets/InfraView-Jmqhg_Yc.js +2 -0
  146. package/ui/dist/assets/{InlineEditableField-mBzpbcLB.js → InlineEditableField-DgMrLDj1.js} +1 -1
  147. package/ui/dist/assets/Input-CBTwa_Iw.js +1 -0
  148. package/ui/dist/assets/IntegrationsPanel-DQL-7Ec6.js +1 -0
  149. package/ui/dist/assets/IntelligenceView-DxD78qfP.js +2 -0
  150. package/ui/dist/assets/LearningPanel-C_JzSbJU.js +1 -0
  151. package/ui/dist/assets/LiveStudio-Db5yeaWo.js +7 -0
  152. package/ui/dist/assets/{LogsPanel-DbP3Mwnr.js → LogsPanel-CpinKwaZ.js} +1 -1
  153. package/ui/dist/assets/McpPanel-D-MqN_f-.js +1 -0
  154. package/ui/dist/assets/MemoryGraphPanel-BnD5jRqf.js +1 -0
  155. package/ui/dist/assets/MemoryTaxonomyPanel-BBI202dd.js +6 -0
  156. package/ui/dist/assets/MemoryWikiPanel-Dn3XZHL0.js +6 -0
  157. package/ui/dist/assets/{MeshPanel-Bf-4brXL.js → MeshPanel-C-mRJpr0.js} +1 -1
  158. package/ui/dist/assets/{MissionCanvas-CJyhnauG.js → MissionCanvas-CbZW83Ch.js} +1 -1
  159. package/ui/dist/assets/{MissionChat-C2Nto3zM.js → MissionChat-Bs75jPAD.js} +1 -1
  160. package/ui/dist/assets/{MissionLibrary-RXyBHsLL.js → MissionLibrary-BxQ6SxPe.js} +1 -1
  161. package/ui/dist/assets/MissionStart-CBuBPasl.js +1 -0
  162. package/ui/dist/assets/Modal-ybPGvlQs.js +9 -0
  163. package/ui/dist/assets/{NvidiaPanel-4DlcQlyl.js → NvidiaPanel-DdG13OX4.js} +1 -1
  164. package/ui/dist/assets/OrganismPanel-xZWUJKyr.js +1 -0
  165. package/ui/dist/assets/OverviewPanel-B45ZYhJV.js +1 -0
  166. package/ui/dist/assets/{PageHeader-bnc85wQN.js → PageHeader-DdrbS1aq.js} +1 -1
  167. package/ui/dist/assets/PersonaProfilesPanel-CKER-EU5.js +8 -0
  168. package/ui/dist/assets/{PersonasPanel-dR8VppcD.js → PersonasPanel-CMMQ3nh3.js} +1 -1
  169. package/ui/dist/assets/{PhoneDeskPanel-CdVOY7H9.js → PhoneDeskPanel-Bw_Y-cVE.js} +2 -2
  170. package/ui/dist/assets/RecipesPanel-DzMcxpJJ.js +1 -0
  171. package/ui/dist/assets/SecurityPanel-BCq3Fzbr.js +1 -0
  172. package/ui/dist/assets/SelfImprovePanel-YE3hT8jK.js +1 -0
  173. package/ui/dist/assets/SelfProposalsPanel-DXuqBM6p.js +1 -0
  174. package/ui/dist/assets/SessionsPanel-DORz5goR.js +1 -0
  175. package/ui/dist/assets/SessionsTab-qYHDOuC8.js +1 -0
  176. package/ui/dist/assets/SettingsPanel-BbwPu1i7.js +1 -0
  177. package/ui/dist/assets/SettingsView-zgqkDDBJ.js +2 -0
  178. package/ui/dist/assets/{SkeletonLoader-Cax7YTqW.js → SkeletonLoader-r6OGXaU9.js} +1 -1
  179. package/ui/dist/assets/SkillsPanel-BjEOBMRo.js +11 -0
  180. package/ui/dist/assets/{SomaView-eG3wI4S1.js → SomaView-DLzApZVW.js} +2 -2
  181. package/ui/dist/assets/{StatCard-Djr487DV.js → StatCard-DLq8aBps.js} +1 -1
  182. package/ui/dist/assets/{StatusBadge-JpCoA33_.js → StatusBadge-BqlvIbdj.js} +1 -1
  183. package/ui/dist/assets/{Tabs-DJHu-roP.js → Tabs-DdUThlp1.js} +1 -1
  184. package/ui/dist/assets/TeamsPanel-uIIKoU7I.js +1 -0
  185. package/ui/dist/assets/{TelemetryPanel-D4PXsd-X.js → TelemetryPanel-dVr3yQQr.js} +1 -1
  186. package/ui/dist/assets/TitanCanvas-xHAJqwG2.js +945 -0
  187. package/ui/dist/assets/ToolsView-CG1mZdiy.js +2 -0
  188. package/ui/dist/assets/{Tooltip-B1LhTXJ8.js → Tooltip-C2tXJcrN.js} +1 -1
  189. package/ui/dist/assets/TraceViewer-BIMD_Osr.js +1 -0
  190. package/ui/dist/assets/TracesPanel-nMUiyMj5.js +1 -0
  191. package/ui/dist/assets/TrainingPanel-CT5R4HWm.js +1 -0
  192. package/ui/dist/assets/{VoiceOverlay-B_ss7Zg_.js → VoiceOverlay-Br4QnCtw.js} +3 -3
  193. package/ui/dist/assets/VramPanel-CdnJYytg.js +1 -0
  194. package/ui/dist/assets/WatchView-TNU6Ns1Q.js +13 -0
  195. package/ui/dist/assets/WorkTab-wTlX_UKP.js +1 -0
  196. package/ui/dist/assets/WorkflowBuilderPanel-CDpVt5ux.js +6 -0
  197. package/ui/dist/assets/WorkflowsPanel-zsFqsLdn.js +11 -0
  198. package/ui/dist/assets/{archive-gZFnGd5A.js → archive-Bh689DNg.js} +1 -1
  199. package/ui/dist/assets/{arrow-left-qA0Qer2h.js → arrow-left-WkVYLm80.js} +1 -1
  200. package/ui/dist/assets/{book-open-DIxdPqmD.js → book-open-ohEXgUsS.js} +1 -1
  201. package/ui/dist/assets/{bot-CvIF1uHi.js → bot-DvEcyQcD.js} +1 -1
  202. package/ui/dist/assets/{chart-column-BQiM-Td4.js → chart-column-w3goFd5f.js} +1 -1
  203. package/ui/dist/assets/{check-DgyDEFtq.js → check-CuRYh4Zh.js} +1 -1
  204. package/ui/dist/assets/{chevron-right-CQ1NTOtd.js → chevron-right-DbLSHmff.js} +1 -1
  205. package/ui/dist/assets/{circle-check-big-CAFcaPPH.js → circle-check-big-Bkba568b.js} +1 -1
  206. package/ui/dist/assets/{circle-stop-C-8xGv0n.js → circle-stop-Bx2ohEg8.js} +1 -1
  207. package/ui/dist/assets/{clipboard-list-9DdqBj1F.js → clipboard-list-Dj9tORnu.js} +1 -1
  208. package/ui/dist/assets/{clock-CF9BCIpL.js → clock-JyQAYy6X.js} +1 -1
  209. package/ui/dist/assets/{dollar-sign-LDRZBae6.js → dollar-sign-XxwPAA2a.js} +1 -1
  210. package/ui/dist/assets/{download-BBNXvBO0.js → download-D1izVEOL.js} +1 -1
  211. package/ui/dist/assets/{external-link-D_ji4Bec.js → external-link-DZ_rZsIt.js} +1 -1
  212. package/ui/dist/assets/{file-text-DrdTDEYp.js → file-text-Cfawu8Bs.js} +1 -1
  213. package/ui/dist/assets/{flask-conical-BGn5PgFX.js → flask-conical-Ql8QxhgY.js} +1 -1
  214. package/ui/dist/assets/{folder-BeZZUGnK.js → folder-DAdIw-Pb.js} +1 -1
  215. package/ui/dist/assets/{funnel-CAJgGO5M.js → funnel-FycfZcXo.js} +1 -1
  216. package/ui/dist/assets/{git-branch-BcXabeOs.js → git-branch-C2qrhGGu.js} +1 -1
  217. package/ui/dist/assets/index-Cml2x9pA.js +507 -0
  218. package/ui/dist/assets/index-yWybhcfI.css +1 -0
  219. package/ui/dist/assets/{layers-DxYDmPA_.js → layers-yzjtGlHB.js} +1 -1
  220. package/ui/dist/assets/{legacy-dHWI7k8P.js → legacy-D21WSMF1.js} +1 -1
  221. package/ui/dist/assets/{lightbulb-B0Du4SM4.js → lightbulb-BZJNK69S.js} +1 -1
  222. package/ui/dist/assets/{link-CUpaumqr.js → link-CnFkBkaY.js} +1 -1
  223. package/ui/dist/assets/{list-todo-CDDhmPQB.js → list-todo-BlgfQHup.js} +1 -1
  224. package/ui/dist/assets/{message-square-D5VWlv-Q.js → message-square-CRsG9u6_.js} +1 -1
  225. package/ui/dist/assets/{mic-Ddcc6Ann.js → mic-B32RHc7Y.js} +1 -1
  226. package/ui/dist/assets/{missions-2zox16Tc.js → missions-1iw8Z2_0.js} +1 -1
  227. package/ui/dist/assets/{network-DaJ7ugwX.js → network-C9RXQGrV.js} +1 -1
  228. package/ui/dist/assets/{pause-BukaK6rs.js → pause-BT1Bc2q3.js} +1 -1
  229. package/ui/dist/assets/{pencil-D_YwQBeg.js → pencil-BK5IU6o0.js} +1 -1
  230. package/ui/dist/assets/{play-BjdwtYMk.js → play-Cl1nC_gc.js} +1 -1
  231. package/ui/dist/assets/{plug-yISDdeW2.js → plug-DvcpOalj.js} +1 -1
  232. package/ui/dist/assets/{plus-BSjTdepW.js → plus-Dpo1qfrl.js} +1 -1
  233. package/ui/dist/assets/{radio-B7kX_yWE.js → radio-C5c9IyqX.js} +1 -1
  234. package/ui/dist/assets/{refresh-cw-CwDpzXUn.js → refresh-cw-C-iZkzuS.js} +1 -1
  235. package/ui/dist/assets/{rotate-ccw-7SQDTI0_.js → rotate-ccw-qzrB3SNw.js} +1 -1
  236. package/ui/dist/assets/{save-CjTPAQM0.js → save-DwR9wQVu.js} +1 -1
  237. package/ui/dist/assets/{search-BP7VlNxX.js → search-D10l0m3-.js} +1 -1
  238. package/ui/dist/assets/{send-C2XDuRPf.js → send-DtXGsaFW.js} +1 -1
  239. package/ui/dist/assets/{server-BE8W-AT4.js → server-BzisF3LL.js} +1 -1
  240. package/ui/dist/assets/settings-Dbwd1_-c.js +6 -0
  241. package/ui/dist/assets/{shield-check-s7la2J2K.js → shield-check-CXlDJyAW.js} +1 -1
  242. package/ui/dist/assets/square-BBC-JKzY.js +11 -0
  243. package/ui/dist/assets/{terminal-B8IK4WsO.js → terminal-DaBIlWEM.js} +1 -1
  244. package/ui/dist/assets/{test-tube-Xfn9DJeg.js → test-tube-CDATRD5t.js} +1 -1
  245. package/ui/dist/assets/{toggle-right-CHpzOIlj.js → toggle-right-DTmrC5RD.js} +1 -1
  246. package/ui/dist/assets/{trash-2-B1C85ePK.js → trash-2-CTeyjxD_.js} +1 -1
  247. package/ui/dist/assets/{trending-up-DDGHQZY1.js → trending-up-CXPRjRV4.js} +1 -1
  248. package/ui/dist/assets/{trophy-D0LhJSPA.js → trophy-DbVdXRtU.js} +1 -1
  249. package/ui/dist/assets/{volume-2-DMaE91b5.js → volume-2-DYDBmm3M.js} +1 -1
  250. package/ui/dist/assets/{wifi-off-DR9h8HGA.js → wifi-off-BBuIGbiP.js} +1 -1
  251. package/ui/dist/assets/zoom-out-D47_pRAO.js +16 -0
  252. package/ui/dist/index.html +2 -2
  253. package/ui/dist/sw.js +1 -1
  254. package/ui/dist/assets/AuditPanel-BaftX5MP.js +0 -1
  255. package/ui/dist/assets/BackupPanel-DAy9G7Wt.js +0 -1
  256. package/ui/dist/assets/CPActivity-BYDsUoMn.js +0 -1
  257. package/ui/dist/assets/CPAgentDetail-Bb9-GAJY.js +0 -1
  258. package/ui/dist/assets/CPAgents-BTZuGnki.js +0 -1
  259. package/ui/dist/assets/CPApprovals-BME2ARkO.js +0 -1
  260. package/ui/dist/assets/CPCosts-mOXwWq0i.js +0 -1
  261. package/ui/dist/assets/CPDashboard-CTlKGXXQ.js +0 -1
  262. package/ui/dist/assets/CPGoals-BNWhNP14.js +0 -1
  263. package/ui/dist/assets/CPInbox-ybe4r8LW.js +0 -16
  264. package/ui/dist/assets/CPIssueDetail-DaMMGbjw.js +0 -1
  265. package/ui/dist/assets/CPIssues-BgpQOISw.js +0 -1
  266. package/ui/dist/assets/CPLayout-bgErauTx.js +0 -2
  267. package/ui/dist/assets/CPOrg-C8l5SIWJ.js +0 -8
  268. package/ui/dist/assets/CPRuns-DB8S7loF.js +0 -1
  269. package/ui/dist/assets/CPVoice-DfwHPewA.js +0 -1
  270. package/ui/dist/assets/CheckpointsPanel-9-l_8GdG.js +0 -1
  271. package/ui/dist/assets/CommandPostHub-z55Yrhj1.js +0 -24
  272. package/ui/dist/assets/CronPanel-kEZK3gpx.js +0 -1
  273. package/ui/dist/assets/EmptyState-CfvU7SdB.js +0 -1
  274. package/ui/dist/assets/EvalPanel-CDG-njyj.js +0 -1
  275. package/ui/dist/assets/FilesPanel-CaLPog2e.js +0 -16
  276. package/ui/dist/assets/FleetPanel-BtlaV6pH.js +0 -1
  277. package/ui/dist/assets/InfraView-C0zEuFrR.js +0 -2
  278. package/ui/dist/assets/Input-CbrMbLgn.js +0 -1
  279. package/ui/dist/assets/IntegrationsPanel-B4TyR6jC.js +0 -1
  280. package/ui/dist/assets/IntelligenceView-DZ4HxYZ3.js +0 -2
  281. package/ui/dist/assets/LearningPanel-B4RIm_iQ.js +0 -1
  282. package/ui/dist/assets/McpPanel-BmNUFozc.js +0 -1
  283. package/ui/dist/assets/MemoryGraphPanel-JPurHV0L.js +0 -16
  284. package/ui/dist/assets/MemoryWikiPanel-DdvCAZHa.js +0 -6
  285. package/ui/dist/assets/MissionStart-wUkcEP0T.js +0 -1
  286. package/ui/dist/assets/Modal-BmS7C6FN.js +0 -1
  287. package/ui/dist/assets/OrganismPanel-C2LYDPrn.js +0 -1
  288. package/ui/dist/assets/OverviewPanel-DK8uuq4D.js +0 -1
  289. package/ui/dist/assets/PersonaProfilesPanel-DGtokXUu.js +0 -8
  290. package/ui/dist/assets/RecipesPanel-D3Zs2wxr.js +0 -1
  291. package/ui/dist/assets/SecurityPanel-BMERf796.js +0 -1
  292. package/ui/dist/assets/SelfImprovePanel-BxqWHXCU.js +0 -1
  293. package/ui/dist/assets/SelfProposalsPanel-CuC94vdx.js +0 -2
  294. package/ui/dist/assets/SessionsPanel-CQ8qvzp7.js +0 -1
  295. package/ui/dist/assets/SessionsTab-B3eHV3jf.js +0 -1
  296. package/ui/dist/assets/SettingsPanel-Cumls7N2.js +0 -1
  297. package/ui/dist/assets/SettingsView-BtA67pol.js +0 -2
  298. package/ui/dist/assets/SkillsPanel-CA415CT8.js +0 -11
  299. package/ui/dist/assets/TeamsPanel-C_Vu6vnY.js +0 -1
  300. package/ui/dist/assets/TitanCanvas-TuYZSZO7.js +0 -1117
  301. package/ui/dist/assets/ToolsView-BvTN6vFn.js +0 -2
  302. package/ui/dist/assets/TraceViewer-Bh8Jo3Dr.js +0 -1
  303. package/ui/dist/assets/TrainingPanel-Dmbd1rJ-.js +0 -1
  304. package/ui/dist/assets/VramPanel-CPICbZ2s.js +0 -1
  305. package/ui/dist/assets/WatchView-BCgLVfiV.js +0 -13
  306. package/ui/dist/assets/WorkTab-iptofXO9.js +0 -1
  307. package/ui/dist/assets/WorkflowsPanel-3RYkFHyf.js +0 -11
  308. package/ui/dist/assets/chevron-up-UyfdjRp6.js +0 -6
  309. package/ui/dist/assets/index-CUgepw5Q.js +0 -337
  310. package/ui/dist/assets/index-Dm6zcSTS.css +0 -1
  311. package/ui/dist/assets/proxy-CWET5FFX.js +0 -9
@@ -148,7 +148,7 @@ class OpenAIProvider extends LLMProvider {
148
148
  })
149
149
  };
150
150
  if (isReasoningModel) {
151
- body.max_completion_tokens = options.maxTokens || 8192;
151
+ body.max_completion_tokens = clampMaxTokens(model, options.maxTokens);
152
152
  } else {
153
153
  body.max_tokens = clampMaxTokens(model, options.maxTokens);
154
154
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/openai.ts"],"sourcesContent":["/**\n * TITAN — OpenAI Provider (GPT-4, o-series)\n */\nimport {\n LLMProvider,\n withTimeoutSignal,\n STREAM_FETCH_TIMEOUT_MS,\n type ChatOptions,\n type ChatResponse,\n type ChatStreamChunk,\n type ToolCall,\n} from './base.js';\nimport { loadConfig } from '../config/config.js';\nimport logger from '../utils/logger.js';\nimport { fetchWithRetry } from '../utils/helpers.js';\nimport { resolveApiKey } from './authResolver.js';\nimport { v4 as uuid } from 'uuid';\nimport { clampMaxTokens } from './modelCapabilities.js';\n\nconst COMPONENT = 'OpenAI';\n\nexport class OpenAIProvider extends LLMProvider {\n readonly name = 'openai';\n readonly displayName = 'OpenAI (GPT)';\n\n private get apiKey(): string {\n const config = loadConfig();\n const p = config.providers.openai;\n return resolveApiKey('openai', p.authProfiles || [], p.apiKey || '', 'OPENAI_API_KEY', p.rotationStrategy, p.credentialCooldownMs);\n }\n\n private get baseUrl(): string {\n const config = loadConfig();\n return config.providers.openai.baseUrl || 'https://api.openai.com';\n }\n\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const model = options.model || 'gpt-4o';\n const apiKey = this.apiKey;\n if (!apiKey) throw new Error('OpenAI API key not configured');\n\n logger.debug(COMPONENT, `Chat request: model=${model}, messages=${options.messages.length}`);\n\n const cleanModel = model.replace('openai/', '');\n const isReasoningModel = /^(o1|o3|o4)/.test(cleanModel);\n\n const body: Record<string, unknown> = {\n model: cleanModel,\n messages: options.messages.map((m) => {\n if (m.role === 'tool') {\n return { role: 'tool', content: m.content, tool_call_id: m.toolCallId };\n }\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant',\n content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.function.name, arguments: tc.function.arguments },\n })),\n };\n }\n // o-series reasoning models use 'developer' role instead of 'system'\n if (m.role === 'system' && isReasoningModel) {\n return { role: 'developer', content: m.content };\n }\n return { role: m.role, content: m.content };\n }),\n };\n\n // o-series models require max_completion_tokens, not max_tokens\n if (isReasoningModel) {\n body.max_completion_tokens = clampMaxTokens(model, options.maxTokens);\n } else {\n body.max_tokens = clampMaxTokens(model, options.maxTokens);\n }\n\n if (options.tools && options.tools.length > 0) {\n body.tools = options.tools;\n // Force at least one tool call on first round when task requires it.\n // Use \"auto\" for o-series (they manage tool use internally via reasoning).\n if (options.forceToolUse && !isReasoningModel) {\n body.tool_choice = 'required';\n }\n }\n\n // o-series models reject the temperature parameter\n if (options.temperature !== undefined && !isReasoningModel) {\n body.temperature = options.temperature;\n }\n\n // Reasoning effort for o-series models\n if (options.thinking && isReasoningModel) {\n const effortMap: Record<string, string> = { low: 'low', medium: 'medium', high: 'high' };\n body.reasoning_effort = effortMap[options.thinkingLevel || 'medium'] || 'medium';\n }\n\n const response = await fetchWithRetry(`${this.baseUrl}/v1/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n // Hunt Finding #37: attach status + Retry-After so the router can respect backoff\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError('OpenAI API', response, errorText, { provider: 'openai', model });\n }\n\n const data = await response.json() as Record<string, unknown>;\n const choices = data.choices as Array<Record<string, unknown>> | undefined;\n\n if (!choices || choices.length === 0) {\n return {\n id: (data.id as string) || uuid(),\n content: '',\n usage: undefined,\n finishReason: 'stop',\n model,\n };\n }\n\n const choice = choices[0];\n const message = choice.message as Record<string, unknown>;\n\n const toolCalls: ToolCall[] = [];\n if (message.tool_calls) {\n for (const tc of message.tool_calls as Array<Record<string, unknown>>) {\n const fn = tc.function as Record<string, string>;\n toolCalls.push({\n id: tc.id as string,\n type: 'function',\n function: { name: fn.name, arguments: fn.arguments },\n });\n }\n }\n\n const usage = data.usage as { prompt_tokens: number; completion_tokens: number; total_tokens: number } | undefined;\n\n return {\n id: (data.id as string) || uuid(),\n content: (message.content as string) || '',\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n usage: usage\n ? {\n promptTokens: usage.prompt_tokens,\n completionTokens: usage.completion_tokens,\n totalTokens: usage.total_tokens,\n }\n : undefined,\n finishReason: toolCalls.length > 0 ? 'tool_calls' : (choice.finish_reason as 'stop' | 'length') || 'stop',\n model,\n };\n }\n\n async *chatStream(options: ChatOptions): AsyncGenerator<ChatStreamChunk> {\n const model = options.model || 'gpt-4o';\n const apiKey = this.apiKey;\n if (!apiKey) { yield { type: 'error', error: 'OpenAI API key not configured' }; return; }\n\n const cleanModel = model.replace('openai/', '');\n const isReasoningModel = /^(o1|o3|o4)/.test(cleanModel);\n\n const body: Record<string, unknown> = {\n model: cleanModel,\n stream: true,\n messages: options.messages.map((m) => {\n if (m.role === 'tool') return { role: 'tool', content: m.content, tool_call_id: m.toolCallId };\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant', content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({ id: tc.id, type: 'function', function: { name: tc.function.name, arguments: tc.function.arguments } })),\n };\n }\n if (m.role === 'system' && isReasoningModel) return { role: 'developer', content: m.content };\n return { role: m.role, content: m.content };\n }),\n };\n\n if (isReasoningModel) { body.max_completion_tokens = options.maxTokens || 8192; }\n else { body.max_tokens = clampMaxTokens(model, options.maxTokens); }\n if (options.tools && options.tools.length > 0) body.tools = options.tools;\n if (options.temperature !== undefined && !isReasoningModel) body.temperature = options.temperature;\n\n // Reasoning effort for o-series models\n if (options.thinking && isReasoningModel) {\n const effortMap: Record<string, string> = { low: 'low', medium: 'medium', high: 'high' };\n body.reasoning_effort = effortMap[options.thinkingLevel || 'medium'] || 'medium';\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/v1/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },\n body: JSON.stringify(body),\n signal: withTimeoutSignal(options.signal, STREAM_FETCH_TIMEOUT_MS),\n });\n\n if (!response.ok || !response.body) {\n const errorText = await response.text();\n // v6.5 — THROW (not yield) so the router routes HTTP errors through\n // retry / fallback chain / circuit breaker, exactly like the\n // non-streaming chat() path. A yielded error chunk dead-ends the\n // SSE path with no failover.\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError('OpenAI API', response, errorText, { provider: 'openai', model });\n }\n\n const toolCalls = new Map<number, { id: string; name: string; args: string }>();\n yield* this.parseOpenAISSE(response.body, toolCalls);\n } catch (error) {\n yield { type: 'error', error: (error as Error).message };\n }\n }\n\n /** Parse OpenAI-format SSE stream and yield ChatStreamChunks */\n private async *parseOpenAISSE(\n body: ReadableStream<Uint8Array>,\n toolCalls: Map<number, { id: string; name: string; args: string }>,\n ): AsyncGenerator<ChatStreamChunk> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const json = line.slice(6).trim();\n if (json === '[DONE]') { break; }\n if (!json) continue;\n\n try {\n const chunk = JSON.parse(json);\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) continue;\n\n if (delta.content) {\n yield { type: 'text', content: delta.content };\n }\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? 0;\n if (!toolCalls.has(idx)) {\n toolCalls.set(idx, { id: tc.id || '', name: '', args: '' });\n }\n const entry = toolCalls.get(idx)!;\n if (tc.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) entry.args += tc.function.arguments;\n }\n }\n } catch { /* skip malformed lines */ }\n }\n }\n\n // Emit accumulated tool calls\n for (const [, tc] of toolCalls) {\n if (tc.id && tc.name) {\n yield { type: 'tool_call', toolCall: { id: tc.id, type: 'function', function: { name: tc.name, arguments: tc.args || '{}' } } };\n }\n }\n yield { type: 'done' };\n }\n\n async listModels(): Promise<string[]> {\n // Hardcoded comprehensive fallback used when no key is configured\n // or live discovery fails. Covers OpenAI's chat-capable production\n // models as of 2026-05. Live discovery (when a key IS set) replaces\n // this with the user's actual catalogue.\n const FALLBACK = [\n // GPT-5 family (2026)\n 'gpt-5',\n 'gpt-5-mini',\n 'gpt-5-nano',\n // GPT-4.5 / 4o family\n 'gpt-4.5-preview',\n 'gpt-4o',\n 'gpt-4o-2024-11-20',\n 'gpt-4o-2024-08-06',\n 'gpt-4o-mini',\n 'gpt-4o-mini-2024-07-18',\n 'gpt-4-turbo',\n 'gpt-4-turbo-2024-04-09',\n 'gpt-4',\n 'chatgpt-4o-latest',\n // o-series reasoning models\n 'o4-mini',\n 'o3',\n 'o3-mini',\n 'o3-pro',\n 'o1',\n 'o1-pro',\n 'o1-mini',\n 'o1-preview',\n // Legacy still in production\n 'gpt-3.5-turbo',\n ];\n if (!this.apiKey) return FALLBACK;\n\n // Live discovery via /v1/models. The response includes embeddings,\n // image-gen, audio, moderation, etc. — filter to chat-capable\n // generation models so the picker doesn't drown in noise.\n const isChatModel = (id: string): boolean => {\n if (/^(text-embedding|whisper|tts|dall-e|moderation|davinci-002|babbage-002|computer-use|omni-moderation)/.test(id)) return false;\n return /^(gpt|o1|o3|o4|chatgpt|ft:gpt)/.test(id);\n };\n try {\n const response = await fetch(`${this.baseUrl}/v1/models`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) {\n logger.debug(COMPONENT, `listModels: ${response.status} from /v1/models, using fallback`);\n return FALLBACK;\n }\n const data = await response.json() as { data?: Array<{ id: string }> };\n const ids = (data.data || []).map((m) => m.id).filter(isChatModel);\n // Sort newest first by name (alphabetical desc tends to bubble new generations up).\n ids.sort().reverse();\n return ids.length > 0 ? ids : FALLBACK;\n } catch (err) {\n logger.debug(COMPONENT, `listModels failed: ${(err as Error).message}, using fallback`);\n return FALLBACK;\n }\n }\n\n isConfigured(): boolean {\n return !!this.apiKey;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n if (!this.apiKey) return false;\n const response = await fetch(`${this.baseUrl}/v1/models`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/providers/openai.ts"],"sourcesContent":["/**\n * TITAN — OpenAI Provider (GPT-4, o-series)\n */\nimport {\n LLMProvider,\n withTimeoutSignal,\n STREAM_FETCH_TIMEOUT_MS,\n type ChatOptions,\n type ChatResponse,\n type ChatStreamChunk,\n type ToolCall,\n} from './base.js';\nimport { loadConfig } from '../config/config.js';\nimport logger from '../utils/logger.js';\nimport { fetchWithRetry } from '../utils/helpers.js';\nimport { resolveApiKey } from './authResolver.js';\nimport { v4 as uuid } from 'uuid';\nimport { clampMaxTokens } from './modelCapabilities.js';\n\nconst COMPONENT = 'OpenAI';\n\nexport class OpenAIProvider extends LLMProvider {\n readonly name = 'openai';\n readonly displayName = 'OpenAI (GPT)';\n\n private get apiKey(): string {\n const config = loadConfig();\n const p = config.providers.openai;\n return resolveApiKey('openai', p.authProfiles || [], p.apiKey || '', 'OPENAI_API_KEY', p.rotationStrategy, p.credentialCooldownMs);\n }\n\n private get baseUrl(): string {\n const config = loadConfig();\n return config.providers.openai.baseUrl || 'https://api.openai.com';\n }\n\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const model = options.model || 'gpt-4o';\n const apiKey = this.apiKey;\n if (!apiKey) throw new Error('OpenAI API key not configured');\n\n logger.debug(COMPONENT, `Chat request: model=${model}, messages=${options.messages.length}`);\n\n const cleanModel = model.replace('openai/', '');\n const isReasoningModel = /^(o1|o3|o4)/.test(cleanModel);\n\n const body: Record<string, unknown> = {\n model: cleanModel,\n messages: options.messages.map((m) => {\n if (m.role === 'tool') {\n return { role: 'tool', content: m.content, tool_call_id: m.toolCallId };\n }\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant',\n content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.function.name, arguments: tc.function.arguments },\n })),\n };\n }\n // o-series reasoning models use 'developer' role instead of 'system'\n if (m.role === 'system' && isReasoningModel) {\n return { role: 'developer', content: m.content };\n }\n return { role: m.role, content: m.content };\n }),\n };\n\n // o-series models require max_completion_tokens, not max_tokens\n if (isReasoningModel) {\n body.max_completion_tokens = clampMaxTokens(model, options.maxTokens);\n } else {\n body.max_tokens = clampMaxTokens(model, options.maxTokens);\n }\n\n if (options.tools && options.tools.length > 0) {\n body.tools = options.tools;\n // Force at least one tool call on first round when task requires it.\n // Use \"auto\" for o-series (they manage tool use internally via reasoning).\n if (options.forceToolUse && !isReasoningModel) {\n body.tool_choice = 'required';\n }\n }\n\n // o-series models reject the temperature parameter\n if (options.temperature !== undefined && !isReasoningModel) {\n body.temperature = options.temperature;\n }\n\n // Reasoning effort for o-series models\n if (options.thinking && isReasoningModel) {\n const effortMap: Record<string, string> = { low: 'low', medium: 'medium', high: 'high' };\n body.reasoning_effort = effortMap[options.thinkingLevel || 'medium'] || 'medium';\n }\n\n const response = await fetchWithRetry(`${this.baseUrl}/v1/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n // Hunt Finding #37: attach status + Retry-After so the router can respect backoff\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError('OpenAI API', response, errorText, { provider: 'openai', model });\n }\n\n const data = await response.json() as Record<string, unknown>;\n const choices = data.choices as Array<Record<string, unknown>> | undefined;\n\n if (!choices || choices.length === 0) {\n return {\n id: (data.id as string) || uuid(),\n content: '',\n usage: undefined,\n finishReason: 'stop',\n model,\n };\n }\n\n const choice = choices[0];\n const message = choice.message as Record<string, unknown>;\n\n const toolCalls: ToolCall[] = [];\n if (message.tool_calls) {\n for (const tc of message.tool_calls as Array<Record<string, unknown>>) {\n const fn = tc.function as Record<string, string>;\n toolCalls.push({\n id: tc.id as string,\n type: 'function',\n function: { name: fn.name, arguments: fn.arguments },\n });\n }\n }\n\n const usage = data.usage as { prompt_tokens: number; completion_tokens: number; total_tokens: number } | undefined;\n\n return {\n id: (data.id as string) || uuid(),\n content: (message.content as string) || '',\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n usage: usage\n ? {\n promptTokens: usage.prompt_tokens,\n completionTokens: usage.completion_tokens,\n totalTokens: usage.total_tokens,\n }\n : undefined,\n finishReason: toolCalls.length > 0 ? 'tool_calls' : (choice.finish_reason as 'stop' | 'length') || 'stop',\n model,\n };\n }\n\n async *chatStream(options: ChatOptions): AsyncGenerator<ChatStreamChunk> {\n const model = options.model || 'gpt-4o';\n const apiKey = this.apiKey;\n if (!apiKey) { yield { type: 'error', error: 'OpenAI API key not configured' }; return; }\n\n const cleanModel = model.replace('openai/', '');\n const isReasoningModel = /^(o1|o3|o4)/.test(cleanModel);\n\n const body: Record<string, unknown> = {\n model: cleanModel,\n stream: true,\n messages: options.messages.map((m) => {\n if (m.role === 'tool') return { role: 'tool', content: m.content, tool_call_id: m.toolCallId };\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant', content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({ id: tc.id, type: 'function', function: { name: tc.function.name, arguments: tc.function.arguments } })),\n };\n }\n if (m.role === 'system' && isReasoningModel) return { role: 'developer', content: m.content };\n return { role: m.role, content: m.content };\n }),\n };\n\n // HIGH-5: clamp on the streaming path too (o-series can truncate JSON\n // mid-object otherwise — the non-stream path at line ~74 already clamps).\n if (isReasoningModel) { body.max_completion_tokens = clampMaxTokens(model, options.maxTokens); }\n else { body.max_tokens = clampMaxTokens(model, options.maxTokens); }\n if (options.tools && options.tools.length > 0) body.tools = options.tools;\n if (options.temperature !== undefined && !isReasoningModel) body.temperature = options.temperature;\n\n // Reasoning effort for o-series models\n if (options.thinking && isReasoningModel) {\n const effortMap: Record<string, string> = { low: 'low', medium: 'medium', high: 'high' };\n body.reasoning_effort = effortMap[options.thinkingLevel || 'medium'] || 'medium';\n }\n\n try {\n const response = await fetch(`${this.baseUrl}/v1/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },\n body: JSON.stringify(body),\n signal: withTimeoutSignal(options.signal, STREAM_FETCH_TIMEOUT_MS),\n });\n\n if (!response.ok || !response.body) {\n const errorText = await response.text();\n // v6.5 — THROW (not yield) so the router routes HTTP errors through\n // retry / fallback chain / circuit breaker, exactly like the\n // non-streaming chat() path. A yielded error chunk dead-ends the\n // SSE path with no failover.\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError('OpenAI API', response, errorText, { provider: 'openai', model });\n }\n\n const toolCalls = new Map<number, { id: string; name: string; args: string }>();\n yield* this.parseOpenAISSE(response.body, toolCalls);\n } catch (error) {\n yield { type: 'error', error: (error as Error).message };\n }\n }\n\n /** Parse OpenAI-format SSE stream and yield ChatStreamChunks */\n private async *parseOpenAISSE(\n body: ReadableStream<Uint8Array>,\n toolCalls: Map<number, { id: string; name: string; args: string }>,\n ): AsyncGenerator<ChatStreamChunk> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const json = line.slice(6).trim();\n if (json === '[DONE]') { break; }\n if (!json) continue;\n\n try {\n const chunk = JSON.parse(json);\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) continue;\n\n if (delta.content) {\n yield { type: 'text', content: delta.content };\n }\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? 0;\n if (!toolCalls.has(idx)) {\n toolCalls.set(idx, { id: tc.id || '', name: '', args: '' });\n }\n const entry = toolCalls.get(idx)!;\n if (tc.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) entry.args += tc.function.arguments;\n }\n }\n } catch { /* skip malformed lines */ }\n }\n }\n\n // Emit accumulated tool calls\n for (const [, tc] of toolCalls) {\n if (tc.id && tc.name) {\n yield { type: 'tool_call', toolCall: { id: tc.id, type: 'function', function: { name: tc.name, arguments: tc.args || '{}' } } };\n }\n }\n yield { type: 'done' };\n }\n\n async listModels(): Promise<string[]> {\n // Hardcoded comprehensive fallback used when no key is configured\n // or live discovery fails. Covers OpenAI's chat-capable production\n // models as of 2026-05. Live discovery (when a key IS set) replaces\n // this with the user's actual catalogue.\n const FALLBACK = [\n // GPT-5 family (2026)\n 'gpt-5',\n 'gpt-5-mini',\n 'gpt-5-nano',\n // GPT-4.5 / 4o family\n 'gpt-4.5-preview',\n 'gpt-4o',\n 'gpt-4o-2024-11-20',\n 'gpt-4o-2024-08-06',\n 'gpt-4o-mini',\n 'gpt-4o-mini-2024-07-18',\n 'gpt-4-turbo',\n 'gpt-4-turbo-2024-04-09',\n 'gpt-4',\n 'chatgpt-4o-latest',\n // o-series reasoning models\n 'o4-mini',\n 'o3',\n 'o3-mini',\n 'o3-pro',\n 'o1',\n 'o1-pro',\n 'o1-mini',\n 'o1-preview',\n // Legacy still in production\n 'gpt-3.5-turbo',\n ];\n if (!this.apiKey) return FALLBACK;\n\n // Live discovery via /v1/models. The response includes embeddings,\n // image-gen, audio, moderation, etc. — filter to chat-capable\n // generation models so the picker doesn't drown in noise.\n const isChatModel = (id: string): boolean => {\n if (/^(text-embedding|whisper|tts|dall-e|moderation|davinci-002|babbage-002|computer-use|omni-moderation)/.test(id)) return false;\n return /^(gpt|o1|o3|o4|chatgpt|ft:gpt)/.test(id);\n };\n try {\n const response = await fetch(`${this.baseUrl}/v1/models`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) {\n logger.debug(COMPONENT, `listModels: ${response.status} from /v1/models, using fallback`);\n return FALLBACK;\n }\n const data = await response.json() as { data?: Array<{ id: string }> };\n const ids = (data.data || []).map((m) => m.id).filter(isChatModel);\n // Sort newest first by name (alphabetical desc tends to bubble new generations up).\n ids.sort().reverse();\n return ids.length > 0 ? ids : FALLBACK;\n } catch (err) {\n logger.debug(COMPONENT, `listModels failed: ${(err as Error).message}, using fallback`);\n return FALLBACK;\n }\n }\n\n isConfigured(): boolean {\n return !!this.apiKey;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n if (!this.apiKey) return false;\n const response = await fetch(`${this.baseUrl}/v1/models`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -10,6 +10,26 @@ import { fetchWithRetry } from "../utils/helpers.js";
10
10
  import { resolveApiKey } from "./authResolver.js";
11
11
  import { v4 as uuid } from "uuid";
12
12
  import { clampMaxTokens } from "./modelCapabilities.js";
13
+ import { getModelCapabilities as getToolCapabilities } from "./ollama.js";
14
+ function applyCompatToolControls(body, model, options) {
15
+ const tools = body.tools;
16
+ if (options.forceToolUse && Array.isArray(tools) && tools.length > 0) {
17
+ const isDeepseekReasoner = /deepseek/i.test(model) && options.thinking === true;
18
+ if (!isDeepseekReasoner && !getToolCapabilities(model).selfSelectsTools) {
19
+ body.tool_choice = "required";
20
+ }
21
+ }
22
+ if (options.format === "json" || options.format && typeof options.format === "object") {
23
+ body.response_format = { type: "json_object" };
24
+ if (typeof body.max_tokens === "number" && body.max_tokens < 2048) body.max_tokens = 2048;
25
+ }
26
+ }
27
+ function parseMaxTokenLimit(errText) {
28
+ const m = errText.match(/max_model_len=(?:max_total_tokens=)?(\d+)|max_total_tokens=(\d+)|maximum context length is (\d+)/i);
29
+ if (!m) return null;
30
+ const n = Number(m[1] || m[2] || m[3]);
31
+ return Number.isFinite(n) && n > 0 ? n : null;
32
+ }
13
33
  class OpenAICompatProvider extends LLMProvider {
14
34
  name;
15
35
  displayName;
@@ -69,6 +89,7 @@ class OpenAICompatProvider extends LLMProvider {
69
89
  if (options.tools && options.tools.length > 0) {
70
90
  body.tools = options.tools;
71
91
  }
92
+ applyCompatToolControls(body, model, options);
72
93
  if (options.temperature !== void 0) {
73
94
  body.temperature = options.temperature;
74
95
  }
@@ -77,11 +98,24 @@ class OpenAICompatProvider extends LLMProvider {
77
98
  "Authorization": `Bearer ${apiKey}`,
78
99
  ...this.config.extraHeaders || {}
79
100
  };
80
- const response = await fetchWithRetry(`${this.baseUrl}/chat/completions`, {
101
+ const doFetch = () => fetchWithRetry(`${this.baseUrl}/chat/completions`, {
81
102
  method: "POST",
82
103
  headers,
83
104
  body: JSON.stringify(body)
84
105
  });
106
+ let response = await doFetch();
107
+ if (!response.ok && response.status === 400 && typeof body.max_tokens === "number") {
108
+ const errText = await response.text();
109
+ const limit = parseMaxTokenLimit(errText);
110
+ if (limit && body.max_tokens > limit) {
111
+ body.max_tokens = Math.max(512, Math.min(Math.floor(limit / 3), 4096));
112
+ logger.warn(this.name, `[AdaptiveMaxTokens] ${model} deployment caps total tokens at ${limit}; retrying with max_tokens=${body.max_tokens}`);
113
+ response = await doFetch();
114
+ } else {
115
+ const { createProviderError } = await import("./errorTaxonomy.js");
116
+ throw createProviderError(`${this.displayName} API`, response, errText, { provider: this.name, model });
117
+ }
118
+ }
85
119
  if (!response.ok) {
86
120
  const errorText = await response.text();
87
121
  const { createProviderError } = await import("./errorTaxonomy.js");
@@ -151,6 +185,7 @@ class OpenAICompatProvider extends LLMProvider {
151
185
  max_tokens: clampMaxTokens(model, options.maxTokens)
152
186
  };
153
187
  if (options.tools && options.tools.length > 0) body.tools = options.tools;
188
+ applyCompatToolControls(body, model, options);
154
189
  if (options.temperature !== void 0) body.temperature = options.temperature;
155
190
  const headers = {
156
191
  "Content-Type": "application/json",
@@ -619,6 +654,7 @@ const PROVIDER_PRESETS = [
619
654
  ];
620
655
  export {
621
656
  OpenAICompatProvider,
622
- PROVIDER_PRESETS
657
+ PROVIDER_PRESETS,
658
+ parseMaxTokenLimit
623
659
  };
624
660
  //# sourceMappingURL=openai_compat.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/openai_compat.ts"],"sourcesContent":["/**\n * TITAN — Generic OpenAI-Compatible Provider\n * A single provider class that works with any OpenAI-compatible API endpoint.\n * Used by: Groq, Mistral, OpenRouter, Fireworks, xAI, Together, DeepSeek,\n * Cerebras, Cohere, Perplexity, and any custom provider.\n */\nimport {\n LLMProvider,\n withTimeoutSignal,\n STREAM_FETCH_TIMEOUT_MS,\n type ChatOptions,\n type ChatResponse,\n type ChatStreamChunk,\n type ToolCall,\n} from './base.js';\nimport { loadConfig } from '../config/config.js';\nimport type { ProviderConfig } from '../config/schema.js';\nimport logger from '../utils/logger.js';\nimport { fetchWithRetry } from '../utils/helpers.js';\nimport { resolveApiKey } from './authResolver.js';\nimport { v4 as uuid } from 'uuid';\nimport { clampMaxTokens } from './modelCapabilities.js';\n\n/** Configuration for an OpenAI-compatible provider */\nexport interface OpenAICompatConfig {\n /** Internal provider name (e.g. 'groq') */\n name: string;\n /** Display name shown to users (e.g. 'Groq (Fast Inference)') */\n displayName: string;\n /** Default API base URL */\n defaultBaseUrl: string;\n /** Environment variable name for the API key */\n envKey: string;\n /** Config key name in titan.json providers section */\n configKey: string;\n /** Default model ID */\n defaultModel: string;\n /** Static model list (returned when health check fails) */\n knownModels: string[];\n /** Extra headers to send with every request */\n extraHeaders?: Record<string, string>;\n /** Whether to fetch models from /v1/models endpoint */\n supportsModelList?: boolean;\n /**\n * The /models catalogue is publicly accessible (no API key required).\n * When true, listModels() will fetch the catalogue even when the user\n * has not configured an API key — useful for picker UIs that want to\n * show the full catalogue before the user has chosen / paid for a key.\n * OpenRouter is the canonical example.\n */\n publicModelList?: boolean;\n /** Keep org/ prefix in model name (e.g. NIM API expects 'nvidia/model-name') */\n keepModelPrefix?: boolean;\n}\n\nexport class OpenAICompatProvider extends LLMProvider {\n readonly name: string;\n readonly displayName: string;\n private readonly config: OpenAICompatConfig;\n\n constructor(config: OpenAICompatConfig) {\n super();\n this.name = config.name;\n this.displayName = config.displayName;\n this.config = config;\n }\n\n private get apiKey(): string {\n const cfg = loadConfig();\n const providerCfg = (cfg.providers as Record<string, unknown>)[this.config.configKey] as ProviderConfig | undefined;\n return resolveApiKey(this.config.name, providerCfg?.authProfiles || [], providerCfg?.apiKey || '', this.config.envKey, providerCfg?.rotationStrategy, providerCfg?.credentialCooldownMs);\n }\n\n private get baseUrl(): string {\n const cfg = loadConfig();\n const providerCfg = (cfg.providers as Record<string, unknown>)[this.config.configKey] as ProviderConfig | undefined;\n return providerCfg?.baseUrl || this.config.defaultBaseUrl;\n }\n\n /** Sanitize messages for strict APIs (e.g., NIM) that reject empty content strings */\n private sanitizeMessages(messages: ChatOptions['messages']): ChatOptions['messages'] {\n return messages.map(m => ({\n ...m,\n content: m.content || (m.role === 'assistant' && m.toolCalls ? '' : ' '),\n }));\n }\n\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const rawModel = options.model || this.config.defaultModel;\n // NIM API requires org/model format — keep prefix as-is or add it\n const model = this.config.keepModelPrefix\n ? (rawModel.includes('/') ? rawModel : `${this.name}/${rawModel}`)\n : rawModel.replace(`${this.name}/`, '');\n\n // Kimi API uses dash model IDs (kimi-k2-6) but TITAN uses dots (kimi-k2.6)\n const apiModel = this.config.configKey === 'kimi'\n ? model.replace(/kimi-k2\\.6/g, 'kimi-k2-6').replace(/kimi-k2\\.5/g, 'kimi-k2-5')\n : model;\n const apiKey = this.apiKey;\n if (!apiKey) throw new Error(`${this.displayName} API key not configured (set ${this.config.envKey} or providers.${this.config.configKey}.apiKey)`);\n\n logger.debug(this.name, `Chat request: model=${model}, messages=${options.messages.length}`);\n\n const sanitized = this.sanitizeMessages(options.messages);\n const body: Record<string, unknown> = {\n model: apiModel,\n messages: sanitized.map((m) => {\n if (m.role === 'tool') {\n return { role: 'tool', content: m.content || ' ', tool_call_id: m.toolCallId };\n }\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant',\n content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.function.name, arguments: tc.function.arguments },\n })),\n };\n }\n return { role: m.role, content: m.content || ' ' };\n }),\n max_tokens: clampMaxTokens(model, options.maxTokens),\n };\n\n if (options.tools && options.tools.length > 0) {\n body.tools = options.tools;\n }\n\n if (options.temperature !== undefined) {\n body.temperature = options.temperature;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n ...(this.config.extraHeaders || {}),\n };\n\n const response = await fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n // Hunt Finding #37: attach status + Retry-After so the router can respect backoff\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError(`${this.displayName} API`, response, errorText, { provider: this.name, model });\n }\n\n const data = await response.json() as Record<string, unknown>;\n const choices = data.choices as Array<Record<string, unknown>> | undefined;\n\n if (!choices || choices.length === 0) {\n return {\n id: (data.id as string) || uuid(),\n content: '',\n usage: undefined,\n finishReason: 'stop',\n model: model.includes('/') ? model : `${this.name}/${model}`,\n };\n }\n\n const choice = choices[0];\n const message = choice.message as Record<string, unknown>;\n\n const toolCalls: ToolCall[] = [];\n if (message.tool_calls) {\n for (const tc of message.tool_calls as Array<Record<string, unknown>>) {\n const fn = tc.function as Record<string, string>;\n toolCalls.push({\n id: (tc.id as string) || uuid(),\n type: 'function',\n function: { name: fn.name, arguments: fn.arguments },\n });\n }\n }\n\n const usage = data.usage as { prompt_tokens: number; completion_tokens: number; total_tokens: number } | undefined;\n\n return {\n id: (data.id as string) || uuid(),\n content: (message.content as string) || '',\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n usage: usage\n ? {\n promptTokens: usage.prompt_tokens,\n completionTokens: usage.completion_tokens,\n totalTokens: usage.total_tokens,\n }\n : undefined,\n finishReason: toolCalls.length > 0 ? 'tool_calls' : (choice.finish_reason as 'stop' | 'length') || 'stop',\n model: model.includes('/') ? model : `${this.name}/${model}`,\n };\n }\n\n async *chatStream(options: ChatOptions): AsyncGenerator<ChatStreamChunk> {\n const rawModel = options.model || this.config.defaultModel;\n const model = this.config.keepModelPrefix\n ? (rawModel.includes('/') ? rawModel : `${this.name}/${rawModel}`)\n : rawModel.replace(`${this.name}/`, '');\n const apiKey = this.apiKey;\n if (!apiKey) { yield { type: 'error', error: `${this.displayName} API key not configured` }; return; }\n\n const sanitized = this.sanitizeMessages(options.messages);\n const body: Record<string, unknown> = {\n model,\n stream: true,\n messages: sanitized.map((m) => {\n if (m.role === 'tool') return { role: 'tool', content: m.content || ' ', tool_call_id: m.toolCallId };\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant', content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({ id: tc.id, type: 'function', function: { name: tc.function.name, arguments: tc.function.arguments } })),\n };\n }\n return { role: m.role, content: m.content || ' ' };\n }),\n max_tokens: clampMaxTokens(model, options.maxTokens),\n };\n if (options.tools && options.tools.length > 0) body.tools = options.tools;\n if (options.temperature !== undefined) body.temperature = options.temperature;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n ...(this.config.extraHeaders || {}),\n };\n\n try {\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: withTimeoutSignal(options.signal, STREAM_FETCH_TIMEOUT_MS),\n });\n\n if (!response.ok || !response.body) {\n const errorText = await response.text();\n // v6.5 — THROW (not yield) so the router routes HTTP errors through\n // retry / fallback chain / circuit breaker, like non-streaming chat().\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError(this.displayName, response, errorText, { provider: this.name, model });\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n const toolCalls = new Map<number, { id: string; name: string; args: string }>();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const json = line.slice(6).trim();\n if (json === '[DONE]' || !json) continue;\n try {\n const chunk = JSON.parse(json);\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) continue;\n if (delta.content) yield { type: 'text', content: delta.content };\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? 0;\n if (!toolCalls.has(idx)) toolCalls.set(idx, { id: tc.id || '', name: '', args: '' });\n const entry = toolCalls.get(idx)!;\n if (tc.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) entry.args += tc.function.arguments;\n }\n }\n } catch { /* skip malformed SSE lines */ }\n }\n }\n\n for (const [, tc] of toolCalls) {\n if (tc.id && tc.name) {\n yield { type: 'tool_call', toolCall: { id: tc.id, type: 'function', function: { name: tc.name, arguments: tc.args || '{}' } } };\n }\n }\n yield { type: 'done' };\n } catch (error) {\n yield { type: 'error', error: (error as Error).message };\n }\n }\n\n async listModels(): Promise<string[]> {\n if (!this.config.supportsModelList) {\n return this.config.knownModels;\n }\n\n // Some upstream catalogues are public (no auth needed) — those\n // providers set `publicModelList: true` so the picker can show\n // the full catalogue even before the user configures a key.\n // OpenRouter is the canonical example (~365 models, no key).\n const isPublic = this.config.publicModelList === true;\n if (!isPublic && !this.apiKey) {\n return this.config.knownModels;\n }\n\n try {\n const headers: Record<string, string> = {\n ...(this.config.extraHeaders || {}),\n };\n if (this.apiKey) headers['Authorization'] = `Bearer ${this.apiKey}`;\n const response = await fetch(`${this.baseUrl}/models`, {\n headers,\n signal: AbortSignal.timeout(8000),\n });\n if (!response.ok) return this.config.knownModels;\n const data = await response.json() as { data?: Array<{ id: string }> };\n const ids = (data.data || []).map((m) => m.id).filter(Boolean);\n // Sort alphabetically for stable UX (the catalogue is\n // already typically grouped by family).\n ids.sort();\n return ids.length > 0 ? ids : this.config.knownModels;\n } catch {\n return this.config.knownModels;\n }\n }\n\n isConfigured(): boolean {\n return !!this.apiKey;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n if (!this.apiKey) return false;\n const response = await fetch(`${this.baseUrl}/models`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n ...(this.config.extraHeaders || {}),\n },\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n\n// ── Provider Presets ──────────────────────────────────────────────\n\nexport const PROVIDER_PRESETS: OpenAICompatConfig[] = [\n {\n name: 'groq',\n displayName: 'Groq (Fast Inference)',\n defaultBaseUrl: 'https://api.groq.com/openai/v1',\n envKey: 'GROQ_API_KEY',\n configKey: 'groq',\n defaultModel: 'llama-3.3-70b-versatile',\n knownModels: ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant', 'mixtral-8x7b-32768', 'gemma2-9b-it', 'deepseek-r1-distill-llama-70b'],\n supportsModelList: true,\n },\n {\n name: 'mistral',\n displayName: 'Mistral AI',\n defaultBaseUrl: 'https://api.mistral.ai/v1',\n envKey: 'MISTRAL_API_KEY',\n configKey: 'mistral',\n defaultModel: 'mistral-small-latest',\n knownModels: ['mistral-large-latest', 'mistral-medium-latest', 'mistral-small-latest', 'codestral-latest', 'mistral-nemo'],\n supportsModelList: true,\n },\n {\n name: 'fireworks',\n displayName: 'Fireworks AI',\n defaultBaseUrl: 'https://api.fireworks.ai/inference/v1',\n envKey: 'FIREWORKS_API_KEY',\n configKey: 'fireworks',\n defaultModel: 'accounts/fireworks/models/llama-v3p3-70b-instruct',\n knownModels: ['accounts/fireworks/models/llama-v3p3-70b-instruct', 'accounts/fireworks/models/mixtral-8x7b-instruct', 'accounts/fireworks/models/qwen3-8b'],\n supportsModelList: true,\n },\n {\n name: 'xai',\n displayName: 'xAI (Grok)',\n defaultBaseUrl: 'https://api.x.ai/v1',\n envKey: 'XAI_API_KEY',\n configKey: 'xai',\n defaultModel: 'grok-3-fast',\n knownModels: ['grok-3', 'grok-3-fast', 'grok-3-mini', 'grok-3-mini-fast'],\n supportsModelList: true,\n },\n {\n name: 'together',\n displayName: 'Together AI',\n defaultBaseUrl: 'https://api.together.xyz/v1',\n envKey: 'TOGETHER_API_KEY',\n configKey: 'together',\n defaultModel: 'meta-llama/Llama-3.3-70B-Instruct-Turbo',\n knownModels: ['meta-llama/Llama-3.3-70B-Instruct-Turbo', 'deepseek-ai/DeepSeek-R1', 'Qwen/Qwen2.5-72B-Instruct-Turbo', 'mistralai/Mixtral-8x7B-Instruct-v0.1'],\n supportsModelList: true,\n },\n {\n name: 'deepseek',\n displayName: 'DeepSeek',\n defaultBaseUrl: 'https://api.deepseek.com/v1',\n envKey: 'DEEPSEEK_API_KEY',\n configKey: 'deepseek',\n defaultModel: 'deepseek-chat',\n knownModels: ['deepseek-chat', 'deepseek-reasoner'],\n supportsModelList: false,\n },\n {\n name: 'cerebras',\n displayName: 'Cerebras (Ultra-Fast)',\n defaultBaseUrl: 'https://api.cerebras.ai/v1',\n envKey: 'CEREBRAS_API_KEY',\n configKey: 'cerebras',\n defaultModel: 'llama-3.3-70b',\n knownModels: ['llama-3.3-70b', 'llama-3.1-8b', 'qwen-3-32b'],\n supportsModelList: true,\n },\n {\n name: 'cohere',\n displayName: 'Cohere',\n defaultBaseUrl: 'https://api.cohere.com/compatibility/v1',\n envKey: 'COHERE_API_KEY',\n configKey: 'cohere',\n defaultModel: 'command-r-plus',\n knownModels: ['command-r-plus', 'command-r', 'command-r7b'],\n supportsModelList: false,\n },\n {\n name: 'perplexity',\n displayName: 'Perplexity (Search-Augmented)',\n defaultBaseUrl: 'https://api.perplexity.ai',\n envKey: 'PERPLEXITY_API_KEY',\n configKey: 'perplexity',\n defaultModel: 'sonar',\n knownModels: ['sonar', 'sonar-pro', 'sonar-reasoning'],\n supportsModelList: false,\n },\n {\n name: 'venice',\n displayName: 'Venice AI (Privacy-First)',\n defaultBaseUrl: 'https://api.venice.ai/api/v1',\n envKey: 'VENICE_API_KEY',\n configKey: 'venice',\n defaultModel: 'llama-3.3-70b',\n knownModels: ['llama-3.3-70b', 'deepseek-r1-671b', 'qwen-2.5-vl-72b'],\n supportsModelList: true,\n },\n {\n name: 'bedrock',\n displayName: 'AWS Bedrock (via Proxy)',\n defaultBaseUrl: 'http://localhost:4000/v1',\n envKey: 'AWS_BEDROCK_API_KEY',\n configKey: 'bedrock',\n defaultModel: 'anthropic.claude-3-5-sonnet-20241022-v2:0',\n knownModels: ['anthropic.claude-3-5-sonnet-20241022-v2:0', 'amazon.titan-text-premier-v1:0', 'meta.llama3-70b-instruct-v1:0'],\n supportsModelList: false,\n },\n {\n name: 'litellm',\n displayName: 'LiteLLM (Universal Proxy)',\n defaultBaseUrl: 'http://localhost:4000/v1',\n envKey: 'LITELLM_API_KEY',\n configKey: 'litellm',\n defaultModel: 'gpt-4o',\n knownModels: ['gpt-4o', 'claude-sonnet-4-20250514', 'gemini-2.5-flash'],\n supportsModelList: true,\n },\n // NOTE: Azure OpenAI uses custom endpoints (https://{resource}.openai.azure.com/openai/deployments/{model})\n // and requires api-version query param + api-key header instead of Bearer token.\n // Users must configure baseUrl to their Azure deployment endpoint.\n {\n name: 'azure',\n displayName: 'Azure OpenAI (Enterprise)',\n defaultBaseUrl: '',\n envKey: 'AZURE_OPENAI_API_KEY',\n configKey: 'azure',\n defaultModel: 'gpt-4o',\n knownModels: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1-preview'],\n supportsModelList: false,\n },\n {\n name: 'deepinfra',\n displayName: 'DeepInfra (Fast Inference)',\n defaultBaseUrl: 'https://api.deepinfra.com/v1/openai',\n envKey: 'DEEPINFRA_API_KEY',\n configKey: 'deepinfra',\n defaultModel: 'meta-llama/Llama-3.3-70B-Instruct',\n knownModels: ['meta-llama/Llama-3.3-70B-Instruct', 'mistralai/Mixtral-8x22B-Instruct-v0.1', 'Qwen/Qwen2.5-72B-Instruct', 'deepseek-ai/DeepSeek-R1'],\n supportsModelList: true,\n },\n {\n name: 'sambanova',\n displayName: 'SambaNova (Fast Inference)',\n defaultBaseUrl: 'https://api.sambanova.ai/v1',\n envKey: 'SAMBANOVA_API_KEY',\n configKey: 'sambanova',\n defaultModel: 'Meta-Llama-3.3-70B-Instruct',\n knownModels: ['Meta-Llama-3.3-70B-Instruct', 'DeepSeek-R1-Distill-Llama-70B', 'Qwen2.5-72B-Instruct'],\n supportsModelList: true,\n },\n {\n name: 'kimi',\n displayName: 'Kimi (Moonshot)',\n defaultBaseUrl: 'https://api.moonshot.ai/v1',\n envKey: 'MOONSHOT_API_KEY',\n configKey: 'kimi',\n defaultModel: 'kimi-k2.5',\n knownModels: ['kimi-k2.6', 'kimi-k2.5', 'kimi-k2', 'moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],\n supportsModelList: true,\n },\n {\n name: 'huggingface',\n displayName: 'Hugging Face Inference',\n defaultBaseUrl: 'https://api-inference.huggingface.co/v1',\n envKey: 'HF_API_KEY',\n configKey: 'huggingface',\n defaultModel: 'meta-llama/Llama-3.3-70B-Instruct',\n knownModels: ['meta-llama/Llama-3.3-70B-Instruct', 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'Qwen/Qwen2.5-72B-Instruct', 'microsoft/Phi-3-medium-4k-instruct'],\n supportsModelList: true,\n },\n {\n name: 'ai21',\n displayName: 'AI21 Labs (Jamba)',\n defaultBaseUrl: 'https://api.ai21.com/studio/v1',\n envKey: 'AI21_API_KEY',\n configKey: 'ai21',\n defaultModel: 'jamba-1.5-large',\n knownModels: ['jamba-1.5-large', 'jamba-1.5-mini', 'jamba-instruct'],\n supportsModelList: false,\n },\n {\n name: 'cohere-v2',\n displayName: 'Cohere v2 (OpenAI-compat)',\n defaultBaseUrl: 'https://api.cohere.com/v2',\n envKey: 'COHERE_API_KEY',\n configKey: 'cohere-v2',\n defaultModel: 'command-a-03-2025',\n knownModels: ['command-a-03-2025', 'command-r-plus-08-2024', 'command-r-08-2024', 'command-r7b-12-2024'],\n supportsModelList: false,\n },\n {\n name: 'reka',\n displayName: 'Reka AI',\n defaultBaseUrl: 'https://api.reka.ai/v1',\n envKey: 'REKA_API_KEY',\n configKey: 'reka',\n defaultModel: 'reka-core',\n knownModels: ['reka-core', 'reka-flash', 'reka-edge'],\n supportsModelList: false,\n },\n {\n name: 'zhipu',\n displayName: 'Zhipu GLM',\n defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4',\n envKey: 'ZHIPU_API_KEY',\n configKey: 'zhipu',\n defaultModel: 'glm-4-plus',\n knownModels: ['glm-4-plus', 'glm-4', 'glm-4-flash', 'glm-4-long'],\n supportsModelList: false,\n },\n {\n name: 'yi',\n displayName: '01.AI (Yi)',\n defaultBaseUrl: 'https://api.01.ai/v1',\n envKey: 'YI_API_KEY',\n configKey: 'yi',\n defaultModel: 'yi-large',\n knownModels: ['yi-large', 'yi-medium', 'yi-spark', 'yi-large-turbo'],\n supportsModelList: true,\n },\n {\n name: 'inflection',\n displayName: 'Inflection (Pi)',\n defaultBaseUrl: 'https://api.inflection.ai/v1',\n envKey: 'INFLECTION_API_KEY',\n configKey: 'inflection',\n defaultModel: 'inflection-3-pi',\n knownModels: ['inflection-3-pi', 'inflection-3-productivity'],\n supportsModelList: false,\n },\n {\n name: 'novita',\n displayName: 'Novita AI',\n defaultBaseUrl: 'https://api.novita.ai/v3/openai',\n envKey: 'NOVITA_API_KEY',\n configKey: 'novita',\n defaultModel: 'meta-llama/llama-3.3-70b-instruct',\n knownModels: ['meta-llama/llama-3.3-70b-instruct', 'deepseek/deepseek-r1', 'qwen/qwen-2.5-72b-instruct', 'mistralai/mistral-large-2411'],\n supportsModelList: true,\n },\n {\n name: 'replicate',\n displayName: 'Replicate',\n defaultBaseUrl: 'https://api.replicate.com/v1',\n envKey: 'REPLICATE_API_KEY',\n configKey: 'replicate',\n defaultModel: 'meta/meta-llama-3-70b-instruct',\n knownModels: ['meta/meta-llama-3-70b-instruct', 'mistralai/mixtral-8x7b-instruct-v0.1', 'meta/meta-llama-3.1-405b-instruct'],\n supportsModelList: false,\n },\n {\n name: 'lepton',\n displayName: 'Lepton AI',\n defaultBaseUrl: 'https://llama3-3-70b.lepton.run/api/v1',\n envKey: 'LEPTON_API_KEY',\n configKey: 'lepton',\n defaultModel: 'llama-3.3-70b',\n knownModels: ['llama-3.3-70b', 'mixtral-8x7b', 'qwen2.5-72b'],\n supportsModelList: false,\n },\n {\n name: 'anyscale',\n displayName: 'Anyscale Endpoints',\n defaultBaseUrl: 'https://api.endpoints.anyscale.com/v1',\n envKey: 'ANYSCALE_API_KEY',\n configKey: 'anyscale',\n defaultModel: 'meta-llama/Meta-Llama-3-70B-Instruct',\n knownModels: ['meta-llama/Meta-Llama-3-70B-Instruct', 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'codellama/CodeLlama-70b-Instruct-hf'],\n supportsModelList: true,\n },\n {\n name: 'octo',\n displayName: 'OctoAI',\n defaultBaseUrl: 'https://text.octoai.run/v1',\n envKey: 'OCTOAI_API_KEY',\n configKey: 'octo',\n defaultModel: 'meta-llama-3.1-70b-instruct',\n knownModels: ['meta-llama-3.1-70b-instruct', 'mixtral-8x7b-instruct', 'qwen2.5-72b-instruct'],\n supportsModelList: true,\n },\n {\n name: 'nous',\n displayName: 'Nous Research (Hermes)',\n defaultBaseUrl: 'https://inference-api.nousresearch.com/v1',\n envKey: 'NOUS_API_KEY',\n configKey: 'nous',\n defaultModel: 'hermes-3-llama-3.1-70b',\n knownModels: ['hermes-3-llama-3.1-70b', 'hermes-3-llama-3.1-8b', 'hermes-2-pro-mistral-7b'],\n supportsModelList: false,\n },\n {\n name: 'openrouter',\n displayName: 'OpenRouter (Universal Gateway)',\n defaultBaseUrl: 'https://openrouter.ai/api/v1',\n envKey: 'OPENROUTER_API_KEY',\n configKey: 'openrouter',\n defaultModel: 'anthropic/claude-3.5-sonnet',\n knownModels: [\n 'anthropic/claude-3.5-sonnet',\n 'anthropic/claude-3.5-haiku',\n 'anthropic/claude-3-opus',\n 'openai/gpt-4o',\n 'openai/gpt-4o-mini',\n 'meta-llama/llama-3.3-70b-instruct',\n 'google/gemini-2.5-flash-preview',\n 'deepseek/deepseek-chat',\n 'deepseek/deepseek-r1',\n 'x-ai/grok-3-beta',\n 'nvidia/llama-3.1-nemotron-70b-instruct',\n ],\n supportsModelList: true,\n // OpenRouter's /api/v1/models is publicly accessible — TITAN can\n // pull the full ~365-model catalogue even before the user has\n // configured an OPENROUTER_API_KEY. Lets the picker show every\n // available model so the user can choose first, then add the key.\n publicModelList: true,\n extraHeaders: {\n 'HTTP-Referer': 'https://titan.local',\n 'X-Title': 'TITAN',\n },\n },\n {\n name: 'nvidia',\n displayName: 'NVIDIA NIM',\n defaultBaseUrl: 'https://integrate.api.nvidia.com/v1',\n envKey: 'NVIDIA_API_KEY',\n configKey: 'nvidia',\n defaultModel: 'nvidia/llama-3.3-nemotron-super-49b-v1',\n knownModels: [\n 'nvidia/llama-3.3-nemotron-super-49b-v1',\n 'nvidia/llama-3.3-nemotron-super-49b-v1.5',\n 'nvidia/llama-3.1-nemotron-ultra-253b-v1',\n 'nvidia/llama-3.1-nemotron-70b-instruct',\n 'nvidia/nemotron-3-nano-30b-a3b',\n 'nvidia/nemotron-3-super-120b-a12b',\n ],\n supportsModelList: true,\n keepModelPrefix: true,\n },\n {\n name: 'minimax',\n displayName: 'MiniMax',\n defaultBaseUrl: 'https://api.minimax.chat/v1',\n envKey: 'MINIMAX_API_KEY',\n configKey: 'minimax',\n defaultModel: 'minimax-m2.7',\n knownModels: [\n 'minimax-m2.7',\n 'minimax-m2.7-highspeed',\n 'minimax-m2.5',\n 'minimax-01',\n 'minimax-text-01',\n ],\n supportsModelList: false,\n },\n];\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/providers/openai_compat.ts"],"sourcesContent":["/**\n * TITAN — Generic OpenAI-Compatible Provider\n * A single provider class that works with any OpenAI-compatible API endpoint.\n * Used by: Groq, Mistral, OpenRouter, Fireworks, xAI, Together, DeepSeek,\n * Cerebras, Cohere, Perplexity, and any custom provider.\n */\nimport {\n LLMProvider,\n withTimeoutSignal,\n STREAM_FETCH_TIMEOUT_MS,\n type ChatOptions,\n type ChatResponse,\n type ChatStreamChunk,\n type ToolCall,\n} from './base.js';\nimport { loadConfig } from '../config/config.js';\nimport type { ProviderConfig } from '../config/schema.js';\nimport logger from '../utils/logger.js';\nimport { fetchWithRetry } from '../utils/helpers.js';\nimport { resolveApiKey } from './authResolver.js';\nimport { v4 as uuid } from 'uuid';\nimport { clampMaxTokens } from './modelCapabilities.js';\n// Reuse the Ollama provider's battle-tested per-model tool-behavior registry\n// (selfSelectsTools/etc.) so cloud models routed through this GENERIC provider\n// get the same model-agnostic treatment instead of a blind passthrough.\nimport { getModelCapabilities as getToolCapabilities } from './ollama.js';\n\n/**\n * Apply model-agnostic tool / structured-output controls to an OpenAI-compatible\n * request body. Without this, this provider (which fronts ~24 backends incl.\n * DeepSeek/Qwen/GLM/Kimi/MiniMax/xAI) silently ignores forceToolUse and format —\n * so weak-self-selecting models answer in prose instead of calling the tool.\n */\nfunction applyCompatToolControls(body: Record<string, unknown>, model: string, options: ChatOptions): void {\n // forceToolUse → tool_choice:'required', but ONLY for models that don't\n // self-select tools well (forcing a self-selecting model wastes a turn), and\n // NEVER for a DeepSeek reasoner with thinking on — that combo is rejected\n // with HTTP 400 by the reasoner endpoint (vllm #41132 / pydantic-ai #5193).\n const tools = body.tools as unknown[] | undefined;\n if (options.forceToolUse && Array.isArray(tools) && tools.length > 0) {\n const isDeepseekReasoner = /deepseek/i.test(model) && options.thinking === true;\n if (!isDeepseekReasoner && !getToolCapabilities(model).selfSelectsTools) {\n body.tool_choice = 'required';\n }\n }\n // format → native JSON mode + an anti-truncation floor (truncated/empty JSON\n // is a common failure mode; json_object is the universally-supported shape).\n if (options.format === 'json' || (options.format && typeof options.format === 'object')) {\n body.response_format = { type: 'json_object' };\n if (typeof body.max_tokens === 'number' && body.max_tokens < 2048) body.max_tokens = 2048;\n }\n}\n\n/**\n * Parse the model's REAL token ceiling out of a \"max_tokens too large\" 400.\n * Deployments cap a model below our static table (e.g. a vLLM behind LiteLLM with\n * max_total_tokens=12288), so a static maxOutput can't be trusted — we adapt to\n * what the deployment actually allows. Returns null if it's not that error.\n * Examples handled:\n * vLLM: \"max_tokens=32768 cannot be greater than max_model_len=max_total_tokens=12288\"\n * OpenAI:\"maximum context length is 8192 tokens\"\n */\nexport function parseMaxTokenLimit(errText: string): number | null {\n const m = errText.match(/max_model_len=(?:max_total_tokens=)?(\\d+)|max_total_tokens=(\\d+)|maximum context length is (\\d+)/i);\n if (!m) return null;\n const n = Number(m[1] || m[2] || m[3]);\n return Number.isFinite(n) && n > 0 ? n : null;\n}\n\n/** Configuration for an OpenAI-compatible provider */\nexport interface OpenAICompatConfig {\n /** Internal provider name (e.g. 'groq') */\n name: string;\n /** Display name shown to users (e.g. 'Groq (Fast Inference)') */\n displayName: string;\n /** Default API base URL */\n defaultBaseUrl: string;\n /** Environment variable name for the API key */\n envKey: string;\n /** Config key name in titan.json providers section */\n configKey: string;\n /** Default model ID */\n defaultModel: string;\n /** Static model list (returned when health check fails) */\n knownModels: string[];\n /** Extra headers to send with every request */\n extraHeaders?: Record<string, string>;\n /** Whether to fetch models from /v1/models endpoint */\n supportsModelList?: boolean;\n /**\n * The /models catalogue is publicly accessible (no API key required).\n * When true, listModels() will fetch the catalogue even when the user\n * has not configured an API key — useful for picker UIs that want to\n * show the full catalogue before the user has chosen / paid for a key.\n * OpenRouter is the canonical example.\n */\n publicModelList?: boolean;\n /** Keep org/ prefix in model name (e.g. NIM API expects 'nvidia/model-name') */\n keepModelPrefix?: boolean;\n}\n\nexport class OpenAICompatProvider extends LLMProvider {\n readonly name: string;\n readonly displayName: string;\n private readonly config: OpenAICompatConfig;\n\n constructor(config: OpenAICompatConfig) {\n super();\n this.name = config.name;\n this.displayName = config.displayName;\n this.config = config;\n }\n\n private get apiKey(): string {\n const cfg = loadConfig();\n const providerCfg = (cfg.providers as Record<string, unknown>)[this.config.configKey] as ProviderConfig | undefined;\n return resolveApiKey(this.config.name, providerCfg?.authProfiles || [], providerCfg?.apiKey || '', this.config.envKey, providerCfg?.rotationStrategy, providerCfg?.credentialCooldownMs);\n }\n\n private get baseUrl(): string {\n const cfg = loadConfig();\n const providerCfg = (cfg.providers as Record<string, unknown>)[this.config.configKey] as ProviderConfig | undefined;\n return providerCfg?.baseUrl || this.config.defaultBaseUrl;\n }\n\n /** Sanitize messages for strict APIs (e.g., NIM) that reject empty content strings */\n private sanitizeMessages(messages: ChatOptions['messages']): ChatOptions['messages'] {\n return messages.map(m => ({\n ...m,\n content: m.content || (m.role === 'assistant' && m.toolCalls ? '' : ' '),\n }));\n }\n\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const rawModel = options.model || this.config.defaultModel;\n // NIM API requires org/model format — keep prefix as-is or add it\n const model = this.config.keepModelPrefix\n ? (rawModel.includes('/') ? rawModel : `${this.name}/${rawModel}`)\n : rawModel.replace(`${this.name}/`, '');\n\n // Kimi API uses dash model IDs (kimi-k2-6) but TITAN uses dots (kimi-k2.6)\n const apiModel = this.config.configKey === 'kimi'\n ? model.replace(/kimi-k2\\.6/g, 'kimi-k2-6').replace(/kimi-k2\\.5/g, 'kimi-k2-5')\n : model;\n const apiKey = this.apiKey;\n if (!apiKey) throw new Error(`${this.displayName} API key not configured (set ${this.config.envKey} or providers.${this.config.configKey}.apiKey)`);\n\n logger.debug(this.name, `Chat request: model=${model}, messages=${options.messages.length}`);\n\n const sanitized = this.sanitizeMessages(options.messages);\n const body: Record<string, unknown> = {\n model: apiModel,\n messages: sanitized.map((m) => {\n if (m.role === 'tool') {\n return { role: 'tool', content: m.content || ' ', tool_call_id: m.toolCallId };\n }\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant',\n content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({\n id: tc.id,\n type: 'function',\n function: { name: tc.function.name, arguments: tc.function.arguments },\n })),\n };\n }\n return { role: m.role, content: m.content || ' ' };\n }),\n max_tokens: clampMaxTokens(model, options.maxTokens),\n };\n\n if (options.tools && options.tools.length > 0) {\n body.tools = options.tools;\n }\n applyCompatToolControls(body, model, options);\n\n if (options.temperature !== undefined) {\n body.temperature = options.temperature;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n ...(this.config.extraHeaders || {}),\n };\n\n const doFetch = () => fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n let response = await doFetch();\n\n // Adaptive max_tokens (model-agnostic): if the deployment caps this model\n // below the max_tokens we requested, it 400s with the real limit. Reduce\n // and retry ONCE so a too-high static ceiling never hard-fails a model.\n if (!response.ok && response.status === 400 && typeof body.max_tokens === 'number') {\n const errText = await response.text();\n const limit = parseMaxTokenLimit(errText);\n if (limit && (body.max_tokens as number) > limit) {\n body.max_tokens = Math.max(512, Math.min(Math.floor(limit / 3), 4096)); // leave room for input\n logger.warn(this.name, `[AdaptiveMaxTokens] ${model} deployment caps total tokens at ${limit}; retrying with max_tokens=${body.max_tokens}`);\n response = await doFetch();\n } else {\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError(`${this.displayName} API`, response, errText, { provider: this.name, model });\n }\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n // Hunt Finding #37: attach status + Retry-After so the router can respect backoff\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError(`${this.displayName} API`, response, errorText, { provider: this.name, model });\n }\n\n const data = await response.json() as Record<string, unknown>;\n const choices = data.choices as Array<Record<string, unknown>> | undefined;\n\n if (!choices || choices.length === 0) {\n return {\n id: (data.id as string) || uuid(),\n content: '',\n usage: undefined,\n finishReason: 'stop',\n model: model.includes('/') ? model : `${this.name}/${model}`,\n };\n }\n\n const choice = choices[0];\n const message = choice.message as Record<string, unknown>;\n\n const toolCalls: ToolCall[] = [];\n if (message.tool_calls) {\n for (const tc of message.tool_calls as Array<Record<string, unknown>>) {\n const fn = tc.function as Record<string, string>;\n toolCalls.push({\n id: (tc.id as string) || uuid(),\n type: 'function',\n function: { name: fn.name, arguments: fn.arguments },\n });\n }\n }\n\n const usage = data.usage as { prompt_tokens: number; completion_tokens: number; total_tokens: number } | undefined;\n\n return {\n id: (data.id as string) || uuid(),\n content: (message.content as string) || '',\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n usage: usage\n ? {\n promptTokens: usage.prompt_tokens,\n completionTokens: usage.completion_tokens,\n totalTokens: usage.total_tokens,\n }\n : undefined,\n finishReason: toolCalls.length > 0 ? 'tool_calls' : (choice.finish_reason as 'stop' | 'length') || 'stop',\n model: model.includes('/') ? model : `${this.name}/${model}`,\n };\n }\n\n async *chatStream(options: ChatOptions): AsyncGenerator<ChatStreamChunk> {\n const rawModel = options.model || this.config.defaultModel;\n const model = this.config.keepModelPrefix\n ? (rawModel.includes('/') ? rawModel : `${this.name}/${rawModel}`)\n : rawModel.replace(`${this.name}/`, '');\n const apiKey = this.apiKey;\n if (!apiKey) { yield { type: 'error', error: `${this.displayName} API key not configured` }; return; }\n\n const sanitized = this.sanitizeMessages(options.messages);\n const body: Record<string, unknown> = {\n model,\n stream: true,\n messages: sanitized.map((m) => {\n if (m.role === 'tool') return { role: 'tool', content: m.content || ' ', tool_call_id: m.toolCallId };\n if (m.role === 'assistant' && m.toolCalls) {\n return {\n role: 'assistant', content: m.content || null,\n tool_calls: m.toolCalls.map((tc) => ({ id: tc.id, type: 'function', function: { name: tc.function.name, arguments: tc.function.arguments } })),\n };\n }\n return { role: m.role, content: m.content || ' ' };\n }),\n max_tokens: clampMaxTokens(model, options.maxTokens),\n };\n if (options.tools && options.tools.length > 0) body.tools = options.tools;\n applyCompatToolControls(body, model, options);\n if (options.temperature !== undefined) body.temperature = options.temperature;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n ...(this.config.extraHeaders || {}),\n };\n\n try {\n const response = await fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: withTimeoutSignal(options.signal, STREAM_FETCH_TIMEOUT_MS),\n });\n\n if (!response.ok || !response.body) {\n const errorText = await response.text();\n // v6.5 — THROW (not yield) so the router routes HTTP errors through\n // retry / fallback chain / circuit breaker, like non-streaming chat().\n const { createProviderError } = await import('./errorTaxonomy.js');\n throw createProviderError(this.displayName, response, errorText, { provider: this.name, model });\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n const toolCalls = new Map<number, { id: string; name: string; args: string }>();\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue;\n const json = line.slice(6).trim();\n if (json === '[DONE]' || !json) continue;\n try {\n const chunk = JSON.parse(json);\n const delta = chunk.choices?.[0]?.delta;\n if (!delta) continue;\n if (delta.content) yield { type: 'text', content: delta.content };\n if (delta.tool_calls) {\n for (const tc of delta.tool_calls) {\n const idx = tc.index ?? 0;\n if (!toolCalls.has(idx)) toolCalls.set(idx, { id: tc.id || '', name: '', args: '' });\n const entry = toolCalls.get(idx)!;\n if (tc.id) entry.id = tc.id;\n if (tc.function?.name) entry.name = tc.function.name;\n if (tc.function?.arguments) entry.args += tc.function.arguments;\n }\n }\n } catch { /* skip malformed SSE lines */ }\n }\n }\n\n for (const [, tc] of toolCalls) {\n if (tc.id && tc.name) {\n yield { type: 'tool_call', toolCall: { id: tc.id, type: 'function', function: { name: tc.name, arguments: tc.args || '{}' } } };\n }\n }\n yield { type: 'done' };\n } catch (error) {\n yield { type: 'error', error: (error as Error).message };\n }\n }\n\n async listModels(): Promise<string[]> {\n if (!this.config.supportsModelList) {\n return this.config.knownModels;\n }\n\n // Some upstream catalogues are public (no auth needed) — those\n // providers set `publicModelList: true` so the picker can show\n // the full catalogue even before the user configures a key.\n // OpenRouter is the canonical example (~365 models, no key).\n const isPublic = this.config.publicModelList === true;\n if (!isPublic && !this.apiKey) {\n return this.config.knownModels;\n }\n\n try {\n const headers: Record<string, string> = {\n ...(this.config.extraHeaders || {}),\n };\n if (this.apiKey) headers['Authorization'] = `Bearer ${this.apiKey}`;\n const response = await fetch(`${this.baseUrl}/models`, {\n headers,\n signal: AbortSignal.timeout(8000),\n });\n if (!response.ok) return this.config.knownModels;\n const data = await response.json() as { data?: Array<{ id: string }> };\n const ids = (data.data || []).map((m) => m.id).filter(Boolean);\n // Sort alphabetically for stable UX (the catalogue is\n // already typically grouped by family).\n ids.sort();\n return ids.length > 0 ? ids : this.config.knownModels;\n } catch {\n return this.config.knownModels;\n }\n }\n\n isConfigured(): boolean {\n return !!this.apiKey;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n if (!this.apiKey) return false;\n const response = await fetch(`${this.baseUrl}/models`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n ...(this.config.extraHeaders || {}),\n },\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n}\n\n// ── Provider Presets ──────────────────────────────────────────────\n\nexport const PROVIDER_PRESETS: OpenAICompatConfig[] = [\n {\n name: 'groq',\n displayName: 'Groq (Fast Inference)',\n defaultBaseUrl: 'https://api.groq.com/openai/v1',\n envKey: 'GROQ_API_KEY',\n configKey: 'groq',\n defaultModel: 'llama-3.3-70b-versatile',\n knownModels: ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant', 'mixtral-8x7b-32768', 'gemma2-9b-it', 'deepseek-r1-distill-llama-70b'],\n supportsModelList: true,\n },\n {\n name: 'mistral',\n displayName: 'Mistral AI',\n defaultBaseUrl: 'https://api.mistral.ai/v1',\n envKey: 'MISTRAL_API_KEY',\n configKey: 'mistral',\n defaultModel: 'mistral-small-latest',\n knownModels: ['mistral-large-latest', 'mistral-medium-latest', 'mistral-small-latest', 'codestral-latest', 'mistral-nemo'],\n supportsModelList: true,\n },\n {\n name: 'fireworks',\n displayName: 'Fireworks AI',\n defaultBaseUrl: 'https://api.fireworks.ai/inference/v1',\n envKey: 'FIREWORKS_API_KEY',\n configKey: 'fireworks',\n defaultModel: 'accounts/fireworks/models/llama-v3p3-70b-instruct',\n knownModels: ['accounts/fireworks/models/llama-v3p3-70b-instruct', 'accounts/fireworks/models/mixtral-8x7b-instruct', 'accounts/fireworks/models/qwen3-8b'],\n supportsModelList: true,\n },\n {\n name: 'xai',\n displayName: 'xAI (Grok)',\n defaultBaseUrl: 'https://api.x.ai/v1',\n envKey: 'XAI_API_KEY',\n configKey: 'xai',\n defaultModel: 'grok-3-fast',\n knownModels: ['grok-3', 'grok-3-fast', 'grok-3-mini', 'grok-3-mini-fast'],\n supportsModelList: true,\n },\n {\n name: 'together',\n displayName: 'Together AI',\n defaultBaseUrl: 'https://api.together.xyz/v1',\n envKey: 'TOGETHER_API_KEY',\n configKey: 'together',\n defaultModel: 'meta-llama/Llama-3.3-70B-Instruct-Turbo',\n knownModels: ['meta-llama/Llama-3.3-70B-Instruct-Turbo', 'deepseek-ai/DeepSeek-R1', 'Qwen/Qwen2.5-72B-Instruct-Turbo', 'mistralai/Mixtral-8x7B-Instruct-v0.1'],\n supportsModelList: true,\n },\n {\n name: 'deepseek',\n displayName: 'DeepSeek',\n defaultBaseUrl: 'https://api.deepseek.com/v1',\n envKey: 'DEEPSEEK_API_KEY',\n configKey: 'deepseek',\n defaultModel: 'deepseek-chat',\n knownModels: ['deepseek-chat', 'deepseek-reasoner'],\n supportsModelList: false,\n },\n {\n name: 'cerebras',\n displayName: 'Cerebras (Ultra-Fast)',\n defaultBaseUrl: 'https://api.cerebras.ai/v1',\n envKey: 'CEREBRAS_API_KEY',\n configKey: 'cerebras',\n defaultModel: 'llama-3.3-70b',\n knownModels: ['llama-3.3-70b', 'llama-3.1-8b', 'qwen-3-32b'],\n supportsModelList: true,\n },\n {\n name: 'cohere',\n displayName: 'Cohere',\n defaultBaseUrl: 'https://api.cohere.com/compatibility/v1',\n envKey: 'COHERE_API_KEY',\n configKey: 'cohere',\n defaultModel: 'command-r-plus',\n knownModels: ['command-r-plus', 'command-r', 'command-r7b'],\n supportsModelList: false,\n },\n {\n name: 'perplexity',\n displayName: 'Perplexity (Search-Augmented)',\n defaultBaseUrl: 'https://api.perplexity.ai',\n envKey: 'PERPLEXITY_API_KEY',\n configKey: 'perplexity',\n defaultModel: 'sonar',\n knownModels: ['sonar', 'sonar-pro', 'sonar-reasoning'],\n supportsModelList: false,\n },\n {\n name: 'venice',\n displayName: 'Venice AI (Privacy-First)',\n defaultBaseUrl: 'https://api.venice.ai/api/v1',\n envKey: 'VENICE_API_KEY',\n configKey: 'venice',\n defaultModel: 'llama-3.3-70b',\n knownModels: ['llama-3.3-70b', 'deepseek-r1-671b', 'qwen-2.5-vl-72b'],\n supportsModelList: true,\n },\n {\n name: 'bedrock',\n displayName: 'AWS Bedrock (via Proxy)',\n defaultBaseUrl: 'http://localhost:4000/v1',\n envKey: 'AWS_BEDROCK_API_KEY',\n configKey: 'bedrock',\n defaultModel: 'anthropic.claude-3-5-sonnet-20241022-v2:0',\n knownModels: ['anthropic.claude-3-5-sonnet-20241022-v2:0', 'amazon.titan-text-premier-v1:0', 'meta.llama3-70b-instruct-v1:0'],\n supportsModelList: false,\n },\n {\n name: 'litellm',\n displayName: 'LiteLLM (Universal Proxy)',\n defaultBaseUrl: 'http://localhost:4000/v1',\n envKey: 'LITELLM_API_KEY',\n configKey: 'litellm',\n defaultModel: 'gpt-4o',\n knownModels: ['gpt-4o', 'claude-sonnet-4-20250514', 'gemini-2.5-flash'],\n supportsModelList: true,\n },\n // NOTE: Azure OpenAI uses custom endpoints (https://{resource}.openai.azure.com/openai/deployments/{model})\n // and requires api-version query param + api-key header instead of Bearer token.\n // Users must configure baseUrl to their Azure deployment endpoint.\n {\n name: 'azure',\n displayName: 'Azure OpenAI (Enterprise)',\n defaultBaseUrl: '',\n envKey: 'AZURE_OPENAI_API_KEY',\n configKey: 'azure',\n defaultModel: 'gpt-4o',\n knownModels: ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1-preview'],\n supportsModelList: false,\n },\n {\n name: 'deepinfra',\n displayName: 'DeepInfra (Fast Inference)',\n defaultBaseUrl: 'https://api.deepinfra.com/v1/openai',\n envKey: 'DEEPINFRA_API_KEY',\n configKey: 'deepinfra',\n defaultModel: 'meta-llama/Llama-3.3-70B-Instruct',\n knownModels: ['meta-llama/Llama-3.3-70B-Instruct', 'mistralai/Mixtral-8x22B-Instruct-v0.1', 'Qwen/Qwen2.5-72B-Instruct', 'deepseek-ai/DeepSeek-R1'],\n supportsModelList: true,\n },\n {\n name: 'sambanova',\n displayName: 'SambaNova (Fast Inference)',\n defaultBaseUrl: 'https://api.sambanova.ai/v1',\n envKey: 'SAMBANOVA_API_KEY',\n configKey: 'sambanova',\n defaultModel: 'Meta-Llama-3.3-70B-Instruct',\n knownModels: ['Meta-Llama-3.3-70B-Instruct', 'DeepSeek-R1-Distill-Llama-70B', 'Qwen2.5-72B-Instruct'],\n supportsModelList: true,\n },\n {\n name: 'kimi',\n displayName: 'Kimi (Moonshot)',\n defaultBaseUrl: 'https://api.moonshot.ai/v1',\n envKey: 'MOONSHOT_API_KEY',\n configKey: 'kimi',\n defaultModel: 'kimi-k2.5',\n knownModels: ['kimi-k2.6', 'kimi-k2.5', 'kimi-k2', 'moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],\n supportsModelList: true,\n },\n {\n name: 'huggingface',\n displayName: 'Hugging Face Inference',\n defaultBaseUrl: 'https://api-inference.huggingface.co/v1',\n envKey: 'HF_API_KEY',\n configKey: 'huggingface',\n defaultModel: 'meta-llama/Llama-3.3-70B-Instruct',\n knownModels: ['meta-llama/Llama-3.3-70B-Instruct', 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'Qwen/Qwen2.5-72B-Instruct', 'microsoft/Phi-3-medium-4k-instruct'],\n supportsModelList: true,\n },\n {\n name: 'ai21',\n displayName: 'AI21 Labs (Jamba)',\n defaultBaseUrl: 'https://api.ai21.com/studio/v1',\n envKey: 'AI21_API_KEY',\n configKey: 'ai21',\n defaultModel: 'jamba-1.5-large',\n knownModels: ['jamba-1.5-large', 'jamba-1.5-mini', 'jamba-instruct'],\n supportsModelList: false,\n },\n {\n name: 'cohere-v2',\n displayName: 'Cohere v2 (OpenAI-compat)',\n defaultBaseUrl: 'https://api.cohere.com/v2',\n envKey: 'COHERE_API_KEY',\n configKey: 'cohere-v2',\n defaultModel: 'command-a-03-2025',\n knownModels: ['command-a-03-2025', 'command-r-plus-08-2024', 'command-r-08-2024', 'command-r7b-12-2024'],\n supportsModelList: false,\n },\n {\n name: 'reka',\n displayName: 'Reka AI',\n defaultBaseUrl: 'https://api.reka.ai/v1',\n envKey: 'REKA_API_KEY',\n configKey: 'reka',\n defaultModel: 'reka-core',\n knownModels: ['reka-core', 'reka-flash', 'reka-edge'],\n supportsModelList: false,\n },\n {\n name: 'zhipu',\n displayName: 'Zhipu GLM',\n defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4',\n envKey: 'ZHIPU_API_KEY',\n configKey: 'zhipu',\n defaultModel: 'glm-4-plus',\n knownModels: ['glm-4-plus', 'glm-4', 'glm-4-flash', 'glm-4-long'],\n supportsModelList: false,\n },\n {\n name: 'yi',\n displayName: '01.AI (Yi)',\n defaultBaseUrl: 'https://api.01.ai/v1',\n envKey: 'YI_API_KEY',\n configKey: 'yi',\n defaultModel: 'yi-large',\n knownModels: ['yi-large', 'yi-medium', 'yi-spark', 'yi-large-turbo'],\n supportsModelList: true,\n },\n {\n name: 'inflection',\n displayName: 'Inflection (Pi)',\n defaultBaseUrl: 'https://api.inflection.ai/v1',\n envKey: 'INFLECTION_API_KEY',\n configKey: 'inflection',\n defaultModel: 'inflection-3-pi',\n knownModels: ['inflection-3-pi', 'inflection-3-productivity'],\n supportsModelList: false,\n },\n {\n name: 'novita',\n displayName: 'Novita AI',\n defaultBaseUrl: 'https://api.novita.ai/v3/openai',\n envKey: 'NOVITA_API_KEY',\n configKey: 'novita',\n defaultModel: 'meta-llama/llama-3.3-70b-instruct',\n knownModels: ['meta-llama/llama-3.3-70b-instruct', 'deepseek/deepseek-r1', 'qwen/qwen-2.5-72b-instruct', 'mistralai/mistral-large-2411'],\n supportsModelList: true,\n },\n {\n name: 'replicate',\n displayName: 'Replicate',\n defaultBaseUrl: 'https://api.replicate.com/v1',\n envKey: 'REPLICATE_API_KEY',\n configKey: 'replicate',\n defaultModel: 'meta/meta-llama-3-70b-instruct',\n knownModels: ['meta/meta-llama-3-70b-instruct', 'mistralai/mixtral-8x7b-instruct-v0.1', 'meta/meta-llama-3.1-405b-instruct'],\n supportsModelList: false,\n },\n {\n name: 'lepton',\n displayName: 'Lepton AI',\n defaultBaseUrl: 'https://llama3-3-70b.lepton.run/api/v1',\n envKey: 'LEPTON_API_KEY',\n configKey: 'lepton',\n defaultModel: 'llama-3.3-70b',\n knownModels: ['llama-3.3-70b', 'mixtral-8x7b', 'qwen2.5-72b'],\n supportsModelList: false,\n },\n {\n name: 'anyscale',\n displayName: 'Anyscale Endpoints',\n defaultBaseUrl: 'https://api.endpoints.anyscale.com/v1',\n envKey: 'ANYSCALE_API_KEY',\n configKey: 'anyscale',\n defaultModel: 'meta-llama/Meta-Llama-3-70B-Instruct',\n knownModels: ['meta-llama/Meta-Llama-3-70B-Instruct', 'mistralai/Mixtral-8x7B-Instruct-v0.1', 'codellama/CodeLlama-70b-Instruct-hf'],\n supportsModelList: true,\n },\n {\n name: 'octo',\n displayName: 'OctoAI',\n defaultBaseUrl: 'https://text.octoai.run/v1',\n envKey: 'OCTOAI_API_KEY',\n configKey: 'octo',\n defaultModel: 'meta-llama-3.1-70b-instruct',\n knownModels: ['meta-llama-3.1-70b-instruct', 'mixtral-8x7b-instruct', 'qwen2.5-72b-instruct'],\n supportsModelList: true,\n },\n {\n name: 'nous',\n displayName: 'Nous Research (Hermes)',\n defaultBaseUrl: 'https://inference-api.nousresearch.com/v1',\n envKey: 'NOUS_API_KEY',\n configKey: 'nous',\n defaultModel: 'hermes-3-llama-3.1-70b',\n knownModels: ['hermes-3-llama-3.1-70b', 'hermes-3-llama-3.1-8b', 'hermes-2-pro-mistral-7b'],\n supportsModelList: false,\n },\n {\n name: 'openrouter',\n displayName: 'OpenRouter (Universal Gateway)',\n defaultBaseUrl: 'https://openrouter.ai/api/v1',\n envKey: 'OPENROUTER_API_KEY',\n configKey: 'openrouter',\n defaultModel: 'anthropic/claude-3.5-sonnet',\n knownModels: [\n 'anthropic/claude-3.5-sonnet',\n 'anthropic/claude-3.5-haiku',\n 'anthropic/claude-3-opus',\n 'openai/gpt-4o',\n 'openai/gpt-4o-mini',\n 'meta-llama/llama-3.3-70b-instruct',\n 'google/gemini-2.5-flash-preview',\n 'deepseek/deepseek-chat',\n 'deepseek/deepseek-r1',\n 'x-ai/grok-3-beta',\n 'nvidia/llama-3.1-nemotron-70b-instruct',\n ],\n supportsModelList: true,\n // OpenRouter's /api/v1/models is publicly accessible — TITAN can\n // pull the full ~365-model catalogue even before the user has\n // configured an OPENROUTER_API_KEY. Lets the picker show every\n // available model so the user can choose first, then add the key.\n publicModelList: true,\n extraHeaders: {\n 'HTTP-Referer': 'https://titan.local',\n 'X-Title': 'TITAN',\n },\n },\n {\n name: 'nvidia',\n displayName: 'NVIDIA NIM',\n defaultBaseUrl: 'https://integrate.api.nvidia.com/v1',\n envKey: 'NVIDIA_API_KEY',\n configKey: 'nvidia',\n defaultModel: 'nvidia/llama-3.3-nemotron-super-49b-v1',\n knownModels: [\n 'nvidia/llama-3.3-nemotron-super-49b-v1',\n 'nvidia/llama-3.3-nemotron-super-49b-v1.5',\n 'nvidia/llama-3.1-nemotron-ultra-253b-v1',\n 'nvidia/llama-3.1-nemotron-70b-instruct',\n 'nvidia/nemotron-3-nano-30b-a3b',\n 'nvidia/nemotron-3-super-120b-a12b',\n ],\n supportsModelList: true,\n keepModelPrefix: true,\n },\n {\n name: 'minimax',\n displayName: 'MiniMax',\n defaultBaseUrl: 'https://api.minimax.chat/v1',\n envKey: 'MINIMAX_API_KEY',\n configKey: 'minimax',\n defaultModel: 'minimax-m2.7',\n knownModels: [\n 'minimax-m2.7',\n 'minimax-m2.7-highspeed',\n 'minimax-m2.5',\n 'minimax-01',\n 'minimax-text-01',\n ],\n supportsModelList: false,\n },\n];\n"],"mappings":"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","names":[]}
@@ -393,6 +393,13 @@ function isRetryableError(error) {
393
393
  function getErrorStatus(error) {
394
394
  return classifyProviderError(error).httpStatus;
395
395
  }
396
+ const __internal_recordSuccess = recordSuccess;
397
+ const __internal_calculateBackoffDelay = calculateBackoffDelay;
398
+ const __internal_parseRetryAfter = parseRetryAfter;
399
+ const __internal_isRetryableError = isRetryableError;
400
+ const __internal_getErrorStatus = getErrorStatus;
401
+ const __internal_RETRY_CONFIG = RETRY_CONFIG;
402
+ const __internal_stripThinkingFromResponse = stripThinkingFromResponse;
396
403
  async function tryFallbackChain(options, primaryModelId, originalError) {
397
404
  const config = loadConfig();
398
405
  const chain = config.agent.fallbackChain;
@@ -943,10 +950,17 @@ async function healthCheckAll() {
943
950
  export {
944
951
  __internal_CIRCUIT_BREAKER_CONFIG,
945
952
  __internal_RETRY_AFTER_FALLBACK_THRESHOLD_MS,
953
+ __internal_RETRY_CONFIG,
954
+ __internal_calculateBackoffDelay,
946
955
  __internal_getCircuitBreaker,
956
+ __internal_getErrorStatus,
947
957
  __internal_isInRateLimitCooldown,
958
+ __internal_isRetryableError,
959
+ __internal_parseRetryAfter,
948
960
  __internal_recordFailure,
949
961
  __internal_recordRateLimitCooldown,
962
+ __internal_recordSuccess,
963
+ __internal_stripThinkingFromResponse,
950
964
  __resetCircuitBreakers__,
951
965
  canRequest,
952
966
  chat,