titan-agent 7.0.0 → 7.1.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 (335) hide show
  1. package/README.md +23 -2
  2. package/dist/agent/agent.js +39 -5
  3. package/dist/agent/agent.js.map +1 -1
  4. package/dist/agent/contextManager.js +1 -1
  5. package/dist/agent/contextManager.js.map +1 -1
  6. package/dist/agent/toolSearch.js +9 -2
  7. package/dist/agent/toolSearch.js.map +1 -1
  8. package/dist/config/schema.js +18 -0
  9. package/dist/config/schema.js.map +1 -1
  10. package/dist/eval/harness.js +4 -1
  11. package/dist/eval/harness.js.map +1 -1
  12. package/dist/gateway/server.js +23 -7
  13. package/dist/gateway/server.js.map +1 -1
  14. package/dist/gateway/slashCommands.js +31 -0
  15. package/dist/gateway/slashCommands.js.map +1 -1
  16. package/dist/mcp/agentTools.js +135 -0
  17. package/dist/mcp/agentTools.js.map +1 -0
  18. package/dist/mcp/server.js +19 -2
  19. package/dist/mcp/server.js.map +1 -1
  20. package/dist/memory/graph.js +2 -0
  21. package/dist/memory/graph.js.map +1 -1
  22. package/dist/providers/errorTaxonomy.js +4 -0
  23. package/dist/providers/errorTaxonomy.js.map +1 -1
  24. package/dist/providers/moa.js +151 -0
  25. package/dist/providers/moa.js.map +1 -0
  26. package/dist/providers/modelCapabilities.js +65 -2
  27. package/dist/providers/modelCapabilities.js.map +1 -1
  28. package/dist/providers/ollama.js +1 -0
  29. package/dist/providers/ollama.js.map +1 -1
  30. package/dist/providers/openai_compat.js +14 -2
  31. package/dist/providers/openai_compat.js.map +1 -1
  32. package/dist/providers/router.js +2 -0
  33. package/dist/providers/router.js.map +1 -1
  34. package/dist/utils/benchMode.js +8 -0
  35. package/dist/utils/benchMode.js.map +1 -0
  36. package/dist/utils/constants.js +1 -1
  37. package/dist/utils/constants.js.map +1 -1
  38. package/package.json +26 -26
  39. package/ui/dist/assets/AboutYouMemory-57X5SqHQ.js +1 -0
  40. package/ui/dist/assets/AuditPanel-AyB8ciLZ.js +1 -0
  41. package/ui/dist/assets/AutonomyPanel-wmVPr-n3.js +1 -0
  42. package/ui/dist/assets/AutopilotPanel-CbLy4lJP.js +1 -0
  43. package/ui/dist/assets/AutoresearchPanel-DxRO1rBF.js +1 -0
  44. package/ui/dist/assets/BackupPanel-BUh9rQ-3.js +1 -0
  45. package/ui/dist/assets/BrowserPanel-OqKwGrIL.js +1 -0
  46. package/ui/dist/assets/CPActivity-DGfS7EY3.js +1 -0
  47. package/ui/dist/assets/CPAgentDetail-p0Kvzhhb.js +1 -0
  48. package/ui/dist/assets/CPAgents-B6wSSQZM.js +1 -0
  49. package/ui/dist/assets/CPApprovals-CYv9Do0i.js +1 -0
  50. package/ui/dist/assets/CPCosts-Dx6Q71rN.js +1 -0
  51. package/ui/dist/assets/CPDashboard-DA8-tE-l.js +1 -0
  52. package/ui/dist/assets/CPFiles-BJ49tzai.js +1 -0
  53. package/ui/dist/assets/CPGoals-h0dKL5V_.js +1 -0
  54. package/ui/dist/assets/CPInbox-CDvefgNH.js +1 -0
  55. package/ui/dist/assets/CPIssueDetail-CnmLzzDD.js +1 -0
  56. package/ui/dist/assets/CPIssues-DknAIMyl.js +1 -0
  57. package/ui/dist/assets/CPLayout-C2nqgkmY.js +2 -0
  58. package/ui/dist/assets/CPOrg-tDbHFphX.js +1 -0
  59. package/ui/dist/assets/CPRuns-UlrIURqG.js +1 -0
  60. package/ui/dist/assets/CPSocial-B-gHgvEw.js +1 -0
  61. package/ui/dist/assets/CPVoice-CJy938ZF.js +1 -0
  62. package/ui/dist/assets/ChannelsPanel-DLbxg1zO.js +1 -0
  63. package/ui/dist/assets/CheckpointsPanel-BB6TT0aE.js +1 -0
  64. package/ui/dist/assets/CommandPostHub-fIslwU_t.js +2 -0
  65. package/ui/dist/assets/ConfirmDialog-6hcNjmAh.js +9 -0
  66. package/ui/dist/assets/CronPanel-DLpw3Y25.js +1 -0
  67. package/ui/dist/assets/DataTable-KVqtDzvP.js +1 -0
  68. package/ui/dist/assets/DreamPanel-lcMXpbEb.js +5 -0
  69. package/ui/dist/assets/EmptyState-D-Dg8B8r.js +1 -0
  70. package/ui/dist/assets/EvalHarnessPanel-BKzRiiQw.js +2 -0
  71. package/ui/dist/assets/EvalPanel-Dtodacmj.js +1 -0
  72. package/ui/dist/assets/FileViewer-DjcVKkO2.js +60 -0
  73. package/ui/dist/assets/FilesPanel-BI90Pplh.js +1 -0
  74. package/ui/dist/assets/FleetPanel-tr0wjAwr.js +1 -0
  75. package/ui/dist/assets/HomelabPanel-m8vMm5rE.js +1 -0
  76. package/ui/dist/assets/InfraView-3WriJnyE.js +2 -0
  77. package/ui/dist/assets/IntegrationsPanel-BmL70fOw.js +1 -0
  78. package/ui/dist/assets/IntelligenceView-BGVxCKD3.js +2 -0
  79. package/ui/dist/assets/LearningPanel-CrYLQ6eV.js +1 -0
  80. package/ui/dist/assets/LiveStudio-CnW3eZYF.js +2 -0
  81. package/ui/dist/assets/LogsPanel-DbShr4Ic.js +1 -0
  82. package/ui/dist/assets/McpPanel-uMYEsPI4.js +1 -0
  83. package/ui/dist/assets/MemoryGraphPanel-C7-Z8f0v.js +1 -0
  84. package/ui/dist/assets/MemoryTaxonomyPanel-KrxN8U1G.js +1 -0
  85. package/ui/dist/assets/MemoryWikiPanel-DI3q6IHC.js +1 -0
  86. package/ui/dist/assets/MeshPanel-D4-g2tlu.js +1 -0
  87. package/ui/dist/assets/MissionCanvas-D8cjakJe.js +61 -0
  88. package/ui/dist/assets/MissionChat-BvqCUf1E.js +3 -0
  89. package/ui/dist/assets/MissionLibrary-CZoJQ9WD.js +1 -0
  90. package/ui/dist/assets/MissionStart-CXCq-_AD.js +1 -0
  91. package/ui/dist/assets/NvidiaPanel-BfI1K5Pg.js +1 -0
  92. package/ui/dist/assets/OrganismPanel-B7Gm9pP-.js +1 -0
  93. package/ui/dist/assets/OverviewPanel-B9tKWRK2.js +1 -0
  94. package/ui/dist/assets/PageHeader-CH85uoZG.js +1 -0
  95. package/ui/dist/assets/PersonaProfilesPanel-BPi8fl-U.js +3 -0
  96. package/ui/dist/assets/PersonasPanel-Dwr7sycT.js +1 -0
  97. package/ui/dist/assets/PhoneDeskPanel-D7qc6wUI.js +1 -0
  98. package/ui/dist/assets/RecipesPanel-DcqPWRSU.js +1 -0
  99. package/ui/dist/assets/SecurityPanel-Bv_B9Ahf.js +1 -0
  100. package/ui/dist/assets/SelfImprovePanel-Ca4rGwEG.js +1 -0
  101. package/ui/dist/assets/SelfProposalsPanel-DteMSASq.js +1 -0
  102. package/ui/dist/assets/SessionsPanel-BdbbKTbL.js +1 -0
  103. package/ui/dist/assets/SessionsTab-BJipiVJs.js +1 -0
  104. package/ui/dist/assets/SettingsPanel-mV7ykOCc.js +1 -0
  105. package/ui/dist/assets/SettingsView-Bu_wYTT5.js +2 -0
  106. package/ui/dist/assets/SkeletonLoader-9H7QWa9E.js +1 -0
  107. package/ui/dist/assets/SkillsPanel-CHwX2kDR.js +1 -0
  108. package/ui/dist/assets/SomaView-Bpsm4ZW7.js +5 -0
  109. package/ui/dist/assets/SomaView-Dghh9om4.css +1 -0
  110. package/ui/dist/assets/StatCard-wmSgMAM3.js +1 -0
  111. package/ui/dist/assets/TeamsPanel-XJiHxdDX.js +1 -0
  112. package/ui/dist/assets/TelemetryPanel-_pmGVxpO.js +1 -0
  113. package/ui/dist/assets/TitanCanvas-Cb7KG80W.css +1 -0
  114. package/ui/dist/assets/TitanCanvas-CmLy7p2N.js +883 -0
  115. package/ui/dist/assets/ToolsView-PHizHZBx.js +2 -0
  116. package/ui/dist/assets/TraceViewer-CYAzIcfB.js +1 -0
  117. package/ui/dist/assets/TracesPanel-CRSN_dzK.js +1 -0
  118. package/ui/dist/assets/TrainingPanel-B9rcuMsV.js +1 -0
  119. package/ui/dist/assets/VoiceOverlay-BL_ns1ZA.js +7 -0
  120. package/ui/dist/assets/VramPanel-BNPQ06_9.js +1 -0
  121. package/ui/dist/assets/WatchView-BgAkNnur.js +13 -0
  122. package/ui/dist/assets/WorkTab-RRpPpEOg.js +1 -0
  123. package/ui/dist/assets/WorkflowBuilderPanel-BPHIH8pf.js +1 -0
  124. package/ui/dist/assets/WorkflowsPanel-DqtmT0NB.js +1 -0
  125. package/ui/dist/assets/approvalHeadline-BRg3ReTi.js +1 -0
  126. package/ui/dist/assets/archive-DcK9HrbE.js +1 -0
  127. package/ui/dist/assets/arrow-left-4c2FnES1.js +1 -0
  128. package/ui/dist/assets/book-open-Ds_yciQm.js +1 -0
  129. package/ui/dist/assets/bot-CWDCc265.js +1 -0
  130. package/ui/dist/assets/chart-column-hhZMdCgB.js +1 -0
  131. package/ui/dist/assets/chevron-right-A_pvnRh_.js +1 -0
  132. package/ui/dist/assets/circle-check-big-C-JUM7wb.js +1 -0
  133. package/ui/dist/assets/circle-stop-yZuG9ZAE.js +1 -0
  134. package/ui/dist/assets/clipboard-list-C2HUEjZc.js +1 -0
  135. package/ui/dist/assets/clock-DSPgndSD.js +1 -0
  136. package/ui/dist/assets/clsx-CjueKrWZ.js +1 -0
  137. package/ui/dist/assets/createLucideIcon-qnlrxww7.js +1 -0
  138. package/ui/dist/assets/database-C1SgHa8T.js +1 -0
  139. package/ui/dist/assets/dollar-sign-D9siqK91.js +1 -0
  140. package/ui/dist/assets/download-CJZWQNfV.js +1 -0
  141. package/ui/dist/assets/external-link-CpQLWKKE.js +1 -0
  142. package/ui/dist/assets/file-text-BbGTi-Po.js +1 -0
  143. package/ui/dist/assets/flask-conical-B1YVft4E.js +1 -0
  144. package/ui/dist/assets/folder-EbR-w2Mq.js +1 -0
  145. package/ui/dist/assets/funnel-D2Dkn8Pf.js +1 -0
  146. package/ui/dist/assets/git-branch-CQ2yNSzU.js +1 -0
  147. package/ui/dist/assets/git-pull-request-BxL5wlGX.js +1 -0
  148. package/ui/dist/assets/index-Cz8190xO.css +2 -0
  149. package/ui/dist/assets/index-WI-E4I3h.js +243 -0
  150. package/ui/dist/assets/jsx-runtime-B15e6lOy.js +1 -0
  151. package/ui/dist/assets/layers-BPu5SRjI.js +1 -0
  152. package/ui/dist/assets/legacy-BIzifT-t.js +3 -0
  153. package/ui/dist/assets/lightbulb-BY7CpMte.js +1 -0
  154. package/ui/dist/assets/link-VDQkrGJw.js +1 -0
  155. package/ui/dist/assets/list-todo-DfnNUV_T.js +1 -0
  156. package/ui/dist/assets/message-square-BpzrINHz.js +1 -0
  157. package/ui/dist/assets/mic-De6oZFaV.js +1 -0
  158. package/ui/dist/assets/missions-y-qg_f9b.js +1 -0
  159. package/ui/dist/assets/network-CM7y1ats.js +1 -0
  160. package/ui/dist/assets/pause-C4TDJSfA.js +1 -0
  161. package/ui/dist/assets/pencil-Dd_vzHE-.js +1 -0
  162. package/ui/dist/assets/play-9WxZWVHA.js +1 -0
  163. package/ui/dist/assets/plug-Dm25Wbrc.js +1 -0
  164. package/ui/dist/assets/plus-CHryCIkk.js +1 -0
  165. package/ui/dist/assets/radio-D-XnoAVu.js +1 -0
  166. package/ui/dist/assets/refresh-cw-Disd5wRB.js +1 -0
  167. package/ui/dist/assets/rotate-ccw-Cw1T2W1T.js +1 -0
  168. package/ui/dist/assets/save-DP7oNar2.js +1 -0
  169. package/ui/dist/assets/search-aNVcX-nv.js +1 -0
  170. package/ui/dist/assets/send-D7iQD57b.js +1 -0
  171. package/ui/dist/assets/server-DFfeYjoM.js +1 -0
  172. package/ui/dist/assets/settings-5NWXzgyY.js +1 -0
  173. package/ui/dist/assets/shared-DLz_Jtg3.js +1 -0
  174. package/ui/dist/assets/shield-check-Cd50jCAn.js +1 -0
  175. package/ui/dist/assets/square-DlcoJ1ZM.js +1 -0
  176. package/ui/dist/assets/terminal-DgFz2Vsf.js +1 -0
  177. package/ui/dist/assets/test-tube-BimtS92_.js +1 -0
  178. package/ui/dist/assets/toggle-right-BMaR-sfT.js +1 -0
  179. package/ui/dist/assets/trash-2-CwUv7ww1.js +1 -0
  180. package/ui/dist/assets/trending-up-Ba9TwEow.js +1 -0
  181. package/ui/dist/assets/trophy-Gfv1QC45.js +1 -0
  182. package/ui/dist/assets/volume-2-BVlfVl2U.js +1 -0
  183. package/ui/dist/assets/wifi-off-CWLeusSV.js +1 -0
  184. package/ui/dist/assets/zoom-out-DeggJ7RM.js +1 -0
  185. package/ui/dist/index.html +4 -2
  186. package/ui/dist/sw.js +1 -1
  187. package/ui/dist/assets/AboutYouMemory-CZKEOd_O.js +0 -11
  188. package/ui/dist/assets/AuditPanel-Bu71N5Er.js +0 -1
  189. package/ui/dist/assets/AutonomyPanel-DB-39dX4.js +0 -11
  190. package/ui/dist/assets/AutopilotPanel-Cj8oKxWv.js +0 -1
  191. package/ui/dist/assets/AutoresearchPanel-3s8pjm6Z.js +0 -6
  192. package/ui/dist/assets/BackupPanel-EUQJMJE7.js +0 -1
  193. package/ui/dist/assets/BrowserPanel-Beo4F5Ar.js +0 -6
  194. package/ui/dist/assets/Button-MdXmb4_n.js +0 -1
  195. package/ui/dist/assets/CPActivity-B1Se9VVc.js +0 -1
  196. package/ui/dist/assets/CPAgentDetail-BYji6tT8.js +0 -1
  197. package/ui/dist/assets/CPAgents-BSUKucTe.js +0 -1
  198. package/ui/dist/assets/CPApprovals-B4v0em6e.js +0 -1
  199. package/ui/dist/assets/CPCosts-9ikh61Kv.js +0 -1
  200. package/ui/dist/assets/CPDashboard-sOok2T5v.js +0 -1
  201. package/ui/dist/assets/CPFiles-DB2nY5JE.js +0 -1
  202. package/ui/dist/assets/CPGoals-8Z1yOY8e.js +0 -1
  203. package/ui/dist/assets/CPInbox-Cq6-UY8F.js +0 -11
  204. package/ui/dist/assets/CPIssueDetail-NAGfmJg8.js +0 -1
  205. package/ui/dist/assets/CPIssues-BzX6Rckx.js +0 -1
  206. package/ui/dist/assets/CPLayout-BcRM6QSg.js +0 -2
  207. package/ui/dist/assets/CPOrg-B7DQ4UQP.js +0 -1
  208. package/ui/dist/assets/CPRuns-D-cpPw_M.js +0 -1
  209. package/ui/dist/assets/CPSocial-DshtmcK0.js +0 -11
  210. package/ui/dist/assets/CPVoice-DfXRnQVU.js +0 -1
  211. package/ui/dist/assets/ChannelsPanel-BnaTOeyf.js +0 -1
  212. package/ui/dist/assets/CheckpointsPanel-C62naE4U.js +0 -1
  213. package/ui/dist/assets/CommandPostHub-B_L1CAss.js +0 -24
  214. package/ui/dist/assets/ConfirmDialog-VErHWAbo.js +0 -1
  215. package/ui/dist/assets/CronPanel-BwMrrZ5d.js +0 -1
  216. package/ui/dist/assets/DataTable-BCqSUuN7.js +0 -1
  217. package/ui/dist/assets/DreamPanel-BNAcCLBB.js +0 -15
  218. package/ui/dist/assets/EmptyState-D9kQf1PX.js +0 -1
  219. package/ui/dist/assets/EvalHarnessPanel-BaMLdBNm.js +0 -2
  220. package/ui/dist/assets/EvalPanel-CW-SSjtg.js +0 -1
  221. package/ui/dist/assets/FileViewer-BL00nsd7.js +0 -61
  222. package/ui/dist/assets/FilesPanel-CeC6YUSd.js +0 -16
  223. package/ui/dist/assets/FleetPanel-EyWF7l3W.js +0 -1
  224. package/ui/dist/assets/HomelabPanel-BRfKRYe7.js +0 -6
  225. package/ui/dist/assets/InfraView-Jmqhg_Yc.js +0 -2
  226. package/ui/dist/assets/InlineEditableField-DgMrLDj1.js +0 -1
  227. package/ui/dist/assets/Input-CBTwa_Iw.js +0 -1
  228. package/ui/dist/assets/IntegrationsPanel-DQL-7Ec6.js +0 -1
  229. package/ui/dist/assets/IntelligenceView-DxD78qfP.js +0 -2
  230. package/ui/dist/assets/LearningPanel-C_JzSbJU.js +0 -1
  231. package/ui/dist/assets/LiveStudio-Db5yeaWo.js +0 -7
  232. package/ui/dist/assets/LogsPanel-CpinKwaZ.js +0 -1
  233. package/ui/dist/assets/McpPanel-D-MqN_f-.js +0 -1
  234. package/ui/dist/assets/MemoryGraphPanel-BnD5jRqf.js +0 -1
  235. package/ui/dist/assets/MemoryTaxonomyPanel-BBI202dd.js +0 -6
  236. package/ui/dist/assets/MemoryWikiPanel-Dn3XZHL0.js +0 -6
  237. package/ui/dist/assets/MeshPanel-C-mRJpr0.js +0 -11
  238. package/ui/dist/assets/MissionCanvas-CbZW83Ch.js +0 -72
  239. package/ui/dist/assets/MissionChat-Bs75jPAD.js +0 -7
  240. package/ui/dist/assets/MissionLibrary-BxQ6SxPe.js +0 -5
  241. package/ui/dist/assets/MissionStart-CBuBPasl.js +0 -1
  242. package/ui/dist/assets/Modal-ybPGvlQs.js +0 -9
  243. package/ui/dist/assets/NvidiaPanel-DdG13OX4.js +0 -1
  244. package/ui/dist/assets/OrganismPanel-xZWUJKyr.js +0 -1
  245. package/ui/dist/assets/OverviewPanel-B45ZYhJV.js +0 -1
  246. package/ui/dist/assets/PageHeader-DdrbS1aq.js +0 -1
  247. package/ui/dist/assets/PersonaProfilesPanel-CKER-EU5.js +0 -8
  248. package/ui/dist/assets/PersonasPanel-CMMQ3nh3.js +0 -1
  249. package/ui/dist/assets/PhoneDeskPanel-Bw_Y-cVE.js +0 -11
  250. package/ui/dist/assets/RecipesPanel-DzMcxpJJ.js +0 -1
  251. package/ui/dist/assets/SecurityPanel-BCq3Fzbr.js +0 -1
  252. package/ui/dist/assets/SelfImprovePanel-YE3hT8jK.js +0 -1
  253. package/ui/dist/assets/SelfProposalsPanel-DXuqBM6p.js +0 -1
  254. package/ui/dist/assets/SessionsPanel-DORz5goR.js +0 -1
  255. package/ui/dist/assets/SessionsTab-qYHDOuC8.js +0 -1
  256. package/ui/dist/assets/SettingsPanel-BbwPu1i7.js +0 -1
  257. package/ui/dist/assets/SettingsView-zgqkDDBJ.js +0 -2
  258. package/ui/dist/assets/SkeletonLoader-r6OGXaU9.js +0 -1
  259. package/ui/dist/assets/SkillsPanel-BjEOBMRo.js +0 -11
  260. package/ui/dist/assets/SomaView-BtCkeWfZ.css +0 -1
  261. package/ui/dist/assets/SomaView-DLzApZVW.js +0 -5
  262. package/ui/dist/assets/StatCard-DLq8aBps.js +0 -1
  263. package/ui/dist/assets/StatusBadge-BqlvIbdj.js +0 -1
  264. package/ui/dist/assets/Tabs-DdUThlp1.js +0 -1
  265. package/ui/dist/assets/TeamsPanel-uIIKoU7I.js +0 -1
  266. package/ui/dist/assets/TelemetryPanel-dVr3yQQr.js +0 -1
  267. package/ui/dist/assets/TitanCanvas-BfitWg9R.css +0 -1
  268. package/ui/dist/assets/TitanCanvas-xHAJqwG2.js +0 -945
  269. package/ui/dist/assets/ToolsView-CG1mZdiy.js +0 -2
  270. package/ui/dist/assets/Tooltip-C2tXJcrN.js +0 -6
  271. package/ui/dist/assets/TraceViewer-BIMD_Osr.js +0 -1
  272. package/ui/dist/assets/TracesPanel-nMUiyMj5.js +0 -1
  273. package/ui/dist/assets/TrainingPanel-CT5R4HWm.js +0 -1
  274. package/ui/dist/assets/VoiceOverlay-Br4QnCtw.js +0 -17
  275. package/ui/dist/assets/VramPanel-CdnJYytg.js +0 -1
  276. package/ui/dist/assets/WatchView-TNU6Ns1Q.js +0 -13
  277. package/ui/dist/assets/WorkTab-wTlX_UKP.js +0 -1
  278. package/ui/dist/assets/WorkflowBuilderPanel-CDpVt5ux.js +0 -6
  279. package/ui/dist/assets/WorkflowsPanel-zsFqsLdn.js +0 -11
  280. package/ui/dist/assets/approvalHeadline-DB9SgR-9.js +0 -1
  281. package/ui/dist/assets/archive-Bh689DNg.js +0 -6
  282. package/ui/dist/assets/arrow-left-WkVYLm80.js +0 -6
  283. package/ui/dist/assets/book-open-ohEXgUsS.js +0 -6
  284. package/ui/dist/assets/bot-DvEcyQcD.js +0 -6
  285. package/ui/dist/assets/chart-column-w3goFd5f.js +0 -6
  286. package/ui/dist/assets/check-CuRYh4Zh.js +0 -6
  287. package/ui/dist/assets/chevron-right-DbLSHmff.js +0 -6
  288. package/ui/dist/assets/circle-check-big-Bkba568b.js +0 -6
  289. package/ui/dist/assets/circle-stop-Bx2ohEg8.js +0 -6
  290. package/ui/dist/assets/clipboard-list-Dj9tORnu.js +0 -6
  291. package/ui/dist/assets/clock-JyQAYy6X.js +0 -6
  292. package/ui/dist/assets/clsx-B-dksMZM.js +0 -1
  293. package/ui/dist/assets/dollar-sign-XxwPAA2a.js +0 -6
  294. package/ui/dist/assets/download-D1izVEOL.js +0 -6
  295. package/ui/dist/assets/external-link-DZ_rZsIt.js +0 -6
  296. package/ui/dist/assets/file-text-Cfawu8Bs.js +0 -6
  297. package/ui/dist/assets/flask-conical-Ql8QxhgY.js +0 -6
  298. package/ui/dist/assets/folder-DAdIw-Pb.js +0 -6
  299. package/ui/dist/assets/funnel-FycfZcXo.js +0 -6
  300. package/ui/dist/assets/git-branch-C2qrhGGu.js +0 -6
  301. package/ui/dist/assets/index-Cml2x9pA.js +0 -507
  302. package/ui/dist/assets/index-yWybhcfI.css +0 -1
  303. package/ui/dist/assets/layers-yzjtGlHB.js +0 -6
  304. package/ui/dist/assets/legacy-D21WSMF1.js +0 -3
  305. package/ui/dist/assets/lightbulb-BZJNK69S.js +0 -6
  306. package/ui/dist/assets/link-CnFkBkaY.js +0 -6
  307. package/ui/dist/assets/list-todo-BlgfQHup.js +0 -6
  308. package/ui/dist/assets/message-square-CRsG9u6_.js +0 -6
  309. package/ui/dist/assets/mic-B32RHc7Y.js +0 -6
  310. package/ui/dist/assets/missions-1iw8Z2_0.js +0 -1
  311. package/ui/dist/assets/network-C9RXQGrV.js +0 -6
  312. package/ui/dist/assets/pause-BT1Bc2q3.js +0 -6
  313. package/ui/dist/assets/pencil-BK5IU6o0.js +0 -6
  314. package/ui/dist/assets/play-Cl1nC_gc.js +0 -6
  315. package/ui/dist/assets/plug-DvcpOalj.js +0 -6
  316. package/ui/dist/assets/plus-Dpo1qfrl.js +0 -6
  317. package/ui/dist/assets/radio-C5c9IyqX.js +0 -6
  318. package/ui/dist/assets/refresh-cw-C-iZkzuS.js +0 -6
  319. package/ui/dist/assets/rotate-ccw-qzrB3SNw.js +0 -6
  320. package/ui/dist/assets/save-DwR9wQVu.js +0 -6
  321. package/ui/dist/assets/search-D10l0m3-.js +0 -6
  322. package/ui/dist/assets/send-DtXGsaFW.js +0 -6
  323. package/ui/dist/assets/server-BzisF3LL.js +0 -6
  324. package/ui/dist/assets/settings-Dbwd1_-c.js +0 -6
  325. package/ui/dist/assets/shield-check-CXlDJyAW.js +0 -6
  326. package/ui/dist/assets/square-BBC-JKzY.js +0 -11
  327. package/ui/dist/assets/terminal-DaBIlWEM.js +0 -6
  328. package/ui/dist/assets/test-tube-CDATRD5t.js +0 -11
  329. package/ui/dist/assets/toggle-right-DTmrC5RD.js +0 -11
  330. package/ui/dist/assets/trash-2-CTeyjxD_.js +0 -6
  331. package/ui/dist/assets/trending-up-CXPRjRV4.js +0 -6
  332. package/ui/dist/assets/trophy-DbVdXRtU.js +0 -6
  333. package/ui/dist/assets/volume-2-DYDBmm3M.js +0 -6
  334. package/ui/dist/assets/wifi-off-BBuIGbiP.js +0 -6
  335. package/ui/dist/assets/zoom-out-D47_pRAO.js +0 -16
@@ -9,7 +9,7 @@ import { compressContext } from "./contextCompressor.js";
9
9
  const COMPONENT = "Context";
10
10
  function calculateBudget(maxContextTokens, systemPrompt, toolDefinitionsCount) {
11
11
  const systemTokens = estimateTokens(systemPrompt);
12
- const toolTokens = toolDefinitionsCount * 120;
12
+ const toolTokens = toolDefinitionsCount * 250;
13
13
  const reserveForResponse = 2e3;
14
14
  return {
15
15
  maxTokens: maxContextTokens,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/agent/contextManager.ts"],"sourcesContent":["/**\n * TITAN — Smart Context Manager\n * Intelligent context window management that none of the competitors do well.\n *\n * Problems this solves:\n * - Auto-GPT wastes tokens on irrelevant history (high cost)\n * - CrewAI has prompt sprawl across agents (unpredictable cost)\n * - Open Interpreter has no context management at all\n *\n * TITAN's approach:\n * - Automatic summarization of old conversation history\n * - Priority-based context allocation (recent > relevant > old)\n * - Token budget tracking and enforcement\n * - Smart truncation that preserves tool call context\n */\nimport logger from '../utils/logger.js';\nimport type { ChatMessage } from '../providers/base.js';\nimport { estimateTokens } from '../utils/tokens.js';\nexport { estimateTokens };\nimport { flushMemoryBeforeCompaction } from '../memory/graph.js';\nimport { getRagContext } from '../memory/vectors.js';\nimport { getPlugins } from '../plugins/registry.js';\nimport { runAssemble, runCompact } from '../plugins/contextEngine.js';\nimport { compressContext, type StructuredSummary } from './contextCompressor.js';\n\nconst COMPONENT = 'Context';\n\ninterface ContextBudget {\n maxTokens: number;\n systemPromptTokens: number;\n toolDefinitionTokens: number;\n remainingForHistory: number;\n}\n\n\n\n/** Calculate the context budget */\nexport function calculateBudget(\n maxContextTokens: number,\n systemPrompt: string,\n toolDefinitionsCount: number,\n): ContextBudget {\n const systemTokens = estimateTokens(systemPrompt);\n const toolTokens = toolDefinitionsCount * 120; // ~120 tokens per tool definition\n const reserveForResponse = 2000; // Reserve for completion\n\n return {\n maxTokens: maxContextTokens,\n systemPromptTokens: systemTokens,\n toolDefinitionTokens: toolTokens,\n remainingForHistory: Math.max(0, maxContextTokens - systemTokens - toolTokens - reserveForResponse),\n };\n}\n\n/** Summarize a batch of messages into a single summary message */\nexport function summarizeMessages(messages: ChatMessage[]): ChatMessage {\n const userMessages = messages.filter((m) => m.role === 'user').map((m) => m.content).filter(Boolean);\n const assistantMessages = messages.filter((m) => m.role === 'assistant').map((m) => m.content).filter(Boolean);\n const toolMessages = messages.filter((m) => m.role === 'tool').length;\n\n const summary = [\n `[Earlier conversation summary — ${messages.length} messages, ${toolMessages} tool calls]`,\n userMessages.length > 0 ? `User discussed: ${userMessages.slice(-3).map((m) => m.slice(0, 80)).join('; ')}` : '',\n assistantMessages.length > 0 ? `Assistant actions: ${assistantMessages.slice(-2).map((m) => m.slice(0, 80)).join('; ')}` : '',\n ].filter(Boolean).join('\\n');\n\n return { role: 'system', content: summary };\n}\n\n/**\n * Compress verbose tool results to save context window space.\n * Keeps the last 5 tool results at full fidelity, summarizes older ones.\n */\nfunction compressToolResults(messages: ChatMessage[]): ChatMessage[] {\n // Count tool messages from the end to find the cutoff\n let toolCount = 0;\n const toolIndices: number[] = [];\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === 'tool') {\n toolCount++;\n toolIndices.push(i);\n }\n }\n\n // If 5 or fewer tool results, nothing to compress\n if (toolCount <= 5) return messages;\n\n // Indices of tool messages to keep at full fidelity (last 5)\n const keepFullSet = new Set(toolIndices.slice(0, 5));\n\n return messages.map((msg, i) => {\n if (msg.role !== 'tool' || keepFullSet.has(i)) return msg;\n const content = msg.content || '';\n if (content.length <= 500) return msg;\n\n // Compress: keep first 150 chars + success/error status\n const isError = content.toLowerCase().includes('error:');\n const summary = `[${msg.name || 'tool'}: ${isError ? 'FAILED' : 'OK'}] ${content.slice(0, 150)}... [${content.length} chars compressed]`;\n return { ...msg, content: summary };\n });\n}\n\n/** Persistent structured summary for iterative context compression */\nlet currentSummary: StructuredSummary | null = null;\n\n/**\n * TITAN pattern: MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES\n * Disables compaction after 3 consecutive failures per session to prevent\n * wasted API calls (This class of bug can waste 250K+ API calls/day).\n */\nlet consecutiveCompactFailures = 0;\nconst MAX_CONSECUTIVE_COMPACT_FAILURES = 3;\n\n/** Reset compact failure counter (call on new session) */\nexport function resetCompactFailures(): void {\n consecutiveCompactFailures = 0;\n}\n\n/** Get the current structured summary (for external access) */\nexport function getStructuredSummary(): StructuredSummary | null {\n return currentSummary;\n}\n\n/** Set the structured summary (e.g., from agent loop state) */\nexport function setStructuredSummary(summary: StructuredSummary | null): void {\n currentSummary = summary;\n}\n\n/**\n * Smart context builder — fits messages within token budget.\n * Uses the 5-phase compression pipeline (Hermes-inspired):\n * 1. Tool output pruning (no LLM call)\n * 2. Head protection (system + first 3 messages)\n * 3. Tail protection (last N messages, 5% of budget)\n * 4. Structured middle summary\n * 5. Iterative summary updates\n */\nexport function buildSmartContext(\n messages: ChatMessage[],\n tokenBudget: number,\n): ChatMessage[] {\n if (messages.length === 0) return [];\n\n // TITAN pattern: skip compaction after consecutive failures\n if (consecutiveCompactFailures >= MAX_CONSECUTIVE_COMPACT_FAILURES) {\n logger.warn(COMPONENT, `Compaction disabled after ${consecutiveCompactFailures} consecutive failures — returning raw messages`);\n return messages;\n }\n\n let result;\n try {\n result = compressContext(messages, tokenBudget, currentSummary);\n consecutiveCompactFailures = 0; // Reset on success\n } catch (err) {\n consecutiveCompactFailures++;\n logger.warn(COMPONENT, `Compaction failed (${consecutiveCompactFailures}/${MAX_CONSECUTIVE_COMPACT_FAILURES}): ${(err as Error).message}`);\n return messages; // Return uncompressed on failure\n }\n\n // Store summary for iterative updates on next compression\n if (result.summary) {\n currentSummary = result.summary;\n }\n\n if (result.savedTokens > 0) {\n logger.debug(COMPONENT, `Smart context: ${messages.length} → ${result.messages.length} messages, saved ~${result.savedTokens} tokens`);\n }\n\n return result.messages;\n}\n\n/**\n * Force context compaction (used by /compact command).\n * Uses the 5-phase pipeline with an aggressive budget to maximize compression.\n */\nexport function forceCompactContext(\n messages: ChatMessage[],\n): { messages: ChatMessage[]; savedTokens: number } {\n if (messages.length <= 4) {\n return { messages, savedTokens: 0 };\n }\n\n // Flush important context to graph memory before discarding (fire-and-forget)\n const toFlush = messages.filter(m => m.role !== 'system');\n flushMemoryBeforeCompaction(toFlush).catch((err) =>\n logger.warn(COMPONENT, `Memory flush before compaction failed: ${(err as Error).message}`),\n );\n\n // Aggressive budget: 4000 tokens forces maximum compression\n const result = compressContext(messages, 4000, currentSummary);\n\n if (result.summary) {\n currentSummary = result.summary;\n }\n\n logger.info(COMPONENT, `Force compacted: ${messages.length} → ${result.messages.length} messages, saved ~${result.savedTokens} tokens`);\n return { messages: result.messages, savedTokens: result.savedTokens };\n}\n\n/** Get context window stats */\nexport function getContextStats(messages: ChatMessage[]): {\n messageCount: number;\n estimatedTokens: number;\n userMessages: number;\n assistantMessages: number;\n toolCalls: number;\n} {\n let tokens = 0;\n let userMsgs = 0;\n let assistantMsgs = 0;\n let toolCalls = 0;\n\n for (const m of messages) {\n tokens += estimateTokens(m.content || '');\n if (m.role === 'user') userMsgs++;\n if (m.role === 'assistant') assistantMsgs++;\n if (m.toolCalls) toolCalls += m.toolCalls.length;\n }\n\n return {\n messageCount: messages.length,\n estimatedTokens: tokens,\n userMessages: userMsgs,\n assistantMessages: assistantMsgs,\n toolCalls,\n };\n}\n\n/**\n * Inject RAG context into messages before the agent turn.\n * Queries the RAG vector store with the latest user message and prepends\n * relevant chunks as a system message.\n */\nexport async function injectRagContext(\n messages: ChatMessage[],\n topK: number = 3,\n): Promise<ChatMessage[]> {\n // Find the last user message\n const lastUserMsg = [...messages].reverse().find(m => m.role === 'user');\n if (!lastUserMsg?.content) return messages;\n\n try {\n const ragContext = await getRagContext(lastUserMsg.content, topK);\n if (!ragContext) return messages;\n\n logger.debug(COMPONENT, `Injecting RAG context (${ragContext.length} chars) for query: \"${lastUserMsg.content.slice(0, 80)}\"`);\n\n const ragMessage: ChatMessage = {\n role: 'system',\n content: `[Relevant knowledge from ingested documents]\\n${ragContext}`,\n };\n\n // Insert RAG context before the last user message\n const result = [...messages];\n const lastUserIndex = result.lastIndexOf(lastUserMsg);\n if (lastUserIndex >= 0) {\n result.splice(lastUserIndex, 0, ragMessage);\n } else {\n result.push(ragMessage);\n }\n return result;\n } catch (e) {\n logger.debug(COMPONENT, `RAG context injection failed: ${(e as Error).message}`);\n return messages;\n }\n}\n\n/**\n * Assemble context with plugin hooks.\n * Runs RAG injection first (built-in), then all registered plugins.\n */\nexport async function assembleContextWithPlugins(\n messages: ChatMessage[],\n userMessage: string,\n ragTopK: number = 3,\n): Promise<ChatMessage[]> {\n // Built-in RAG injection as first step\n let result = await injectRagContext(messages, ragTopK);\n\n // Run registered plugin assemble hooks\n const plugins = getPlugins();\n if (plugins.length > 0) {\n result = await runAssemble(plugins, result, userMessage);\n }\n\n return result;\n}\n\n/**\n * Compact context with plugin hooks.\n * Runs built-in smart context first, then all registered plugins.\n */\nexport async function compactContextWithPlugins(\n messages: ChatMessage[],\n maxTokens: number,\n): Promise<ChatMessage[]> {\n // Built-in smart context compaction\n let result = buildSmartContext(messages, maxTokens);\n\n // Run registered plugin compact hooks\n const plugins = getPlugins();\n if (plugins.length > 0) {\n result = await runCompact(plugins, result, maxTokens);\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/agent/contextManager.ts"],"sourcesContent":["/**\n * TITAN — Smart Context Manager\n * Intelligent context window management that none of the competitors do well.\n *\n * Problems this solves:\n * - Auto-GPT wastes tokens on irrelevant history (high cost)\n * - CrewAI has prompt sprawl across agents (unpredictable cost)\n * - Open Interpreter has no context management at all\n *\n * TITAN's approach:\n * - Automatic summarization of old conversation history\n * - Priority-based context allocation (recent > relevant > old)\n * - Token budget tracking and enforcement\n * - Smart truncation that preserves tool call context\n */\nimport logger from '../utils/logger.js';\nimport type { ChatMessage } from '../providers/base.js';\nimport { estimateTokens } from '../utils/tokens.js';\nexport { estimateTokens };\nimport { flushMemoryBeforeCompaction } from '../memory/graph.js';\nimport { getRagContext } from '../memory/vectors.js';\nimport { getPlugins } from '../plugins/registry.js';\nimport { runAssemble, runCompact } from '../plugins/contextEngine.js';\nimport { compressContext, type StructuredSummary } from './contextCompressor.js';\n\nconst COMPONENT = 'Context';\n\ninterface ContextBudget {\n maxTokens: number;\n systemPromptTokens: number;\n toolDefinitionTokens: number;\n remainingForHistory: number;\n}\n\n\n\n/** Calculate the context budget */\nexport function calculateBudget(\n maxContextTokens: number,\n systemPrompt: string,\n toolDefinitionsCount: number,\n): ContextBudget {\n const systemTokens = estimateTokens(systemPrompt);\n const toolTokens = toolDefinitionsCount * 250; // measured avg 887 chars (~250 tok) per definition — 120 undercounted 4x and blew small contexts\n const reserveForResponse = 2000; // Reserve for completion\n\n return {\n maxTokens: maxContextTokens,\n systemPromptTokens: systemTokens,\n toolDefinitionTokens: toolTokens,\n remainingForHistory: Math.max(0, maxContextTokens - systemTokens - toolTokens - reserveForResponse),\n };\n}\n\n/** Summarize a batch of messages into a single summary message */\nexport function summarizeMessages(messages: ChatMessage[]): ChatMessage {\n const userMessages = messages.filter((m) => m.role === 'user').map((m) => m.content).filter(Boolean);\n const assistantMessages = messages.filter((m) => m.role === 'assistant').map((m) => m.content).filter(Boolean);\n const toolMessages = messages.filter((m) => m.role === 'tool').length;\n\n const summary = [\n `[Earlier conversation summary — ${messages.length} messages, ${toolMessages} tool calls]`,\n userMessages.length > 0 ? `User discussed: ${userMessages.slice(-3).map((m) => m.slice(0, 80)).join('; ')}` : '',\n assistantMessages.length > 0 ? `Assistant actions: ${assistantMessages.slice(-2).map((m) => m.slice(0, 80)).join('; ')}` : '',\n ].filter(Boolean).join('\\n');\n\n return { role: 'system', content: summary };\n}\n\n/**\n * Compress verbose tool results to save context window space.\n * Keeps the last 5 tool results at full fidelity, summarizes older ones.\n */\nfunction compressToolResults(messages: ChatMessage[]): ChatMessage[] {\n // Count tool messages from the end to find the cutoff\n let toolCount = 0;\n const toolIndices: number[] = [];\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i].role === 'tool') {\n toolCount++;\n toolIndices.push(i);\n }\n }\n\n // If 5 or fewer tool results, nothing to compress\n if (toolCount <= 5) return messages;\n\n // Indices of tool messages to keep at full fidelity (last 5)\n const keepFullSet = new Set(toolIndices.slice(0, 5));\n\n return messages.map((msg, i) => {\n if (msg.role !== 'tool' || keepFullSet.has(i)) return msg;\n const content = msg.content || '';\n if (content.length <= 500) return msg;\n\n // Compress: keep first 150 chars + success/error status\n const isError = content.toLowerCase().includes('error:');\n const summary = `[${msg.name || 'tool'}: ${isError ? 'FAILED' : 'OK'}] ${content.slice(0, 150)}... [${content.length} chars compressed]`;\n return { ...msg, content: summary };\n });\n}\n\n/** Persistent structured summary for iterative context compression */\nlet currentSummary: StructuredSummary | null = null;\n\n/**\n * TITAN pattern: MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES\n * Disables compaction after 3 consecutive failures per session to prevent\n * wasted API calls (This class of bug can waste 250K+ API calls/day).\n */\nlet consecutiveCompactFailures = 0;\nconst MAX_CONSECUTIVE_COMPACT_FAILURES = 3;\n\n/** Reset compact failure counter (call on new session) */\nexport function resetCompactFailures(): void {\n consecutiveCompactFailures = 0;\n}\n\n/** Get the current structured summary (for external access) */\nexport function getStructuredSummary(): StructuredSummary | null {\n return currentSummary;\n}\n\n/** Set the structured summary (e.g., from agent loop state) */\nexport function setStructuredSummary(summary: StructuredSummary | null): void {\n currentSummary = summary;\n}\n\n/**\n * Smart context builder — fits messages within token budget.\n * Uses the 5-phase compression pipeline (Hermes-inspired):\n * 1. Tool output pruning (no LLM call)\n * 2. Head protection (system + first 3 messages)\n * 3. Tail protection (last N messages, 5% of budget)\n * 4. Structured middle summary\n * 5. Iterative summary updates\n */\nexport function buildSmartContext(\n messages: ChatMessage[],\n tokenBudget: number,\n): ChatMessage[] {\n if (messages.length === 0) return [];\n\n // TITAN pattern: skip compaction after consecutive failures\n if (consecutiveCompactFailures >= MAX_CONSECUTIVE_COMPACT_FAILURES) {\n logger.warn(COMPONENT, `Compaction disabled after ${consecutiveCompactFailures} consecutive failures — returning raw messages`);\n return messages;\n }\n\n let result;\n try {\n result = compressContext(messages, tokenBudget, currentSummary);\n consecutiveCompactFailures = 0; // Reset on success\n } catch (err) {\n consecutiveCompactFailures++;\n logger.warn(COMPONENT, `Compaction failed (${consecutiveCompactFailures}/${MAX_CONSECUTIVE_COMPACT_FAILURES}): ${(err as Error).message}`);\n return messages; // Return uncompressed on failure\n }\n\n // Store summary for iterative updates on next compression\n if (result.summary) {\n currentSummary = result.summary;\n }\n\n if (result.savedTokens > 0) {\n logger.debug(COMPONENT, `Smart context: ${messages.length} → ${result.messages.length} messages, saved ~${result.savedTokens} tokens`);\n }\n\n return result.messages;\n}\n\n/**\n * Force context compaction (used by /compact command).\n * Uses the 5-phase pipeline with an aggressive budget to maximize compression.\n */\nexport function forceCompactContext(\n messages: ChatMessage[],\n): { messages: ChatMessage[]; savedTokens: number } {\n if (messages.length <= 4) {\n return { messages, savedTokens: 0 };\n }\n\n // Flush important context to graph memory before discarding (fire-and-forget)\n const toFlush = messages.filter(m => m.role !== 'system');\n flushMemoryBeforeCompaction(toFlush).catch((err) =>\n logger.warn(COMPONENT, `Memory flush before compaction failed: ${(err as Error).message}`),\n );\n\n // Aggressive budget: 4000 tokens forces maximum compression\n const result = compressContext(messages, 4000, currentSummary);\n\n if (result.summary) {\n currentSummary = result.summary;\n }\n\n logger.info(COMPONENT, `Force compacted: ${messages.length} → ${result.messages.length} messages, saved ~${result.savedTokens} tokens`);\n return { messages: result.messages, savedTokens: result.savedTokens };\n}\n\n/** Get context window stats */\nexport function getContextStats(messages: ChatMessage[]): {\n messageCount: number;\n estimatedTokens: number;\n userMessages: number;\n assistantMessages: number;\n toolCalls: number;\n} {\n let tokens = 0;\n let userMsgs = 0;\n let assistantMsgs = 0;\n let toolCalls = 0;\n\n for (const m of messages) {\n tokens += estimateTokens(m.content || '');\n if (m.role === 'user') userMsgs++;\n if (m.role === 'assistant') assistantMsgs++;\n if (m.toolCalls) toolCalls += m.toolCalls.length;\n }\n\n return {\n messageCount: messages.length,\n estimatedTokens: tokens,\n userMessages: userMsgs,\n assistantMessages: assistantMsgs,\n toolCalls,\n };\n}\n\n/**\n * Inject RAG context into messages before the agent turn.\n * Queries the RAG vector store with the latest user message and prepends\n * relevant chunks as a system message.\n */\nexport async function injectRagContext(\n messages: ChatMessage[],\n topK: number = 3,\n): Promise<ChatMessage[]> {\n // Find the last user message\n const lastUserMsg = [...messages].reverse().find(m => m.role === 'user');\n if (!lastUserMsg?.content) return messages;\n\n try {\n const ragContext = await getRagContext(lastUserMsg.content, topK);\n if (!ragContext) return messages;\n\n logger.debug(COMPONENT, `Injecting RAG context (${ragContext.length} chars) for query: \"${lastUserMsg.content.slice(0, 80)}\"`);\n\n const ragMessage: ChatMessage = {\n role: 'system',\n content: `[Relevant knowledge from ingested documents]\\n${ragContext}`,\n };\n\n // Insert RAG context before the last user message\n const result = [...messages];\n const lastUserIndex = result.lastIndexOf(lastUserMsg);\n if (lastUserIndex >= 0) {\n result.splice(lastUserIndex, 0, ragMessage);\n } else {\n result.push(ragMessage);\n }\n return result;\n } catch (e) {\n logger.debug(COMPONENT, `RAG context injection failed: ${(e as Error).message}`);\n return messages;\n }\n}\n\n/**\n * Assemble context with plugin hooks.\n * Runs RAG injection first (built-in), then all registered plugins.\n */\nexport async function assembleContextWithPlugins(\n messages: ChatMessage[],\n userMessage: string,\n ragTopK: number = 3,\n): Promise<ChatMessage[]> {\n // Built-in RAG injection as first step\n let result = await injectRagContext(messages, ragTopK);\n\n // Run registered plugin assemble hooks\n const plugins = getPlugins();\n if (plugins.length > 0) {\n result = await runAssemble(plugins, result, userMessage);\n }\n\n return result;\n}\n\n/**\n * Compact context with plugin hooks.\n * Runs built-in smart context first, then all registered plugins.\n */\nexport async function compactContextWithPlugins(\n messages: ChatMessage[],\n maxTokens: number,\n): Promise<ChatMessage[]> {\n // Built-in smart context compaction\n let result = buildSmartContext(messages, maxTokens);\n\n // Run registered plugin compact hooks\n const plugins = getPlugins();\n if (plugins.length > 0) {\n result = await runCompact(plugins, result, maxTokens);\n }\n\n return result;\n}\n"],"mappings":"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","names":[]}
@@ -47,8 +47,15 @@ const DEFAULT_CORE_TOOLS = [
47
47
  "list_spaces"
48
48
  ];
49
49
  function buildToolCatalog() {
50
- const tools = getRegisteredTools();
51
- return tools.filter((t) => t.name !== "tool_search").map((t) => `${t.name}: ${t.description.slice(0, 50)}`).join(" | ");
50
+ const tools = getRegisteredTools().filter((t) => t.name !== "tool_search");
51
+ const groups = /* @__PURE__ */ new Map();
52
+ for (const t of tools) {
53
+ const ns = t.name.includes("_") ? t.name.split("_")[0] : t.name;
54
+ const g = groups.get(ns) || [];
55
+ g.push(t.name);
56
+ groups.set(ns, g);
57
+ }
58
+ return [...groups.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([ns, names]) => names.length === 1 ? names[0] : `${ns}: ${names.join(", ")}`).join(" | ");
52
59
  }
53
60
  function searchTools(query, metadataOnly = false) {
54
61
  const tools = getRegisteredTools();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/agent/toolSearch.ts"],"sourcesContent":["/**\n * TITAN — Tool Search\n *\n * Meta-tool that lets the LLM discover tools on demand instead of seeing\n * all 80+ tool schemas on every request. Reduces input tokens by 60-80%.\n *\n * How it works:\n * 1. Only core tools + tool_search are sent to the LLM (5-8 tools, ~600 tokens)\n * 2. tool_search description includes a compact catalog of ALL available tools\n * 3. When the LLM calls tool_search, matching tools are returned\n * 4. Agent loop adds discovered tools to activeTools for subsequent rounds\n *\n * Inspired by Anthropic's tool search pattern (2025) but works with ALL providers.\n */\nimport { getRegisteredTools, type ToolHandler } from './toolRunner.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'ToolSearch';\n\n/** Default core tools — always sent to the LLM without needing search */\nexport const DEFAULT_CORE_TOOLS = [\n 'shell',\n 'read_file',\n 'write_file',\n 'edit_file',\n 'list_dir',\n 'web_search',\n 'web_fetch',\n 'web_act',\n 'smart_form_fill',\n 'weather',\n 'memory',\n // v7.0: \"remind me at X\" is a core personal-assistant verb — models were\n // fabricating reminders precisely because this tool wasn't in their view.\n 'reminder',\n 'system_info',\n 'goal_list',\n 'spawn_agent',\n 'tool_search',\n 'tool_expand',\n 'self_doctor',\n 'ha_control',\n 'ha_devices',\n 'ha_status',\n 'gallery_search',\n 'gallery_get',\n 'gallery_list',\n // v6.0.2 — Canvas widget tools must always be visible so the model\n // reaches for them on \"build me X\" prompts (the v6.0 thesis). Before\n // this, only gallery_search was in core; create_widget was only\n // discoverable via tool_search, which the model rarely called for\n // novel asks like \"build me a solar system\" — it'd fall through to\n // shell + mkdir instead. These four tools are cheap (~80 tokens\n // combined) and they're load-bearing for the Living Canvas pitch.\n 'create_widget',\n 'update_widget',\n 'remove_widget',\n 'list_active_widgets',\n // Spaces tools — same logic: workspaces are a v6.0 first-class concept,\n // the model needs to know it can create / switch / list them by name.\n 'create_space',\n 'switch_space',\n 'list_spaces',\n];\n\n/** Build a compact one-line catalog of all tools for the tool_search description */\nexport function buildToolCatalog(): string {\n const tools = getRegisteredTools();\n return tools\n .filter(t => t.name !== 'tool_search')\n .map(t => `${t.name}: ${t.description.slice(0, 50)}`)\n .join(' | ');\n}\n\n/**\n * Search registered tools by keyword query.\n *\n * Progressive disclosure mode (Hermes competitive gap fix):\n * When metadataOnly=true, returns tools with truncated descriptions\n * and no parameter schemas — ~20 tokens each instead of ~200.\n * The model then calls tool_expand(name) to get the full schema\n * for just the tools it needs.\n */\nexport function searchTools(query: string, metadataOnly = false): ToolHandler[] {\n const tools = getRegisteredTools();\n const terms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\n const scored = tools\n .filter(t => t.name !== 'tool_search' && t.name !== 'tool_expand')\n .map(t => {\n const text = `${t.name} ${t.description}`.toLowerCase();\n const score = terms.reduce((s, term) => s + (text.includes(term) ? 1 : 0), 0);\n return { tool: t, score };\n })\n .filter(({ score }) => score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 8);\n\n if (metadataOnly) {\n // Return lightweight metadata — just name + one-line description\n return scored.map(({ tool }) => ({\n ...tool,\n description: tool.description.slice(0, 80),\n parameters: { type: 'object' as const, properties: {}, required: [] },\n }));\n }\n\n return scored.map(({ tool }) => tool);\n}\n\n/**\n * Expand a single tool's full schema by name.\n * Part of the progressive disclosure pattern — model calls tool_search\n * to get names, then tool_expand to get the full schema for just the\n * tools it needs.\n */\nexport function expandTool(name: string): ToolHandler | null {\n const tools = getRegisteredTools();\n return tools.find(t => t.name === name) || null;\n}\n\n/** Get the tool_search tool handler */\nexport function getToolSearchHandler(): ToolHandler {\n const catalog = buildToolCatalog();\n\n return {\n name: 'tool_search',\n description: `Search for tools by keyword to discover capabilities. Call this FIRST when you need a tool not in your current list. Available tools: ${catalog}`,\n parameters: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query — keywords describing what you need (e.g. \"email send\", \"browser screenshot\", \"github pr\", \"cron schedule\")',\n },\n },\n required: ['query'],\n },\n execute: async (args: Record<string, unknown>) => {\n const query = (args.query as string) || '';\n if (!query.trim()) {\n return 'Please provide a search query. Example: tool_search({query: \"email\"})';\n }\n\n const results = searchTools(query);\n\n if (results.length === 0) {\n return `No tools found matching \"${query}\". Try broader keywords.`;\n }\n\n logger.info(COMPONENT, `Search \"${query}\" → ${results.length} tools: [${results.map(t => t.name).join(', ')}]`);\n\n const formatted = results.map(t => {\n const params = t.parameters as Record<string, unknown>;\n const props = (params.properties || {}) as Record<string, unknown>;\n const paramNames = Object.keys(props).join(', ');\n return `**${t.name}**(${paramNames}): ${t.description}`;\n }).join('\\n');\n\n return `Found ${results.length} tools:\\n${formatted}\\n\\nYou can now call these tools directly.`;\n },\n };\n}\n\n/**\n * Get the tool_expand handler — progressive disclosure (Hermes gap fix).\n * Returns the full JSON schema for a single tool by name.\n */\nexport function getToolExpandHandler(): ToolHandler {\n return {\n name: 'tool_expand',\n description: 'Get the full parameter schema for a specific tool. Use after tool_search to see the detailed parameters before calling the tool.',\n parameters: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description: 'The exact tool name to expand (e.g. \"email_send\", \"freelance_search\")',\n },\n },\n required: ['name'],\n },\n execute: async (args: Record<string, unknown>) => {\n const name = (args.name as string) || '';\n if (!name.trim()) {\n return 'Please provide a tool name. Example: tool_expand({name: \"email_send\"})';\n }\n\n const tool = expandTool(name);\n if (!tool) {\n return `Tool \"${name}\" not found. Use tool_search to find the correct name.`;\n }\n\n logger.info(COMPONENT, `Expand \"${name}\" → full schema loaded`);\n\n const params = tool.parameters as Record<string, unknown>;\n const props = (params.properties || {}) as Record<string, { type?: string; description?: string }>;\n const required = (params.required || []) as string[];\n\n const paramDocs = Object.entries(props).map(([key, val]) => {\n const req = required.includes(key) ? ' (required)' : '';\n return ` - **${key}**${req}: ${val.description || val.type || 'any'}`;\n }).join('\\n');\n\n return `## ${tool.name}\\n${tool.description}\\n\\n### Parameters\\n${paramDocs || ' (no parameters)'}\\n\\nYou can now call ${tool.name}() with these parameters.`;\n },\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/agent/toolSearch.ts"],"sourcesContent":["/**\n * TITAN — Tool Search\n *\n * Meta-tool that lets the LLM discover tools on demand instead of seeing\n * all 80+ tool schemas on every request. Reduces input tokens by 60-80%.\n *\n * How it works:\n * 1. Only core tools + tool_search are sent to the LLM (5-8 tools, ~600 tokens)\n * 2. tool_search description includes a compact catalog of ALL available tools\n * 3. When the LLM calls tool_search, matching tools are returned\n * 4. Agent loop adds discovered tools to activeTools for subsequent rounds\n *\n * Inspired by Anthropic's tool search pattern (2025) but works with ALL providers.\n */\nimport { getRegisteredTools, type ToolHandler } from './toolRunner.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'ToolSearch';\n\n/** Default core tools — always sent to the LLM without needing search */\nexport const DEFAULT_CORE_TOOLS = [\n 'shell',\n 'read_file',\n 'write_file',\n 'edit_file',\n 'list_dir',\n 'web_search',\n 'web_fetch',\n 'web_act',\n 'smart_form_fill',\n 'weather',\n 'memory',\n // v7.0: \"remind me at X\" is a core personal-assistant verb — models were\n // fabricating reminders precisely because this tool wasn't in their view.\n 'reminder',\n 'system_info',\n 'goal_list',\n 'spawn_agent',\n 'tool_search',\n 'tool_expand',\n 'self_doctor',\n 'ha_control',\n 'ha_devices',\n 'ha_status',\n 'gallery_search',\n 'gallery_get',\n 'gallery_list',\n // v6.0.2 — Canvas widget tools must always be visible so the model\n // reaches for them on \"build me X\" prompts (the v6.0 thesis). Before\n // this, only gallery_search was in core; create_widget was only\n // discoverable via tool_search, which the model rarely called for\n // novel asks like \"build me a solar system\" — it'd fall through to\n // shell + mkdir instead. These four tools are cheap (~80 tokens\n // combined) and they're load-bearing for the Living Canvas pitch.\n 'create_widget',\n 'update_widget',\n 'remove_widget',\n 'list_active_widgets',\n // Spaces tools — same logic: workspaces are a v6.0 first-class concept,\n // the model needs to know it can create / switch / list them by name.\n 'create_space',\n 'switch_space',\n 'list_spaces',\n];\n\n/** Build a compact one-line catalog of all tools for the tool_search description */\nexport function buildToolCatalog(): string {\n // v7.1: names-only, grouped by namespace prefix. The old form embedded a\n // 50-char description per tool — 18.5KB (~5K tokens) inside tool_search's\n // OWN description, the single fattest item in every request. Names alone\n // keep the full surface discoverable (tool_search returns full schemas on\n // demand) at ~1/5 the size — for every model, local or cloud.\n const tools = getRegisteredTools().filter(t => t.name !== 'tool_search');\n const groups = new Map<string, string[]>();\n for (const t of tools) {\n const ns = t.name.includes('_') ? t.name.split('_')[0] : t.name;\n const g = groups.get(ns) || [];\n g.push(t.name);\n groups.set(ns, g);\n }\n return [...groups.entries()]\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([ns, names]) => (names.length === 1 ? names[0] : `${ns}: ${names.join(', ')}`))\n .join(' | ');\n}\n\n/**\n * Search registered tools by keyword query.\n *\n * Progressive disclosure mode (Hermes competitive gap fix):\n * When metadataOnly=true, returns tools with truncated descriptions\n * and no parameter schemas — ~20 tokens each instead of ~200.\n * The model then calls tool_expand(name) to get the full schema\n * for just the tools it needs.\n */\nexport function searchTools(query: string, metadataOnly = false): ToolHandler[] {\n const tools = getRegisteredTools();\n const terms = query.toLowerCase().split(/\\s+/).filter(Boolean);\n\n const scored = tools\n .filter(t => t.name !== 'tool_search' && t.name !== 'tool_expand')\n .map(t => {\n const text = `${t.name} ${t.description}`.toLowerCase();\n const score = terms.reduce((s, term) => s + (text.includes(term) ? 1 : 0), 0);\n return { tool: t, score };\n })\n .filter(({ score }) => score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 8);\n\n if (metadataOnly) {\n // Return lightweight metadata — just name + one-line description\n return scored.map(({ tool }) => ({\n ...tool,\n description: tool.description.slice(0, 80),\n parameters: { type: 'object' as const, properties: {}, required: [] },\n }));\n }\n\n return scored.map(({ tool }) => tool);\n}\n\n/**\n * Expand a single tool's full schema by name.\n * Part of the progressive disclosure pattern — model calls tool_search\n * to get names, then tool_expand to get the full schema for just the\n * tools it needs.\n */\nexport function expandTool(name: string): ToolHandler | null {\n const tools = getRegisteredTools();\n return tools.find(t => t.name === name) || null;\n}\n\n/** Get the tool_search tool handler */\nexport function getToolSearchHandler(): ToolHandler {\n const catalog = buildToolCatalog();\n\n return {\n name: 'tool_search',\n description: `Search for tools by keyword to discover capabilities. Call this FIRST when you need a tool not in your current list. Available tools: ${catalog}`,\n parameters: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query — keywords describing what you need (e.g. \"email send\", \"browser screenshot\", \"github pr\", \"cron schedule\")',\n },\n },\n required: ['query'],\n },\n execute: async (args: Record<string, unknown>) => {\n const query = (args.query as string) || '';\n if (!query.trim()) {\n return 'Please provide a search query. Example: tool_search({query: \"email\"})';\n }\n\n const results = searchTools(query);\n\n if (results.length === 0) {\n return `No tools found matching \"${query}\". Try broader keywords.`;\n }\n\n logger.info(COMPONENT, `Search \"${query}\" → ${results.length} tools: [${results.map(t => t.name).join(', ')}]`);\n\n const formatted = results.map(t => {\n const params = t.parameters as Record<string, unknown>;\n const props = (params.properties || {}) as Record<string, unknown>;\n const paramNames = Object.keys(props).join(', ');\n return `**${t.name}**(${paramNames}): ${t.description}`;\n }).join('\\n');\n\n return `Found ${results.length} tools:\\n${formatted}\\n\\nYou can now call these tools directly.`;\n },\n };\n}\n\n/**\n * Get the tool_expand handler — progressive disclosure (Hermes gap fix).\n * Returns the full JSON schema for a single tool by name.\n */\nexport function getToolExpandHandler(): ToolHandler {\n return {\n name: 'tool_expand',\n description: 'Get the full parameter schema for a specific tool. Use after tool_search to see the detailed parameters before calling the tool.',\n parameters: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n description: 'The exact tool name to expand (e.g. \"email_send\", \"freelance_search\")',\n },\n },\n required: ['name'],\n },\n execute: async (args: Record<string, unknown>) => {\n const name = (args.name as string) || '';\n if (!name.trim()) {\n return 'Please provide a tool name. Example: tool_expand({name: \"email_send\"})';\n }\n\n const tool = expandTool(name);\n if (!tool) {\n return `Tool \"${name}\" not found. Use tool_search to find the correct name.`;\n }\n\n logger.info(COMPONENT, `Expand \"${name}\" → full schema loaded`);\n\n const params = tool.parameters as Record<string, unknown>;\n const props = (params.properties || {}) as Record<string, { type?: string; description?: string }>;\n const required = (params.required || []) as string[];\n\n const paramDocs = Object.entries(props).map(([key, val]) => {\n const req = required.includes(key) ? ' (required)' : '';\n return ` - **${key}**${req}: ${val.description || val.type || 'any'}`;\n }).join('\\n');\n\n return `## ${tool.name}\\n${tool.description}\\n\\n### Parameters\\n${paramDocs || ' (no parameters)'}\\n\\nYou can now call ${tool.name}() with these parameters.`;\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -575,6 +575,24 @@ const TitanConfigSchema = z.object({
575
575
  })).default({})
576
576
  }).default({}),
577
577
  organism: OrganismConfigSchema.default({}),
578
+ /** v7.1 MoA — Mixture-of-Agents presets. A preset = N reference advisor
579
+ * models (trimmed context, no tools, parallel with timeouts) + 1 acting
580
+ * aggregator. Selectable anywhere as the virtual model `moa/<preset>`.
581
+ * Local-first: the default `local-council` mixes models across the
582
+ * user's own machines for $0 per turn. */
583
+ moa: z.object({
584
+ presets: z.record(z.string(), z.object({
585
+ references: z.array(z.object({
586
+ model: z.string(),
587
+ maxTokens: z.number().int().positive().optional(),
588
+ temperature: z.number().min(0).max(2).optional(),
589
+ timeoutMs: z.number().int().positive().optional()
590
+ })).min(1),
591
+ aggregator: z.string(),
592
+ enabled: z.boolean().default(true),
593
+ maxTokens: z.number().int().positive().optional()
594
+ })).default({})
595
+ }).default({}),
578
596
  /** v7.0 Muscle Memory — automatic, replay-verified skill learning.
579
597
  * Safe to enable by default: proposals never auto-adopt; every learned
580
598
  * skill must pass a deterministic replay exam before it is shown. */