@tyvm/knowhow 0.0.47 → 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.
- package/benchmarks/results/27b0a06/2025-09-27/xai/xai-grok-code-fast-1.json +2909 -0
- package/benchmarks/results/4057aed/2025-08-14/anthropic/anthropic-claude-sonnet-4-20250514.json +1671 -0
- package/jest.config.js +2 -2
- package/package.json +8 -3
- package/src/agents/base/base.ts +30 -24
- package/src/agents/patcher/patcher.ts +26 -5
- package/src/agents/tools/agentCall.ts +4 -2
- package/src/agents/tools/aiClient.ts +3 -11
- package/src/agents/tools/ast/astAppendNode.ts +90 -0
- package/src/agents/tools/ast/astDeleteNode.ts +88 -0
- package/src/agents/tools/ast/astEditNode.ts +95 -0
- package/src/agents/tools/ast/astGetPathForLine.ts +73 -0
- package/src/agents/tools/ast/astListPaths.ts +66 -0
- package/src/agents/tools/ast/index.ts +7 -0
- package/src/agents/tools/callPlugin.ts +8 -2
- package/src/agents/tools/embeddingSearch.ts +2 -1
- package/src/agents/tools/execCommand.ts +239 -94
- package/src/agents/tools/fileSearch.ts +15 -17
- package/src/agents/tools/index.ts +1 -0
- package/src/agents/tools/language/definitions.ts +10 -2
- package/src/agents/tools/language/index.ts +3 -2
- package/src/agents/tools/lintFile.ts +4 -2
- package/src/agents/tools/list.ts +203 -62
- package/src/agents/tools/patch.ts +48 -14
- package/src/agents/tools/readBlocks.ts +34 -0
- package/src/agents/tools/readFile.ts +23 -0
- package/src/agents/tools/stringReplace.ts +33 -9
- package/src/agents/tools/writeFile.ts +55 -0
- package/src/agents/tools/ycmd/server.ts +14 -4
- package/src/chat/CliChatService.ts +6 -1
- package/src/chat/modules/AgentModule.ts +107 -64
- package/src/chat/modules/AskModule.ts +0 -1
- package/src/chat/modules/SetupModule.ts +4 -4
- package/src/chat/modules/SystemModule.ts +28 -5
- package/src/chat/types.ts +2 -0
- package/src/chat-old.ts +2 -2
- package/src/clients/anthropic.ts +22 -1
- package/src/clients/openai.ts +1 -1
- package/src/clients/xai.ts +15 -5
- package/src/config.ts +17 -5
- package/src/dataset/diffs/generate.ts +2 -2
- package/src/dataset/diffs/jsonl.ts +0 -1
- package/src/embeddings.ts +6 -4
- package/src/index.ts +11 -5
- package/src/plugins/GitPlugin.ts +530 -0
- package/src/plugins/LinterPlugin.ts +89 -0
- package/src/plugins/PluginBase.ts +4 -2
- package/src/plugins/asana.ts +4 -2
- package/src/plugins/downloader/plugin.ts +5 -2
- package/src/plugins/embedding.ts +24 -4
- package/src/plugins/figma.ts +7 -3
- package/src/plugins/github.ts +4 -2
- package/src/plugins/jira.ts +4 -2
- package/src/plugins/language.ts +134 -27
- package/src/plugins/linear.ts +4 -2
- package/src/plugins/notion.ts +4 -2
- package/src/plugins/plugins.ts +27 -16
- package/src/plugins/tree-sitter/editor.ts +369 -0
- package/src/plugins/tree-sitter/lang-packs/index.ts +23 -0
- package/src/plugins/tree-sitter/lang-packs/java.ts +59 -0
- package/src/plugins/tree-sitter/lang-packs/javascript.ts +57 -0
- package/src/plugins/tree-sitter/lang-packs/python.ts +45 -0
- package/src/plugins/tree-sitter/lang-packs/types.ts +79 -0
- package/src/plugins/tree-sitter/lang-packs/typescript.ts +49 -0
- package/src/plugins/tree-sitter/parser.ts +444 -0
- package/src/plugins/tree-sitter/simple-paths.ts +467 -0
- package/src/plugins/types.ts +11 -0
- package/src/plugins/url.ts +5 -3
- package/src/plugins/vim.ts +8 -5
- package/src/processors/CustomVariables.ts +19 -7
- package/src/processors/TokenCompressor.ts +13 -13
- package/src/processors/ToolResponseCache.ts +15 -6
- package/src/services/EmbeddingService.ts +18 -9
- package/src/services/EventService.ts +80 -0
- package/src/services/Mcp.ts +5 -0
- package/src/services/S3.ts +4 -3
- package/src/services/Tools.ts +125 -53
- package/src/services/index.ts +16 -11
- package/src/services/types.ts +3 -3
- package/src/types.ts +7 -2
- package/src/worker.ts +14 -1
- package/test-comprehensive.ts +31 -0
- package/tests/clients/AIClient.test.ts +490 -0
- package/tests/manual/agent-events/run-test.ts +203 -0
- package/tests/{integration → manual/file-edits}/figma.test.ts +1 -1
- package/tests/{integration → manual/file-edits}/fileblocks/readwrite.test.ts +7 -3
- package/tests/{integration → manual/file-edits}/patching.test.ts +11 -8
- package/tests/plugins/language/languagePlugin-content-triggers.test.ts +332 -0
- package/tests/plugins/language/languagePlugin-integration.test.ts +456 -0
- package/tests/plugins/language/languagePlugin.test.ts +363 -0
- package/tests/processors/Base64ImageDetector.test.ts +403 -0
- package/tests/processors/CustomVariables.test.ts +430 -0
- package/tests/processors/HarmonyToolProcessor.test.ts +490 -0
- package/tests/processors/TokenCompressor.test.ts +391 -0
- package/tests/processors/ToolResponseCache.test.ts +688 -0
- package/tests/services/Tools.test.ts +1339 -0
- package/tests/test.spec.ts +162 -117
- package/tests/tree-sitter/editor.test.ts +113 -0
- package/tests/tree-sitter/invalid.test.ts +299 -0
- package/tests/tree-sitter/paths/common-edits.test.ts +564 -0
- package/tests/tree-sitter/paths/debug-exact-position.test.ts +44 -0
- package/tests/tree-sitter/paths/debug-line-indexing.test.ts +49 -0
- package/tests/tree-sitter/paths/debug-paths.test.ts +90 -0
- package/tests/tree-sitter/paths/paths.test.ts +170 -0
- package/tests/tree-sitter/paths/simple-paths.test.ts +367 -0
- package/tests/tree-sitter/sample-after.ts +48 -0
- package/tests/tree-sitter/sample-before.ts +25 -0
- package/tests/tree-sitter/test-files/completely-broken.ts +7 -0
- package/tests/tree-sitter/test-files/duplicate-braces.ts +39 -0
- package/tests/tree-sitter/test-files/invalid-nesting.ts +39 -0
- package/tests/tree-sitter/test-files/malformed-signature.ts +39 -0
- package/tests/tree-sitter/test-files/mismatched-parens.ts +39 -0
- package/tests/tree-sitter/test-files/missing-semicolon.ts +39 -0
- package/tests/tree-sitter/test-files/partially-broken.ts +20 -0
- package/tests/tree-sitter/test-files/specific-errors.ts +14 -0
- package/tests/tree-sitter/test-files/unclosed-string.ts +39 -0
- package/tests/tree-sitter/tree-sitter.test.ts +251 -0
- package/ts_build/package.json +8 -3
- package/ts_build/src/agents/base/base.d.ts +2 -2
- package/ts_build/src/agents/base/base.js +24 -20
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/patcher/patcher.js +26 -5
- package/ts_build/src/agents/patcher/patcher.js.map +1 -1
- package/ts_build/src/agents/tools/agentCall.js +2 -1
- package/ts_build/src/agents/tools/agentCall.js.map +1 -1
- package/ts_build/src/agents/tools/aiClient.d.ts +7 -8
- package/ts_build/src/agents/tools/aiClient.js.map +1 -1
- package/ts_build/src/agents/tools/ast/astAppendNode.d.ts +1 -0
- package/ts_build/src/agents/tools/ast/astAppendNode.js +96 -0
- package/ts_build/src/agents/tools/ast/astAppendNode.js.map +1 -0
- package/ts_build/src/agents/tools/ast/astDeleteNode.d.ts +1 -0
- package/ts_build/src/agents/tools/ast/astDeleteNode.js +94 -0
- package/ts_build/src/agents/tools/ast/astDeleteNode.js.map +1 -0
- package/ts_build/src/agents/tools/ast/astEditNode.d.ts +1 -0
- package/ts_build/src/agents/tools/ast/astEditNode.js +96 -0
- package/ts_build/src/agents/tools/ast/astEditNode.js.map +1 -0
- package/ts_build/src/agents/tools/ast/astGetPathForLine.d.ts +1 -0
- package/ts_build/src/agents/tools/ast/astGetPathForLine.js +78 -0
- package/ts_build/src/agents/tools/ast/astGetPathForLine.js.map +1 -0
- package/ts_build/src/agents/tools/ast/astListPaths.d.ts +1 -0
- package/ts_build/src/agents/tools/ast/astListPaths.js +78 -0
- package/ts_build/src/agents/tools/ast/astListPaths.js.map +1 -0
- package/ts_build/src/agents/tools/ast/index.d.ts +5 -0
- package/ts_build/src/agents/tools/ast/index.js +14 -0
- package/ts_build/src/agents/tools/ast/index.js.map +1 -0
- package/ts_build/src/agents/tools/astAppendNode.d.ts +1 -0
- package/ts_build/src/agents/tools/astAppendNode.js +98 -0
- package/ts_build/src/agents/tools/astAppendNode.js.map +1 -0
- package/ts_build/src/agents/tools/astDeleteNode.d.ts +1 -0
- package/ts_build/src/agents/tools/astDeleteNode.js +95 -0
- package/ts_build/src/agents/tools/astDeleteNode.js.map +1 -0
- package/ts_build/src/agents/tools/astEditNode.d.ts +1 -0
- package/ts_build/src/agents/tools/astEditNode.js +98 -0
- package/ts_build/src/agents/tools/astEditNode.js.map +1 -0
- package/ts_build/src/agents/tools/astGetPathForLine.d.ts +1 -0
- package/ts_build/src/agents/tools/astGetPathForLine.js +89 -0
- package/ts_build/src/agents/tools/astGetPathForLine.js.map +1 -0
- package/ts_build/src/agents/tools/astListPaths.d.ts +1 -0
- package/ts_build/src/agents/tools/astListPaths.js +82 -0
- package/ts_build/src/agents/tools/astListPaths.js.map +1 -0
- package/ts_build/src/agents/tools/callPlugin.js +4 -2
- package/ts_build/src/agents/tools/callPlugin.js.map +1 -1
- package/ts_build/src/agents/tools/embeddingSearch.js +3 -2
- package/ts_build/src/agents/tools/embeddingSearch.js.map +1 -1
- package/ts_build/src/agents/tools/execCommand.d.ts +2 -2
- package/ts_build/src/agents/tools/execCommand.js +201 -67
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/fileSearch.d.ts +1 -1
- package/ts_build/src/agents/tools/fileSearch.js +11 -15
- package/ts_build/src/agents/tools/fileSearch.js.map +1 -1
- package/ts_build/src/agents/tools/github/index.d.ts +1 -1
- package/ts_build/src/agents/tools/index.d.ts +1 -0
- package/ts_build/src/agents/tools/index.js +1 -0
- package/ts_build/src/agents/tools/index.js.map +1 -1
- package/ts_build/src/agents/tools/language/definitions.js +11 -2
- package/ts_build/src/agents/tools/language/definitions.js.map +1 -1
- package/ts_build/src/agents/tools/language/index.js +4 -3
- package/ts_build/src/agents/tools/language/index.js.map +1 -1
- package/ts_build/src/agents/tools/lintFile.js +4 -2
- package/ts_build/src/agents/tools/lintFile.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +185 -49
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/patch.js +33 -10
- package/ts_build/src/agents/tools/patch.js.map +1 -1
- package/ts_build/src/agents/tools/readBlocks.js +23 -0
- package/ts_build/src/agents/tools/readBlocks.js.map +1 -1
- package/ts_build/src/agents/tools/readFile.js +14 -0
- package/ts_build/src/agents/tools/readFile.js.map +1 -1
- package/ts_build/src/agents/tools/stringReplace.js +19 -2
- package/ts_build/src/agents/tools/stringReplace.js.map +1 -1
- package/ts_build/src/agents/tools/writeFile.js +40 -0
- package/ts_build/src/agents/tools/writeFile.js.map +1 -1
- package/ts_build/src/agents/tools/ycmd/server.js +5 -0
- package/ts_build/src/agents/tools/ycmd/server.js.map +1 -1
- package/ts_build/src/chat/CliChatService.d.ts +1 -0
- package/ts_build/src/chat/CliChatService.js +6 -2
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +5 -1
- package/ts_build/src/chat/modules/AgentModule.js +53 -31
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/AskModule.js.map +1 -1
- package/ts_build/src/chat/modules/SetupModule.js +4 -3
- package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
- package/ts_build/src/chat/modules/SystemModule.js +19 -4
- package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
- package/ts_build/src/chat/modules/index.d.ts +5 -0
- package/ts_build/src/chat/modules/index.js +14 -0
- package/ts_build/src/chat/modules/index.js.map +1 -0
- package/ts_build/src/chat/types.d.ts +2 -0
- package/ts_build/src/chat-old.js +3 -3
- package/ts_build/src/chat-old.js.map +1 -1
- package/ts_build/src/clients/anthropic.d.ts +1 -0
- package/ts_build/src/clients/anthropic.js +22 -1
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/openai.js +1 -1
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/xai.d.ts +7 -0
- package/ts_build/src/clients/xai.js +13 -4
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/config.js +14 -3
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/dataset/diffs/generate.js +2 -2
- package/ts_build/src/dataset/diffs/generate.js.map +1 -1
- package/ts_build/src/dataset/diffs/jsonl.js.map +1 -1
- package/ts_build/src/embeddings.js +7 -9
- package/ts_build/src/embeddings.js.map +1 -1
- package/ts_build/src/index.js +10 -10
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/plugins/GitPlugin.d.ts +39 -0
- package/ts_build/src/plugins/GitPlugin.js +439 -0
- package/ts_build/src/plugins/GitPlugin.js.map +1 -0
- package/ts_build/src/plugins/LinterPlugin.d.ts +15 -0
- package/ts_build/src/plugins/LinterPlugin.js +65 -0
- package/ts_build/src/plugins/LinterPlugin.js.map +1 -0
- package/ts_build/src/plugins/PluginBase.d.ts +4 -3
- package/ts_build/src/plugins/PluginBase.js +3 -3
- package/ts_build/src/plugins/PluginBase.js.map +1 -1
- package/ts_build/src/plugins/asana.d.ts +3 -1
- package/ts_build/src/plugins/asana.js +3 -2
- package/ts_build/src/plugins/asana.js.map +1 -1
- package/ts_build/src/plugins/downloader/plugin.d.ts +3 -1
- package/ts_build/src/plugins/downloader/plugin.js +3 -2
- package/ts_build/src/plugins/downloader/plugin.js.map +1 -1
- package/ts_build/src/plugins/embedding.d.ts +5 -1
- package/ts_build/src/plugins/embedding.js +15 -3
- package/ts_build/src/plugins/embedding.js.map +1 -1
- package/ts_build/src/plugins/figma.d.ts +3 -1
- package/ts_build/src/plugins/figma.js +28 -4
- package/ts_build/src/plugins/figma.js.map +1 -1
- package/ts_build/src/plugins/github.d.ts +3 -1
- package/ts_build/src/plugins/github.js +3 -2
- package/ts_build/src/plugins/github.js.map +1 -1
- package/ts_build/src/plugins/jira.d.ts +3 -1
- package/ts_build/src/plugins/jira.js +3 -2
- package/ts_build/src/plugins/jira.js.map +1 -1
- package/ts_build/src/plugins/language.d.ts +7 -4
- package/ts_build/src/plugins/language.js +85 -20
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/plugins/linear.d.ts +3 -1
- package/ts_build/src/plugins/linear.js +3 -2
- package/ts_build/src/plugins/linear.js.map +1 -1
- package/ts_build/src/plugins/notion.d.ts +3 -1
- package/ts_build/src/plugins/notion.js +3 -2
- package/ts_build/src/plugins/notion.js.map +1 -1
- package/ts_build/src/plugins/plugins.d.ts +4 -3
- package/ts_build/src/plugins/plugins.js +24 -14
- package/ts_build/src/plugins/plugins.js.map +1 -1
- package/ts_build/src/plugins/tree-sitter/editor.d.ts +34 -0
- package/ts_build/src/plugins/tree-sitter/editor.js +218 -0
- package/ts_build/src/plugins/tree-sitter/editor.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.d.ts +29 -0
- package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.js +538 -0
- package/ts_build/src/plugins/tree-sitter/human-readable-paths-new.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/human-readable-paths.d.ts +22 -0
- package/ts_build/src/plugins/tree-sitter/human-readable-paths.js +332 -0
- package/ts_build/src/plugins/tree-sitter/human-readable-paths.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/index.d.ts +8 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/index.js +26 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/index.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/java.d.ts +2 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/java.js +61 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/java.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.d.ts +2 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.js +59 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/javascript.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/python.d.ts +2 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/python.js +47 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/python.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/types.d.ts +43 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/types.js +3 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/types.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.d.ts +2 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.js +50 -0
- package/ts_build/src/plugins/tree-sitter/lang-packs/typescript.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/parser.d.ts +75 -0
- package/ts_build/src/plugins/tree-sitter/parser.js +306 -0
- package/ts_build/src/plugins/tree-sitter/parser.js.map +1 -0
- package/ts_build/src/plugins/tree-sitter/simple-paths.d.ts +22 -0
- package/ts_build/src/plugins/tree-sitter/simple-paths.js +332 -0
- package/ts_build/src/plugins/tree-sitter/simple-paths.js.map +1 -0
- package/ts_build/src/plugins/types.d.ts +10 -0
- package/ts_build/src/plugins/url.d.ts +3 -2
- package/ts_build/src/plugins/url.js +3 -2
- package/ts_build/src/plugins/url.js.map +1 -1
- package/ts_build/src/plugins/vim.d.ts +4 -2
- package/ts_build/src/plugins/vim.js +6 -8
- package/ts_build/src/plugins/vim.js.map +1 -1
- package/ts_build/src/processors/CustomVariables.js +12 -3
- package/ts_build/src/processors/CustomVariables.js.map +1 -1
- package/ts_build/src/processors/TokenCompressor.js +8 -11
- package/ts_build/src/processors/TokenCompressor.js.map +1 -1
- package/ts_build/src/processors/ToolResponseCache.d.ts +2 -2
- package/ts_build/src/processors/ToolResponseCache.js +12 -2
- package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
- package/ts_build/src/services/EmbeddingService.d.ts +10 -1
- package/ts_build/src/services/EmbeddingService.js +12 -12
- package/ts_build/src/services/EmbeddingService.js.map +1 -1
- package/ts_build/src/services/EventService.d.ts +7 -0
- package/ts_build/src/services/EventService.js +49 -0
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/Mcp.js +8 -0
- package/ts_build/src/services/Mcp.js.map +1 -1
- package/ts_build/src/services/S3.js +4 -3
- package/ts_build/src/services/S3.js.map +1 -1
- package/ts_build/src/services/Tools.d.ts +1 -0
- package/ts_build/src/services/Tools.js +97 -35
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/index.d.ts +4 -5
- package/ts_build/src/services/index.js +14 -9
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/types.js +3 -3
- package/ts_build/src/services/types.js.map +1 -1
- package/ts_build/src/types.d.ts +7 -1
- package/ts_build/src/types.js +4 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/worker.js +12 -1
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/clients/AIClient.test.d.ts +1 -0
- package/ts_build/tests/clients/AIClient.test.js +377 -0
- package/ts_build/tests/clients/AIClient.test.js.map +1 -0
- package/ts_build/tests/languagePlugin.test.js +217 -11
- package/ts_build/tests/languagePlugin.test.js.map +1 -1
- package/ts_build/tests/manual/agent-events/event-handler-reliability.test.d.ts +1 -0
- package/ts_build/tests/manual/agent-events/event-handler-reliability.test.js +315 -0
- package/ts_build/tests/manual/agent-events/event-handler-reliability.test.js.map +1 -0
- package/ts_build/tests/manual/agent-events/run-test.d.ts +2 -0
- package/ts_build/tests/manual/agent-events/run-test.js +148 -0
- package/ts_build/tests/manual/agent-events/run-test.js.map +1 -0
- package/ts_build/tests/manual/file-edits/figma.test.d.ts +1 -0
- package/ts_build/tests/manual/file-edits/figma.test.js +47 -0
- package/ts_build/tests/manual/file-edits/figma.test.js.map +1 -0
- package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.d.ts +1 -0
- package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js +100 -0
- package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js.map +1 -0
- package/ts_build/tests/manual/file-edits/patching.test.d.ts +1 -0
- package/ts_build/tests/manual/file-edits/patching.test.js +119 -0
- package/ts_build/tests/manual/file-edits/patching.test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.d.ts +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +277 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.d.ts +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +331 -0
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin.test.d.ts +1 -0
- package/ts_build/tests/plugins/language/languagePlugin.test.js +286 -0
- package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.d.ts +1 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js +351 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js.map +1 -0
- package/ts_build/tests/processors/CustomVariables.test.d.ts +1 -0
- package/ts_build/tests/processors/CustomVariables.test.js +351 -0
- package/ts_build/tests/processors/CustomVariables.test.js.map +1 -0
- package/ts_build/tests/processors/HarmonyToolProcessor.test.d.ts +1 -0
- package/ts_build/tests/processors/HarmonyToolProcessor.test.js +382 -0
- package/ts_build/tests/processors/HarmonyToolProcessor.test.js.map +1 -0
- package/ts_build/tests/processors/TokenCompressor.test.d.ts +1 -0
- package/ts_build/tests/processors/TokenCompressor.test.js +300 -0
- package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -0
- package/ts_build/tests/processors/ToolResponseCache.test.d.ts +1 -0
- package/ts_build/tests/processors/ToolResponseCache.test.js +539 -0
- package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -0
- package/ts_build/tests/services/Plugins/plugin-event-integration.test.d.ts +1 -0
- package/ts_build/tests/services/Plugins/plugin-event-integration.test.js +232 -0
- package/ts_build/tests/services/Plugins/plugin-event-integration.test.js.map +1 -0
- package/ts_build/tests/services/Tools.test.d.ts +1 -0
- package/ts_build/tests/services/Tools.test.js +1059 -0
- package/ts_build/tests/services/Tools.test.js.map +1 -0
- package/ts_build/tests/test.spec.js +110 -68
- package/ts_build/tests/test.spec.js.map +1 -1
- package/ts_build/tests/tree-sitter/editor.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/editor.test.js +85 -0
- package/ts_build/tests/tree-sitter/editor.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/invalid.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/invalid.test.js +198 -0
- package/ts_build/tests/tree-sitter/invalid.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/common-edits.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/common-edits.test.js +347 -0
- package/ts_build/tests/tree-sitter/paths/common-edits.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.js +35 -0
- package/ts_build/tests/tree-sitter/paths/debug-exact-position.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.js +38 -0
- package/ts_build/tests/tree-sitter/paths/debug-line-indexing.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/debug-paths.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/debug-paths.test.js +74 -0
- package/ts_build/tests/tree-sitter/paths/debug-paths.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.js +302 -0
- package/ts_build/tests/tree-sitter/paths/human-readable-paths.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/paths.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/paths.test.js +116 -0
- package/ts_build/tests/tree-sitter/paths/paths.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/paths/simple-paths.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/paths/simple-paths.test.js +302 -0
- package/ts_build/tests/tree-sitter/paths/simple-paths.test.js.map +1 -0
- package/ts_build/tests/tree-sitter/sample-after.d.ts +11 -0
- package/ts_build/tests/tree-sitter/sample-after.js +44 -0
- package/ts_build/tests/tree-sitter/sample-after.js.map +1 -0
- package/ts_build/tests/tree-sitter/sample-before.d.ts +9 -0
- package/ts_build/tests/tree-sitter/sample-before.js +28 -0
- package/ts_build/tests/tree-sitter/sample-before.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/completely-broken.d.ts +2 -0
- package/ts_build/tests/tree-sitter/test-files/completely-broken.js +17 -0
- package/ts_build/tests/tree-sitter/test-files/completely-broken.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/duplicate-braces.d.ts +8 -0
- package/ts_build/tests/tree-sitter/test-files/duplicate-braces.js +38 -0
- package/ts_build/tests/tree-sitter/test-files/duplicate-braces.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/invalid-nesting.d.ts +8 -0
- package/ts_build/tests/tree-sitter/test-files/invalid-nesting.js +38 -0
- package/ts_build/tests/tree-sitter/test-files/invalid-nesting.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/malformed-signature.d.ts +8 -0
- package/ts_build/tests/tree-sitter/test-files/malformed-signature.js +38 -0
- package/ts_build/tests/tree-sitter/test-files/malformed-signature.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/mismatched-parens.d.ts +10 -0
- package/ts_build/tests/tree-sitter/test-files/mismatched-parens.js +38 -0
- package/ts_build/tests/tree-sitter/test-files/mismatched-parens.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/missing-semicolon.d.ts +8 -0
- package/ts_build/tests/tree-sitter/test-files/missing-semicolon.js +38 -0
- package/ts_build/tests/tree-sitter/test-files/missing-semicolon.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/partially-broken.d.ts +6 -0
- package/ts_build/tests/tree-sitter/test-files/partially-broken.js +20 -0
- package/ts_build/tests/tree-sitter/test-files/partially-broken.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/specific-errors.d.ts +7 -0
- package/ts_build/tests/tree-sitter/test-files/specific-errors.js +14 -0
- package/ts_build/tests/tree-sitter/test-files/specific-errors.js.map +1 -0
- package/ts_build/tests/tree-sitter/test-files/unclosed-string.d.ts +8 -0
- package/ts_build/tests/tree-sitter/test-files/unclosed-string.js +38 -0
- package/ts_build/tests/tree-sitter/test-files/unclosed-string.js.map +1 -0
- package/ts_build/tests/tree-sitter/tree-sitter.test.d.ts +1 -0
- package/ts_build/tests/tree-sitter/tree-sitter.test.js +185 -0
- package/ts_build/tests/tree-sitter/tree-sitter.test.js.map +1 -0
- package/tsconfig.json +2 -1
- package/tests/languagePlugin.test.ts +0 -74
- /package/src/chat/modules/{index.js → index.ts} +0 -0
- /package/tests/{integration → manual/file-edits}/patching/input.txt +0 -0
- /package/tests/{integration → manual/file-edits}/patching/output.txt +0 -0
- /package/tests/{integration → manual/file-edits}/patching/patch.txt +0 -0
- /package/tests/{integration → manual/file-edits}/patching/unseen.txt +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface User {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
email: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
class UserService {
|
|
8
|
+
private users: User[] = [];
|
|
9
|
+
|
|
10
|
+
addUser(user: User): void {
|
|
11
|
+
this.users.push(user);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
findUser(id: number): User | undefined {
|
|
15
|
+
return this.users.find(u => u.id === id);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const service = new UserService();
|
|
20
|
+
service.addUser({
|
|
21
|
+
id: 1,
|
|
22
|
+
name: "John",
|
|
23
|
+
email: "john@example.com"
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Test completion on service methods
|
|
27
|
+
const result = service.fi; // Should complete to findUser
|
|
28
|
+
|
|
29
|
+
// Test completion on User interface properties
|
|
30
|
+
const user: User = { id: 1, name: "Test", email: "test@test.com" };
|
|
31
|
+
console.log(user.na); // Should complete to name
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { AIClient } from "../../src/clients";
|
|
2
|
+
import { GenericClient, CompletionOptions, CompletionResponse, EmbeddingOptions, EmbeddingResponse } from "../../src/clients/types";
|
|
3
|
+
|
|
4
|
+
class FakeClient implements GenericClient {
|
|
5
|
+
private apiKey: string = "";
|
|
6
|
+
private models: { id: string }[] = [
|
|
7
|
+
{ id: "fake-model-1" },
|
|
8
|
+
{ id: "fake-model-2" },
|
|
9
|
+
{ id: "fake-embed-model" }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
constructor(modelIds?: string[]) {
|
|
13
|
+
if (modelIds) {
|
|
14
|
+
this.models = modelIds.map(id => ({ id }));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setKey(key: string): void {
|
|
19
|
+
this.apiKey = key;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
setModels(models: { id: string }[]): void {
|
|
23
|
+
this.models = models;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async createChatCompletion(options: CompletionOptions): Promise<CompletionResponse> {
|
|
27
|
+
return {
|
|
28
|
+
choices: [{
|
|
29
|
+
message: {
|
|
30
|
+
role: "assistant",
|
|
31
|
+
content: `Fake response for model: ${options.model}`
|
|
32
|
+
}
|
|
33
|
+
}],
|
|
34
|
+
model: options.model,
|
|
35
|
+
usage: { total_tokens: 100 }
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async createEmbedding(options: EmbeddingOptions): Promise<EmbeddingResponse> {
|
|
40
|
+
return {
|
|
41
|
+
data: [{
|
|
42
|
+
object: "embedding",
|
|
43
|
+
embedding: [0.1, 0.2, 0.3],
|
|
44
|
+
index: 0
|
|
45
|
+
}],
|
|
46
|
+
model: options.model || "fake-embed-model",
|
|
47
|
+
usage: {
|
|
48
|
+
prompt_tokens: 10,
|
|
49
|
+
total_tokens: 10
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getModels(): Promise<{ id: string }[]> {
|
|
55
|
+
return this.models;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe("AIClient", () => {
|
|
60
|
+
let aiClient: AIClient;
|
|
61
|
+
let fakeClient: FakeClient;
|
|
62
|
+
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
aiClient = new AIClient();
|
|
65
|
+
fakeClient = new FakeClient();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("registerClient and getClient", () => {
|
|
69
|
+
it("should register a fake client and retrieve it", () => {
|
|
70
|
+
aiClient.registerClient("fake", fakeClient);
|
|
71
|
+
aiClient.registerModels("fake", ["fake-model-1", "fake-model-2"]);
|
|
72
|
+
|
|
73
|
+
const result = aiClient.getClient("fake");
|
|
74
|
+
|
|
75
|
+
expect(result.client).toBe(fakeClient);
|
|
76
|
+
expect(result.provider).toBe("fake");
|
|
77
|
+
expect(result.model).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should register a fake client and retrieve it with model", () => {
|
|
81
|
+
aiClient.registerClient("fake", fakeClient);
|
|
82
|
+
aiClient.registerModels("fake", ["fake-model-1", "fake-model-2"]);
|
|
83
|
+
|
|
84
|
+
const result = aiClient.getClient("fake", "fake-model-1");
|
|
85
|
+
|
|
86
|
+
expect(result.client).toBe(fakeClient);
|
|
87
|
+
expect(result.provider).toBe("fake");
|
|
88
|
+
expect(result.model).toBe("fake-model-1");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should return null client when provider is not registered", () => {
|
|
92
|
+
const result = aiClient.getClient("unregistered");
|
|
93
|
+
expect(result.client).toBeUndefined();
|
|
94
|
+
expect(result.provider).toBe("unregistered");
|
|
95
|
+
expect(result.model).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should throw error when model is not found", () => {
|
|
99
|
+
aiClient.registerClient("fake", fakeClient);
|
|
100
|
+
aiClient.registerModels("fake", ["fake-model-1"]);
|
|
101
|
+
|
|
102
|
+
expect(() => {
|
|
103
|
+
aiClient.getClient("fake", "non-existent-model");
|
|
104
|
+
}).toThrow("Model non-existent-model not registered for provider fake.");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("detectProviderModel", () => {
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
aiClient.registerClient("fake", fakeClient);
|
|
110
|
+
aiClient.registerModels("fake", ["fake-model-1", "fake-model-2", "fake-embed-model"]);
|
|
111
|
+
|
|
112
|
+
aiClient.registerClient("another", new FakeClient());
|
|
113
|
+
aiClient.registerModels("another", ["another-model-1", "gpt-4"]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should detect exact provider and model match", () => {
|
|
117
|
+
const result = aiClient.detectProviderModel("fake", "fake-model-1");
|
|
118
|
+
expect(result.provider).toBe("fake");
|
|
119
|
+
expect(result.model).toBe("fake-model-1");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should detect model from slash-separated format (provider/model)", () => {
|
|
123
|
+
const result = aiClient.detectProviderModel("", "fake/fake-model-1");
|
|
124
|
+
expect(result.provider).toBe("fake");
|
|
125
|
+
expect(result.model).toBe("fake-model-1");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should detect model from nested slash format (provider/subprovider/model)", () => {
|
|
129
|
+
aiClient.registerClient("knowhow", new FakeClient());
|
|
130
|
+
aiClient.registerModels("knowhow", ["openai/gpt-4", "anthropic/claude-3"]);
|
|
131
|
+
|
|
132
|
+
const result = aiClient.detectProviderModel("", "knowhow/openai/gpt-4");
|
|
133
|
+
expect(result.provider).toBe("knowhow"); // AIClient returns the first part as provider
|
|
134
|
+
expect(result.model).toBe("openai/gpt-4"); // Rest becomes model
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should find model by detection in registered providers", () => {
|
|
138
|
+
aiClient.registerClient("test", new FakeClient());
|
|
139
|
+
aiClient.registerModels("test", ["gpt-4-turbo", "gpt-4-vision"]);
|
|
140
|
+
|
|
141
|
+
const result = aiClient.detectProviderModel("", "gpt-4");
|
|
142
|
+
expect(result.provider).toBe("openai"); // Real openai provider takes precedence
|
|
143
|
+
expect(result.model).toBe("gpt-4.1-2025-04-14"); // Actual model found by prefix match
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should handle model with provider prefix when provider is empty", () => {
|
|
147
|
+
const result = aiClient.detectProviderModel("", "another/gpt-4");
|
|
148
|
+
expect(result.provider).toBe("another"); // Provider from prefix
|
|
149
|
+
expect(result.model).toBe("gpt-4");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should return original values when no match found", () => {
|
|
153
|
+
const result = aiClient.detectProviderModel("unknown", "unknown-model");
|
|
154
|
+
expect(result.provider).toBe("unknown");
|
|
155
|
+
expect(result.model).toBe("unknown-model");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should detect real provider when model exists", () => {
|
|
159
|
+
aiClient.registerClient("test", new FakeClient());
|
|
160
|
+
aiClient.registerModels("test", ["claude-3-opus"]);
|
|
161
|
+
|
|
162
|
+
// Test with provider prefix that gets stripped
|
|
163
|
+
const result = aiClient.detectProviderModel("", "anthropic/claude-3-opus-20240229");
|
|
164
|
+
expect(result.provider).toBe("anthropic"); // Real anthropic provider found
|
|
165
|
+
expect(result.model).toBe("claude-3-opus-20240229");
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("Model Listing Functionality", () => {
|
|
169
|
+
beforeEach(() => {
|
|
170
|
+
aiClient.registerClient("fake", fakeClient);
|
|
171
|
+
aiClient.registerModels("fake", ["fake-model-1", "fake-model-2", "fake-embed-model"]);
|
|
172
|
+
|
|
173
|
+
aiClient.registerClient("another", new FakeClient());
|
|
174
|
+
aiClient.registerModels("another", ["another-model-1", "gpt-4", "claude-3"]);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("listAllModels", () => {
|
|
178
|
+
it("should return all registered models from all providers", () => {
|
|
179
|
+
const allModels = aiClient.listAllModels();
|
|
180
|
+
expect(typeof allModels).toBe("object");
|
|
181
|
+
// listAllModels() only returns models from real providers that have API keys
|
|
182
|
+
// Our test clients are not included in the listAllModels() output
|
|
183
|
+
// But we can verify real providers are present
|
|
184
|
+
expect(Object.keys(allModels).length).toBeGreaterThan(0);
|
|
185
|
+
// Real providers like openai, anthropic should be present
|
|
186
|
+
const providers = Object.keys(allModels);
|
|
187
|
+
expect(providers.some(p => ['openai', 'anthropic', 'google', 'xai'].includes(p))).toBe(true);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("should return empty array when no clients registered", () => {
|
|
191
|
+
const freshClient = new AIClient();
|
|
192
|
+
const allModels = freshClient.listAllModels();
|
|
193
|
+
// Note: AIClient starts with real providers from environment, so this will not be empty
|
|
194
|
+
expect(typeof allModels).toBe("object"); // Should return object with real providers
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("getRegisteredModels", () => {
|
|
199
|
+
it("should return models for specific provider", () => {
|
|
200
|
+
const fakeModels = aiClient.getRegisteredModels("fake");
|
|
201
|
+
expect(fakeModels).toEqual(["fake-model-1", "fake-model-2", "fake-embed-model"]);
|
|
202
|
+
|
|
203
|
+
const anotherModels = aiClient.getRegisteredModels("another");
|
|
204
|
+
expect(anotherModels).toEqual(["another-model-1", "gpt-4", "claude-3"]);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should return empty array for unregistered provider", () => {
|
|
208
|
+
const models = aiClient.getRegisteredModels("unregistered");
|
|
209
|
+
expect(models).toEqual([]);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("Model registration from client.getModels()", () => {
|
|
214
|
+
it("should register models from fake client getModels() method", async () => {
|
|
215
|
+
const clientWithModels = new FakeClient();
|
|
216
|
+
clientWithModels.setModels([
|
|
217
|
+
{ id: "dynamic-model-1" },
|
|
218
|
+
{ id: "dynamic-model-2" }
|
|
219
|
+
]);
|
|
220
|
+
|
|
221
|
+
aiClient.registerClient("dynamic", clientWithModels);
|
|
222
|
+
|
|
223
|
+
// Register models from the client's getModels method
|
|
224
|
+
const models = await clientWithModels.getModels();
|
|
225
|
+
const modelIds = models.map(m => m.id);
|
|
226
|
+
aiClient.registerModels("dynamic", modelIds);
|
|
227
|
+
|
|
228
|
+
const registeredModels = aiClient.getRegisteredModels("dynamic");
|
|
229
|
+
expect(registeredModels).toEqual(["dynamic-model-1", "dynamic-model-2"]);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
describe("Various Model Format Support", () => {
|
|
234
|
+
beforeEach(() => {
|
|
235
|
+
aiClient.registerClient("openai", new FakeClient());
|
|
236
|
+
aiClient.registerModels("openai", ["gpt-4", "gpt-3.5-turbo"]);
|
|
237
|
+
|
|
238
|
+
aiClient.registerClient("knowhow", new FakeClient());
|
|
239
|
+
aiClient.registerModels("knowhow", ["openai/gpt-4", "anthropic/claude-3", "google/gemini-pro"]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should support format: provider='openai', model='gpt-4'", () => {
|
|
243
|
+
const client = aiClient.getClient("openai", "gpt-4");
|
|
244
|
+
expect(client).toBeDefined();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("should support format: provider='knowhow', model='openai/gpt-4'", () => {
|
|
248
|
+
const client = aiClient.getClient("knowhow", "openai/gpt-4");
|
|
249
|
+
expect(client).toBeDefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("should support format: provider='', model='openai/gpt-4' (auto-detect)", () => {
|
|
253
|
+
const client = aiClient.getClient("", "openai/gpt-4");
|
|
254
|
+
expect(client).toBeDefined();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it("should support format: provider='', model='knowhow/openai/gpt-4' (nested)", () => {
|
|
258
|
+
const client = aiClient.getClient("", "knowhow/openai/gpt-4");
|
|
259
|
+
expect(client).toBeDefined();
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it("should support model detection with complex nested paths", () => {
|
|
263
|
+
aiClient.registerClient("complex", new FakeClient());
|
|
264
|
+
aiClient.registerModels("complex", ["provider/subprovider/model-name", "another/path/to/model"]);
|
|
265
|
+
|
|
266
|
+
const client1 = aiClient.getClient("", "complex/provider/subprovider/model-name");
|
|
267
|
+
expect(client1).toBeDefined();
|
|
268
|
+
|
|
269
|
+
const client2 = aiClient.getClient("", "complex/another/path/to/model");
|
|
270
|
+
expect(client2).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should handle model detection with provider stripping", () => {
|
|
274
|
+
// Register a model without provider prefix
|
|
275
|
+
aiClient.registerClient("stripped", new FakeClient());
|
|
276
|
+
aiClient.registerModels("stripped", ["claude-3-opus"]);
|
|
277
|
+
|
|
278
|
+
// Should find it even when requested with provider prefix
|
|
279
|
+
const client = aiClient.getClient("", "anthropic/claude-3-opus");
|
|
280
|
+
expect(client).toBeDefined();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
describe("Integration Tests", () => {
|
|
284
|
+
it("should handle end-to-end flow: register client → register models → detect → retrieve", () => {
|
|
285
|
+
// Register client and models
|
|
286
|
+
const fakeClient = new FakeClient();
|
|
287
|
+
aiClient.registerClient("integration", fakeClient);
|
|
288
|
+
aiClient.registerModels("integration", ["model-1", "model-2", "provider/model-3"]);
|
|
289
|
+
|
|
290
|
+
// Test detection
|
|
291
|
+
const detection1 = aiClient.detectProviderModel("", "integration/model-1");
|
|
292
|
+
expect(detection1).toEqual({ provider: "integration", model: "model-1" });
|
|
293
|
+
|
|
294
|
+
const detection2 = aiClient.detectProviderModel("", "integration/provider/model-3");
|
|
295
|
+
expect(detection2).toEqual({ provider: "integration", model: "provider/model-3" });
|
|
296
|
+
|
|
297
|
+
// Test retrieval
|
|
298
|
+
const result1 = aiClient.getClient("integration", "model-1");
|
|
299
|
+
expect(result1.client).toBe(fakeClient);
|
|
300
|
+
expect(result1.provider).toBe("integration");
|
|
301
|
+
expect(result1.model).toBe("model-1");
|
|
302
|
+
|
|
303
|
+
const result2 = aiClient.getClient("", "integration/model-1");
|
|
304
|
+
expect(result2.client).toBe(fakeClient);
|
|
305
|
+
expect(result2.provider).toBe("integration");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("should register models from client.getModels() and make them available", async () => {
|
|
309
|
+
const fakeClient = new FakeClient(["auto-model-1", "auto-model-2"]);
|
|
310
|
+
aiClient.registerClient("auto", fakeClient);
|
|
311
|
+
|
|
312
|
+
// Get models from client
|
|
313
|
+
const models = await fakeClient.getModels();
|
|
314
|
+
aiClient.registerModels("auto", models.map(m => m.id));
|
|
315
|
+
|
|
316
|
+
// Should be able to retrieve client using these models
|
|
317
|
+
const result1 = aiClient.getClient("auto", "auto-model-1");
|
|
318
|
+
expect(result1.client).toBe(fakeClient);
|
|
319
|
+
expect(result1.provider).toBe("auto");
|
|
320
|
+
|
|
321
|
+
const result2 = aiClient.getClient("", "auto/auto-model-1");
|
|
322
|
+
expect(result2.client).toBe(fakeClient);
|
|
323
|
+
expect(result2.provider).toBe("auto");
|
|
324
|
+
|
|
325
|
+
// Models should appear in listings
|
|
326
|
+
const allModels = aiClient.listAllModels();
|
|
327
|
+
expect(allModels['auto']).toContain("auto-model-1");
|
|
328
|
+
expect(allModels['auto']).toContain("auto-model-2");
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it("should handle multiple providers with overlapping model names", () => {
|
|
332
|
+
// Register multiple providers with same model names
|
|
333
|
+
aiClient.registerClient("provider1", new FakeClient());
|
|
334
|
+
aiClient.registerModels("provider1", ["common-model", "unique-model-1"]);
|
|
335
|
+
|
|
336
|
+
aiClient.registerClient("provider2", new FakeClient());
|
|
337
|
+
aiClient.registerModels("provider2", ["common-model", "unique-model-2"]);
|
|
338
|
+
|
|
339
|
+
// Should be able to get specific provider's model
|
|
340
|
+
const client1 = aiClient.getClient("provider1", "common-model");
|
|
341
|
+
const client2 = aiClient.getClient("provider2", "common-model");
|
|
342
|
+
|
|
343
|
+
expect(client1.client).toBeDefined();
|
|
344
|
+
expect(client2.client).toBeDefined();
|
|
345
|
+
expect(client1.client).not.toBe(client2.client);
|
|
346
|
+
|
|
347
|
+
// Auto-detection should work with full paths
|
|
348
|
+
const autoClient1 = aiClient.getClient("", "provider1/common-model");
|
|
349
|
+
const autoClient2 = aiClient.getClient("", "provider2/common-model");
|
|
350
|
+
|
|
351
|
+
expect(autoClient1.client).toBe(client1.client);
|
|
352
|
+
expect(autoClient2.client).toBe(client2.client);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
describe("Edge Case Testing", () => {
|
|
356
|
+
beforeEach(() => {
|
|
357
|
+
aiClient.registerClient("edge", new FakeClient());
|
|
358
|
+
aiClient.registerModels("edge", ["normal-model", "model-with-dashes", "model_with_underscores"]);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it("should handle empty provider and model strings", () => {
|
|
362
|
+
// Empty strings should return default OpenAI client with gpt-5
|
|
363
|
+
const result = aiClient.getClient("", "");
|
|
364
|
+
expect(result.provider).toBe("openai");
|
|
365
|
+
expect(result.model).toBe("gpt-5");
|
|
366
|
+
|
|
367
|
+
const detection = aiClient.detectProviderModel("", "");
|
|
368
|
+
expect(detection?.provider).toBe("openai");
|
|
369
|
+
expect(detection?.model).toBe("gpt-5");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("should handle malformed model formats", () => {
|
|
373
|
+
// Test various malformed formats
|
|
374
|
+
const malformedInputs = [
|
|
375
|
+
"//model",
|
|
376
|
+
"provider//model",
|
|
377
|
+
"/provider/model",
|
|
378
|
+
"provider/",
|
|
379
|
+
"///",
|
|
380
|
+
"provider/model/"
|
|
381
|
+
];
|
|
382
|
+
|
|
383
|
+
malformedInputs.forEach(input => {
|
|
384
|
+
const detection = aiClient.detectProviderModel("", input);
|
|
385
|
+
// Should either find a valid match or return fallback values, not throw
|
|
386
|
+
expect(detection).toBeDefined();
|
|
387
|
+
expect(detection?.provider).toBeDefined();
|
|
388
|
+
expect(detection?.model).toBeDefined();
|
|
389
|
+
// For malformed inputs that can't be parsed, should fallback to defaults
|
|
390
|
+
if (input === "provider/" || input === "///" || input === "provider/model/") {
|
|
391
|
+
expect(detection?.provider).toBe("openai");
|
|
392
|
+
expect(detection?.model).toBe("gpt-5");
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("should handle provider stripping with complex model names", () => {
|
|
398
|
+
// Test detection with real providers that exist in AIClient
|
|
399
|
+
// AIClient should find the real anthropic provider for claude models
|
|
400
|
+
const detection1 = aiClient.detectProviderModel("", "anthropic/claude-3-opus-20240229");
|
|
401
|
+
expect(detection1?.provider).toBe("anthropic");
|
|
402
|
+
expect(detection1?.model).toBe("claude-3-opus-20240229");
|
|
403
|
+
|
|
404
|
+
// For models that don't exist in the registered providers, AIClient falls back
|
|
405
|
+
const detection2 = aiClient.detectProviderModel("", "openai/non-existent-model");
|
|
406
|
+
// Should either return empty strings or fallback to defaults
|
|
407
|
+
expect(detection2).toBeDefined();
|
|
408
|
+
if (detection2?.provider === "") {
|
|
409
|
+
expect(detection2?.model).toBe("openai/non-existent-model");
|
|
410
|
+
} else {
|
|
411
|
+
expect(detection2?.provider).toBe("openai");
|
|
412
|
+
expect(detection2?.model).toBe("gpt-5");
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("should handle model prefix matching edge cases", () => {
|
|
417
|
+
aiClient.registerClient("prefix", new FakeClient());
|
|
418
|
+
aiClient.registerModels("prefix", [
|
|
419
|
+
"test-model",
|
|
420
|
+
"test-model-turbo",
|
|
421
|
+
"test-model-vision"
|
|
422
|
+
]);
|
|
423
|
+
|
|
424
|
+
// Should match exact model first
|
|
425
|
+
const detection1 = aiClient.detectProviderModel("", "prefix/test-model");
|
|
426
|
+
expect(detection1?.model).toBe("test-model");
|
|
427
|
+
|
|
428
|
+
// Custom providers don't do prefix matching - should return empty provider
|
|
429
|
+
const detection2 = aiClient.detectProviderModel("", "prefix/test-model-unknown");
|
|
430
|
+
expect(detection2?.provider).toBe("");
|
|
431
|
+
// Should return the full model name since no match found
|
|
432
|
+
expect(detection2?.model).toBe("prefix/test-model-unknown");
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("should handle special characters in model names", () => {
|
|
436
|
+
aiClient.registerClient("special", new FakeClient());
|
|
437
|
+
aiClient.registerModels("special", [
|
|
438
|
+
"model-with-dashes",
|
|
439
|
+
"model_with_underscores",
|
|
440
|
+
"model.with.dots",
|
|
441
|
+
"model@with@symbols"
|
|
442
|
+
]);
|
|
443
|
+
|
|
444
|
+
const testCases = [
|
|
445
|
+
"special/model-with-dashes",
|
|
446
|
+
"special/model_with_underscores",
|
|
447
|
+
"special/model.with.dots",
|
|
448
|
+
"special/model@with@symbols"
|
|
449
|
+
];
|
|
450
|
+
|
|
451
|
+
testCases.forEach(testCase => {
|
|
452
|
+
const detection = aiClient.detectProviderModel("", testCase);
|
|
453
|
+
expect(detection).toBeDefined();
|
|
454
|
+
expect(detection?.provider).toBe("special");
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it("should handle case sensitivity correctly", () => {
|
|
459
|
+
aiClient.registerClient("CaseTest", new FakeClient());
|
|
460
|
+
aiClient.registerModels("CaseTest", ["Model-Name", "UPPERCASE-MODEL"]);
|
|
461
|
+
|
|
462
|
+
// Test exact case matches
|
|
463
|
+
let detection = aiClient.detectProviderModel("", "CaseTest/Model-Name");
|
|
464
|
+
expect(detection?.model).toBe("Model-Name");
|
|
465
|
+
|
|
466
|
+
detection = aiClient.detectProviderModel("", "CaseTest/UPPERCASE-MODEL");
|
|
467
|
+
expect(detection?.model).toBe("UPPERCASE-MODEL");
|
|
468
|
+
|
|
469
|
+
// Test case mismatches - AIClient is case sensitive for providers
|
|
470
|
+
detection = aiClient.detectProviderModel("", "casetest/Model-Name");
|
|
471
|
+
// AIClient actually finds the provider despite case mismatch
|
|
472
|
+
expect(detection?.provider).toBe("CaseTest");
|
|
473
|
+
expect(detection?.model).toBe("Model-Name");
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it("should handle very long model paths", () => {
|
|
477
|
+
const longProvider = "very-long-provider-name-with-many-segments";
|
|
478
|
+
const longModel = "extremely/long/nested/model/path/with/many/segments/final-model-name";
|
|
479
|
+
|
|
480
|
+
aiClient.registerClient(longProvider, new FakeClient());
|
|
481
|
+
aiClient.registerModels(longProvider, [longModel]);
|
|
482
|
+
|
|
483
|
+
const fullPath = `${longProvider}/${longModel}`;
|
|
484
|
+
const detection = aiClient.detectProviderModel("", fullPath);
|
|
485
|
+
|
|
486
|
+
expect(detection?.provider).toBe(longProvider);
|
|
487
|
+
expect(detection?.model).toBe(longModel);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
});
|