@tyvm/knowhow 0.0.145 → 0.0.147

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 (320) hide show
  1. package/autodoc/cli-reference.md +36 -7
  2. package/bin/knowhow.js +8 -6
  3. package/package.json +1 -1
  4. package/src/agents/base/base.ts +24 -0
  5. package/src/agents/historyRollback.ts +36 -0
  6. package/src/agents/tools/startAgentTask.ts +41 -9
  7. package/src/auth/browserLogin.ts +9 -3
  8. package/src/auth/keyAuth.ts +115 -0
  9. package/src/auth/keyManager.ts +166 -0
  10. package/src/chat/CliChatService.ts +16 -0
  11. package/src/chat/modules/AgentModule.ts +144 -56
  12. package/src/chat/modules/AskModule.ts +2 -0
  13. package/src/chat/modules/BaseChatModule.ts +0 -1
  14. package/src/chat/modules/CustomCommandsModule.ts +2 -0
  15. package/src/chat/modules/InternalChatModule.ts +2 -0
  16. package/src/chat/modules/RemoteSyncModule.ts +4 -0
  17. package/src/chat/modules/RendererModule.ts +2 -0
  18. package/src/chat/modules/SearchModule.ts +2 -0
  19. package/src/chat/modules/SessionsModule.ts +110 -39
  20. package/src/chat/modules/SetupModule.ts +2 -0
  21. package/src/chat/modules/ShellCommandModule.ts +2 -0
  22. package/src/chat/modules/SystemModule.ts +2 -0
  23. package/src/chat/types.ts +5 -2
  24. package/src/cli.ts +1 -1
  25. package/src/clients/anthropic.ts +24 -0
  26. package/src/clients/fireworks.ts +3 -0
  27. package/src/clients/gemini.ts +8 -0
  28. package/src/clients/index.ts +2 -0
  29. package/src/clients/openai.ts +7 -4
  30. package/src/clients/types.ts +30 -7
  31. package/src/clients/xai.ts +23 -4
  32. package/src/commands/agent.ts +11 -39
  33. package/src/commands/agents.ts +403 -53
  34. package/src/commands/misc.ts +3 -2
  35. package/src/commands/services.ts +49 -3
  36. package/src/login.ts +89 -28
  37. package/src/plugins/plugins.ts +16 -0
  38. package/src/processors/TokenCompressor.ts +40 -8
  39. package/src/processors/ToolResponseCache.ts +17 -8
  40. package/src/processors/tools/boundedToolResponse.ts +49 -0
  41. package/src/processors/tools/grepToolResponse.ts +164 -38
  42. package/src/processors/tools/index.ts +2 -0
  43. package/src/processors/tools/jqToolResponse.ts +40 -10
  44. package/src/processors/tools/listStoredToolResponses.ts +51 -10
  45. package/src/processors/tools/tailToolResponse.ts +85 -17
  46. package/src/services/AgentService.ts +2 -0
  47. package/src/services/AgentSyncFs.ts +65 -0
  48. package/src/services/AgentSyncKnowhowWeb.ts +22 -4
  49. package/src/services/BehaviorsService.ts +2 -0
  50. package/src/services/DockerService.ts +2 -0
  51. package/src/services/EmbeddingService.ts +2 -0
  52. package/src/services/EmbeddingsService.ts +3 -0
  53. package/src/services/KnowhowClient.ts +68 -7
  54. package/src/services/LazyToolsService.ts +16 -0
  55. package/src/services/Mcp.ts +11 -2
  56. package/src/services/McpServer.ts +2 -0
  57. package/src/services/MessageProcessor.ts +2 -0
  58. package/src/services/MinimalToolsService.ts +2 -0
  59. package/src/services/RuntimeReloadService.ts +31 -0
  60. package/src/services/SessionManager.ts +5 -0
  61. package/src/services/SkillsService.ts +2 -0
  62. package/src/services/SyncedAgentWatcher.ts +2 -0
  63. package/src/services/SyncerService.ts +23 -8
  64. package/src/services/TaskRegistry.ts +2 -0
  65. package/src/services/Tools.ts +13 -0
  66. package/src/services/TracingService.ts +116 -0
  67. package/src/services/index.ts +10 -0
  68. package/src/services/modules/index.ts +49 -3
  69. package/src/services/modules/types.ts +8 -0
  70. package/src/types.ts +2 -0
  71. package/src/util/Trace.ts +236 -0
  72. package/src/utils/http.ts +18 -2
  73. package/tests/clients/fireworks.test.ts +65 -0
  74. package/tests/clients/reasoningEffort.test.ts +79 -0
  75. package/tests/compressor/toolResponseCache.test.ts +2 -1
  76. package/tests/manual/clients/completions.test.ts +27 -10
  77. package/tests/processors/TokenCompressor.test.ts +17 -3
  78. package/tests/processors/tools/boundedRetrievalTools.test.ts +68 -0
  79. package/tests/processors/tools/grepToolResponse.test.ts +88 -1
  80. package/tests/unit/agents/historyRollback.test.ts +53 -0
  81. package/tests/unit/auth/keyAuth.test.ts +102 -0
  82. package/tests/unit/auth/keyManager.test.ts +67 -0
  83. package/tests/unit/chat/historyCommandArgs.test.ts +37 -0
  84. package/tests/unit/commands/agents.test.ts +68 -0
  85. package/tests/unit/login.test.ts +119 -0
  86. package/tests/unit/plugins/pluginLoading.test.ts +31 -0
  87. package/tests/unit/services/AgentSyncKnowhowWeb.test.ts +38 -0
  88. package/tests/unit/services/LazyToolsService.test.ts +29 -0
  89. package/tests/unit/services/RuntimeReloadService.test.ts +29 -0
  90. package/tests/unit/services/SessionManager.test.ts +43 -0
  91. package/tests/unit/services/SyncerService.test.ts +45 -0
  92. package/tests/unit/util/Trace.test.ts +119 -0
  93. package/tests/unit/utils/http.test.ts +43 -0
  94. package/ts_build/package.json +1 -1
  95. package/ts_build/src/agents/base/base.d.ts +1 -0
  96. package/ts_build/src/agents/base/base.js +31 -2
  97. package/ts_build/src/agents/base/base.js.map +1 -1
  98. package/ts_build/src/agents/historyRollback.d.ts +2 -0
  99. package/ts_build/src/agents/historyRollback.js +22 -0
  100. package/ts_build/src/agents/historyRollback.js.map +1 -0
  101. package/ts_build/src/agents/tools/startAgentTask.d.ts +2 -0
  102. package/ts_build/src/agents/tools/startAgentTask.js +36 -9
  103. package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
  104. package/ts_build/src/auth/browserLogin.d.ts +1 -0
  105. package/ts_build/src/auth/browserLogin.js +5 -2
  106. package/ts_build/src/auth/browserLogin.js.map +1 -1
  107. package/ts_build/src/auth/keyAuth.d.ts +5 -0
  108. package/ts_build/src/auth/keyAuth.js +79 -0
  109. package/ts_build/src/auth/keyAuth.js.map +1 -0
  110. package/ts_build/src/auth/keyManager.d.ts +14 -0
  111. package/ts_build/src/auth/keyManager.js +145 -0
  112. package/ts_build/src/auth/keyManager.js.map +1 -0
  113. package/ts_build/src/chat/CliChatService.js +15 -0
  114. package/ts_build/src/chat/CliChatService.js.map +1 -1
  115. package/ts_build/src/chat/modules/AgentModule.d.ts +13 -1
  116. package/ts_build/src/chat/modules/AgentModule.js +96 -43
  117. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  118. package/ts_build/src/chat/modules/AskModule.js +12 -2
  119. package/ts_build/src/chat/modules/AskModule.js.map +1 -1
  120. package/ts_build/src/chat/modules/BaseChatModule.js.map +1 -1
  121. package/ts_build/src/chat/modules/CustomCommandsModule.js +12 -2
  122. package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
  123. package/ts_build/src/chat/modules/InternalChatModule.js +16 -2
  124. package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
  125. package/ts_build/src/chat/modules/RemoteSyncModule.js +19 -2
  126. package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
  127. package/ts_build/src/chat/modules/RendererModule.js +17 -2
  128. package/ts_build/src/chat/modules/RendererModule.js.map +1 -1
  129. package/ts_build/src/chat/modules/SearchModule.js +12 -2
  130. package/ts_build/src/chat/modules/SearchModule.js.map +1 -1
  131. package/ts_build/src/chat/modules/SessionsModule.d.ts +6 -0
  132. package/ts_build/src/chat/modules/SessionsModule.js +114 -24
  133. package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
  134. package/ts_build/src/chat/modules/SetupModule.js +17 -2
  135. package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
  136. package/ts_build/src/chat/modules/ShellCommandModule.js +12 -2
  137. package/ts_build/src/chat/modules/ShellCommandModule.js.map +1 -1
  138. package/ts_build/src/chat/modules/SystemModule.js +12 -2
  139. package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
  140. package/ts_build/src/chat/types.d.ts +5 -2
  141. package/ts_build/src/cli.js +1 -1
  142. package/ts_build/src/cli.js.map +1 -1
  143. package/ts_build/src/clients/anthropic.d.ts +1 -0
  144. package/ts_build/src/clients/anthropic.js +12 -0
  145. package/ts_build/src/clients/anthropic.js.map +1 -1
  146. package/ts_build/src/clients/fireworks.js +1 -0
  147. package/ts_build/src/clients/fireworks.js.map +1 -1
  148. package/ts_build/src/clients/gemini.js +8 -0
  149. package/ts_build/src/clients/gemini.js.map +1 -1
  150. package/ts_build/src/clients/index.js +19 -4
  151. package/ts_build/src/clients/index.js.map +1 -1
  152. package/ts_build/src/clients/openai.js +4 -2
  153. package/ts_build/src/clients/openai.js.map +1 -1
  154. package/ts_build/src/clients/types.d.ts +4 -1
  155. package/ts_build/src/clients/types.js +14 -0
  156. package/ts_build/src/clients/types.js.map +1 -1
  157. package/ts_build/src/clients/xai.d.ts +1 -0
  158. package/ts_build/src/clients/xai.js +23 -4
  159. package/ts_build/src/clients/xai.js.map +1 -1
  160. package/ts_build/src/commands/agent.js +7 -22
  161. package/ts_build/src/commands/agent.js.map +1 -1
  162. package/ts_build/src/commands/agents.d.ts +1 -1
  163. package/ts_build/src/commands/agents.js +174 -16
  164. package/ts_build/src/commands/agents.js.map +1 -1
  165. package/ts_build/src/commands/misc.js +3 -2
  166. package/ts_build/src/commands/misc.js.map +1 -1
  167. package/ts_build/src/commands/services.d.ts +2 -0
  168. package/ts_build/src/commands/services.js +45 -3
  169. package/ts_build/src/commands/services.js.map +1 -1
  170. package/ts_build/src/login.d.ts +1 -1
  171. package/ts_build/src/login.js +53 -15
  172. package/ts_build/src/login.js.map +1 -1
  173. package/ts_build/src/plugins/plugins.d.ts +1 -0
  174. package/ts_build/src/plugins/plugins.js +14 -0
  175. package/ts_build/src/plugins/plugins.js.map +1 -1
  176. package/ts_build/src/processors/TokenCompressor.js +15 -6
  177. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  178. package/ts_build/src/processors/ToolResponseCache.d.ts +3 -3
  179. package/ts_build/src/processors/ToolResponseCache.js +8 -8
  180. package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
  181. package/ts_build/src/processors/tools/boundedToolResponse.d.ts +7 -0
  182. package/ts_build/src/processors/tools/boundedToolResponse.js +27 -0
  183. package/ts_build/src/processors/tools/boundedToolResponse.js.map +1 -0
  184. package/ts_build/src/processors/tools/grepToolResponse.d.ts +4 -0
  185. package/ts_build/src/processors/tools/grepToolResponse.js +101 -25
  186. package/ts_build/src/processors/tools/grepToolResponse.js.map +1 -1
  187. package/ts_build/src/processors/tools/index.d.ts +2 -2
  188. package/ts_build/src/processors/tools/index.js.map +1 -1
  189. package/ts_build/src/processors/tools/jqToolResponse.d.ts +5 -1
  190. package/ts_build/src/processors/tools/jqToolResponse.js +26 -9
  191. package/ts_build/src/processors/tools/jqToolResponse.js.map +1 -1
  192. package/ts_build/src/processors/tools/listStoredToolResponses.d.ts +7 -1
  193. package/ts_build/src/processors/tools/listStoredToolResponses.js +39 -9
  194. package/ts_build/src/processors/tools/listStoredToolResponses.js.map +1 -1
  195. package/ts_build/src/processors/tools/tailToolResponse.d.ts +5 -0
  196. package/ts_build/src/processors/tools/tailToolResponse.js +56 -13
  197. package/ts_build/src/processors/tools/tailToolResponse.js.map +1 -1
  198. package/ts_build/src/services/AgentService.js +18 -2
  199. package/ts_build/src/services/AgentService.js.map +1 -1
  200. package/ts_build/src/services/AgentSyncFs.d.ts +3 -0
  201. package/ts_build/src/services/AgentSyncFs.js +62 -15
  202. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  203. package/ts_build/src/services/AgentSyncKnowhowWeb.d.ts +2 -0
  204. package/ts_build/src/services/AgentSyncKnowhowWeb.js +28 -6
  205. package/ts_build/src/services/AgentSyncKnowhowWeb.js.map +1 -1
  206. package/ts_build/src/services/BehaviorsService.js +12 -2
  207. package/ts_build/src/services/BehaviorsService.js.map +1 -1
  208. package/ts_build/src/services/DockerService.js +20 -8
  209. package/ts_build/src/services/DockerService.js.map +1 -1
  210. package/ts_build/src/services/EmbeddingService.js +16 -2
  211. package/ts_build/src/services/EmbeddingService.js.map +1 -1
  212. package/ts_build/src/services/EmbeddingsService.js +12 -2
  213. package/ts_build/src/services/EmbeddingsService.js.map +1 -1
  214. package/ts_build/src/services/KnowhowClient.d.ts +7 -2
  215. package/ts_build/src/services/KnowhowClient.js +108 -10
  216. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  217. package/ts_build/src/services/LazyToolsService.d.ts +2 -0
  218. package/ts_build/src/services/LazyToolsService.js +26 -2
  219. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  220. package/ts_build/src/services/Mcp.js +20 -4
  221. package/ts_build/src/services/Mcp.js.map +1 -1
  222. package/ts_build/src/services/McpServer.js +17 -2
  223. package/ts_build/src/services/McpServer.js.map +1 -1
  224. package/ts_build/src/services/MessageProcessor.js +16 -2
  225. package/ts_build/src/services/MessageProcessor.js.map +1 -1
  226. package/ts_build/src/services/MinimalToolsService.js +16 -2
  227. package/ts_build/src/services/MinimalToolsService.js.map +1 -1
  228. package/ts_build/src/services/RuntimeReloadService.d.ts +12 -0
  229. package/ts_build/src/services/RuntimeReloadService.js +26 -0
  230. package/ts_build/src/services/RuntimeReloadService.js.map +1 -0
  231. package/ts_build/src/services/SessionManager.js +19 -2
  232. package/ts_build/src/services/SessionManager.js.map +1 -1
  233. package/ts_build/src/services/SkillsService.js +16 -2
  234. package/ts_build/src/services/SkillsService.js.map +1 -1
  235. package/ts_build/src/services/SyncedAgentWatcher.js +16 -2
  236. package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
  237. package/ts_build/src/services/SyncerService.d.ts +1 -0
  238. package/ts_build/src/services/SyncerService.js +27 -5
  239. package/ts_build/src/services/SyncerService.js.map +1 -1
  240. package/ts_build/src/services/TaskRegistry.js +12 -2
  241. package/ts_build/src/services/TaskRegistry.js.map +1 -1
  242. package/ts_build/src/services/Tools.d.ts +1 -0
  243. package/ts_build/src/services/Tools.js +21 -2
  244. package/ts_build/src/services/Tools.js.map +1 -1
  245. package/ts_build/src/services/TracingService.d.ts +16 -0
  246. package/ts_build/src/services/TracingService.js +35 -0
  247. package/ts_build/src/services/TracingService.js.map +1 -0
  248. package/ts_build/src/services/index.d.ts +8 -0
  249. package/ts_build/src/services/index.js +9 -1
  250. package/ts_build/src/services/index.js.map +1 -1
  251. package/ts_build/src/services/modules/index.d.ts +6 -0
  252. package/ts_build/src/services/modules/index.js +29 -3
  253. package/ts_build/src/services/modules/index.js.map +1 -1
  254. package/ts_build/src/services/modules/types.d.ts +3 -0
  255. package/ts_build/src/types.d.ts +1 -0
  256. package/ts_build/src/types.js.map +1 -1
  257. package/ts_build/src/util/Trace.d.ts +11 -0
  258. package/ts_build/src/util/Trace.js +107 -0
  259. package/ts_build/src/util/Trace.js.map +1 -0
  260. package/ts_build/src/utils/http.d.ts +6 -2
  261. package/ts_build/src/utils/http.js +8 -2
  262. package/ts_build/src/utils/http.js.map +1 -1
  263. package/ts_build/tests/clients/fireworks.test.d.ts +1 -0
  264. package/ts_build/tests/clients/fireworks.test.js +65 -0
  265. package/ts_build/tests/clients/fireworks.test.js.map +1 -0
  266. package/ts_build/tests/clients/reasoningEffort.test.d.ts +1 -0
  267. package/ts_build/tests/clients/reasoningEffort.test.js +68 -0
  268. package/ts_build/tests/clients/reasoningEffort.test.js.map +1 -0
  269. package/ts_build/tests/compressor/toolResponseCache.test.js +1 -1
  270. package/ts_build/tests/compressor/toolResponseCache.test.js.map +1 -1
  271. package/ts_build/tests/manual/clients/completions.test.js +19 -6
  272. package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
  273. package/ts_build/tests/processors/TokenCompressor.test.js +11 -2
  274. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -1
  275. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.d.ts +1 -0
  276. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js +57 -0
  277. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js.map +1 -0
  278. package/ts_build/tests/processors/tools/grepToolResponse.test.js +37 -0
  279. package/ts_build/tests/processors/tools/grepToolResponse.test.js.map +1 -1
  280. package/ts_build/tests/unit/agents/historyRollback.test.d.ts +1 -0
  281. package/ts_build/tests/unit/agents/historyRollback.test.js +42 -0
  282. package/ts_build/tests/unit/agents/historyRollback.test.js.map +1 -0
  283. package/ts_build/tests/unit/auth/keyAuth.test.d.ts +1 -0
  284. package/ts_build/tests/unit/auth/keyAuth.test.js +77 -0
  285. package/ts_build/tests/unit/auth/keyAuth.test.js.map +1 -0
  286. package/ts_build/tests/unit/auth/keyManager.test.d.ts +1 -0
  287. package/ts_build/tests/unit/auth/keyManager.test.js +52 -0
  288. package/ts_build/tests/unit/auth/keyManager.test.js.map +1 -0
  289. package/ts_build/tests/unit/chat/historyCommandArgs.test.d.ts +1 -0
  290. package/ts_build/tests/unit/chat/historyCommandArgs.test.js +29 -0
  291. package/ts_build/tests/unit/chat/historyCommandArgs.test.js.map +1 -0
  292. package/ts_build/tests/unit/commands/agents.test.d.ts +1 -0
  293. package/ts_build/tests/unit/commands/agents.test.js +91 -0
  294. package/ts_build/tests/unit/commands/agents.test.js.map +1 -0
  295. package/ts_build/tests/unit/login.test.d.ts +1 -0
  296. package/ts_build/tests/unit/login.test.js +97 -0
  297. package/ts_build/tests/unit/login.test.js.map +1 -0
  298. package/ts_build/tests/unit/plugins/pluginLoading.test.js +59 -0
  299. package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +1 -1
  300. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.d.ts +1 -0
  301. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js +32 -0
  302. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js.map +1 -0
  303. package/ts_build/tests/unit/services/LazyToolsService.test.d.ts +1 -0
  304. package/ts_build/tests/unit/services/LazyToolsService.test.js +27 -0
  305. package/ts_build/tests/unit/services/LazyToolsService.test.js.map +1 -0
  306. package/ts_build/tests/unit/services/RuntimeReloadService.test.d.ts +1 -0
  307. package/ts_build/tests/unit/services/RuntimeReloadService.test.js +26 -0
  308. package/ts_build/tests/unit/services/RuntimeReloadService.test.js.map +1 -0
  309. package/ts_build/tests/unit/services/SessionManager.test.d.ts +1 -0
  310. package/ts_build/tests/unit/services/SessionManager.test.js +72 -0
  311. package/ts_build/tests/unit/services/SessionManager.test.js.map +1 -0
  312. package/ts_build/tests/unit/services/SyncerService.test.d.ts +1 -0
  313. package/ts_build/tests/unit/services/SyncerService.test.js +40 -0
  314. package/ts_build/tests/unit/services/SyncerService.test.js.map +1 -0
  315. package/ts_build/tests/unit/util/Trace.test.d.ts +1 -0
  316. package/ts_build/tests/unit/util/Trace.test.js +107 -0
  317. package/ts_build/tests/unit/util/Trace.test.js.map +1 -0
  318. package/ts_build/tests/unit/utils/http.test.d.ts +1 -0
  319. package/ts_build/tests/unit/utils/http.test.js +69 -0
  320. package/ts_build/tests/unit/utils/http.test.js.map +1 -0
@@ -1,4 +1,5 @@
1
1
  import { ChatCompletionTool } from "openai/resources/chat";
2
+ import { TraceAll } from "../util/Trace";
2
3
  import { replaceEscapedNewLines, restoreEscapedNewLines } from "../utils";
3
4
  import { includedTools } from "../agents/tools/list";
4
5
  import { AgentService } from "./AgentService";
@@ -61,6 +62,7 @@ export interface ToolContext {
61
62
  * larger context bloat from having every tool defined in system prompt
62
63
  *
63
64
  */
65
+ @TraceAll()
64
66
  export class ToolsService {
65
67
  private context: ToolContext = {};
66
68
 
@@ -79,6 +81,17 @@ export class ToolsService {
79
81
  }
80
82
  }
81
83
 
84
+ /**
85
+ * Remove every registered tool and handler while retaining service context,
86
+ * wrappers, and overrides. Runtime reload uses this before rebuilding the
87
+ * catalog from built-ins, MCP servers, and configured modules.
88
+ */
89
+ resetTools(): void {
90
+ this.tools = [];
91
+ this.functions = {};
92
+ this.originalFunctions = {};
93
+ }
94
+
82
95
  getContext(): ToolContext {
83
96
  return this.context;
84
97
  }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * TracingService — a zero-dependency, no-op-by-default tracing abstraction
3
+ * for the @tyvm/knowhow core package.
4
+ *
5
+ * The core package ships with NO OpenTelemetry dependencies. This service
6
+ * defines the interface that the decorators in `src/util/Trace.ts` call into,
7
+ * and holds a singleton "current tracer" that starts as a no-op.
8
+ *
9
+ * A module (e.g. @tyvm/knowhow-module-tracing) can call
10
+ * `TracingService.register(impl)` during its `init()` to swap in a real OTEL
11
+ * implementation. After that, every @Trace / @TraceAll / tracify call in the
12
+ * knowhow codebase will produce real spans — with zero changes to the core.
13
+ */
14
+
15
+ export interface SpanHandle {
16
+ /** Set a string/number/boolean attribute on the span. */
17
+ setAttribute(key: string, value: string | number | boolean): void;
18
+ /** Mark the span as errored and record the exception. */
19
+ recordError(err: unknown): void;
20
+ /** End the span (records wall-clock end time). */
21
+ end(): void;
22
+ }
23
+
24
+ export interface TracerImpl {
25
+ /**
26
+ * Start a span. The implementation is responsible for making it a child of
27
+ * the currently-active span (via OpenTelemetry context propagation or
28
+ * equivalent).
29
+ *
30
+ * @param name Span name, e.g. "ClassName.methodName"
31
+ * @param attributes Initial attributes to attach
32
+ */
33
+ startSpan(
34
+ name: string,
35
+ attributes?: Record<string, string | number | boolean>
36
+ ): SpanHandle;
37
+
38
+ /**
39
+ * Run `fn` with the given span active so that child spans created inside it
40
+ * are automatically parented to this one.
41
+ *
42
+ * If context propagation is not supported, implementations can simply call
43
+ * `fn()` directly.
44
+ */
45
+ withSpan<T>(span: SpanHandle, fn: () => T): T;
46
+ }
47
+
48
+ // ─── No-op implementation used until a real tracer is registered ─────────────
49
+
50
+ const noopSpan: SpanHandle = {
51
+ setAttribute() {},
52
+ recordError() {},
53
+ end() {},
54
+ };
55
+
56
+ const noopTracer: TracerImpl = {
57
+ startSpan() {
58
+ return noopSpan;
59
+ },
60
+ withSpan(_span, fn) {
61
+ return fn();
62
+ },
63
+ };
64
+
65
+ // ─── Singleton state ──────────────────────────────────────────────────────────
66
+
67
+ let _impl: TracerImpl = noopTracer;
68
+
69
+ /**
70
+ * TracingService — access point for the current tracer implementation.
71
+ *
72
+ * Usage in decorators / instrumentation code:
73
+ * ```ts
74
+ * import { TracingService } from '../services/TracingService';
75
+ * const span = TracingService.startSpan('MyClass.myMethod');
76
+ * ```
77
+ *
78
+ * Usage in a module to plug in a real OTEL tracer:
79
+ * ```ts
80
+ * import { TracingService } from '@tyvm/knowhow/...';
81
+ * TracingService.register(myOtelTracerImpl);
82
+ * ```
83
+ */
84
+ export const TracingService = {
85
+ /**
86
+ * Register a real tracer implementation. Called by the tracing module during
87
+ * `init()`. The registration is global and immediate — all subsequent
88
+ * decorator/tracify calls will use this implementation.
89
+ */
90
+ register(impl: TracerImpl): void {
91
+ _impl = impl;
92
+ },
93
+
94
+ /** Reset to the no-op tracer (useful for tests). */
95
+ reset(): void {
96
+ _impl = noopTracer;
97
+ },
98
+
99
+ /** Whether a real (non-no-op) tracer has been registered. */
100
+ isEnabled(): boolean {
101
+ return _impl !== noopTracer;
102
+ },
103
+
104
+ /** Start a span using the current implementation. */
105
+ startSpan(
106
+ name: string,
107
+ attributes?: Record<string, string | number | boolean>
108
+ ): SpanHandle {
109
+ return _impl.startSpan(name, attributes);
110
+ },
111
+
112
+ /** Run a function with a span active (context propagation). */
113
+ withSpan<T>(span: SpanHandle, fn: () => T): T {
114
+ return _impl.withSpan(span, fn);
115
+ },
116
+ };
@@ -15,8 +15,10 @@ import { SessionManager } from "./SessionManager";
15
15
  import { TaskRegistry } from "./TaskRegistry";
16
16
  import { MediaProcessorService } from "./MediaProcessorService";
17
17
  import { BehaviorsService } from "./BehaviorsService";
18
+ import { RuntimeReloadService } from "./RuntimeReloadService";
18
19
 
19
20
  import { ConversionService } from "./conversion/ConversionService";
21
+ import { TracingService } from "./TracingService";
20
22
 
21
23
  export * from "./AgentService";
22
24
  export * from "./EventService";
@@ -38,13 +40,18 @@ export * from "./SyncedAgentWatcher";
38
40
  export * from "./SyncerService";
39
41
  export * from "./watchers";
40
42
  export { Clients } from "../clients";
43
+ export * from "../util/Trace";
44
+ export { TracingService } from "./TracingService";
45
+ export type { TracerImpl, SpanHandle } from "./TracingService";
41
46
  export * from "./conversion";
47
+ export * from "./RuntimeReloadService";
42
48
  export { BehaviorsService } from "./BehaviorsService";
43
49
 
44
50
  let Singletons = {} as {
45
51
  Tools: ToolsService;
46
52
  Events: EventService;
47
53
  Agents: AgentService;
54
+ Tracing: typeof TracingService;
48
55
  Embeddings: EmbeddingsService;
49
56
  Flags: FlagsService;
50
57
  Mcp: McpService;
@@ -56,6 +63,7 @@ let Singletons = {} as {
56
63
  MediaProcessor: MediaProcessorService;
57
64
  Conversion: ConversionService;
58
65
  Behaviors: BehaviorsService;
66
+ RuntimeReload: RuntimeReloadService;
59
67
  };
60
68
 
61
69
  export const services = (): typeof Singletons => {
@@ -76,6 +84,7 @@ export const services = (): typeof Singletons => {
76
84
  Singletons = {
77
85
  Agents,
78
86
  AwsS3: new S3Service(),
87
+ Tracing: TracingService,
79
88
  Clients,
80
89
  Docker: new DockerService(),
81
90
  Events,
@@ -88,6 +97,7 @@ export const services = (): typeof Singletons => {
88
97
  Tools,
89
98
  knowhowApiClient: new KnowhowSimpleClient(),
90
99
  Behaviors,
100
+ RuntimeReload: new RuntimeReloadService(),
91
101
  };
92
102
 
93
103
  Singletons.Tools.setContext({
@@ -39,6 +39,13 @@ function globalResolvePaths(): string[] {
39
39
  }
40
40
 
41
41
  export class ModulesService {
42
+ private _loadedModules: {
43
+ modulePath: string;
44
+ resolvedPath: string;
45
+ module: KnowhowModule;
46
+ params: any;
47
+ }[] = [];
48
+
42
49
  async getDefaultContext() {
43
50
  return { ...services() };
44
51
  }
@@ -87,6 +94,7 @@ export class ModulesService {
87
94
  // best driver during phase 2.
88
95
  const loadedModules: {
89
96
  modulePath: string;
97
+ resolvedPath: string;
90
98
  module: KnowhowModule;
91
99
  }[] = [];
92
100
 
@@ -128,6 +136,7 @@ export class ModulesService {
128
136
  // global install).
129
137
  let importedModule: KnowhowModule;
130
138
  let loaded = false;
139
+ let selectedResolvedPath = modulePath;
131
140
  const errors: { candidate: string; error: Error }[] = [];
132
141
  for (const resolvedPath of candidates) {
133
142
  try {
@@ -147,6 +156,7 @@ export class ModulesService {
147
156
  context: context as ModuleContext,
148
157
  });
149
158
  }
159
+ selectedResolvedPath = resolvedPath;
150
160
  loaded = true;
151
161
  break;
152
162
  } catch (err: any) {
@@ -168,12 +178,17 @@ export class ModulesService {
168
178
  );
169
179
  continue;
170
180
  }
171
- loadedModules.push({ modulePath, module: importedModule });
181
+ loadedModules.push({
182
+ modulePath,
183
+ resolvedPath: selectedResolvedPath,
184
+ module: importedModule,
185
+ });
172
186
  }
173
187
 
174
188
  // Phase 2: init every successfully-loaded module now that all `register`
175
189
  // phases have run and injected their services into `context`.
176
- for (const { modulePath, module: importedModule } of loadedModules) {
190
+ for (const { modulePath, resolvedPath, module: importedModule } of loadedModules) {
191
+ const initParams = { config, cwd: process.cwd(), context: context as ModuleContext };
177
192
  try {
178
193
  await importedModule.init({
179
194
  config,
@@ -190,6 +205,8 @@ export class ModulesService {
190
205
  );
191
206
  continue;
192
207
  }
208
+ this._loadedModules.push({ modulePath, resolvedPath, module: importedModule, params: initParams });
209
+
193
210
  // Only register tools/agents/plugins/clients if the relevant services
194
211
  // are available in context (they may not be during early CLI command registration)
195
212
  if (context.Agents) {
@@ -226,6 +243,32 @@ export class ModulesService {
226
243
  }
227
244
  }
228
245
 
246
+ /**
247
+ * Call `destroy()` on every successfully-initialized module, in reverse
248
+ * initialization order (last-in, first-out). Errors are caught and logged
249
+ * so one broken module does not prevent others from cleaning up.
250
+ */
251
+ async destroyModules() {
252
+ const toDestroy = [...this._loadedModules].reverse();
253
+ // Clear first so repeated shutdown/reload attempts cannot destroy twice.
254
+ this._loadedModules = [];
255
+ for (const { modulePath, resolvedPath, module: mod, params } of toDestroy) {
256
+ if (typeof mod.destroy === "function") {
257
+ try {
258
+ await mod.destroy(params);
259
+ } catch (err: any) {
260
+ process.stderr.write(
261
+ `\n⚠️ Error in module destroy "${modulePath}": ${err?.message || err}\n\n`
262
+ );
263
+ }
264
+ }
265
+ // Re-require the entry point so source/configuration changes are visible.
266
+ if (require.cache[resolvedPath]) {
267
+ delete require.cache[resolvedPath];
268
+ }
269
+ }
270
+ }
271
+
229
272
  async loadModulesFromConfig(context?: ModuleContext) {
230
273
  const config = await getConfig();
231
274
 
@@ -241,9 +284,12 @@ export class ModulesService {
241
284
 
242
285
  // Load global-config modules resolving against the global install's
243
286
  // node_modules (~/.knowhow/node_modules) first.
287
+ // Pass a merged config so that keys defined in the global config (e.g.
288
+ // `tracing`) are visible to globally-declared modules during init().
289
+ // Local config keys take precedence so that local overrides still work.
244
290
  if (globalModules.length > 0) {
245
291
  await this.loadModulesFrom(
246
- { ...config, modules: globalModules },
292
+ { ...globalConfig, ...config, modules: globalModules },
247
293
  context,
248
294
  globalResolvePaths()
249
295
  );
@@ -16,6 +16,7 @@ import { ConversionService } from "../conversion/ConversionService";
16
16
  import { BehaviorsService } from "../BehaviorsService";
17
17
  import { ComputerUseService } from "./computerUse";
18
18
 
19
+ import { TracingService as TracingServiceType } from "../TracingService";
19
20
  /*
20
21
  *
21
22
  * A a module should allow the dynamic composition of npm modules that are installed globally by referencing an array of config
@@ -66,6 +67,7 @@ export interface ModuleContext {
66
67
  Behaviors?: BehaviorsService;
67
68
  ComputerUse?: ComputerUseService;
68
69
  [key: string]: any;
70
+ Tracing?: typeof TracingServiceType;
69
71
  }
70
72
 
71
73
  export interface KnowhowModule {
@@ -89,6 +91,12 @@ export interface KnowhowModule {
89
91
  * services registered by other modules' `register` phase, etc.).
90
92
  */
91
93
  init: (params: InitParams) => Promise<void>;
94
+ /**
95
+ * Phase 3 (optional): called when the CLI is shutting down. Use this to
96
+ * cleanly release resources — close connections, flush buffers, stop
97
+ * watchers, etc. Mirror of `init`.
98
+ */
99
+ destroy?: (params: InitParams) => Promise<void>;
92
100
  commands: ModuleChatCommand[];
93
101
  tools: ModuleTool[];
94
102
  agents: ModuleAgent[];
package/src/types.ts CHANGED
@@ -75,6 +75,8 @@ export type Config = {
75
75
  promptsDir: string;
76
76
  lintCommands?: { [fileExtension: string]: string };
77
77
  orgId?: string;
78
+ /** Private Ed25519 identity selected with `knowhow login --identity`. */
79
+ cliIdentityPath?: string;
78
80
  syncRemote?: boolean;
79
81
  micCommand?: string;
80
82
  defaultMic?: string;
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Trace.ts — Method / class decorators and `tracify()` helper for the
3
+ * @tyvm/knowhow package.
4
+ *
5
+ * These decorators are zero-cost when no tracer is registered (the default).
6
+ * Once `@tyvm/knowhow-module-tracing` (or any other module) calls
7
+ * `TracingService.register(impl)`, every decorated method starts emitting
8
+ * real spans automatically — no code changes required.
9
+ *
10
+ * API mirrors the backend's `Trace.ts` so patterns learned there carry over:
11
+ *
12
+ * @Trace() — wrap a single method
13
+ * @TraceAll() — wrap every public method on a class
14
+ * tracify(obj, ns) — wrap an already-constructed instance
15
+ *
16
+ * @example
17
+ * import { Trace, TraceAll, tracify } from '../util/Trace';
18
+ *
19
+ * @TraceAll()
20
+ * export class MessageProcessor {
21
+ * async process(msg: Message) { ... } // → span "MessageProcessor.process"
22
+ * }
23
+ *
24
+ * @Trace()
25
+ * async fetchEmbeddings(text: string) { ... } // → span "ClassName.fetchEmbeddings"
26
+ *
27
+ * export const myClient = tracify(new SomeClient(), 'someClient');
28
+ */
29
+
30
+ import { TracingService } from "../services/TracingService";
31
+
32
+ // ─── Shared span lifecycle helper ─────────────────────────────────────────────
33
+
34
+ function runWithSpan<T>(
35
+ spanName: string,
36
+ attributes: Record<string, string | number | boolean>,
37
+ fn: () => T
38
+ ): T {
39
+ const span = TracingService.startSpan(spanName, attributes);
40
+
41
+ const finish = (err?: unknown) => {
42
+ if (err !== undefined) {
43
+ span.recordError(err);
44
+ }
45
+ span.end();
46
+ };
47
+
48
+ try {
49
+ const result = TracingService.withSpan(span, fn);
50
+
51
+ if (result instanceof Promise) {
52
+ return result.then(
53
+ (value) => {
54
+ finish();
55
+ return value;
56
+ },
57
+ (err) => {
58
+ finish(err);
59
+ throw err;
60
+ }
61
+ ) as unknown as T;
62
+ }
63
+
64
+ finish();
65
+ return result;
66
+ } catch (err) {
67
+ finish(err);
68
+ throw err;
69
+ }
70
+ }
71
+
72
+ // ─── @Trace() — single-method decorator ──────────────────────────────────────
73
+
74
+ export interface TraceOptions {
75
+ /** Override the span name (default: `ClassName.methodName`) */
76
+ spanName?: string;
77
+ /** Additional static attributes attached to every span */
78
+ attributes?: Record<string, string | number | boolean>;
79
+ }
80
+
81
+ /**
82
+ * @Trace() method decorator — wraps the decorated method in a tracing span.
83
+ *
84
+ * Span name defaults to `ClassName.methodName`. Errors are recorded on the
85
+ * span and re-thrown. Works with both sync and async methods.
86
+ *
87
+ * @example
88
+ * @Trace()
89
+ * async fetchEmbeddings(text: string) { ... }
90
+ *
91
+ * @Trace({ spanName: 'embeddings.fetch', attributes: { 'peer.service': 'openai' } })
92
+ * async fetchEmbeddings(text: string) { ... }
93
+ */
94
+ export function Trace(options: TraceOptions = {}) {
95
+ return function (
96
+ target: object,
97
+ propertyKey: string,
98
+ descriptor: PropertyDescriptor
99
+ ): PropertyDescriptor {
100
+ const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
101
+ const className = (target as any).constructor?.name ?? "Unknown";
102
+ const resolvedSpanName =
103
+ options.spanName ?? `${className}.${propertyKey}`;
104
+ const staticAttrs: Record<string, string | number | boolean> = {
105
+ "code.function": propertyKey,
106
+ "code.namespace": className,
107
+ ...options.attributes,
108
+ };
109
+
110
+ descriptor.value = function (this: unknown, ...args: unknown[]) {
111
+ return runWithSpan(resolvedSpanName, staticAttrs, () =>
112
+ originalMethod.apply(this, args)
113
+ );
114
+ };
115
+
116
+ return descriptor;
117
+ };
118
+ }
119
+
120
+ // ─── @TraceAll() — class decorator ───────────────────────────────────────────
121
+
122
+ export interface TraceAllOptions {
123
+ /** Additional static attributes attached to every span */
124
+ attributes?: Record<string, string | number | boolean>;
125
+ /** Method names to skip (in addition to constructor and `_`-prefixed) */
126
+ skip?: string[];
127
+ }
128
+
129
+ /**
130
+ * @TraceAll() class decorator — wraps every public method on the class in a
131
+ * tracing span named `ClassName.methodName`.
132
+ *
133
+ * Skips the constructor and any methods whose name starts with `_`.
134
+ *
135
+ * @example
136
+ * @TraceAll()
137
+ * export class MessageProcessor {
138
+ * async process(msg: Message) { ... } // → span "MessageProcessor.process"
139
+ * }
140
+ */
141
+ export function TraceAll(options: TraceAllOptions = {}) {
142
+ const skip = new Set(options.skip ?? []);
143
+
144
+ return function <T extends abstract new (...args: unknown[]) => object>(
145
+ constructor: T
146
+ ): T {
147
+ const className = constructor.name;
148
+ const proto = constructor.prototype as Record<string, unknown>;
149
+
150
+ for (const key of Object.getOwnPropertyNames(proto)) {
151
+ if (key === "constructor") continue;
152
+ if (key.startsWith("_")) continue;
153
+ if (skip.has(key)) continue;
154
+
155
+ const descriptor = Object.getOwnPropertyDescriptor(proto, key);
156
+ if (!descriptor || typeof descriptor.value !== "function") continue;
157
+
158
+ const originalMethod = descriptor.value as (
159
+ ...args: unknown[]
160
+ ) => unknown;
161
+ const spanName = `${className}.${key}`;
162
+ const staticAttrs: Record<string, string | number | boolean> = {
163
+ "code.function": key,
164
+ "code.namespace": className,
165
+ ...options.attributes,
166
+ };
167
+
168
+ descriptor.value = function (this: unknown, ...args: unknown[]) {
169
+ return runWithSpan(spanName, staticAttrs, () =>
170
+ originalMethod.apply(this, args)
171
+ );
172
+ };
173
+
174
+ Object.defineProperty(proto, key, descriptor);
175
+ }
176
+
177
+ return constructor;
178
+ };
179
+ }
180
+
181
+ // ─── tracify() — instance-level wrapper ──────────────────────────────────────
182
+
183
+ /**
184
+ * tracify — wraps every method on an already-constructed object instance in a
185
+ * tracing span.
186
+ *
187
+ * Ideal for third-party singletons (SDK clients etc.) that cannot be decorated
188
+ * at the class level.
189
+ *
190
+ * @param instance The object whose methods should be traced.
191
+ * @param namespace Prefix for span names, e.g. "embeddingsClient".
192
+ * @param options Optional extra attributes / skip list.
193
+ *
194
+ * @example
195
+ * export const embeddingsClient = tracify(new OpenAI(), 'openai');
196
+ */
197
+ export function tracify<T extends object>(
198
+ instance: T,
199
+ namespace: string,
200
+ options: TraceAllOptions = {}
201
+ ): T {
202
+ const skip = new Set(options.skip ?? []);
203
+
204
+ return new Proxy(instance, {
205
+ get(target, prop, receiver) {
206
+ const value = Reflect.get(target, prop, receiver);
207
+ const methodName = typeof prop === "string" ? prop : String(prop);
208
+
209
+ // Pass symbols through unwrapped
210
+ if (typeof prop === "symbol") return value;
211
+
212
+ // Skip private / user-skipped names
213
+ if (methodName.startsWith("_") || skip.has(methodName)) return value;
214
+
215
+ // Recursively wrap nested objects (e.g. prisma.user.findMany)
216
+ if (value !== null && typeof value === "object") {
217
+ return tracify(value as object, `${namespace}.${methodName}`, options);
218
+ }
219
+
220
+ if (typeof value !== "function") return value;
221
+
222
+ const spanName = `${namespace}.${methodName}`;
223
+ const staticAttrs: Record<string, string | number | boolean> = {
224
+ "code.function": methodName,
225
+ "code.namespace": namespace,
226
+ ...options.attributes,
227
+ };
228
+
229
+ return function (this: unknown, ...args: unknown[]) {
230
+ return runWithSpan(spanName, staticAttrs, () =>
231
+ (value as Function).apply(target, args)
232
+ );
233
+ };
234
+ },
235
+ });
236
+ }
package/src/utils/http.ts CHANGED
@@ -21,6 +21,15 @@ export class HttpError extends Error {
21
21
  }
22
22
  }
23
23
 
24
+ /**
25
+ * Optional, non-enumerable hook carried by an authenticated headers object.
26
+ * The hook may replace an expired credential before one safe 401 retry.
27
+ */
28
+ export const HTTP_UNAUTHORIZED_HANDLER = Symbol("httpUnauthorizedHandler");
29
+ export type RefreshableHeaders = Record<string, string> & {
30
+ [HTTP_UNAUTHORIZED_HANDLER]?: () => Promise<void>;
31
+ };
32
+
24
33
  async function parseBody<T>(response: Response, responseType?: string): Promise<T> {
25
34
  if (responseType === "arraybuffer") {
26
35
  return (await response.arrayBuffer()) as unknown as T;
@@ -41,13 +50,14 @@ async function request<T = any>(
41
50
  url: string,
42
51
  options: {
43
52
  method?: string;
44
- headers?: Record<string, string>;
53
+ headers?: RefreshableHeaders;
45
54
  body?: any;
46
55
  responseType?: "json" | "arraybuffer" | "stream" | "text";
47
56
  params?: Record<string, any>;
48
57
  /** Timeout in milliseconds. Default: 30000 (30s). Use 0 to disable. */
49
58
  timeout?: number;
50
- } = {}
59
+ } = {},
60
+ mayRefresh = true
51
61
  ): Promise<HttpResponse<T>> {
52
62
  const { method = "GET", headers = {}, body, responseType, params, timeout = 30000 } = options;
53
63
 
@@ -102,6 +112,12 @@ async function request<T = any>(
102
112
  }
103
113
 
104
114
  if (!response.ok) {
115
+ const refresh = headers[HTTP_UNAUTHORIZED_HANDLER];
116
+ if (response.status === 401 && mayRefresh && refresh) {
117
+ await refresh();
118
+ return request<T>(url, options, false);
119
+ }
120
+
105
121
  const text = await response.text().catch(() => "");
106
122
  let parsedBody: any;
107
123
  try {
@@ -0,0 +1,65 @@
1
+ import http from "../../src/utils/http";
2
+ import { GenericFireworksClient } from "../../src/clients/fireworks";
3
+ import { FireworksModels } from "../../src/clients/pricing/fireworks";
4
+
5
+ jest.mock("../../src/utils/http", () => ({
6
+ __esModule: true,
7
+ default: { post: jest.fn() },
8
+ }));
9
+
10
+ const post = http.post as jest.MockedFunction<typeof http.post>;
11
+
12
+ describe("GenericFireworksClient", () => {
13
+ beforeEach(() => {
14
+ post.mockReset();
15
+ post.mockResolvedValue({
16
+ data: {
17
+ choices: [{ message: { role: "assistant", content: "ok" } }],
18
+ model: FireworksModels.DeepseekV4Flash,
19
+ usage: { prompt_tokens: 2, completion_tokens: 1, total_tokens: 3 },
20
+ },
21
+ } as any);
22
+ });
23
+
24
+ it("removes non-Fireworks options and tool return metadata", async () => {
25
+ const client = new GenericFireworksClient("test-key");
26
+
27
+ await client.createChatCompletion({
28
+ model: FireworksModels.DeepseekV4Flash,
29
+ messages: [{ role: "user", content: "hello" }],
30
+ max_tokens: 100,
31
+ reasoning_summary: true,
32
+ long_ttl_cache: true,
33
+ tools: [{
34
+ type: "function",
35
+ function: {
36
+ name: "lookup",
37
+ description: "Look something up",
38
+ parameters: { type: "object", properties: {} },
39
+ returns: { type: "string" },
40
+ } as any,
41
+ }],
42
+ });
43
+
44
+ expect(post).toHaveBeenCalledTimes(1);
45
+ const [url, body, requestOptions] = post.mock.calls[0];
46
+ expect(url).toBe("https://api.fireworks.ai/inference/v1/chat/completions");
47
+ expect(requestOptions).toMatchObject({
48
+ headers: { Authorization: "Bearer test-key" },
49
+ });
50
+ expect(body).toMatchObject({
51
+ model: FireworksModels.DeepseekV4Flash,
52
+ messages: [{ role: "user", content: "hello" }],
53
+ max_tokens: 100,
54
+ tool_choice: "auto",
55
+ });
56
+ const serializedBody = JSON.parse(JSON.stringify(body));
57
+ expect(serializedBody).not.toHaveProperty("reasoning_summary");
58
+ expect(serializedBody).not.toHaveProperty("long_ttl_cache");
59
+ expect(serializedBody.tools[0].function).toEqual({
60
+ name: "lookup",
61
+ description: "Look something up",
62
+ parameters: { type: "object", properties: {} },
63
+ });
64
+ });
65
+ });