@tyvm/knowhow 0.0.33 → 0.0.34

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 (504) hide show
  1. package/autodoc/plugins/downloader/downloader.mdx +2 -2
  2. package/benchmarks/.dockerignore +7 -0
  3. package/benchmarks/README.md +166 -0
  4. package/benchmarks/docker/Dockerfile +68 -0
  5. package/benchmarks/example-config.yml +27 -0
  6. package/benchmarks/jest.config.js +13 -0
  7. package/benchmarks/package-lock.json +4297 -0
  8. package/benchmarks/package.json +39 -0
  9. package/benchmarks/results/4542435/2025-08-05/lms/lms-openai-gpt-oss-20b.json +2814 -0
  10. package/benchmarks/results/4542435/2025-08-05/lms/lms-qwen-qwen3-30b-a3b-2507.json +2014 -0
  11. package/benchmarks/results/4fb9125/2025-08-07/anthropic/anthropic-claude-sonnet-4-20250514.json +3121 -0
  12. package/benchmarks/results/5766aee/2025-08-02/lms-qwen/qwen3-coder-30b.json +98 -0
  13. package/benchmarks/results/6d73808/2025-08-07/openai/openai-gpt-5.json +3256 -0
  14. package/benchmarks/results/77bf0a6/2025-08-02/lms-qwen/qwen3-30b-a3b-2507.json +4298 -0
  15. package/benchmarks/results/8c0d445/2025-08-03/anthropic/anthropic-claude-sonnet-4-20250514.json +3031 -0
  16. package/benchmarks/results/8c0d445/2025-08-03/openai/openai-gpt-4.1-2025-04-14.json +2990 -0
  17. package/benchmarks/results/ac6b2ab/2025-08-03/anthropic/anthropic-claude-sonnet-4-20250514.json +3256 -0
  18. package/benchmarks/results/ac6b2ab/2025-08-03/lms/lms-qwen-qwen3-coder-30b.json +3007 -0
  19. package/benchmarks/results/ac6b2ab/2025-08-03/openai/openai-gpt-4.1-2025-04-14.json +3256 -0
  20. package/benchmarks/results/ac6b2ab/2025-08-03/openai/openai-gpt-4.1-mini-2025-04-14.json +3036 -0
  21. package/benchmarks/results/ac6b2ab/2025-08-03/openai/openai-gpt-4.1-nano-2025-04-14.json +3280 -0
  22. package/benchmarks/results/adff675/2025-08-04/lms/lms-qwen-qwen3-30b-a3b-2507.json +1920 -0
  23. package/benchmarks/results/adff675/2025-08-04/lms/lms-qwen-qwen3-coder-30b.json +3281 -0
  24. package/benchmarks/results/b502ed9/2025-08-03/lms-qwen/qwen3-coder-30b.json +2896 -0
  25. package/benchmarks/results/d1a8129/2025-08-03/lms/lms-qwen-qwen3-coder-30b.json +3011 -0
  26. package/benchmarks/results/e60471c/2025-08-03/lms/qwen3-30b-a3b-2507.json +3003 -0
  27. package/benchmarks/scripts/build-and-run.sh +47 -0
  28. package/benchmarks/scripts/clone-exercism.sh +92 -0
  29. package/benchmarks/scripts/validate.sh +48 -0
  30. package/benchmarks/src/__tests__/runner.test.ts +27 -0
  31. package/benchmarks/src/cli.ts +90 -0
  32. package/benchmarks/src/evaluators/EvaluatorRegistry.ts +64 -0
  33. package/benchmarks/src/evaluators/JavaScriptEvaluator.ts +183 -0
  34. package/benchmarks/src/evaluators/index.ts +3 -0
  35. package/benchmarks/src/evaluators/types.ts +22 -0
  36. package/benchmarks/src/index.ts +3 -0
  37. package/benchmarks/src/providers.ts +13 -0
  38. package/benchmarks/src/runner.ts +824 -0
  39. package/benchmarks/src/types.ts +63 -0
  40. package/benchmarks/tsconfig.json +19 -0
  41. package/jest.config.js +2 -1
  42. package/leaderboard/README.md +148 -0
  43. package/leaderboard/app/api/benchmark-data/route.ts +131 -0
  44. package/leaderboard/app/api/benchmark-detail/route.ts +172 -0
  45. package/leaderboard/app/details/[model]/[provider]/[language]/page.tsx +501 -0
  46. package/leaderboard/app/exercise/[model]/[provider]/[language]/[exercise]/page.tsx +375 -0
  47. package/leaderboard/app/globals.css +27 -0
  48. package/leaderboard/app/layout.tsx +21 -0
  49. package/leaderboard/app/page.tsx +170 -0
  50. package/leaderboard/components/LeaderboardTable.tsx +168 -0
  51. package/leaderboard/components/PerformanceChart.tsx +109 -0
  52. package/leaderboard/next-env.d.ts +5 -0
  53. package/leaderboard/next.config.js +4 -0
  54. package/leaderboard/package-lock.json +6363 -0
  55. package/leaderboard/package.json +28 -0
  56. package/leaderboard/postcss.config.js +6 -0
  57. package/leaderboard/tailwind.config.js +17 -0
  58. package/leaderboard/tsconfig.json +28 -0
  59. package/leaderboard/types/benchmark.ts +67 -0
  60. package/leaderboard/utils/dataProcessor.ts +33 -0
  61. package/package.json +2 -1
  62. package/src/agents/base/base.ts +147 -21
  63. package/src/agents/base/prompt.ts +28 -0
  64. package/src/agents/index.ts +3 -0
  65. package/src/agents/patcher/patcher.ts +6 -4
  66. package/src/agents/setup/setup.ts +56 -0
  67. package/src/agents/tools/agentCall.ts +6 -2
  68. package/src/agents/tools/aiClient.ts +74 -8
  69. package/src/agents/tools/execCommand.ts +13 -14
  70. package/src/agents/tools/executeScript/README.md +16 -0
  71. package/src/agents/tools/index.ts +2 -0
  72. package/src/agents/tools/list.ts +73 -16
  73. package/src/agents/tools/startAgentTask.ts +109 -0
  74. package/src/agents/tools/textSearch.ts +1 -1
  75. package/src/agents/tools/visionTool.ts +31 -2
  76. package/src/agents/tools/ycmd/client.ts +608 -0
  77. package/src/agents/tools/ycmd/definitions.ts +294 -0
  78. package/src/agents/tools/ycmd/detection.ts +211 -0
  79. package/src/agents/tools/ycmd/index.ts +11 -0
  80. package/src/agents/tools/ycmd/installer.ts +251 -0
  81. package/src/agents/tools/ycmd/server.ts +535 -0
  82. package/src/agents/tools/ycmd/serverManager.ts +316 -0
  83. package/src/agents/tools/ycmd/tools/completion.ts +113 -0
  84. package/src/agents/tools/ycmd/tools/diagnostics.ts +155 -0
  85. package/src/agents/tools/ycmd/tools/getLocations.ts +173 -0
  86. package/src/agents/tools/ycmd/tools/goto.ts +169 -0
  87. package/src/agents/tools/ycmd/tools/refactor.ts +204 -0
  88. package/src/agents/tools/ycmd/tools/signature.ts +174 -0
  89. package/src/agents/tools/ycmd/tools/start.ts +95 -0
  90. package/src/agents/tools/ycmd/utils/pathUtils.ts +59 -0
  91. package/src/ai.ts +15 -0
  92. package/src/chat/CliChatService.ts +277 -0
  93. package/src/chat/modules/AgentModule.ts +980 -0
  94. package/src/chat/modules/AskModule.ts +98 -0
  95. package/src/chat/modules/BaseChatModule.ts +66 -0
  96. package/src/chat/modules/InternalChatModule.ts +174 -0
  97. package/src/chat/modules/SearchModule.ts +166 -0
  98. package/src/chat/modules/SetupModule.ts +185 -0
  99. package/src/chat/modules/SystemModule.ts +120 -0
  100. package/src/chat/modules/VoiceModule.ts +70 -0
  101. package/src/chat/modules/index.js +5 -0
  102. package/src/chat/types.ts +97 -0
  103. package/src/chat.ts +9 -1
  104. package/src/chat2.ts +62 -0
  105. package/src/cli.ts +264 -35
  106. package/src/clients/anthropic.ts +14 -7
  107. package/src/clients/gemini.ts +15 -7
  108. package/src/clients/http.ts +17 -7
  109. package/src/clients/index.ts +117 -4
  110. package/src/clients/knowhow.ts +7 -2
  111. package/src/clients/knowhowMcp.ts +118 -0
  112. package/src/clients/openai.ts +32 -8
  113. package/src/clients/types.ts +1 -0
  114. package/src/clients/xai.ts +17 -5
  115. package/src/config.ts +30 -5
  116. package/src/conversion.ts +4 -1
  117. package/src/login.ts +26 -9
  118. package/src/microphone.ts +0 -1
  119. package/src/plugins/downloader/downloader.ts +72 -24
  120. package/src/plugins/downloader/plugin.ts +3 -1
  121. package/src/plugins/plugins.ts +3 -0
  122. package/src/processors/CustomVariables.ts +425 -0
  123. package/src/processors/HarmonyToolProcessor.ts +264 -0
  124. package/src/processors/XmlToolCallProcessor.ts +533 -0
  125. package/src/processors/index.ts +3 -0
  126. package/src/prompts/KnowhowConfigExamples.ts +376 -0
  127. package/src/services/KnowhowClient.ts +49 -3
  128. package/src/services/Mcp.ts +42 -3
  129. package/src/services/McpServer.ts +14 -4
  130. package/src/services/McpWebsocketTransport.ts +21 -7
  131. package/src/services/MessageProcessor.ts +10 -5
  132. package/src/services/index.ts +5 -0
  133. package/src/services/script-execution/ScriptExecutor.ts +34 -1
  134. package/src/services/types.ts +17 -14
  135. package/src/types.ts +17 -0
  136. package/src/utils/index.ts +138 -0
  137. package/tests/XmlToolCallProcessor.test.ts +468 -0
  138. package/tests/manual/ycmd/debug_diagnostics_test.ts +127 -0
  139. package/tests/manual/ycmd/fixtures/debug_diagnostics.ts +26 -0
  140. package/tests/manual/ycmd/fixtures/file_change_test.ts +17 -0
  141. package/tests/manual/ycmd/minimal_advanced_test.ts +108 -0
  142. package/tests/manual/ycmd/simple_diagnostics_test.ts +61 -0
  143. package/tests/manual/ycmd/simple_test.ts +74 -0
  144. package/tests/manual/ycmd/test-typescript-sample.ts +34 -0
  145. package/tests/manual/ycmd/test_advanced_features.ts +407 -0
  146. package/tests/manual/ycmd/test_advanced_with_tools.ts +320 -0
  147. package/tests/manual/ycmd/test_comprehensive_typescript.ts +179 -0
  148. package/tests/manual/ycmd/test_diagnostics_file_changes.ts +249 -0
  149. package/tests/manual/ycmd/test_diagnostics_fix.ts +99 -0
  150. package/tests/manual/ycmd/test_diagnostics_simple.ts +100 -0
  151. package/tests/manual/ycmd/test_diagnostics_timing.ts +120 -0
  152. package/tests/manual/ycmd/test_discover_commands.ts +310 -0
  153. package/tests/manual/ycmd/test_endpoints.ts +115 -0
  154. package/tests/manual/ycmd/test_final_comprehensive.ts +218 -0
  155. package/tests/manual/ycmd/test_final_validation.ts +150 -0
  156. package/tests/manual/ycmd/test_implementation.js +42 -0
  157. package/tests/manual/ycmd/test_individual_ycmd_tool.ts +39 -0
  158. package/tests/manual/ycmd/test_server_manager.ts +52 -0
  159. package/tests/manual/ycmd/test_simple_debug.ts +86 -0
  160. package/tests/manual/ycmd/test_tsserver_workflow.js +83 -0
  161. package/tests/manual/ycmd/test_tsserver_workflow.ts +122 -0
  162. package/tests/manual/ycmd/test_typescript_simple.ts +48 -0
  163. package/tests/manual/ycmd/test_typescript_ycmd.ts +105 -0
  164. package/tests/manual/ycmd/test_workspace_config.ts +90 -0
  165. package/tests/manual/ycmd/test_ycmd_auto_start.ts +137 -0
  166. package/tests/manual/ycmd/test_ycmd_comprehensive.ts +73 -0
  167. package/tests/manual/ycmd/test_ycmd_connection.py +10 -0
  168. package/tests/manual/ycmd/test_ycmd_direct.ts +142 -0
  169. package/tests/manual/ycmd/test_ycmd_experiment.ts +48 -0
  170. package/tests/manual/ycmd/test_ycmd_final.ts +200 -0
  171. package/tests/manual/ycmd/test_ycmd_fixed.py +18 -0
  172. package/tests/manual/ycmd/test_ycmd_integration.ts +112 -0
  173. package/tests/manual/ycmd/test_ycmd_simple.ts +45 -0
  174. package/tests/manual/ycmd/test_ycmd_usage.py +27 -0
  175. package/tests/manual/ycmd/working_simple_test.ts +134 -0
  176. package/ts_build/src/agents/base/base.d.ts +14 -1
  177. package/ts_build/src/agents/base/base.js +91 -17
  178. package/ts_build/src/agents/base/base.js.map +1 -1
  179. package/ts_build/src/agents/base/prompt.d.ts +1 -1
  180. package/ts_build/src/agents/base/prompt.js +28 -0
  181. package/ts_build/src/agents/base/prompt.js.map +1 -1
  182. package/ts_build/src/agents/index.d.ts +2 -0
  183. package/ts_build/src/agents/index.js +2 -0
  184. package/ts_build/src/agents/index.js.map +1 -1
  185. package/ts_build/src/agents/patcher/patcher.js +6 -3
  186. package/ts_build/src/agents/patcher/patcher.js.map +1 -1
  187. package/ts_build/src/agents/setup/setup.d.ts +8 -0
  188. package/ts_build/src/agents/setup/setup.js +59 -0
  189. package/ts_build/src/agents/setup/setup.js.map +1 -0
  190. package/ts_build/src/agents/tools/agentCall.js +5 -2
  191. package/ts_build/src/agents/tools/agentCall.js.map +1 -1
  192. package/ts_build/src/agents/tools/aiClient.d.ts +6 -5
  193. package/ts_build/src/agents/tools/aiClient.js +37 -6
  194. package/ts_build/src/agents/tools/aiClient.js.map +1 -1
  195. package/ts_build/src/agents/tools/execCommand.d.ts +2 -2
  196. package/ts_build/src/agents/tools/execCommand.js +5 -6
  197. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  198. package/ts_build/src/agents/tools/executeScript/index.d.ts +1 -1
  199. package/ts_build/src/agents/tools/index.d.ts +2 -0
  200. package/ts_build/src/agents/tools/index.js +2 -0
  201. package/ts_build/src/agents/tools/index.js.map +1 -1
  202. package/ts_build/src/agents/tools/list.js +66 -16
  203. package/ts_build/src/agents/tools/list.js.map +1 -1
  204. package/ts_build/src/agents/tools/startAgentTask.d.ts +13 -0
  205. package/ts_build/src/agents/tools/startAgentTask.js +74 -0
  206. package/ts_build/src/agents/tools/startAgentTask.js.map +1 -0
  207. package/ts_build/src/agents/tools/startChatTask.d.ts +13 -0
  208. package/ts_build/src/agents/tools/startChatTask.js +73 -0
  209. package/ts_build/src/agents/tools/startChatTask.js.map +1 -0
  210. package/ts_build/src/agents/tools/textSearch.js +1 -1
  211. package/ts_build/src/agents/tools/textSearch.js.map +1 -1
  212. package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
  213. package/ts_build/src/agents/tools/visionTool.js +23 -3
  214. package/ts_build/src/agents/tools/visionTool.js.map +1 -1
  215. package/ts_build/src/agents/tools/ycmd/client.d.ts +93 -0
  216. package/ts_build/src/agents/tools/ycmd/client.js +355 -0
  217. package/ts_build/src/agents/tools/ycmd/client.js.map +1 -0
  218. package/ts_build/src/agents/tools/ycmd/definitions.d.ts +345 -0
  219. package/ts_build/src/agents/tools/ycmd/definitions.js +298 -0
  220. package/ts_build/src/agents/tools/ycmd/definitions.js.map +1 -0
  221. package/ts_build/src/agents/tools/ycmd/detection.d.ts +11 -0
  222. package/ts_build/src/agents/tools/ycmd/detection.js +175 -0
  223. package/ts_build/src/agents/tools/ycmd/detection.js.map +1 -0
  224. package/ts_build/src/agents/tools/ycmd/index.d.ts +8 -0
  225. package/ts_build/src/agents/tools/ycmd/index.js +20 -0
  226. package/ts_build/src/agents/tools/ycmd/index.js.map +1 -0
  227. package/ts_build/src/agents/tools/ycmd/installer.d.ts +19 -0
  228. package/ts_build/src/agents/tools/ycmd/installer.js +196 -0
  229. package/ts_build/src/agents/tools/ycmd/installer.js.map +1 -0
  230. package/ts_build/src/agents/tools/ycmd/server.d.ts +35 -0
  231. package/ts_build/src/agents/tools/ycmd/server.js +363 -0
  232. package/ts_build/src/agents/tools/ycmd/server.js.map +1 -0
  233. package/ts_build/src/agents/tools/ycmd/serverManager.d.ts +39 -0
  234. package/ts_build/src/agents/tools/ycmd/serverManager.js +210 -0
  235. package/ts_build/src/agents/tools/ycmd/serverManager.js.map +1 -0
  236. package/ts_build/src/agents/tools/ycmd/tools/completion.d.ts +22 -0
  237. package/ts_build/src/agents/tools/ycmd/tools/completion.js +72 -0
  238. package/ts_build/src/agents/tools/ycmd/tools/completion.js.map +1 -0
  239. package/ts_build/src/agents/tools/ycmd/tools/diagnostics.d.ts +42 -0
  240. package/ts_build/src/agents/tools/ycmd/tools/diagnostics.js +88 -0
  241. package/ts_build/src/agents/tools/ycmd/tools/diagnostics.js.map +1 -0
  242. package/ts_build/src/agents/tools/ycmd/tools/getLocations.d.ts +22 -0
  243. package/ts_build/src/agents/tools/ycmd/tools/getLocations.js +142 -0
  244. package/ts_build/src/agents/tools/ycmd/tools/getLocations.js.map +1 -0
  245. package/ts_build/src/agents/tools/ycmd/tools/goto.d.ts +20 -0
  246. package/ts_build/src/agents/tools/ycmd/tools/goto.js +101 -0
  247. package/ts_build/src/agents/tools/ycmd/tools/goto.js.map +1 -0
  248. package/ts_build/src/agents/tools/ycmd/tools/refactor.d.ts +32 -0
  249. package/ts_build/src/agents/tools/ycmd/tools/refactor.js +123 -0
  250. package/ts_build/src/agents/tools/ycmd/tools/refactor.js.map +1 -0
  251. package/ts_build/src/agents/tools/ycmd/tools/signature.d.ts +25 -0
  252. package/ts_build/src/agents/tools/ycmd/tools/signature.js +110 -0
  253. package/ts_build/src/agents/tools/ycmd/tools/signature.js.map +1 -0
  254. package/ts_build/src/agents/tools/ycmd/tools/start.d.ts +17 -0
  255. package/ts_build/src/agents/tools/ycmd/tools/start.js +65 -0
  256. package/ts_build/src/agents/tools/ycmd/tools/start.js.map +1 -0
  257. package/ts_build/src/agents/tools/ycmd/utils/pathUtils.d.ts +4 -0
  258. package/ts_build/src/agents/tools/ycmd/utils/pathUtils.js +67 -0
  259. package/ts_build/src/agents/tools/ycmd/utils/pathUtils.js.map +1 -0
  260. package/ts_build/src/ai.d.ts +1 -0
  261. package/ts_build/src/ai.js +40 -1
  262. package/ts_build/src/ai.js.map +1 -1
  263. package/ts_build/src/chat/ChatCommandHandler.d.ts +36 -0
  264. package/ts_build/src/chat/ChatCommandHandler.js +268 -0
  265. package/ts_build/src/chat/ChatCommandHandler.js.map +1 -0
  266. package/ts_build/src/chat/ChatInputManager.d.ts +22 -0
  267. package/ts_build/src/chat/ChatInputManager.js +85 -0
  268. package/ts_build/src/chat/ChatInputManager.js.map +1 -0
  269. package/ts_build/src/chat/ChatManager.d.ts +49 -0
  270. package/ts_build/src/chat/ChatManager.js +271 -0
  271. package/ts_build/src/chat/ChatManager.js.map +1 -0
  272. package/ts_build/src/chat/ChatSession.d.ts +32 -0
  273. package/ts_build/src/chat/ChatSession.js +3 -0
  274. package/ts_build/src/chat/ChatSession.js.map +1 -0
  275. package/ts_build/src/chat/ChatSessionManager.d.ts +19 -0
  276. package/ts_build/src/chat/ChatSessionManager.js +188 -0
  277. package/ts_build/src/chat/ChatSessionManager.js.map +1 -0
  278. package/ts_build/src/chat/ChatStateManager.d.ts +58 -0
  279. package/ts_build/src/chat/ChatStateManager.js +156 -0
  280. package/ts_build/src/chat/ChatStateManager.js.map +1 -0
  281. package/ts_build/src/chat/CliChatService.d.ts +35 -0
  282. package/ts_build/src/chat/CliChatService.js +201 -0
  283. package/ts_build/src/chat/CliChatService.js.map +1 -0
  284. package/ts_build/src/chat/InterruptibleInput.d.ts +20 -0
  285. package/ts_build/src/chat/InterruptibleInput.js +109 -0
  286. package/ts_build/src/chat/InterruptibleInput.js.map +1 -0
  287. package/ts_build/src/chat/interfaces/ChatModule.d.ts +6 -0
  288. package/ts_build/src/chat/interfaces/ChatModule.js +3 -0
  289. package/ts_build/src/chat/interfaces/ChatModule.js.map +1 -0
  290. package/ts_build/src/chat/modules/AgentModule.d.ts +56 -0
  291. package/ts_build/src/chat/modules/AgentModule.js +705 -0
  292. package/ts_build/src/chat/modules/AgentModule.js.map +1 -0
  293. package/ts_build/src/chat/modules/AskModule.d.ts +10 -0
  294. package/ts_build/src/chat/modules/AskModule.js +63 -0
  295. package/ts_build/src/chat/modules/AskModule.js.map +1 -0
  296. package/ts_build/src/chat/modules/BaseChatModule.d.ts +14 -0
  297. package/ts_build/src/chat/modules/BaseChatModule.js +32 -0
  298. package/ts_build/src/chat/modules/BaseChatModule.js.map +1 -0
  299. package/ts_build/src/chat/modules/InternalChatModule.d.ts +24 -0
  300. package/ts_build/src/chat/modules/InternalChatModule.js +127 -0
  301. package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -0
  302. package/ts_build/src/chat/modules/SearchModule.d.ts +12 -0
  303. package/ts_build/src/chat/modules/SearchModule.js +119 -0
  304. package/ts_build/src/chat/modules/SearchModule.js.map +1 -0
  305. package/ts_build/src/chat/modules/SetupModule.d.ts +15 -0
  306. package/ts_build/src/chat/modules/SetupModule.js +147 -0
  307. package/ts_build/src/chat/modules/SetupModule.js.map +1 -0
  308. package/ts_build/src/chat/modules/SystemModule.d.ts +14 -0
  309. package/ts_build/src/chat/modules/SystemModule.js +90 -0
  310. package/ts_build/src/chat/modules/SystemModule.js.map +1 -0
  311. package/ts_build/src/chat/modules/VoiceModule.d.ts +11 -0
  312. package/ts_build/src/chat/modules/VoiceModule.js +57 -0
  313. package/ts_build/src/chat/modules/VoiceModule.js.map +1 -0
  314. package/ts_build/src/chat/types.d.ts +83 -0
  315. package/ts_build/src/chat/types.js +3 -0
  316. package/ts_build/src/chat/types.js.map +1 -0
  317. package/ts_build/src/chat.js +7 -1
  318. package/ts_build/src/chat.js.map +1 -1
  319. package/ts_build/src/chat2.d.ts +3 -0
  320. package/ts_build/src/chat2.js +47 -0
  321. package/ts_build/src/chat2.js.map +1 -0
  322. package/ts_build/src/cli.js +218 -37
  323. package/ts_build/src/cli.js.map +1 -1
  324. package/ts_build/src/clients/anthropic.d.ts +5 -2
  325. package/ts_build/src/clients/anthropic.js +12 -7
  326. package/ts_build/src/clients/anthropic.js.map +1 -1
  327. package/ts_build/src/clients/gemini.d.ts +6 -3
  328. package/ts_build/src/clients/gemini.js +13 -7
  329. package/ts_build/src/clients/gemini.js.map +1 -1
  330. package/ts_build/src/clients/http.d.ts +1 -0
  331. package/ts_build/src/clients/http.js +12 -5
  332. package/ts_build/src/clients/http.js.map +1 -1
  333. package/ts_build/src/clients/index.d.ts +10 -0
  334. package/ts_build/src/clients/index.js +74 -4
  335. package/ts_build/src/clients/index.js.map +1 -1
  336. package/ts_build/src/clients/knowhow.d.ts +3 -1
  337. package/ts_build/src/clients/knowhow.js +8 -2
  338. package/ts_build/src/clients/knowhow.js.map +1 -1
  339. package/ts_build/src/clients/knowhowMcp.d.ts +20 -0
  340. package/ts_build/src/clients/knowhowMcp.js +86 -0
  341. package/ts_build/src/clients/knowhowMcp.js.map +1 -0
  342. package/ts_build/src/clients/openai.d.ts +5 -2
  343. package/ts_build/src/clients/openai.js +29 -8
  344. package/ts_build/src/clients/openai.js.map +1 -1
  345. package/ts_build/src/clients/types.d.ts +1 -0
  346. package/ts_build/src/clients/xai.d.ts +5 -2
  347. package/ts_build/src/clients/xai.js +15 -5
  348. package/ts_build/src/clients/xai.js.map +1 -1
  349. package/ts_build/src/config.js +24 -3
  350. package/ts_build/src/config.js.map +1 -1
  351. package/ts_build/src/conversion.js +6 -4
  352. package/ts_build/src/conversion.js.map +1 -1
  353. package/ts_build/src/login.d.ts +1 -1
  354. package/ts_build/src/login.js +21 -7
  355. package/ts_build/src/login.js.map +1 -1
  356. package/ts_build/src/microphone.js.map +1 -1
  357. package/ts_build/src/plugins/downloader/downloader.d.ts +4 -5
  358. package/ts_build/src/plugins/downloader/downloader.js +55 -26
  359. package/ts_build/src/plugins/downloader/downloader.js.map +1 -1
  360. package/ts_build/src/plugins/downloader/plugin.js +5 -3
  361. package/ts_build/src/plugins/downloader/plugin.js.map +1 -1
  362. package/ts_build/src/plugins/plugins.js +3 -0
  363. package/ts_build/src/plugins/plugins.js.map +1 -1
  364. package/ts_build/src/processors/CustomVariables.d.ts +32 -0
  365. package/ts_build/src/processors/CustomVariables.js +297 -0
  366. package/ts_build/src/processors/CustomVariables.js.map +1 -0
  367. package/ts_build/src/processors/HarmonyToolProcessor.d.ts +15 -0
  368. package/ts_build/src/processors/HarmonyToolProcessor.js +154 -0
  369. package/ts_build/src/processors/HarmonyToolProcessor.js.map +1 -0
  370. package/ts_build/src/processors/XmlToolCallProcessor.d.ts +14 -0
  371. package/ts_build/src/processors/XmlToolCallProcessor.js +357 -0
  372. package/ts_build/src/processors/XmlToolCallProcessor.js.map +1 -0
  373. package/ts_build/src/processors/index.d.ts +3 -0
  374. package/ts_build/src/processors/index.js +7 -1
  375. package/ts_build/src/processors/index.js.map +1 -1
  376. package/ts_build/src/prompts/KnowhowConfigExamples.d.ts +2 -0
  377. package/ts_build/src/prompts/KnowhowConfigExamples.js +379 -0
  378. package/ts_build/src/prompts/KnowhowConfigExamples.js.map +1 -0
  379. package/ts_build/src/services/KnowhowClient.d.ts +22 -0
  380. package/ts_build/src/services/KnowhowClient.js +14 -2
  381. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  382. package/ts_build/src/services/Mcp.d.ts +1 -0
  383. package/ts_build/src/services/Mcp.js +20 -3
  384. package/ts_build/src/services/Mcp.js.map +1 -1
  385. package/ts_build/src/services/McpServer.d.ts +1 -1
  386. package/ts_build/src/services/McpServer.js +8 -4
  387. package/ts_build/src/services/McpServer.js.map +1 -1
  388. package/ts_build/src/services/McpWebsocketTransport.js +17 -7
  389. package/ts_build/src/services/McpWebsocketTransport.js.map +1 -1
  390. package/ts_build/src/services/MessageProcessor.d.ts +1 -1
  391. package/ts_build/src/services/MessageProcessor.js +4 -4
  392. package/ts_build/src/services/MessageProcessor.js.map +1 -1
  393. package/ts_build/src/services/index.d.ts +2 -0
  394. package/ts_build/src/services/index.js +4 -0
  395. package/ts_build/src/services/index.js.map +1 -1
  396. package/ts_build/src/services/script-execution/ScriptExecutor.d.ts +1 -0
  397. package/ts_build/src/services/script-execution/ScriptExecutor.js +23 -0
  398. package/ts_build/src/services/script-execution/ScriptExecutor.js.map +1 -1
  399. package/ts_build/src/services/types.d.ts +2 -6
  400. package/ts_build/src/services/types.js +4 -4
  401. package/ts_build/src/services/types.js.map +1 -1
  402. package/ts_build/src/types.d.ts +11 -0
  403. package/ts_build/src/types.js +8 -0
  404. package/ts_build/src/types.js.map +1 -1
  405. package/ts_build/src/utils/index.d.ts +2 -0
  406. package/ts_build/src/utils/index.js +102 -1
  407. package/ts_build/src/utils/index.js.map +1 -1
  408. package/ts_build/tests/XmlToolCallProcessor.test.d.ts +1 -0
  409. package/ts_build/tests/XmlToolCallProcessor.test.js +376 -0
  410. package/ts_build/tests/XmlToolCallProcessor.test.js.map +1 -0
  411. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.d.ts +1 -0
  412. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js +114 -0
  413. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js.map +1 -0
  414. package/ts_build/tests/manual/ycmd/minimal_advanced_test.d.ts +2 -0
  415. package/ts_build/tests/manual/ycmd/minimal_advanced_test.js +104 -0
  416. package/ts_build/tests/manual/ycmd/minimal_advanced_test.js.map +1 -0
  417. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.d.ts +1 -0
  418. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js +74 -0
  419. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js.map +1 -0
  420. package/ts_build/tests/manual/ycmd/simple_test.d.ts +2 -0
  421. package/ts_build/tests/manual/ycmd/simple_test.js +82 -0
  422. package/ts_build/tests/manual/ycmd/simple_test.js.map +1 -0
  423. package/ts_build/tests/manual/ycmd/test-typescript-sample.d.ts +14 -0
  424. package/ts_build/tests/manual/ycmd/test-typescript-sample.js +20 -0
  425. package/ts_build/tests/manual/ycmd/test-typescript-sample.js.map +1 -0
  426. package/ts_build/tests/manual/ycmd/test_advanced_features.d.ts +2 -0
  427. package/ts_build/tests/manual/ycmd/test_advanced_features.js +297 -0
  428. package/ts_build/tests/manual/ycmd/test_advanced_features.js.map +1 -0
  429. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.d.ts +3 -0
  430. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js +262 -0
  431. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js.map +1 -0
  432. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.d.ts +2 -0
  433. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js +186 -0
  434. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js.map +1 -0
  435. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.d.ts +1 -0
  436. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js +174 -0
  437. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js.map +1 -0
  438. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.d.ts +2 -0
  439. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js +106 -0
  440. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js.map +1 -0
  441. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.d.ts +1 -0
  442. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js +104 -0
  443. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js.map +1 -0
  444. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.d.ts +1 -0
  445. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js +119 -0
  446. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js.map +1 -0
  447. package/ts_build/tests/manual/ycmd/test_discover_commands.d.ts +2 -0
  448. package/ts_build/tests/manual/ycmd/test_discover_commands.js +243 -0
  449. package/ts_build/tests/manual/ycmd/test_discover_commands.js.map +1 -0
  450. package/ts_build/tests/manual/ycmd/test_endpoints.d.ts +2 -0
  451. package/ts_build/tests/manual/ycmd/test_endpoints.js +120 -0
  452. package/ts_build/tests/manual/ycmd/test_endpoints.js.map +1 -0
  453. package/ts_build/tests/manual/ycmd/test_final_comprehensive.d.ts +2 -0
  454. package/ts_build/tests/manual/ycmd/test_final_comprehensive.js +221 -0
  455. package/ts_build/tests/manual/ycmd/test_final_comprehensive.js.map +1 -0
  456. package/ts_build/tests/manual/ycmd/test_final_validation.d.ts +2 -0
  457. package/ts_build/tests/manual/ycmd/test_final_validation.js +160 -0
  458. package/ts_build/tests/manual/ycmd/test_final_validation.js.map +1 -0
  459. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.d.ts +2 -0
  460. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js +37 -0
  461. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js.map +1 -0
  462. package/ts_build/tests/manual/ycmd/test_server_manager.d.ts +1 -0
  463. package/ts_build/tests/manual/ycmd/test_server_manager.js +38 -0
  464. package/ts_build/tests/manual/ycmd/test_server_manager.js.map +1 -0
  465. package/ts_build/tests/manual/ycmd/test_simple_debug.d.ts +2 -0
  466. package/ts_build/tests/manual/ycmd/test_simple_debug.js +99 -0
  467. package/ts_build/tests/manual/ycmd/test_simple_debug.js.map +1 -0
  468. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.d.ts +1 -0
  469. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js +128 -0
  470. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js.map +1 -0
  471. package/ts_build/tests/manual/ycmd/test_typescript_simple.d.ts +1 -0
  472. package/ts_build/tests/manual/ycmd/test_typescript_simple.js +66 -0
  473. package/ts_build/tests/manual/ycmd/test_typescript_simple.js.map +1 -0
  474. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.d.ts +1 -0
  475. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js +105 -0
  476. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js.map +1 -0
  477. package/ts_build/tests/manual/ycmd/test_workspace_config.d.ts +1 -0
  478. package/ts_build/tests/manual/ycmd/test_workspace_config.js +89 -0
  479. package/ts_build/tests/manual/ycmd/test_workspace_config.js.map +1 -0
  480. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.d.ts +2 -0
  481. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js +130 -0
  482. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js.map +1 -0
  483. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.d.ts +1 -0
  484. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js +83 -0
  485. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js.map +1 -0
  486. package/ts_build/tests/manual/ycmd/test_ycmd_direct.d.ts +2 -0
  487. package/ts_build/tests/manual/ycmd/test_ycmd_direct.js +149 -0
  488. package/ts_build/tests/manual/ycmd/test_ycmd_direct.js.map +1 -0
  489. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.d.ts +15 -0
  490. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js +58 -0
  491. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js.map +1 -0
  492. package/ts_build/tests/manual/ycmd/test_ycmd_final.d.ts +2 -0
  493. package/ts_build/tests/manual/ycmd/test_ycmd_final.js +195 -0
  494. package/ts_build/tests/manual/ycmd/test_ycmd_final.js.map +1 -0
  495. package/ts_build/tests/manual/ycmd/test_ycmd_integration.d.ts +3 -0
  496. package/ts_build/tests/manual/ycmd/test_ycmd_integration.js +110 -0
  497. package/ts_build/tests/manual/ycmd/test_ycmd_integration.js.map +1 -0
  498. package/ts_build/tests/manual/ycmd/test_ycmd_simple.d.ts +2 -0
  499. package/ts_build/tests/manual/ycmd/test_ycmd_simple.js +36 -0
  500. package/ts_build/tests/manual/ycmd/test_ycmd_simple.js.map +1 -0
  501. package/ts_build/tests/manual/ycmd/working_simple_test.d.ts +2 -0
  502. package/ts_build/tests/manual/ycmd/working_simple_test.js +134 -0
  503. package/ts_build/tests/manual/ycmd/working_simple_test.js.map +1 -0
  504. package/tsconfig.json +3 -1
@@ -0,0 +1,118 @@
1
+ import {
2
+ GenericClient,
3
+ CompletionOptions,
4
+ CompletionResponse,
5
+ EmbeddingOptions,
6
+ EmbeddingResponse,
7
+ } from "./types";
8
+ import { McpService } from "../services/Mcp";
9
+
10
+ /*
11
+ *
12
+ * If an MCP supports the following methods, then we can use it as a generic client.
13
+ * Once it's a generic client, it can be used by agents, or any other part of the system that leverages Clients
14
+ */
15
+ export class KnowhowMcpClient implements GenericClient {
16
+ private mcpService: McpService;
17
+
18
+ constructor(mcpService: McpService, private handlesConnection = false) {
19
+ this.mcpService = mcpService;
20
+ }
21
+
22
+ setKey(key: string) {
23
+ return;
24
+ }
25
+
26
+ async connect(): Promise<void> {
27
+ if (this.handlesConnection) {
28
+ await this.mcpService.connectAll();
29
+ }
30
+ }
31
+
32
+ async disconnect(): Promise<void> {
33
+ if (this.handlesConnection) {
34
+ await this.mcpService.closeTransports();
35
+ }
36
+ }
37
+
38
+ async callFunction<T>(
39
+ toolName: string,
40
+ args: Record<string, any>
41
+ ): Promise<T> {
42
+ try {
43
+ await this.connect();
44
+ const result = await this.mcpService.callFunction<T>(toolName, args);
45
+ return result as T;
46
+ } catch (error) {
47
+ console.error("Error calling MCP function:", toolName, args);
48
+ console.error(error);
49
+ } finally {
50
+ await this.disconnect();
51
+ }
52
+ }
53
+
54
+ async createChatCompletion(
55
+ options: CompletionOptions & { provider: string }
56
+ ): Promise<CompletionResponse> {
57
+ const data = await this.callFunction<CompletionResponse>(
58
+ "createAiCompletion",
59
+ {
60
+ provider: options.provider || "",
61
+ options: {
62
+ ...options,
63
+ max_tokens: options.max_tokens || 3000,
64
+
65
+ ...(options.tools && {
66
+ tools: options.tools,
67
+ tool_choice: "auto",
68
+ }),
69
+ },
70
+ }
71
+ );
72
+
73
+ console.log("Completion Response:", JSON.stringify(data, null, 2));
74
+
75
+ return data;
76
+ }
77
+
78
+ async createEmbedding(
79
+ options: EmbeddingOptions & { provider: string }
80
+ ): Promise<EmbeddingResponse> {
81
+ return this.callFunction<EmbeddingResponse>("createEmbedding", {
82
+ provider: options.provider || "",
83
+ options: {
84
+ ...options,
85
+ },
86
+ });
87
+ }
88
+
89
+ async getModels(): Promise<{ id: string }[]> {
90
+ try {
91
+ const parsedResult = await this.callFunction<any>("listAllModels", {});
92
+ // Convert the models object to the expected format
93
+ if (typeof parsedResult === "object") {
94
+ const models: { id: string }[] = [];
95
+
96
+ // Handle case where result is already an array of {id: string}
97
+ if (Array.isArray(parsedResult)) {
98
+ return parsedResult;
99
+ }
100
+
101
+ // Handle case where result is {provider: [model1, model2]}
102
+ for (const [provider, modelList] of Object.entries(parsedResult)) {
103
+ if (Array.isArray(modelList)) {
104
+ for (const model of modelList) {
105
+ models.push({ id: `${provider}/${model}` });
106
+ }
107
+ }
108
+ }
109
+
110
+ return models;
111
+ }
112
+
113
+ throw new Error("Invalid response format from MCP service");
114
+ } catch (error) {
115
+ throw new Error(`Failed to get models via MCP: ${error.message}`);
116
+ }
117
+ }
118
+ }
@@ -17,10 +17,18 @@ import { EmbeddingModels, Models, OpenAiReasoningModels } from "../types";
17
17
 
18
18
  const config = getConfigSync();
19
19
 
20
- export class GenericOpenAiClient extends OpenAI implements GenericClient {
21
- constructor() {
22
- super({
23
- apiKey: process.env.OPENAI_KEY,
20
+ export class GenericOpenAiClient implements GenericClient {
21
+ client: OpenAI;
22
+ apiKey?: string;
23
+
24
+ constructor(apiKey = process.env.OPENAI_KEY) {
25
+ this.setKey(apiKey);
26
+ }
27
+
28
+ setKey(apiKey: string) {
29
+ this.apiKey = apiKey;
30
+ this.client = new OpenAI({
31
+ apiKey,
24
32
  ...(config.openaiBaseUrl && { baseURL: config.openaiBaseUrl }),
25
33
  });
26
34
  }
@@ -40,13 +48,14 @@ export class GenericOpenAiClient extends OpenAI implements GenericClient {
40
48
  return msg as ChatCompletionMessageParam;
41
49
  });
42
50
 
43
- const response = await this.chat.completions.create({
51
+ const response = await this.client.chat.completions.create({
44
52
  model: options.model,
45
53
  messages: openaiMessages,
46
54
  max_tokens: options.max_tokens,
47
55
  ...(OpenAiReasoningModels.includes(options.model) && {
48
56
  max_tokens: undefined,
49
- max_completion_tokens: options.max_tokens,
57
+ max_completion_tokens: Math.max(options.max_tokens, 100),
58
+ // Health check requires some thoughts
50
59
  }),
51
60
 
52
61
  ...(options.tools && {
@@ -166,6 +175,21 @@ export class GenericOpenAiClient extends OpenAI implements GenericClient {
166
175
  cached_input: 0,
167
176
  output: 10.0,
168
177
  },
178
+ [Models.openai.GPT_5]: {
179
+ input: 1.25,
180
+ cached_input: 0.125,
181
+ output: 10,
182
+ },
183
+ [Models.openai.GPT_5_Mini]: {
184
+ input: 0.25,
185
+ cached_input: 0.025,
186
+ output: 2,
187
+ },
188
+ [Models.openai.GPT_5_Nano]: {
189
+ input: 0.05,
190
+ cached_input: 0.005,
191
+ output: 0.4,
192
+ },
169
193
  /*
170
194
  *[Models.openai.Computer_Use]: {
171
195
  * input: 3.0,
@@ -226,7 +250,7 @@ export class GenericOpenAiClient extends OpenAI implements GenericClient {
226
250
  }
227
251
 
228
252
  async getModels() {
229
- const models = await this.models.list();
253
+ const models = await this.client.models.list();
230
254
  return models.data.map((m) => {
231
255
  return {
232
256
  id: m.id,
@@ -237,7 +261,7 @@ export class GenericOpenAiClient extends OpenAI implements GenericClient {
237
261
  }
238
262
 
239
263
  async createEmbedding(options: EmbeddingOptions): Promise<EmbeddingResponse> {
240
- const openAiEmbedding = await this.embeddings.create({
264
+ const openAiEmbedding = await this.client.embeddings.create({
241
265
  input: options.input,
242
266
  model: options.model,
243
267
  });
@@ -85,6 +85,7 @@ export interface EmbeddingResponse {
85
85
  }
86
86
 
87
87
  export interface GenericClient {
88
+ setKey(key: string): void;
88
89
  createChatCompletion(options: CompletionOptions): Promise<CompletionResponse>;
89
90
  createEmbedding(options: EmbeddingOptions): Promise<EmbeddingResponse>;
90
91
  getModels(): Promise<{ id: string }[]>;
@@ -16,10 +16,22 @@ import { Models } from "../types";
16
16
 
17
17
  const config = getConfigSync();
18
18
 
19
- export class GenericXAIClient extends OpenAI implements GenericClient {
20
- constructor() {
21
- super({
22
- apiKey: process.env.XAI_API_KEY,
19
+ export class GenericXAIClient implements GenericClient {
20
+ private client: OpenAI;
21
+ private apiKey: string;
22
+
23
+ constructor(apiKey = process.env.XAI_API_KEY) {
24
+ this.apiKey = apiKey || "";
25
+ this.client = new OpenAI({
26
+ apiKey: apiKey || process.env.XAI_API_KEY,
27
+ baseURL: "https://api.x.ai/v1",
28
+ });
29
+ }
30
+
31
+ setKey(apiKey: string) {
32
+ this.apiKey = apiKey;
33
+ this.client = new OpenAI({
34
+ apiKey,
23
35
  baseURL: "https://api.x.ai/v1",
24
36
  });
25
37
  }
@@ -39,7 +51,7 @@ export class GenericXAIClient extends OpenAI implements GenericClient {
39
51
  return msg as ChatCompletionMessageParam;
40
52
  });
41
53
 
42
- const response = await this.chat.completions.create({
54
+ const response = await this.client.chat.completions.create({
43
55
  model: options.model,
44
56
  messages: xaiMessages,
45
57
  max_tokens: options.max_tokens,
package/src/config.ts CHANGED
@@ -73,6 +73,14 @@ const defaultConfig = {
73
73
  ],
74
74
 
75
75
  modelProviders: [{ url: "http://localhost:1234", provider: "lms" }],
76
+
77
+ ycmd: {
78
+ enabled: false,
79
+ installPath: undefined, // Will default to ~/.knowhow/ycmd
80
+ port: 0, // 0 for auto-assign
81
+ logLevel: "info",
82
+ completionTimeout: 5000,
83
+ },
76
84
  } as Config;
77
85
 
78
86
  const defaultLanguage = {
@@ -148,6 +156,14 @@ export async function updateLanguageConfig(language: Language) {
148
156
  }
149
157
 
150
158
  export async function updateConfig(config: Config) {
159
+ if (!config || typeof config !== "object") {
160
+ throw new Error("Invalid config object");
161
+ }
162
+
163
+ await fs.promises.copyFile(
164
+ ".knowhow/knowhow.json",
165
+ ".knowhow/knowhow.json.bak"
166
+ );
151
167
  await writeFile(".knowhow/knowhow.json", JSON.stringify(config, null, 2));
152
168
  }
153
169
 
@@ -185,15 +201,24 @@ export function getConfigSync() {
185
201
  }
186
202
  }
187
203
 
204
+ let loggedWarning = false;
188
205
  export async function getConfig() {
189
206
  if (!fs.existsSync(".knowhow/knowhow.json")) {
190
- console.warn(
191
- "KnowHow config file not found. Please run `knowhow init` to create it."
192
- );
207
+ if (!loggedWarning) {
208
+ loggedWarning = true;
209
+ console.warn(
210
+ "KnowHow config file not found. Please run `knowhow init` to create it."
211
+ );
212
+ }
193
213
  return {} as Config;
194
214
  }
195
- const config = JSON.parse(await readFile(".knowhow/knowhow.json", "utf8"));
196
- return config as Config;
215
+ try {
216
+ const config = await readFile(".knowhow/knowhow.json", "utf8");
217
+ return JSON.parse(config) as Config;
218
+ } catch (error) {
219
+ console.error("Error reading .knowhow/knowhow.json:", error);
220
+ throw new Error("Failed to load KnowHow configuration.");
221
+ }
197
222
  }
198
223
 
199
224
  export async function loadPrompt(promptName: string) {
package/src/conversion.ts CHANGED
@@ -2,7 +2,7 @@ import pdf from "pdf-parse";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
4
  import { readFile, fileExists } from "./utils";
5
- import { Downloader } from "./plugins/downloader/downloader";
5
+ import { services } from "./services";
6
6
 
7
7
  export async function processAudio(
8
8
  filePath: string,
@@ -21,6 +21,7 @@ export async function processAudio(
21
21
  : JSON.parse(fileContent);
22
22
  }
23
23
 
24
+ const { Downloader } = services();
24
25
  const chunks = await Downloader.chunk(
25
26
  filePath,
26
27
  parsed.dir,
@@ -73,9 +74,11 @@ export async function processVideo(
73
74
  );
74
75
 
75
76
  console.log("Extracting keyframes...");
77
+ const { Downloader } = services();
76
78
  const videoAnalysis = await Downloader.extractKeyframes(
77
79
  filePath,
78
80
  outputPath,
81
+ reusePreviousTranscript,
79
82
  chunkTime
80
83
  );
81
84
 
package/src/login.ts CHANGED
@@ -3,22 +3,20 @@ import fs from "fs";
3
3
  import path from "path";
4
4
  import { chmod } from "fs/promises";
5
5
  import { ask } from "./utils";
6
+ import { getConfig, updateConfig } from "./config";
7
+ import { KNOWHOW_API_URL } from "./services/KnowhowClient";
6
8
 
7
- const API_URL = process.env.KNOWHOW_API_URL;
8
-
9
- export async function login(): Promise<void> {
10
- if (!API_URL) {
9
+ export async function login(jwtFlag?: string): Promise<void> {
10
+ if (!KNOWHOW_API_URL) {
11
11
  throw new Error("Error: KNOWHOW_API_URL environment variable not set.");
12
12
  }
13
13
 
14
- const [flag] = process.argv.slice(3);
15
-
16
- if (flag === "--jwt") {
14
+ if (jwtFlag) {
17
15
  const jwt = await ask("Enter your JWT: ");
18
16
 
19
17
  // Update the JWT file
20
18
  const configDir = path.join(process.cwd(), ".knowhow");
21
- const jwtFile = path.join(configDir, ".jwt");
19
+ const jwtFile = path.join(process.cwd(), ".knowhow", ".jwt");
22
20
 
23
21
  if (!fs.existsSync(configDir)) {
24
22
  fs.mkdirSync(configDir, { recursive: true });
@@ -31,7 +29,7 @@ export async function login(): Promise<void> {
31
29
  // Get current user/org information
32
30
  try {
33
31
  const storedJwt = await loadJwt();
34
- const response = await axios.get(`${API_URL}/api/users/me`, {
32
+ const response = await axios.get(`${KNOWHOW_API_URL}/api/users/me`, {
35
33
  headers: {
36
34
  Authorization: `Bearer ${storedJwt}`,
37
35
  },
@@ -47,6 +45,25 @@ export async function login(): Promise<void> {
47
45
  console.log(
48
46
  `Current user: ${user.email}, \nOrganization: ${currentOrg?.organization?.name} - ${orgId}`
49
47
  );
48
+
49
+ const config = await getConfig();
50
+ const proxyUrl = KNOWHOW_API_URL + "/api/proxy";
51
+ const hasProvider = config.modelProviders.find(
52
+ (provider) => provider.provider === "knowhow" && provider.url === proxyUrl
53
+ );
54
+ if (!hasProvider) {
55
+ if (!config.modelProviders) {
56
+ config.modelProviders = [];
57
+ }
58
+
59
+ config.modelProviders.push({
60
+ provider: "knowhow",
61
+ url: proxyUrl,
62
+ jwtFile: ".knowhow/.jwt",
63
+ });
64
+
65
+ await updateConfig(config);
66
+ }
50
67
  } catch (error) {
51
68
  if (axios.isAxiosError(error) && error.response) {
52
69
  throw new Error(
package/src/microphone.ts CHANGED
@@ -3,7 +3,6 @@ import * as fs from "fs";
3
3
  import * as path from "path";
4
4
  import { openai } from "./ai";
5
5
  import { execAsync, ask } from "./utils";
6
- import { Downloader } from "./plugins/downloader/downloader";
7
6
  import { convertToText, convertAudioToText } from "./conversion";
8
7
 
9
8
  interface MicrophoneConfig {
@@ -5,14 +5,14 @@ import Logger from "progress-estimator";
5
5
  import { DownloadInfo, KeyframeInfo, TranscriptChunk } from "./types";
6
6
  import { visionTool } from "../../agents/tools/visionTool";
7
7
  import { execAsync, fileExists, readFile, mkdir } from "../../utils";
8
- import { openai } from "../../ai";
8
+ import OpenAI from "openai";
9
9
  import { Clients } from "../../clients";
10
10
  import { Models } from "../../types";
11
11
 
12
12
  const logger = Logger();
13
13
 
14
14
  export class DownloaderService {
15
- constructor(private openAi: typeof openai, private clients: typeof Clients) {}
15
+ constructor(private openAi: OpenAI, private clients: typeof Clients) {}
16
16
 
17
17
  async askGptVision(
18
18
  imageUrl: string,
@@ -99,7 +99,7 @@ export class DownloaderService {
99
99
  }
100
100
  }
101
101
 
102
- const command = `ffmpeg -i "${filePath}" -f segment -segment_time ${CHUNK_LENGTH_SECONDS} -map 0:a:0 -acodec mp3 -vn "${outputDirPath}/chunk%03d.mp3"`;
102
+ const command = `ffmpeg -i "${filePath}" -f segment -segment_time ${CHUNK_LENGTH_SECONDS} -map 0:a:0 -acodec mp3 -vn "${outputDirPath}/chunk%04d.mp3"`;
103
103
  await execAsync(command);
104
104
 
105
105
  const folderFiles = await fs.promises.readdir(outputDirPath);
@@ -115,6 +115,18 @@ export class DownloaderService {
115
115
  outputPath: string,
116
116
  reusePreviousTranscript = true
117
117
  ): AsyncGenerator<TranscriptChunk> {
118
+ const exists = await fileExists(outputPath);
119
+ if (exists && reusePreviousTranscript) {
120
+ console.log("Transcription already exists, using cached data");
121
+ const contents = await readFile(outputPath);
122
+ const data = JSON.parse(contents.toString()) as TranscriptChunk[];
123
+ for (const item of data) {
124
+ yield item;
125
+ }
126
+ return;
127
+ }
128
+
129
+ const allTranscripts = [];
118
130
  for (const file of files) {
119
131
  const chunkName = path.parse(file).name;
120
132
  const chunkTranscriptPath = path.join(
@@ -124,13 +136,19 @@ export class DownloaderService {
124
136
  const chunkExists = await fileExists(chunkTranscriptPath);
125
137
 
126
138
  if (chunkExists && reusePreviousTranscript) {
127
- console.log(chunkTranscriptPath, " transcription already exists, skipping");
139
+ console.log(
140
+ chunkTranscriptPath,
141
+ " transcription already exists, using cached data"
142
+ );
128
143
  const contents = await readFile(chunkTranscriptPath);
129
- yield {
144
+ const cached = {
130
145
  chunkPath: chunkTranscriptPath,
131
146
  text: contents.toString(),
132
147
  usd_cost: 0,
133
148
  };
149
+
150
+ yield cached;
151
+ allTranscripts.push(cached);
134
152
  continue;
135
153
  }
136
154
 
@@ -149,12 +167,16 @@ export class DownloaderService {
149
167
  await fs.promises.writeFile(chunkTranscriptPath, transcript.text);
150
168
 
151
169
  // save chunk transcript to file
152
- yield {
170
+ const data = {
153
171
  chunkPath: chunkTranscriptPath,
154
172
  text: transcript.text,
155
173
  usd_cost: 30 * 0.0001, // assume 30 seconds,
156
174
  };
175
+ yield data;
176
+ allTranscripts.push(data);
157
177
  }
178
+
179
+ fs.writeFileSync(outputPath, JSON.stringify(allTranscripts, null, 2));
158
180
  }
159
181
 
160
182
  public async transcribeChunks(
@@ -164,7 +186,7 @@ export class DownloaderService {
164
186
  ): Promise<string[]> {
165
187
  const exists = await fileExists(outputPath);
166
188
  if (exists && reusePreviousTranscript) {
167
- console.log("Transcription already exists, skipping");
189
+ console.log("Transcription already exists, using cached data");
168
190
  const contents = await readFile(outputPath);
169
191
  return JSON.parse(contents.toString()) as string[];
170
192
  }
@@ -185,12 +207,13 @@ export class DownloaderService {
185
207
 
186
208
  public async *streamKeyFrameExtraction(
187
209
  filePath: string,
188
- outputPath: string,
210
+ videoJsonPath: string,
211
+ reusePreviousKeyframes: boolean = true,
189
212
  interval: number = 10
190
213
  ): AsyncGenerator<KeyframeInfo> {
191
- if (fs.existsSync(outputPath)) {
192
- console.log("Keyframes already exist, skipping");
193
- const contents = await readFile(outputPath);
214
+ if (reusePreviousKeyframes && fs.existsSync(videoJsonPath)) {
215
+ console.log("Keyframes already exist, using cached data");
216
+ const contents = await readFile(videoJsonPath);
194
217
  const data = JSON.parse(contents.toString()) as KeyframeInfo[];
195
218
  for (const keyframe of data) {
196
219
  yield { ...keyframe, usd_cost: 0 };
@@ -199,16 +222,18 @@ export class DownloaderService {
199
222
  }
200
223
 
201
224
  const parsed = path.parse(filePath);
202
- const outputDir = path.dirname(outputPath);
225
+ const outputDir = path.dirname(videoJsonPath);
203
226
  const fileName = parsed.name;
204
227
  const keyframesDir = path.join(outputDir, `/keyframes`);
205
228
  await fs.promises.mkdir(keyframesDir, { recursive: true });
206
229
 
207
230
  const command = `ffmpeg -i "${filePath}" -vf "fps=1/${interval},scale=640:-1" "${keyframesDir}/frame%04d.jpg"`;
208
231
  await execAsync(command);
232
+ console.log("Extracting keyframe:", command);
209
233
 
210
234
  const keyframes = await fs.promises.readdir(keyframesDir);
211
235
 
236
+ const allKeyframes = [];
212
237
  for (const keyframe of keyframes) {
213
238
  const keyframePath = path.join(keyframesDir, keyframe);
214
239
  const keyframeName = path.parse(keyframe).name;
@@ -218,10 +243,11 @@ export class DownloaderService {
218
243
  );
219
244
  const descriptionExists = await fileExists(keyframeDescriptionPath);
220
245
 
221
- if (descriptionExists) {
246
+ if (descriptionExists && reusePreviousKeyframes) {
222
247
  const cached = await readFile(keyframeDescriptionPath);
223
248
  const cachedJson = JSON.parse(cached.toString()) as KeyframeInfo;
224
249
  yield { ...cachedJson, usd_cost: 0 };
250
+ allKeyframes.push(cachedJson);
225
251
  continue;
226
252
  }
227
253
 
@@ -237,18 +263,26 @@ export class DownloaderService {
237
263
  JSON.stringify(keyframeJson, null, 2)
238
264
  );
239
265
  yield keyframeJson;
266
+ allKeyframes.push(keyframeJson);
240
267
  }
268
+
269
+ await fs.promises.writeFile(
270
+ videoJsonPath,
271
+ JSON.stringify(allKeyframes, null, 2)
272
+ );
241
273
  }
242
274
 
243
275
  public async extractKeyframes(
244
276
  filePath: string,
245
277
  outputPath: string,
278
+ reusePreviousKeyframes: boolean = true,
246
279
  interval: number = 10
247
280
  ): Promise<KeyframeInfo[]> {
248
281
  const keyframes: KeyframeInfo[] = [];
249
282
  for await (const keyframe of this.streamKeyFrameExtraction(
250
283
  filePath,
251
284
  outputPath,
285
+ reusePreviousKeyframes,
252
286
  interval
253
287
  )) {
254
288
  keyframes.push(keyframe);
@@ -265,6 +299,7 @@ export class DownloaderService {
265
299
  encoding: "base64",
266
300
  });
267
301
  const image = `data:image/jpeg;base64,${base64}`;
302
+ console.log("Describing keyframe:", keyframePath);
268
303
  const response = await this.askGptVision(image, question);
269
304
  return response;
270
305
  }
@@ -285,7 +320,9 @@ export class DownloaderService {
285
320
  // Skip chunking if the full output exists
286
321
  const exists = await fileExists(outputPath);
287
322
  if (exists && reusePreviousTranscript) {
288
- console.log(`Transcription ${outputPath} already exists, skipping`);
323
+ console.log(
324
+ `Transcription ${outputPath} already exists, using cached data`
325
+ );
289
326
  const fileContent = await readFile(outputPath, "utf8");
290
327
  return outputPath.endsWith("txt")
291
328
  ? fileContent.split("\n")
@@ -318,14 +355,21 @@ export class DownloaderService {
318
355
  // Skip chunking if the full output exists
319
356
  const exists = await fileExists(outputPath);
320
357
  if (exists && reusePreviousTranscript) {
321
- console.log(`Transcription ${outputPath} already exists, skipping`);
358
+ console.log(
359
+ `Transcription ${outputPath} already exists, using cached data`
360
+ );
322
361
  const fileContent = await readFile(outputPath, "utf8");
323
362
  const lines = outputPath.endsWith("txt")
324
363
  ? fileContent.split("\n")
325
364
  : JSON.parse(fileContent);
326
365
 
327
- for (const line of lines)
328
- yield { chunkPath: "", text: line, usd_cost: 0 };
366
+ for (const line of lines) {
367
+ if (typeof line === "string") {
368
+ yield { chunkPath: "", text: line, usd_cost: 0 };
369
+ } else {
370
+ yield line as TranscriptChunk;
371
+ }
372
+ }
329
373
  return;
330
374
  }
331
375
 
@@ -364,6 +408,7 @@ export class DownloaderService {
364
408
  const videoAnalysis = await this.extractKeyframes(
365
409
  filePath,
366
410
  outputPath,
411
+ reusePreviousTranscript,
367
412
  chunkTime
368
413
  );
369
414
 
@@ -381,19 +426,20 @@ export class DownloaderService {
381
426
  chunkTime = 30
382
427
  ) {
383
428
  const parsed = path.parse(filePath);
384
- const outputPath = `${parsed.dir}/${parsed.name}/video.json`;
429
+ const videoJson = `${parsed.dir}/${parsed.name}/video.json`;
385
430
 
386
431
  console.log("Processing audio...");
387
- const transcriptions = await this.streamProcessAudio(
432
+ const transcriptions = this.streamProcessAudio(
388
433
  filePath,
389
434
  reusePreviousTranscript,
390
435
  chunkTime
391
436
  );
392
437
 
393
438
  console.log("Extracting keyframes...");
394
- const videoAnalysis = await this.streamKeyFrameExtraction(
439
+ const videoAnalysis = this.streamKeyFrameExtraction(
395
440
  filePath,
396
- outputPath,
441
+ videoJson,
442
+ reusePreviousTranscript,
397
443
  chunkTime
398
444
  );
399
445
 
@@ -402,10 +448,12 @@ export class DownloaderService {
402
448
  ?.value as TranscriptChunk;
403
449
  yield {
404
450
  frame,
405
- transcription,
451
+ transcription: transcription || {
452
+ chunkPath: "",
453
+ text: "[missing transcript]",
454
+ usd_cost: 0,
455
+ },
406
456
  };
407
457
  }
408
458
  }
409
459
  }
410
-
411
- export const Downloader = new DownloaderService(openai, Clients);
@@ -2,7 +2,7 @@ import fs from "fs";
2
2
  import { PluginBase, PluginMeta } from "../PluginBase";
3
3
  import { MinimalEmbedding } from "../../types";
4
4
  import { convertToText, processVideo } from "../../conversion";
5
- import { Downloader } from "./downloader";
5
+ import { services } from "../../services";
6
6
 
7
7
  export class DownloaderPlugin extends PluginBase {
8
8
  static readonly meta: PluginMeta = {
@@ -40,6 +40,7 @@ export class DownloaderPlugin extends PluginBase {
40
40
  try {
41
41
  console.log("DOWNLOADER PLUGIN: attempting", url);
42
42
  const downloadDir = ".knowhow/downloads/";
43
+ const { Downloader } = services();
43
44
  const fileInfo = await Downloader.download(url, downloadDir);
44
45
  const filePath = `${downloadDir}${fileInfo.id}.${fileInfo.ext}`;
45
46
  transcript += await convertToText(filePath);
@@ -59,6 +60,7 @@ export class DownloaderPlugin extends PluginBase {
59
60
  const embeddings: MinimalEmbedding[] = [];
60
61
  for (const url of urls) {
61
62
  const downloadDir = ".knowhow/downloads/";
63
+ const { Downloader } = services();
62
64
  const fileInfo = await Downloader.download(url, downloadDir);
63
65
  const filePath = `${downloadDir}${fileInfo.id}.${fileInfo.ext}`;
64
66
  const processed = await processVideo(filePath);