@tyvm/knowhow 0.0.46 → 0.0.48

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 (461) hide show
  1. package/benchmarks/results/27b0a06/2025-09-27/xai/xai-grok-code-fast-1.json +2909 -0
  2. package/benchmarks/results/4057aed/2025-08-14/anthropic/anthropic-claude-sonnet-4-20250514.json +1671 -0
  3. package/jest.config.js +2 -2
  4. package/package.json +8 -3
  5. package/src/agents/base/base.ts +30 -24
  6. package/src/agents/patcher/patcher.ts +26 -5
  7. package/src/agents/tools/agentCall.ts +4 -2
  8. package/src/agents/tools/aiClient.ts +3 -11
  9. package/src/agents/tools/ast/astAppendNode.ts +90 -0
  10. package/src/agents/tools/ast/astDeleteNode.ts +88 -0
  11. package/src/agents/tools/ast/astEditNode.ts +95 -0
  12. package/src/agents/tools/ast/astGetPathForLine.ts +73 -0
  13. package/src/agents/tools/ast/astListPaths.ts +66 -0
  14. package/src/agents/tools/ast/index.ts +7 -0
  15. package/src/agents/tools/callPlugin.ts +8 -2
  16. package/src/agents/tools/embeddingSearch.ts +2 -1
  17. package/src/agents/tools/execCommand.ts +239 -94
  18. package/src/agents/tools/fileSearch.ts +15 -17
  19. package/src/agents/tools/index.ts +1 -0
  20. package/src/agents/tools/language/definitions.ts +10 -2
  21. package/src/agents/tools/language/index.ts +3 -2
  22. package/src/agents/tools/lintFile.ts +4 -2
  23. package/src/agents/tools/list.ts +203 -62
  24. package/src/agents/tools/patch.ts +48 -14
  25. package/src/agents/tools/readBlocks.ts +34 -0
  26. package/src/agents/tools/readFile.ts +23 -0
  27. package/src/agents/tools/stringReplace.ts +33 -9
  28. package/src/agents/tools/writeFile.ts +55 -0
  29. package/src/agents/tools/ycmd/server.ts +14 -4
  30. package/src/chat/CliChatService.ts +6 -1
  31. package/src/chat/modules/AgentModule.ts +107 -64
  32. package/src/chat/modules/AskModule.ts +0 -1
  33. package/src/chat/modules/SetupModule.ts +4 -4
  34. package/src/chat/modules/SystemModule.ts +28 -5
  35. package/src/chat/types.ts +2 -0
  36. package/src/chat-old.ts +2 -2
  37. package/src/clients/anthropic.ts +22 -1
  38. package/src/clients/openai.ts +1 -1
  39. package/src/clients/types.ts +1 -1
  40. package/src/clients/xai.ts +15 -5
  41. package/src/config.ts +17 -5
  42. package/src/dataset/diffs/generate.ts +2 -2
  43. package/src/dataset/diffs/jsonl.ts +0 -1
  44. package/src/embeddings.ts +6 -4
  45. package/src/index.ts +11 -5
  46. package/src/plugins/GitPlugin.ts +530 -0
  47. package/src/plugins/LinterPlugin.ts +89 -0
  48. package/src/plugins/PluginBase.ts +4 -2
  49. package/src/plugins/asana.ts +4 -2
  50. package/src/plugins/downloader/plugin.ts +5 -2
  51. package/src/plugins/embedding.ts +24 -4
  52. package/src/plugins/figma.ts +7 -3
  53. package/src/plugins/github.ts +4 -2
  54. package/src/plugins/jira.ts +4 -2
  55. package/src/plugins/language.ts +134 -27
  56. package/src/plugins/linear.ts +4 -2
  57. package/src/plugins/notion.ts +4 -2
  58. package/src/plugins/plugins.ts +27 -16
  59. package/src/plugins/tree-sitter/editor.ts +369 -0
  60. package/src/plugins/tree-sitter/lang-packs/index.ts +23 -0
  61. package/src/plugins/tree-sitter/lang-packs/java.ts +59 -0
  62. package/src/plugins/tree-sitter/lang-packs/javascript.ts +57 -0
  63. package/src/plugins/tree-sitter/lang-packs/python.ts +45 -0
  64. package/src/plugins/tree-sitter/lang-packs/types.ts +79 -0
  65. package/src/plugins/tree-sitter/lang-packs/typescript.ts +49 -0
  66. package/src/plugins/tree-sitter/parser.ts +444 -0
  67. package/src/plugins/tree-sitter/simple-paths.ts +467 -0
  68. package/src/plugins/types.ts +11 -0
  69. package/src/plugins/url.ts +5 -3
  70. package/src/plugins/vim.ts +8 -5
  71. package/src/processors/CustomVariables.ts +19 -7
  72. package/src/processors/TokenCompressor.ts +13 -13
  73. package/src/processors/ToolResponseCache.ts +15 -6
  74. package/src/services/EmbeddingService.ts +18 -9
  75. package/src/services/EventService.ts +80 -0
  76. package/src/services/Mcp.ts +5 -0
  77. package/src/services/S3.ts +4 -3
  78. package/src/services/Tools.ts +125 -53
  79. package/src/services/index.ts +16 -11
  80. package/src/services/types.ts +3 -3
  81. package/src/types.ts +7 -2
  82. package/src/worker.ts +14 -1
  83. package/test-comprehensive.ts +31 -0
  84. package/tests/clients/AIClient.test.ts +490 -0
  85. package/tests/manual/agent-events/run-test.ts +203 -0
  86. package/tests/{integration → manual/file-edits}/figma.test.ts +1 -1
  87. package/tests/{integration → manual/file-edits}/fileblocks/readwrite.test.ts +7 -3
  88. package/tests/{integration → manual/file-edits}/patching.test.ts +11 -8
  89. package/tests/plugins/language/languagePlugin-content-triggers.test.ts +332 -0
  90. package/tests/plugins/language/languagePlugin-integration.test.ts +456 -0
  91. package/tests/plugins/language/languagePlugin.test.ts +363 -0
  92. package/tests/processors/Base64ImageDetector.test.ts +403 -0
  93. package/tests/processors/CustomVariables.test.ts +430 -0
  94. package/tests/processors/HarmonyToolProcessor.test.ts +490 -0
  95. package/tests/processors/TokenCompressor.test.ts +391 -0
  96. package/tests/processors/ToolResponseCache.test.ts +688 -0
  97. package/tests/services/Tools.test.ts +1339 -0
  98. package/tests/test.spec.ts +162 -117
  99. package/tests/tree-sitter/editor.test.ts +113 -0
  100. package/tests/tree-sitter/invalid.test.ts +299 -0
  101. package/tests/tree-sitter/paths/common-edits.test.ts +564 -0
  102. package/tests/tree-sitter/paths/debug-exact-position.test.ts +44 -0
  103. package/tests/tree-sitter/paths/debug-line-indexing.test.ts +49 -0
  104. package/tests/tree-sitter/paths/debug-paths.test.ts +90 -0
  105. package/tests/tree-sitter/paths/paths.test.ts +170 -0
  106. package/tests/tree-sitter/paths/simple-paths.test.ts +367 -0
  107. package/tests/tree-sitter/sample-after.ts +48 -0
  108. package/tests/tree-sitter/sample-before.ts +25 -0
  109. package/tests/tree-sitter/test-files/completely-broken.ts +7 -0
  110. package/tests/tree-sitter/test-files/duplicate-braces.ts +39 -0
  111. package/tests/tree-sitter/test-files/invalid-nesting.ts +39 -0
  112. package/tests/tree-sitter/test-files/malformed-signature.ts +39 -0
  113. package/tests/tree-sitter/test-files/mismatched-parens.ts +39 -0
  114. package/tests/tree-sitter/test-files/missing-semicolon.ts +39 -0
  115. package/tests/tree-sitter/test-files/partially-broken.ts +20 -0
  116. package/tests/tree-sitter/test-files/specific-errors.ts +14 -0
  117. package/tests/tree-sitter/test-files/unclosed-string.ts +39 -0
  118. package/tests/tree-sitter/tree-sitter.test.ts +251 -0
  119. package/ts_build/package.json +8 -3
  120. package/ts_build/src/agents/base/base.d.ts +2 -2
  121. package/ts_build/src/agents/base/base.js +24 -20
  122. package/ts_build/src/agents/base/base.js.map +1 -1
  123. package/ts_build/src/agents/patcher/patcher.js +26 -5
  124. package/ts_build/src/agents/patcher/patcher.js.map +1 -1
  125. package/ts_build/src/agents/tools/agentCall.js +2 -1
  126. package/ts_build/src/agents/tools/agentCall.js.map +1 -1
  127. package/ts_build/src/agents/tools/aiClient.d.ts +7 -8
  128. package/ts_build/src/agents/tools/aiClient.js.map +1 -1
  129. package/ts_build/src/agents/tools/ast/astAppendNode.d.ts +1 -0
  130. package/ts_build/src/agents/tools/ast/astAppendNode.js +96 -0
  131. package/ts_build/src/agents/tools/ast/astAppendNode.js.map +1 -0
  132. package/ts_build/src/agents/tools/ast/astDeleteNode.d.ts +1 -0
  133. package/ts_build/src/agents/tools/ast/astDeleteNode.js +94 -0
  134. package/ts_build/src/agents/tools/ast/astDeleteNode.js.map +1 -0
  135. package/ts_build/src/agents/tools/ast/astEditNode.d.ts +1 -0
  136. package/ts_build/src/agents/tools/ast/astEditNode.js +96 -0
  137. package/ts_build/src/agents/tools/ast/astEditNode.js.map +1 -0
  138. package/ts_build/src/agents/tools/ast/astGetPathForLine.d.ts +1 -0
  139. package/ts_build/src/agents/tools/ast/astGetPathForLine.js +78 -0
  140. package/ts_build/src/agents/tools/ast/astGetPathForLine.js.map +1 -0
  141. package/ts_build/src/agents/tools/ast/astListPaths.d.ts +1 -0
  142. package/ts_build/src/agents/tools/ast/astListPaths.js +78 -0
  143. package/ts_build/src/agents/tools/ast/astListPaths.js.map +1 -0
  144. package/ts_build/src/agents/tools/ast/index.d.ts +5 -0
  145. package/ts_build/src/agents/tools/ast/index.js +14 -0
  146. package/ts_build/src/agents/tools/ast/index.js.map +1 -0
  147. package/ts_build/src/agents/tools/astAppendNode.d.ts +1 -0
  148. package/ts_build/src/agents/tools/astAppendNode.js +98 -0
  149. package/ts_build/src/agents/tools/astAppendNode.js.map +1 -0
  150. package/ts_build/src/agents/tools/astDeleteNode.d.ts +1 -0
  151. package/ts_build/src/agents/tools/astDeleteNode.js +95 -0
  152. package/ts_build/src/agents/tools/astDeleteNode.js.map +1 -0
  153. package/ts_build/src/agents/tools/astEditNode.d.ts +1 -0
  154. package/ts_build/src/agents/tools/astEditNode.js +98 -0
  155. package/ts_build/src/agents/tools/astEditNode.js.map +1 -0
  156. package/ts_build/src/agents/tools/astGetPathForLine.d.ts +1 -0
  157. package/ts_build/src/agents/tools/astGetPathForLine.js +89 -0
  158. package/ts_build/src/agents/tools/astGetPathForLine.js.map +1 -0
  159. package/ts_build/src/agents/tools/astListPaths.d.ts +1 -0
  160. package/ts_build/src/agents/tools/astListPaths.js +82 -0
  161. package/ts_build/src/agents/tools/astListPaths.js.map +1 -0
  162. package/ts_build/src/agents/tools/callPlugin.js +4 -2
  163. package/ts_build/src/agents/tools/callPlugin.js.map +1 -1
  164. package/ts_build/src/agents/tools/embeddingSearch.js +3 -2
  165. package/ts_build/src/agents/tools/embeddingSearch.js.map +1 -1
  166. package/ts_build/src/agents/tools/execCommand.d.ts +2 -2
  167. package/ts_build/src/agents/tools/execCommand.js +201 -67
  168. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  169. package/ts_build/src/agents/tools/fileSearch.d.ts +1 -1
  170. package/ts_build/src/agents/tools/fileSearch.js +11 -15
  171. package/ts_build/src/agents/tools/fileSearch.js.map +1 -1
  172. package/ts_build/src/agents/tools/github/index.d.ts +1 -1
  173. package/ts_build/src/agents/tools/index.d.ts +1 -0
  174. package/ts_build/src/agents/tools/index.js +1 -0
  175. package/ts_build/src/agents/tools/index.js.map +1 -1
  176. package/ts_build/src/agents/tools/language/definitions.js +11 -2
  177. package/ts_build/src/agents/tools/language/definitions.js.map +1 -1
  178. package/ts_build/src/agents/tools/language/index.js +4 -3
  179. package/ts_build/src/agents/tools/language/index.js.map +1 -1
  180. package/ts_build/src/agents/tools/lintFile.js +4 -2
  181. package/ts_build/src/agents/tools/lintFile.js.map +1 -1
  182. package/ts_build/src/agents/tools/list.js +185 -49
  183. package/ts_build/src/agents/tools/list.js.map +1 -1
  184. package/ts_build/src/agents/tools/patch.js +33 -10
  185. package/ts_build/src/agents/tools/patch.js.map +1 -1
  186. package/ts_build/src/agents/tools/readBlocks.js +23 -0
  187. package/ts_build/src/agents/tools/readBlocks.js.map +1 -1
  188. package/ts_build/src/agents/tools/readFile.js +14 -0
  189. package/ts_build/src/agents/tools/readFile.js.map +1 -1
  190. package/ts_build/src/agents/tools/stringReplace.js +19 -2
  191. package/ts_build/src/agents/tools/stringReplace.js.map +1 -1
  192. package/ts_build/src/agents/tools/writeFile.js +40 -0
  193. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  194. package/ts_build/src/agents/tools/ycmd/server.js +5 -0
  195. package/ts_build/src/agents/tools/ycmd/server.js.map +1 -1
  196. package/ts_build/src/chat/CliChatService.d.ts +1 -0
  197. package/ts_build/src/chat/CliChatService.js +6 -2
  198. package/ts_build/src/chat/CliChatService.js.map +1 -1
  199. package/ts_build/src/chat/modules/AgentModule.d.ts +5 -1
  200. package/ts_build/src/chat/modules/AgentModule.js +53 -31
  201. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  202. package/ts_build/src/chat/modules/AskModule.js.map +1 -1
  203. package/ts_build/src/chat/modules/SetupModule.js +4 -3
  204. package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
  205. package/ts_build/src/chat/modules/SystemModule.js +19 -4
  206. package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
  207. package/ts_build/src/chat/modules/index.d.ts +5 -0
  208. package/ts_build/src/chat/modules/index.js +14 -0
  209. package/ts_build/src/chat/modules/index.js.map +1 -0
  210. package/ts_build/src/chat/types.d.ts +2 -0
  211. package/ts_build/src/chat-old.js +3 -3
  212. package/ts_build/src/chat-old.js.map +1 -1
  213. package/ts_build/src/clients/anthropic.d.ts +1 -0
  214. package/ts_build/src/clients/anthropic.js +22 -1
  215. package/ts_build/src/clients/anthropic.js.map +1 -1
  216. package/ts_build/src/clients/openai.js +1 -1
  217. package/ts_build/src/clients/openai.js.map +1 -1
  218. package/ts_build/src/clients/types.d.ts +1 -1
  219. package/ts_build/src/clients/xai.d.ts +7 -0
  220. package/ts_build/src/clients/xai.js +13 -4
  221. package/ts_build/src/clients/xai.js.map +1 -1
  222. package/ts_build/src/config.js +14 -3
  223. package/ts_build/src/config.js.map +1 -1
  224. package/ts_build/src/dataset/diffs/generate.js +2 -2
  225. package/ts_build/src/dataset/diffs/generate.js.map +1 -1
  226. package/ts_build/src/dataset/diffs/jsonl.js.map +1 -1
  227. package/ts_build/src/embeddings.js +7 -9
  228. package/ts_build/src/embeddings.js.map +1 -1
  229. package/ts_build/src/index.js +10 -10
  230. package/ts_build/src/index.js.map +1 -1
  231. package/ts_build/src/plugins/GitPlugin.d.ts +39 -0
  232. package/ts_build/src/plugins/GitPlugin.js +439 -0
  233. package/ts_build/src/plugins/GitPlugin.js.map +1 -0
  234. package/ts_build/src/plugins/LinterPlugin.d.ts +15 -0
  235. package/ts_build/src/plugins/LinterPlugin.js +65 -0
  236. package/ts_build/src/plugins/LinterPlugin.js.map +1 -0
  237. package/ts_build/src/plugins/PluginBase.d.ts +4 -3
  238. package/ts_build/src/plugins/PluginBase.js +3 -3
  239. package/ts_build/src/plugins/PluginBase.js.map +1 -1
  240. package/ts_build/src/plugins/asana.d.ts +3 -1
  241. package/ts_build/src/plugins/asana.js +3 -2
  242. package/ts_build/src/plugins/asana.js.map +1 -1
  243. package/ts_build/src/plugins/downloader/plugin.d.ts +3 -1
  244. package/ts_build/src/plugins/downloader/plugin.js +3 -2
  245. package/ts_build/src/plugins/downloader/plugin.js.map +1 -1
  246. package/ts_build/src/plugins/embedding.d.ts +5 -1
  247. package/ts_build/src/plugins/embedding.js +15 -3
  248. package/ts_build/src/plugins/embedding.js.map +1 -1
  249. package/ts_build/src/plugins/figma.d.ts +3 -1
  250. package/ts_build/src/plugins/figma.js +28 -4
  251. package/ts_build/src/plugins/figma.js.map +1 -1
  252. package/ts_build/src/plugins/github.d.ts +3 -1
  253. package/ts_build/src/plugins/github.js +3 -2
  254. package/ts_build/src/plugins/github.js.map +1 -1
  255. package/ts_build/src/plugins/jira.d.ts +3 -1
  256. package/ts_build/src/plugins/jira.js +3 -2
  257. package/ts_build/src/plugins/jira.js.map +1 -1
  258. package/ts_build/src/plugins/language.d.ts +7 -4
  259. package/ts_build/src/plugins/language.js +85 -20
  260. package/ts_build/src/plugins/language.js.map +1 -1
  261. package/ts_build/src/plugins/linear.d.ts +3 -1
  262. package/ts_build/src/plugins/linear.js +3 -2
  263. package/ts_build/src/plugins/linear.js.map +1 -1
  264. package/ts_build/src/plugins/notion.d.ts +3 -1
  265. package/ts_build/src/plugins/notion.js +3 -2
  266. package/ts_build/src/plugins/notion.js.map +1 -1
  267. package/ts_build/src/plugins/plugins.d.ts +4 -3
  268. package/ts_build/src/plugins/plugins.js +24 -14
  269. package/ts_build/src/plugins/plugins.js.map +1 -1
  270. package/ts_build/src/plugins/tree-sitter/editor.d.ts +34 -0
  271. package/ts_build/src/plugins/tree-sitter/editor.js +218 -0
  272. package/ts_build/src/plugins/tree-sitter/editor.js.map +1 -0
  273. package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.d.ts +29 -0
  274. package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.js +538 -0
  275. package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.js.map +1 -0
  276. package/ts_build/src/plugins/tree-sitter/human-readable-paths.d.ts +22 -0
  277. package/ts_build/src/plugins/tree-sitter/human-readable-paths.js +332 -0
  278. package/ts_build/src/plugins/tree-sitter/human-readable-paths.js.map +1 -0
  279. package/ts_build/src/plugins/tree-sitter/lang-packs/index.d.ts +8 -0
  280. package/ts_build/src/plugins/tree-sitter/lang-packs/index.js +26 -0
  281. package/ts_build/src/plugins/tree-sitter/lang-packs/index.js.map +1 -0
  282. package/ts_build/src/plugins/tree-sitter/lang-packs/java.d.ts +2 -0
  283. package/ts_build/src/plugins/tree-sitter/lang-packs/java.js +61 -0
  284. package/ts_build/src/plugins/tree-sitter/lang-packs/java.js.map +1 -0
  285. package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.d.ts +2 -0
  286. package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.js +59 -0
  287. package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.js.map +1 -0
  288. package/ts_build/src/plugins/tree-sitter/lang-packs/python.d.ts +2 -0
  289. package/ts_build/src/plugins/tree-sitter/lang-packs/python.js +47 -0
  290. package/ts_build/src/plugins/tree-sitter/lang-packs/python.js.map +1 -0
  291. package/ts_build/src/plugins/tree-sitter/lang-packs/types.d.ts +43 -0
  292. package/ts_build/src/plugins/tree-sitter/lang-packs/types.js +3 -0
  293. package/ts_build/src/plugins/tree-sitter/lang-packs/types.js.map +1 -0
  294. package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.d.ts +2 -0
  295. package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.js +50 -0
  296. package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.js.map +1 -0
  297. package/ts_build/src/plugins/tree-sitter/parser.d.ts +75 -0
  298. package/ts_build/src/plugins/tree-sitter/parser.js +306 -0
  299. package/ts_build/src/plugins/tree-sitter/parser.js.map +1 -0
  300. package/ts_build/src/plugins/tree-sitter/simple-paths.d.ts +22 -0
  301. package/ts_build/src/plugins/tree-sitter/simple-paths.js +332 -0
  302. package/ts_build/src/plugins/tree-sitter/simple-paths.js.map +1 -0
  303. package/ts_build/src/plugins/types.d.ts +10 -0
  304. package/ts_build/src/plugins/url.d.ts +3 -2
  305. package/ts_build/src/plugins/url.js +3 -2
  306. package/ts_build/src/plugins/url.js.map +1 -1
  307. package/ts_build/src/plugins/vim.d.ts +4 -2
  308. package/ts_build/src/plugins/vim.js +6 -8
  309. package/ts_build/src/plugins/vim.js.map +1 -1
  310. package/ts_build/src/processors/CustomVariables.js +12 -3
  311. package/ts_build/src/processors/CustomVariables.js.map +1 -1
  312. package/ts_build/src/processors/TokenCompressor.js +8 -11
  313. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  314. package/ts_build/src/processors/ToolResponseCache.d.ts +2 -2
  315. package/ts_build/src/processors/ToolResponseCache.js +12 -2
  316. package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
  317. package/ts_build/src/services/EmbeddingService.d.ts +10 -1
  318. package/ts_build/src/services/EmbeddingService.js +12 -12
  319. package/ts_build/src/services/EmbeddingService.js.map +1 -1
  320. package/ts_build/src/services/EventService.d.ts +7 -0
  321. package/ts_build/src/services/EventService.js +49 -0
  322. package/ts_build/src/services/EventService.js.map +1 -1
  323. package/ts_build/src/services/Mcp.js +8 -0
  324. package/ts_build/src/services/Mcp.js.map +1 -1
  325. package/ts_build/src/services/S3.js +4 -3
  326. package/ts_build/src/services/S3.js.map +1 -1
  327. package/ts_build/src/services/Tools.d.ts +1 -0
  328. package/ts_build/src/services/Tools.js +97 -35
  329. package/ts_build/src/services/Tools.js.map +1 -1
  330. package/ts_build/src/services/index.d.ts +4 -5
  331. package/ts_build/src/services/index.js +14 -9
  332. package/ts_build/src/services/index.js.map +1 -1
  333. package/ts_build/src/services/types.js +3 -3
  334. package/ts_build/src/services/types.js.map +1 -1
  335. package/ts_build/src/types.d.ts +7 -1
  336. package/ts_build/src/types.js +4 -0
  337. package/ts_build/src/types.js.map +1 -1
  338. package/ts_build/src/worker.js +12 -1
  339. package/ts_build/src/worker.js.map +1 -1
  340. package/ts_build/tests/clients/AIClient.test.d.ts +1 -0
  341. package/ts_build/tests/clients/AIClient.test.js +377 -0
  342. package/ts_build/tests/clients/AIClient.test.js.map +1 -0
  343. package/ts_build/tests/languagePlugin.test.js +217 -11
  344. package/ts_build/tests/languagePlugin.test.js.map +1 -1
  345. package/ts_build/tests/manual/agent-events/event-handler-reliability.test.d.ts +1 -0
  346. package/ts_build/tests/manual/agent-events/event-handler-reliability.test.js +315 -0
  347. package/ts_build/tests/manual/agent-events/event-handler-reliability.test.js.map +1 -0
  348. package/ts_build/tests/manual/agent-events/run-test.d.ts +2 -0
  349. package/ts_build/tests/manual/agent-events/run-test.js +148 -0
  350. package/ts_build/tests/manual/agent-events/run-test.js.map +1 -0
  351. package/ts_build/tests/manual/file-edits/figma.test.d.ts +1 -0
  352. package/ts_build/tests/manual/file-edits/figma.test.js +47 -0
  353. package/ts_build/tests/manual/file-edits/figma.test.js.map +1 -0
  354. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.d.ts +1 -0
  355. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js +100 -0
  356. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js.map +1 -0
  357. package/ts_build/tests/manual/file-edits/patching.test.d.ts +1 -0
  358. package/ts_build/tests/manual/file-edits/patching.test.js +119 -0
  359. package/ts_build/tests/manual/file-edits/patching.test.js.map +1 -0
  360. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.d.ts +1 -0
  361. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +277 -0
  362. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -0
  363. package/ts_build/tests/plugins/language/languagePlugin-integration.test.d.ts +1 -0
  364. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +331 -0
  365. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -0
  366. package/ts_build/tests/plugins/language/languagePlugin.test.d.ts +1 -0
  367. package/ts_build/tests/plugins/language/languagePlugin.test.js +286 -0
  368. package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -0
  369. package/ts_build/tests/processors/Base64ImageDetector.test.d.ts +1 -0
  370. package/ts_build/tests/processors/Base64ImageDetector.test.js +351 -0
  371. package/ts_build/tests/processors/Base64ImageDetector.test.js.map +1 -0
  372. package/ts_build/tests/processors/CustomVariables.test.d.ts +1 -0
  373. package/ts_build/tests/processors/CustomVariables.test.js +351 -0
  374. package/ts_build/tests/processors/CustomVariables.test.js.map +1 -0
  375. package/ts_build/tests/processors/HarmonyToolProcessor.test.d.ts +1 -0
  376. package/ts_build/tests/processors/HarmonyToolProcessor.test.js +382 -0
  377. package/ts_build/tests/processors/HarmonyToolProcessor.test.js.map +1 -0
  378. package/ts_build/tests/processors/TokenCompressor.test.d.ts +1 -0
  379. package/ts_build/tests/processors/TokenCompressor.test.js +300 -0
  380. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -0
  381. package/ts_build/tests/processors/ToolResponseCache.test.d.ts +1 -0
  382. package/ts_build/tests/processors/ToolResponseCache.test.js +539 -0
  383. package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -0
  384. package/ts_build/tests/services/Plugins/plugin-event-integration.test.d.ts +1 -0
  385. package/ts_build/tests/services/Plugins/plugin-event-integration.test.js +232 -0
  386. package/ts_build/tests/services/Plugins/plugin-event-integration.test.js.map +1 -0
  387. package/ts_build/tests/services/Tools.test.d.ts +1 -0
  388. package/ts_build/tests/services/Tools.test.js +1059 -0
  389. package/ts_build/tests/services/Tools.test.js.map +1 -0
  390. package/ts_build/tests/test.spec.js +110 -68
  391. package/ts_build/tests/test.spec.js.map +1 -1
  392. package/ts_build/tests/tree-sitter/editor.test.d.ts +1 -0
  393. package/ts_build/tests/tree-sitter/editor.test.js +85 -0
  394. package/ts_build/tests/tree-sitter/editor.test.js.map +1 -0
  395. package/ts_build/tests/tree-sitter/invalid.test.d.ts +1 -0
  396. package/ts_build/tests/tree-sitter/invalid.test.js +198 -0
  397. package/ts_build/tests/tree-sitter/invalid.test.js.map +1 -0
  398. package/ts_build/tests/tree-sitter/paths/common-edits.test.d.ts +1 -0
  399. package/ts_build/tests/tree-sitter/paths/common-edits.test.js +347 -0
  400. package/ts_build/tests/tree-sitter/paths/common-edits.test.js.map +1 -0
  401. package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.d.ts +1 -0
  402. package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.js +35 -0
  403. package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.js.map +1 -0
  404. package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.d.ts +1 -0
  405. package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.js +38 -0
  406. package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.js.map +1 -0
  407. package/ts_build/tests/tree-sitter/paths/debug-paths.test.d.ts +1 -0
  408. package/ts_build/tests/tree-sitter/paths/debug-paths.test.js +74 -0
  409. package/ts_build/tests/tree-sitter/paths/debug-paths.test.js.map +1 -0
  410. package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.d.ts +1 -0
  411. package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.js +302 -0
  412. package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.js.map +1 -0
  413. package/ts_build/tests/tree-sitter/paths/paths.test.d.ts +1 -0
  414. package/ts_build/tests/tree-sitter/paths/paths.test.js +116 -0
  415. package/ts_build/tests/tree-sitter/paths/paths.test.js.map +1 -0
  416. package/ts_build/tests/tree-sitter/paths/simple-paths.test.d.ts +1 -0
  417. package/ts_build/tests/tree-sitter/paths/simple-paths.test.js +302 -0
  418. package/ts_build/tests/tree-sitter/paths/simple-paths.test.js.map +1 -0
  419. package/ts_build/tests/tree-sitter/sample-after.d.ts +11 -0
  420. package/ts_build/tests/tree-sitter/sample-after.js +44 -0
  421. package/ts_build/tests/tree-sitter/sample-after.js.map +1 -0
  422. package/ts_build/tests/tree-sitter/sample-before.d.ts +9 -0
  423. package/ts_build/tests/tree-sitter/sample-before.js +28 -0
  424. package/ts_build/tests/tree-sitter/sample-before.js.map +1 -0
  425. package/ts_build/tests/tree-sitter/test-files/completely-broken.d.ts +2 -0
  426. package/ts_build/tests/tree-sitter/test-files/completely-broken.js +17 -0
  427. package/ts_build/tests/tree-sitter/test-files/completely-broken.js.map +1 -0
  428. package/ts_build/tests/tree-sitter/test-files/duplicate-braces.d.ts +8 -0
  429. package/ts_build/tests/tree-sitter/test-files/duplicate-braces.js +38 -0
  430. package/ts_build/tests/tree-sitter/test-files/duplicate-braces.js.map +1 -0
  431. package/ts_build/tests/tree-sitter/test-files/invalid-nesting.d.ts +8 -0
  432. package/ts_build/tests/tree-sitter/test-files/invalid-nesting.js +38 -0
  433. package/ts_build/tests/tree-sitter/test-files/invalid-nesting.js.map +1 -0
  434. package/ts_build/tests/tree-sitter/test-files/malformed-signature.d.ts +8 -0
  435. package/ts_build/tests/tree-sitter/test-files/malformed-signature.js +38 -0
  436. package/ts_build/tests/tree-sitter/test-files/malformed-signature.js.map +1 -0
  437. package/ts_build/tests/tree-sitter/test-files/mismatched-parens.d.ts +10 -0
  438. package/ts_build/tests/tree-sitter/test-files/mismatched-parens.js +38 -0
  439. package/ts_build/tests/tree-sitter/test-files/mismatched-parens.js.map +1 -0
  440. package/ts_build/tests/tree-sitter/test-files/missing-semicolon.d.ts +8 -0
  441. package/ts_build/tests/tree-sitter/test-files/missing-semicolon.js +38 -0
  442. package/ts_build/tests/tree-sitter/test-files/missing-semicolon.js.map +1 -0
  443. package/ts_build/tests/tree-sitter/test-files/partially-broken.d.ts +6 -0
  444. package/ts_build/tests/tree-sitter/test-files/partially-broken.js +20 -0
  445. package/ts_build/tests/tree-sitter/test-files/partially-broken.js.map +1 -0
  446. package/ts_build/tests/tree-sitter/test-files/specific-errors.d.ts +7 -0
  447. package/ts_build/tests/tree-sitter/test-files/specific-errors.js +14 -0
  448. package/ts_build/tests/tree-sitter/test-files/specific-errors.js.map +1 -0
  449. package/ts_build/tests/tree-sitter/test-files/unclosed-string.d.ts +8 -0
  450. package/ts_build/tests/tree-sitter/test-files/unclosed-string.js +38 -0
  451. package/ts_build/tests/tree-sitter/test-files/unclosed-string.js.map +1 -0
  452. package/ts_build/tests/tree-sitter/tree-sitter.test.d.ts +1 -0
  453. package/ts_build/tests/tree-sitter/tree-sitter.test.js +185 -0
  454. package/ts_build/tests/tree-sitter/tree-sitter.test.js.map +1 -0
  455. package/tsconfig.json +2 -1
  456. package/tests/languagePlugin.test.ts +0 -74
  457. /package/src/chat/modules/{index.js → index.ts} +0 -0
  458. /package/tests/{integration → manual/file-edits}/patching/input.txt +0 -0
  459. /package/tests/{integration → manual/file-edits}/patching/output.txt +0 -0
  460. /package/tests/{integration → manual/file-edits}/patching/patch.txt +0 -0
  461. /package/tests/{integration → manual/file-edits}/patching/unseen.txt +0 -0
@@ -0,0 +1,688 @@
1
+ import { Message } from "../../src/clients/types";
2
+ import { ToolResponseCache, jqToolResponseDefinition } from "../../src/processors/ToolResponseCache";
3
+ import { ToolsService } from "../../src/services";
4
+
5
+ // Mock node-jq
6
+ jest.mock("node-jq", () => ({
7
+ run: jest.fn().mockImplementation(async (query: string, data: any, options: any) => {
8
+ // Simulate common JQ queries based on the test data
9
+
10
+ // Handle .test query on {"test": "value"}
11
+ if (query === ".test") {
12
+ if (data && data.test !== undefined) {
13
+ return JSON.stringify(data.test);
14
+ }
15
+ }
16
+
17
+ // Handle .id query for extracting id values
18
+ if (query === ".id") {
19
+ return data && data.id !== undefined ? data.id.toString() : "null";
20
+ }
21
+
22
+ // Handle .data | length query for counting array elements
23
+ if (query === ".data | length") {
24
+ if (data && Array.isArray(data.data)) {
25
+ return data.data.length.toString();
26
+ }
27
+ }
28
+
29
+ // Handle .data | add query for summing array elements
30
+ if (query === ".data | add") {
31
+ if (data && Array.isArray(data.data)) {
32
+ const sum = data.data.reduce((a, b) => a + b, 0);
33
+ return sum.toString();
34
+ }
35
+ }
36
+
37
+ // Handle .unicode query for special characters test
38
+ if (query === ".unicode") {
39
+ if (data && data.unicode !== undefined) {
40
+ return JSON.stringify(data.unicode);
41
+ }
42
+ }
43
+
44
+ // Handle .empty query for empty string test
45
+ if (query === ".empty") {
46
+ if (data && data.empty !== undefined) {
47
+ return JSON.stringify(data.empty);
48
+ }
49
+ }
50
+
51
+ // Handle .nullValue query for null value test
52
+ if (query === ".nullValue") {
53
+ if (data && data.nullValue !== undefined) {
54
+ return JSON.stringify(data.nullValue);
55
+ }
56
+ }
57
+
58
+ // Handle .name query on {name: "test", data: [1, 2, 3]}
59
+ if (query === ".name") {
60
+ if (data && data.name) {
61
+ return JSON.stringify(data.name);
62
+ }
63
+ }
64
+
65
+ // Handle .data[] query on {name: "test", data: [1, 2, 3]}
66
+ if (query === ".data[]") {
67
+ if (data && Array.isArray(data.data)) {
68
+ return data.data.join("\n");
69
+ }
70
+ }
71
+
72
+ // Handle map(.value) on [{id: 1, value: "a"}, {id: 2, value: "b"}]
73
+ if (query === "map(.value)") {
74
+ if (Array.isArray(data)) {
75
+ const values = data.map(item => item.value);
76
+ return JSON.stringify(values);
77
+ }
78
+ }
79
+
80
+ // Handle map({identifier: .id, content: .value}) transformation
81
+ if (query === "map({identifier: .id, content: .value})") {
82
+ if (Array.isArray(data)) {
83
+ const transformed = data.map(item => ({
84
+ identifier: item.id,
85
+ content: item.value
86
+ }));
87
+ return JSON.stringify(transformed);
88
+ }
89
+ }
90
+
91
+ // Handle "." query (return entire object, formatted)
92
+ if (query === ".") {
93
+ return JSON.stringify(data, null, 2);
94
+ }
95
+
96
+ // Handle .nested.inner query for nested JSON
97
+ if (query === ".nested.inner") {
98
+ if (data && data.nested && data.nested.inner) {
99
+ return JSON.stringify(data.nested.inner);
100
+ }
101
+ }
102
+
103
+ // Handle map(select(.id > 10)) - empty result
104
+ if (query === "map(select(.id > 10))") {
105
+ return JSON.stringify([]);
106
+ }
107
+
108
+ // Handle invalid queries - throw error
109
+ if (query === ".invalid[") {
110
+ throw new Error("Invalid JQ query syntax");
111
+ }
112
+
113
+ // Handle deep nested queries
114
+ if (query === ".level1.level2.level3.level4.level5.deepValue") {
115
+ if (data && data.level1 && data.level1.level2 && data.level1.level2.level3 &&
116
+ data.level1.level2.level3.level4 && data.level1.level2.level3.level4.level5) {
117
+ return JSON.stringify(data.level1.level2.level3.level4.level5.deepValue);
118
+ }
119
+ }
120
+
121
+ // Handle queries on invalid JSON data
122
+ if (typeof data === "string" && data === "invalid json string") {
123
+ throw new Error("Invalid JSON input");
124
+ }
125
+
126
+ // Default fallback - return stringified data
127
+ try {
128
+ return JSON.stringify(data);
129
+ } catch (error) {
130
+ throw new Error(`JQ query failed: ${error}`);
131
+ }
132
+ })
133
+ }));
134
+
135
+ const mockJq = require("node-jq");
136
+
137
+ describe("ToolResponseCache", () => {
138
+ let cache: ToolResponseCache;
139
+ let mockToolsService: jest.Mocked<ToolsService>;
140
+
141
+ beforeEach(() => {
142
+ jest.clearAllMocks();
143
+
144
+ mockToolsService = {
145
+ addTool: jest.fn(),
146
+ addFunctions: jest.fn(),
147
+ getTool: jest.fn().mockReturnValue(undefined),
148
+ callTool: jest.fn(),
149
+ } as any;
150
+
151
+ cache = new ToolResponseCache(mockToolsService);
152
+ });
153
+
154
+ describe("constructor", () => {
155
+ it("should create an instance and register tool with ToolsService", () => {
156
+ expect(cache).toBeDefined();
157
+ expect(cache).toBeInstanceOf(ToolResponseCache);
158
+ expect(mockToolsService.addTool).toHaveBeenCalledWith(jqToolResponseDefinition);
159
+ expect(mockToolsService.addFunctions).toHaveBeenCalledWith({
160
+ jqToolResponse: expect.any(Function),
161
+ });
162
+ });
163
+
164
+ it("should not register tool if it already exists", () => {
165
+ mockToolsService.getTool.mockReturnValue(jqToolResponseDefinition);
166
+ const newCache = new ToolResponseCache(mockToolsService);
167
+
168
+ // Should only be called once from the first instance
169
+ expect(mockToolsService.addTool).toHaveBeenCalledTimes(1);
170
+ });
171
+ });
172
+
173
+ describe("createProcessor", () => {
174
+ it("should create a message processor function", () => {
175
+ const processor = cache.createProcessor();
176
+ expect(typeof processor).toBe("function");
177
+ });
178
+
179
+ it("should process tool response messages", async () => {
180
+ const processor = cache.createProcessor();
181
+
182
+ const messages: Message[] = [
183
+ {
184
+ role: "tool",
185
+ tool_call_id: "call_123",
186
+ content: '{"data": [{"name": "test", "value": 42}]}'
187
+ }
188
+ ];
189
+
190
+ await processor(messages, messages);
191
+
192
+ // Verify message was stored
193
+ expect(cache.getStorageKeys()).toContain("call_123");
194
+ expect(cache.retrieveRawResponse("call_123")).toBe('{"data": [{"name": "test", "value": 42}]}');
195
+ });
196
+
197
+ it("should ignore non-tool messages", async () => {
198
+ const processor = cache.createProcessor();
199
+
200
+ const messages: Message[] = [
201
+ {
202
+ role: "user",
203
+ content: "This is a user message"
204
+ },
205
+ {
206
+ role: "assistant",
207
+ content: "This is an assistant message"
208
+ }
209
+ ];
210
+
211
+ await processor(messages, messages);
212
+
213
+ expect(cache.getStorageSize()).toBe(0);
214
+ });
215
+ it("should ignore tool messages without tool_call_id", async () => {
216
+ const processor = cache.createProcessor();
217
+
218
+ const messages: Message[] = [
219
+ {
220
+ role: "tool",
221
+ content: "Tool response without call ID"
222
+ } as Message
223
+ ];
224
+
225
+ await processor(messages, messages);
226
+
227
+ expect(cache.getStorageSize()).toBe(0);
228
+ });
229
+
230
+ it("should ignore tool messages with non-string content", async () => {
231
+ const processor = cache.createProcessor();
232
+
233
+ const messages: Message[] = [
234
+ {
235
+ role: "tool",
236
+ tool_call_id: "call_123",
237
+ content: null
238
+ } as Message,
239
+ {
240
+ role: "tool",
241
+ tool_call_id: "call_456",
242
+ content: undefined
243
+ } as Message,
244
+ {
245
+ role: "tool",
246
+ tool_call_id: "call_789",
247
+ content: 42 as any
248
+ } as Message
249
+ ];
250
+
251
+ await processor(messages, messages);
252
+
253
+ expect(cache.getStorageSize()).toBe(0);
254
+ });
255
+
256
+ it("should apply filter function when provided", async () => {
257
+ const filterFn = (msg: Message) => msg.tool_call_id === "call_allowed";
258
+ const processor = cache.createProcessor(filterFn);
259
+
260
+ const messages: Message[] = [
261
+ {
262
+ role: "tool",
263
+ tool_call_id: "call_allowed",
264
+ content: "Allowed content"
265
+ },
266
+ {
267
+ role: "tool",
268
+ tool_call_id: "call_blocked",
269
+ content: "Blocked content"
270
+ }
271
+ ];
272
+
273
+ await processor(messages, messages);
274
+
275
+ expect(cache.getStorageKeys()).toContain("call_allowed");
276
+ expect(cache.getStorageKeys()).not.toContain("call_blocked");
277
+ expect(cache.getStorageSize()).toBe(1);
278
+ });
279
+ });
280
+
281
+ describe("storeToolResponse", () => {
282
+ it("should store tool response content with metadata", () => {
283
+ const content = '{"test": "data"}';
284
+ const toolCallId = "call_123";
285
+
286
+ // Access private method for testing
287
+ (cache as any).storeToolResponse(content, toolCallId);
288
+
289
+ expect(cache.retrieveRawResponse(toolCallId)).toBe(content);
290
+ expect(cache.getStorageKeys()).toContain(toolCallId);
291
+
292
+ // Check metadata
293
+ const metadata = (cache as any).metadataStorage[toolCallId];
294
+ expect(metadata.toolCallId).toBe(toolCallId);
295
+ expect(metadata.originalLength).toBe(content.length);
296
+ expect(metadata.storedAt).toBeGreaterThan(0);
297
+ });
298
+ });
299
+ describe("queryToolResponse", () => {
300
+ beforeEach(() => {
301
+ // Store some test data
302
+ cache.storeToolResponse('{"name": "test", "data": [1, 2, 3]}', "call_123");
303
+ cache.storeToolResponse('[{"id": 1, "value": "a"}, {"id": 2, "value": "b"}]', "call_456");
304
+ cache.storeToolResponse('{"nested": "{\\"inner\\": \\"value\\"}"}', "call_789");
305
+ cache.storeToolResponse('invalid json string', "call_invalid");
306
+ });
307
+
308
+ it("should execute simple JQ queries successfully", async () => {
309
+ const result = await cache.queryToolResponse("call_123", ".name");
310
+ expect(result).toBe('"test"');
311
+ });
312
+
313
+ it("should execute array queries", async () => {
314
+ const result = await cache.queryToolResponse("call_123", ".data[]");
315
+ expect(result).toBe("1\n2\n3");
316
+ });
317
+
318
+ it("should execute complex JQ queries", async () => {
319
+ const result = await cache.queryToolResponse("call_456", 'map(.value)');
320
+ expect(result).toBe('["a","b"]');
321
+ });
322
+
323
+ it("should handle object transformation queries", async () => {
324
+ const result = await cache.queryToolResponse("call_456", 'map({identifier: .id, content: .value})');
325
+ const parsed = JSON.parse(result);
326
+ expect(parsed).toEqual([
327
+ {identifier: 1, content: "a"},
328
+ {identifier: 2, content: "b"}
329
+ ]);
330
+ });
331
+
332
+ it("should return error for missing tool call ID", async () => {
333
+ const result = await cache.queryToolResponse("missing_id", ".test");
334
+ expect(result).toContain("Error: No tool response found");
335
+ expect(result).toContain("missing_id");
336
+ expect(result).toContain("Available IDs:");
337
+ });
338
+
339
+ it("should handle invalid JQ queries with error message", async () => {
340
+ const result = await cache.queryToolResponse("call_123", ".invalid[");
341
+ expect(result).toContain("JQ Query Error:");
342
+ });
343
+
344
+ it("should handle non-JSON data with helpful error", async () => {
345
+ const result = await cache.queryToolResponse("call_invalid", ".test");
346
+ expect(result).toContain("Error: Tool response data is not valid JSON");
347
+ expect(result).toContain("toolCallId \"call_invalid\"");
348
+ });
349
+
350
+ it("should return formatted JSON for complex results", async () => {
351
+ const result = await cache.queryToolResponse("call_456", ".");
352
+ expect(result).toContain("[\n");
353
+ expect(result).toContain(" {");
354
+ expect(result).toContain(" \"id\":");
355
+ });
356
+
357
+ it("should handle nested JSON strings parsing", async () => {
358
+ const result = await cache.queryToolResponse("call_789", ".nested.inner");
359
+ expect(result).toBe('"value"');
360
+ });
361
+
362
+ it("should handle empty query results", async () => {
363
+ const result = await cache.queryToolResponse("call_456", 'map(select(.id > 10))');
364
+ expect(result).toBe("[]");
365
+ });
366
+ });
367
+
368
+ describe("parseNestedJsonStrings", () => {
369
+ it("should parse simple JSON strings", () => {
370
+ const input = '{"test": "value"}';
371
+ const result = cache.parseNestedJsonStrings(input);
372
+ expect(result).toEqual({test: "value"});
373
+ });
374
+
375
+ it("should parse nested JSON strings recursively", () => {
376
+ const input = '{"outer": "{\\"inner\\": \\"value\\"}"}';
377
+ const result = cache.parseNestedJsonStrings(input);
378
+ expect(result).toEqual({
379
+ outer: {inner: "value"}
380
+ });
381
+ });
382
+
383
+ it("should handle arrays with JSON strings", () => {
384
+ const input = ['{"test": "value1"}', '{"test": "value2"}'];
385
+ const result = cache.parseNestedJsonStrings(input);
386
+ expect(result).toEqual([
387
+ {test: "value1"},
388
+ {test: "value2"}
389
+ ]);
390
+ });
391
+
392
+ it("should handle mixed nested structures", () => {
393
+ const input = {
394
+ stringField: '{"nested": "value"}',
395
+ arrayField: ['{"item": 1}', '{"item": 2}'],
396
+ objectField: {
397
+ deepString: '{"deep": "nested"}'
398
+ }
399
+ };
400
+ const result = cache.parseNestedJsonStrings(input);
401
+ expect(result).toEqual({
402
+ stringField: {nested: "value"},
403
+ arrayField: [{item: 1}, {item: 2}],
404
+ objectField: {
405
+ deepString: {deep: "nested"}
406
+ }
407
+ });
408
+ });
409
+
410
+ it("should leave non-JSON strings unchanged", () => {
411
+ const input = {
412
+ jsonString: '{"test": "value"}',
413
+ regularString: "just a string",
414
+ number: 42,
415
+ boolean: true
416
+ };
417
+ const result = cache.parseNestedJsonStrings(input);
418
+ expect(result).toEqual({
419
+ jsonString: {test: "value"},
420
+ regularString: "just a string",
421
+ number: 42,
422
+ boolean: true
423
+ });
424
+ });
425
+
426
+ it("should handle malformed JSON strings gracefully", () => {
427
+ const input = '{"invalid": json}';
428
+ const result = cache.parseNestedJsonStrings(input);
429
+ expect(result).toBe(input); // Should return original string
430
+ });
431
+ });
432
+ describe("retrieveRawResponse", () => {
433
+ it("should return stored raw content", () => {
434
+ const content = '{"test": "data"}';
435
+ cache.storeToolResponse(content, "call_123");
436
+
437
+ const result = cache.retrieveRawResponse("call_123");
438
+ expect(result).toBe(content);
439
+ });
440
+
441
+ it("should return null for missing tool call ID", () => {
442
+ const result = cache.retrieveRawResponse("missing_id");
443
+ expect(result).toBeNull();
444
+ });
445
+ });
446
+
447
+ describe("clearStorage", () => {
448
+ it("should clear all stored data and metadata", () => {
449
+ cache.storeToolResponse('{"test": "data"}', "call_123");
450
+ cache.storeToolResponse('{"more": "data"}', "call_456");
451
+
452
+ expect(cache.getStorageSize()).toBe(2);
453
+
454
+ cache.clearStorage();
455
+
456
+ expect(cache.getStorageSize()).toBe(0);
457
+ expect(cache.getStorageKeys()).toEqual([]);
458
+ expect(cache.retrieveRawResponse("call_123")).toBeNull();
459
+ expect(cache.retrieveRawResponse("call_456")).toBeNull();
460
+ });
461
+ });
462
+
463
+ describe("getStorageKeys", () => {
464
+ it("should return empty array when no data stored", () => {
465
+ expect(cache.getStorageKeys()).toEqual([]);
466
+ });
467
+
468
+ it("should return all stored tool call IDs", () => {
469
+ cache.storeToolResponse('{"test": "data1"}', "call_123");
470
+ cache.storeToolResponse('{"test": "data2"}', "call_456");
471
+ cache.storeToolResponse('{"test": "data3"}', "call_789");
472
+
473
+ const keys = cache.getStorageKeys();
474
+ expect(keys).toContain("call_123");
475
+ expect(keys).toContain("call_456");
476
+ expect(keys).toContain("call_789");
477
+ expect(keys).toHaveLength(3);
478
+ });
479
+ });
480
+
481
+ describe("getStorageSize", () => {
482
+ it("should return 0 for empty storage", () => {
483
+ expect(cache.getStorageSize()).toBe(0);
484
+ });
485
+
486
+ it("should return correct count after storing responses", () => {
487
+ expect(cache.getStorageSize()).toBe(0);
488
+
489
+ cache.storeToolResponse('{"test": "data1"}', "call_123");
490
+ expect(cache.getStorageSize()).toBe(1);
491
+
492
+ cache.storeToolResponse('{"test": "data2"}', "call_456");
493
+ expect(cache.getStorageSize()).toBe(2);
494
+
495
+ cache.clearStorage();
496
+ expect(cache.getStorageSize()).toBe(0);
497
+ });
498
+ });
499
+
500
+ describe("registerTool", () => {
501
+ let mockToolsService: jest.Mocked<ToolsService>;
502
+
503
+ beforeEach(() => {
504
+ mockToolsService = {
505
+ getTool: jest.fn(),
506
+ addTool: jest.fn(),
507
+ addFunctions: jest.fn()
508
+ } as any;
509
+ });
510
+
511
+ it("should register tool when not already present", () => {
512
+ mockToolsService.getTool.mockReturnValue(null);
513
+
514
+ cache.registerTool(mockToolsService);
515
+
516
+ expect(mockToolsService.getTool).toHaveBeenCalledWith("jqToolResponse");
517
+ expect(mockToolsService.addTool).toHaveBeenCalledWith(expect.objectContaining({
518
+ type: "function",
519
+ function: expect.objectContaining({
520
+ name: "jqToolResponse"
521
+ })
522
+ }));
523
+ expect(mockToolsService.addFunctions).toHaveBeenCalledWith({
524
+ jqToolResponse: expect.any(Function)
525
+ });
526
+ });
527
+
528
+ it("should not register tool when already present", () => {
529
+ mockToolsService.getTool.mockReturnValue({} as any);
530
+
531
+ cache.registerTool(mockToolsService);
532
+
533
+ expect(mockToolsService.getTool).toHaveBeenCalledWith("jqToolResponse");
534
+ expect(mockToolsService.addTool).not.toHaveBeenCalled();
535
+ expect(mockToolsService.addFunctions).not.toHaveBeenCalled();
536
+ });
537
+
538
+ it("should register function that calls queryToolResponse", async () => {
539
+ mockToolsService.getTool.mockReturnValue(null);
540
+
541
+ cache.registerTool(mockToolsService);
542
+
543
+ const addFunctionsCall = mockToolsService.addFunctions.mock.calls[0][0];
544
+ const jqFunction = addFunctionsCall.jqToolResponse;
545
+
546
+ // Store test data
547
+ cache.storeToolResponse('{"test": "value"}', "call_123");
548
+
549
+ // Test the registered function
550
+ const result = await jqFunction("call_123", ".test");
551
+ expect(result).toBe('"value"');
552
+ });
553
+ });
554
+
555
+ describe("Edge Cases and Error Handling", () => {
556
+ it("should handle very large JSON objects", async () => {
557
+ const largeObject = {
558
+ data: Array(1000).fill(0).map((_, i) => ({
559
+ id: i,
560
+ name: `item_${i}`,
561
+ description: `This is item number ${i} with some additional text to make it larger`
562
+ }))
563
+ };
564
+ const largeContent = JSON.stringify(largeObject);
565
+
566
+ cache.storeToolResponse(largeContent, "call_large");
567
+
568
+ const result = await cache.queryToolResponse("call_large", ".data | length");
569
+ expect(result).toBe("1000");
570
+ });
571
+
572
+ it("should handle special characters in JSON", async () => {
573
+ const specialContent = JSON.stringify({
574
+ unicode: "Hello 世界 🌍",
575
+ escaped: "Line 1\nLine 2\tTabbed",
576
+ quotes: 'He said "Hello" to me'
577
+ });
578
+
579
+ cache.storeToolResponse(specialContent, "call_special");
580
+
581
+ const result = await cache.queryToolResponse("call_special", ".unicode");
582
+ expect(result).toBe('"Hello 世界 🌍"');
583
+ });
584
+
585
+ it("should handle empty strings and null values", async () => {
586
+ const content = JSON.stringify({
587
+ empty: "",
588
+ nullValue: null,
589
+ zero: 0,
590
+ false: false
591
+ });
592
+
593
+ cache.storeToolResponse(content, "call_empty");
594
+
595
+ const emptyResult = await cache.queryToolResponse("call_empty", ".empty");
596
+ expect(emptyResult).toBe('""');
597
+
598
+ const nullResult = await cache.queryToolResponse("call_empty", ".nullValue");
599
+ expect(nullResult).toBe("null");
600
+ });
601
+
602
+ it("should handle concurrent storage operations", async () => {
603
+ const promises = Array(10).fill(0).map((_, i) =>
604
+ Promise.resolve(cache.storeToolResponse(`{"id": ${i}}`, `call_${i}`))
605
+ );
606
+
607
+ await Promise.all(promises);
608
+
609
+ expect(cache.getStorageSize()).toBe(10);
610
+
611
+ const results = await Promise.all(
612
+ Array(10).fill(0).map((_, i) =>
613
+ cache.queryToolResponse(`call_${i}`, ".id")
614
+ )
615
+ );
616
+
617
+ results.forEach((result, i) => {
618
+ expect(result).toBe(i.toString());
619
+ });
620
+ });
621
+
622
+ it("should handle deeply nested JSON structures", async () => {
623
+ const deepObject = {
624
+ level1: {
625
+ level2: {
626
+ level3: {
627
+ level4: {
628
+ level5: {
629
+ deepValue: "found it!"
630
+ }
631
+ }
632
+ }
633
+ }
634
+ }
635
+ };
636
+
637
+ cache.storeToolResponse(JSON.stringify(deepObject), "call_deep");
638
+
639
+ const result = await cache.queryToolResponse("call_deep", ".level1.level2.level3.level4.level5.deepValue");
640
+ expect(result).toBe('"found it!"');
641
+ });
642
+ });
643
+
644
+ describe("Integration with Message Processing", () => {
645
+ it("should integrate with complete message processing workflow", async () => {
646
+ const processor = cache.createProcessor();
647
+
648
+ const messages: Message[] = [
649
+ {
650
+ role: "user",
651
+ content: "Test request"
652
+ },
653
+ {
654
+ role: "assistant",
655
+ content: "Processing...",
656
+ tool_calls: [
657
+ {
658
+ id: "call_123",
659
+ type: "function",
660
+ function: {
661
+ name: "testTool",
662
+ arguments: "{}"
663
+ }
664
+ }
665
+ ]
666
+ },
667
+ {
668
+ role: "tool",
669
+ tool_call_id: "call_123",
670
+ content: JSON.stringify({
671
+ result: "success",
672
+ data: [1, 2, 3, 4, 5]
673
+ })
674
+ }
675
+ ];
676
+
677
+ await processor(messages, messages);
678
+
679
+ expect(cache.getStorageSize()).toBe(1);
680
+
681
+ const result = await cache.queryToolResponse("call_123", ".data | length");
682
+ expect(result).toBe("5");
683
+
684
+ const sumResult = await cache.queryToolResponse("call_123", ".data | add");
685
+ expect(result).toBe("5");
686
+ });
687
+ });
688
+ });