@gguf/coder 0.3.0 → 0.3.1
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/.editorconfig +16 -0
- package/.env.example +63 -0
- package/.gitattributes +1 -0
- package/.semgrepignore +19 -0
- package/coder-dummy-file.ts +52 -0
- package/coder.config.example.json +59 -0
- package/coder.config.json +13 -0
- package/color_picker.html +36 -0
- package/package.json +2 -14
- package/scripts/extract-changelog.js +73 -0
- package/scripts/fetch-models.js +143 -0
- package/scripts/test.sh +40 -0
- package/scripts/update-homebrew-formula.sh +125 -0
- package/scripts/update-nix-version.sh +157 -0
- package/source/ai-sdk-client/AISDKClient.spec.ts +117 -0
- package/source/ai-sdk-client/AISDKClient.ts +155 -0
- package/source/ai-sdk-client/chat/chat-handler.spec.ts +121 -0
- package/source/ai-sdk-client/chat/chat-handler.ts +276 -0
- package/source/ai-sdk-client/chat/streaming-handler.spec.ts +173 -0
- package/source/ai-sdk-client/chat/streaming-handler.ts +110 -0
- package/source/ai-sdk-client/chat/tool-processor.spec.ts +92 -0
- package/source/ai-sdk-client/chat/tool-processor.ts +70 -0
- package/source/ai-sdk-client/converters/message-converter.spec.ts +220 -0
- package/source/ai-sdk-client/converters/message-converter.ts +113 -0
- package/source/ai-sdk-client/converters/tool-converter.spec.ts +90 -0
- package/source/ai-sdk-client/converters/tool-converter.ts +46 -0
- package/source/ai-sdk-client/error-handling/error-extractor.spec.ts +55 -0
- package/source/ai-sdk-client/error-handling/error-extractor.ts +15 -0
- package/source/ai-sdk-client/error-handling/error-parser.spec.ts +169 -0
- package/source/ai-sdk-client/error-handling/error-parser.ts +161 -0
- package/source/ai-sdk-client/index.ts +7 -0
- package/source/ai-sdk-client/providers/provider-factory.spec.ts +71 -0
- package/source/ai-sdk-client/providers/provider-factory.ts +41 -0
- package/source/ai-sdk-client/types.ts +9 -0
- package/source/ai-sdk-client-empty-message.spec.ts +141 -0
- package/source/ai-sdk-client-error-handling.spec.ts +186 -0
- package/source/ai-sdk-client-maxretries.spec.ts +114 -0
- package/source/ai-sdk-client-preparestep.spec.ts +279 -0
- package/source/app/App.spec.tsx +32 -0
- package/source/app/App.tsx +480 -0
- package/source/app/components/AppContainer.spec.tsx +96 -0
- package/source/app/components/AppContainer.tsx +56 -0
- package/source/app/components/ChatInterface.spec.tsx +163 -0
- package/source/app/components/ChatInterface.tsx +144 -0
- package/source/app/components/ModalSelectors.spec.tsx +141 -0
- package/source/app/components/ModalSelectors.tsx +135 -0
- package/source/app/helpers.spec.ts +97 -0
- package/source/app/helpers.ts +63 -0
- package/source/app/index.ts +4 -0
- package/source/app/types.ts +39 -0
- package/source/app/utils/appUtils.ts +294 -0
- package/source/app/utils/conversationState.ts +310 -0
- package/source/app.spec.tsx +244 -0
- package/source/cli.spec.ts +73 -0
- package/source/cli.tsx +51 -0
- package/source/client-factory.spec.ts +48 -0
- package/source/client-factory.ts +178 -0
- package/source/command-parser.spec.ts +127 -0
- package/source/command-parser.ts +36 -0
- package/source/commands/checkpoint.spec.tsx +277 -0
- package/source/commands/checkpoint.tsx +366 -0
- package/source/commands/clear.tsx +22 -0
- package/source/commands/custom-commands.tsx +121 -0
- package/source/commands/exit.ts +21 -0
- package/source/commands/export.spec.tsx +131 -0
- package/source/commands/export.tsx +79 -0
- package/source/commands/help.tsx +120 -0
- package/source/commands/index.ts +17 -0
- package/source/commands/init.tsx +339 -0
- package/source/commands/lsp-command.spec.tsx +281 -0
- package/source/commands/lsp.tsx +120 -0
- package/source/commands/mcp-command.spec.tsx +313 -0
- package/source/commands/mcp.tsx +162 -0
- package/source/commands/model-database.spec.tsx +758 -0
- package/source/commands/model-database.tsx +418 -0
- package/source/commands/model.ts +12 -0
- package/source/commands/provider.ts +12 -0
- package/source/commands/setup-config.tsx +16 -0
- package/source/commands/simple-commands.spec.tsx +175 -0
- package/source/commands/status.ts +12 -0
- package/source/commands/theme.ts +12 -0
- package/source/commands/update.spec.tsx +261 -0
- package/source/commands/update.tsx +201 -0
- package/source/commands/usage.spec.tsx +495 -0
- package/source/commands/usage.tsx +100 -0
- package/source/commands.spec.ts +436 -0
- package/source/commands.ts +83 -0
- package/source/components/assistant-message.spec.tsx +796 -0
- package/source/components/assistant-message.tsx +34 -0
- package/source/components/bash-execution-indicator.tsx +21 -0
- package/source/components/cancelling-indicator.tsx +16 -0
- package/source/components/chat-queue.spec.tsx +83 -0
- package/source/components/chat-queue.tsx +36 -0
- package/source/components/checkpoint-display.spec.tsx +219 -0
- package/source/components/checkpoint-display.tsx +126 -0
- package/source/components/checkpoint-selector.spec.tsx +173 -0
- package/source/components/checkpoint-selector.tsx +173 -0
- package/source/components/development-mode-indicator.spec.tsx +268 -0
- package/source/components/development-mode-indicator.tsx +38 -0
- package/source/components/message-box.spec.tsx +427 -0
- package/source/components/message-box.tsx +87 -0
- package/source/components/model-selector.tsx +132 -0
- package/source/components/provider-selector.tsx +75 -0
- package/source/components/random-spinner.tsx +19 -0
- package/source/components/security-disclaimer.tsx +73 -0
- package/source/components/status-connection-display.spec.tsx +133 -0
- package/source/components/status.tsx +267 -0
- package/source/components/theme-selector.tsx +126 -0
- package/source/components/tool-confirmation.tsx +190 -0
- package/source/components/tool-execution-indicator.tsx +33 -0
- package/source/components/tool-message.tsx +85 -0
- package/source/components/ui/titled-box.spec.tsx +207 -0
- package/source/components/ui/titled-box.tsx +57 -0
- package/source/components/usage/progress-bar.spec.tsx +398 -0
- package/source/components/usage/progress-bar.tsx +30 -0
- package/source/components/usage/usage-display.spec.tsx +780 -0
- package/source/components/usage/usage-display.tsx +291 -0
- package/source/components/user-input.spec.tsx +327 -0
- package/source/components/user-input.tsx +533 -0
- package/source/components/user-message.spec.tsx +230 -0
- package/source/components/user-message.tsx +84 -0
- package/source/components/welcome-message.tsx +76 -0
- package/source/config/env-substitution.ts +65 -0
- package/source/config/index.spec.ts +171 -0
- package/source/config/index.ts +154 -0
- package/source/config/paths.spec.ts +241 -0
- package/source/config/paths.ts +55 -0
- package/source/config/preferences.ts +51 -0
- package/source/config/themes.ts +315 -0
- package/source/constants.ts +130 -0
- package/source/context/mode-context.spec.ts +79 -0
- package/source/context/mode-context.ts +24 -0
- package/source/custom-commands/executor.spec.ts +142 -0
- package/source/custom-commands/executor.ts +64 -0
- package/source/custom-commands/loader.spec.ts +314 -0
- package/source/custom-commands/loader.ts +153 -0
- package/source/custom-commands/parser.ts +196 -0
- package/source/hooks/chat-handler/conversation/conversation-loop.spec.ts +39 -0
- package/source/hooks/chat-handler/conversation/conversation-loop.tsx +511 -0
- package/source/hooks/chat-handler/conversation/tool-executor.spec.ts +50 -0
- package/source/hooks/chat-handler/conversation/tool-executor.tsx +109 -0
- package/source/hooks/chat-handler/index.ts +12 -0
- package/source/hooks/chat-handler/state/streaming-state.spec.ts +26 -0
- package/source/hooks/chat-handler/state/streaming-state.ts +19 -0
- package/source/hooks/chat-handler/types.ts +38 -0
- package/source/hooks/chat-handler/useChatHandler.spec.tsx +321 -0
- package/source/hooks/chat-handler/useChatHandler.tsx +194 -0
- package/source/hooks/chat-handler/utils/context-checker.spec.ts +60 -0
- package/source/hooks/chat-handler/utils/context-checker.tsx +73 -0
- package/source/hooks/chat-handler/utils/message-helpers.spec.ts +42 -0
- package/source/hooks/chat-handler/utils/message-helpers.tsx +36 -0
- package/source/hooks/chat-handler/utils/tool-filters.spec.ts +109 -0
- package/source/hooks/chat-handler/utils/tool-filters.ts +64 -0
- package/source/hooks/useAppHandlers.tsx +291 -0
- package/source/hooks/useAppInitialization.tsx +422 -0
- package/source/hooks/useAppState.tsx +311 -0
- package/source/hooks/useDirectoryTrust.tsx +98 -0
- package/source/hooks/useInputState.ts +414 -0
- package/source/hooks/useModeHandlers.tsx +302 -0
- package/source/hooks/useNonInteractiveMode.ts +140 -0
- package/source/hooks/useTerminalWidth.tsx +81 -0
- package/source/hooks/useTheme.ts +18 -0
- package/source/hooks/useToolHandler.tsx +349 -0
- package/source/hooks/useUIState.ts +61 -0
- package/source/init/agents-template-generator.ts +421 -0
- package/source/init/existing-rules-extractor.ts +319 -0
- package/source/init/file-scanner.spec.ts +227 -0
- package/source/init/file-scanner.ts +238 -0
- package/source/init/framework-detector.ts +382 -0
- package/source/init/language-detector.ts +269 -0
- package/source/init/project-analyzer.spec.ts +231 -0
- package/source/init/project-analyzer.ts +458 -0
- package/source/lsp/index.ts +31 -0
- package/source/lsp/lsp-client.spec.ts +508 -0
- package/source/lsp/lsp-client.ts +487 -0
- package/source/lsp/lsp-manager.spec.ts +477 -0
- package/source/lsp/lsp-manager.ts +419 -0
- package/source/lsp/protocol.spec.ts +502 -0
- package/source/lsp/protocol.ts +360 -0
- package/source/lsp/server-discovery.spec.ts +654 -0
- package/source/lsp/server-discovery.ts +515 -0
- package/source/markdown-parser/html-entities.spec.ts +88 -0
- package/source/markdown-parser/html-entities.ts +45 -0
- package/source/markdown-parser/index.spec.ts +281 -0
- package/source/markdown-parser/index.ts +126 -0
- package/source/markdown-parser/table-parser.spec.ts +133 -0
- package/source/markdown-parser/table-parser.ts +114 -0
- package/source/markdown-parser/utils.spec.ts +70 -0
- package/source/markdown-parser/utils.ts +13 -0
- package/source/mcp/mcp-client.spec.ts +81 -0
- package/source/mcp/mcp-client.ts +625 -0
- package/source/mcp/transport-factory.spec.ts +406 -0
- package/source/mcp/transport-factory.ts +312 -0
- package/source/message-handler.ts +67 -0
- package/source/model-database/database-engine.spec.ts +494 -0
- package/source/model-database/database-engine.ts +50 -0
- package/source/model-database/model-database.spec.ts +363 -0
- package/source/model-database/model-database.ts +91 -0
- package/source/model-database/model-engine.spec.ts +447 -0
- package/source/model-database/model-engine.ts +65 -0
- package/source/model-database/model-fetcher.spec.ts +583 -0
- package/source/model-database/model-fetcher.ts +330 -0
- package/source/models/index.ts +1 -0
- package/source/models/models-cache.spec.ts +214 -0
- package/source/models/models-cache.ts +78 -0
- package/source/models/models-dev-client.spec.ts +379 -0
- package/source/models/models-dev-client.ts +329 -0
- package/source/models/models-types.ts +68 -0
- package/source/prompt-history.ts +155 -0
- package/source/security/command-injection.spec.ts +240 -0
- package/source/services/checkpoint-manager.spec.ts +523 -0
- package/source/services/checkpoint-manager.ts +466 -0
- package/source/services/file-snapshot.spec.ts +569 -0
- package/source/services/file-snapshot.ts +220 -0
- package/source/test-utils/render-with-theme.tsx +48 -0
- package/source/tokenization/index.ts +1 -0
- package/source/tokenization/tokenizer-factory.spec.ts +170 -0
- package/source/tokenization/tokenizer-factory.ts +125 -0
- package/source/tokenization/tokenizers/anthropic-tokenizer.spec.ts +200 -0
- package/source/tokenization/tokenizers/anthropic-tokenizer.ts +43 -0
- package/source/tokenization/tokenizers/fallback-tokenizer.spec.ts +236 -0
- package/source/tokenization/tokenizers/fallback-tokenizer.ts +26 -0
- package/source/tokenization/tokenizers/llama-tokenizer.spec.ts +224 -0
- package/source/tokenization/tokenizers/llama-tokenizer.ts +41 -0
- package/source/tokenization/tokenizers/openai-tokenizer.spec.ts +184 -0
- package/source/tokenization/tokenizers/openai-tokenizer.ts +57 -0
- package/source/tool-calling/index.ts +5 -0
- package/source/tool-calling/json-parser.spec.ts +639 -0
- package/source/tool-calling/json-parser.ts +247 -0
- package/source/tool-calling/tool-parser.spec.ts +395 -0
- package/source/tool-calling/tool-parser.ts +120 -0
- package/source/tool-calling/xml-parser.spec.ts +662 -0
- package/source/tool-calling/xml-parser.ts +289 -0
- package/source/tools/execute-bash.spec.tsx +353 -0
- package/source/tools/execute-bash.tsx +219 -0
- package/source/tools/execute-function.spec.ts +130 -0
- package/source/tools/fetch-url.spec.tsx +342 -0
- package/source/tools/fetch-url.tsx +172 -0
- package/source/tools/find-files.spec.tsx +924 -0
- package/source/tools/find-files.tsx +293 -0
- package/source/tools/index.ts +102 -0
- package/source/tools/lsp-get-diagnostics.tsx +192 -0
- package/source/tools/needs-approval.spec.ts +282 -0
- package/source/tools/read-file.spec.tsx +801 -0
- package/source/tools/read-file.tsx +387 -0
- package/source/tools/search-file-contents.spec.tsx +1273 -0
- package/source/tools/search-file-contents.tsx +293 -0
- package/source/tools/string-replace.spec.tsx +730 -0
- package/source/tools/string-replace.tsx +548 -0
- package/source/tools/tool-manager.ts +210 -0
- package/source/tools/tool-registry.spec.ts +415 -0
- package/source/tools/tool-registry.ts +228 -0
- package/source/tools/web-search.tsx +223 -0
- package/source/tools/write-file.spec.tsx +559 -0
- package/source/tools/write-file.tsx +228 -0
- package/source/types/app.ts +37 -0
- package/source/types/checkpoint.ts +48 -0
- package/source/types/commands.ts +46 -0
- package/source/types/components.ts +27 -0
- package/source/types/config.ts +103 -0
- package/source/types/core-connection-status.spec.ts +67 -0
- package/source/types/core.ts +181 -0
- package/source/types/hooks.ts +50 -0
- package/source/types/index.ts +12 -0
- package/source/types/markdown-parser.ts +11 -0
- package/source/types/mcp.ts +52 -0
- package/source/types/system.ts +16 -0
- package/source/types/tokenization.ts +41 -0
- package/source/types/ui.ts +40 -0
- package/source/types/usage.ts +58 -0
- package/source/types/utils.ts +16 -0
- package/source/usage/calculator.spec.ts +385 -0
- package/source/usage/calculator.ts +104 -0
- package/source/usage/storage.spec.ts +703 -0
- package/source/usage/storage.ts +238 -0
- package/source/usage/tracker.spec.ts +456 -0
- package/source/usage/tracker.ts +102 -0
- package/source/utils/atomic-deletion.spec.ts +194 -0
- package/source/utils/atomic-deletion.ts +127 -0
- package/source/utils/bounded-map.spec.ts +300 -0
- package/source/utils/bounded-map.ts +193 -0
- package/source/utils/checkpoint-utils.spec.ts +222 -0
- package/source/utils/checkpoint-utils.ts +92 -0
- package/source/utils/error-formatter.spec.ts +169 -0
- package/source/utils/error-formatter.ts +194 -0
- package/source/utils/file-autocomplete.spec.ts +173 -0
- package/source/utils/file-autocomplete.ts +196 -0
- package/source/utils/file-cache.spec.ts +309 -0
- package/source/utils/file-cache.ts +195 -0
- package/source/utils/file-content-loader.spec.ts +180 -0
- package/source/utils/file-content-loader.ts +179 -0
- package/source/utils/file-mention-handler.spec.ts +261 -0
- package/source/utils/file-mention-handler.ts +84 -0
- package/source/utils/file-mention-parser.spec.ts +182 -0
- package/source/utils/file-mention-parser.ts +170 -0
- package/source/utils/fuzzy-matching.spec.ts +149 -0
- package/source/utils/fuzzy-matching.ts +146 -0
- package/source/utils/indentation-normalizer.spec.ts +216 -0
- package/source/utils/indentation-normalizer.ts +76 -0
- package/source/utils/installation-detector.spec.ts +178 -0
- package/source/utils/installation-detector.ts +153 -0
- package/source/utils/logging/config.spec.ts +311 -0
- package/source/utils/logging/config.ts +210 -0
- package/source/utils/logging/console-facade.spec.ts +184 -0
- package/source/utils/logging/console-facade.ts +384 -0
- package/source/utils/logging/correlation.spec.ts +679 -0
- package/source/utils/logging/correlation.ts +474 -0
- package/source/utils/logging/formatters.spec.ts +464 -0
- package/source/utils/logging/formatters.ts +207 -0
- package/source/utils/logging/health-monitor/alerts/alert-manager.spec.ts +93 -0
- package/source/utils/logging/health-monitor/alerts/alert-manager.ts +79 -0
- package/source/utils/logging/health-monitor/checks/configuration-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/configuration-check.ts +43 -0
- package/source/utils/logging/health-monitor/checks/logging-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/logging-check.ts +58 -0
- package/source/utils/logging/health-monitor/checks/memory-check.spec.ts +100 -0
- package/source/utils/logging/health-monitor/checks/memory-check.ts +78 -0
- package/source/utils/logging/health-monitor/checks/performance-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/performance-check.ts +56 -0
- package/source/utils/logging/health-monitor/checks/request-check.spec.ts +56 -0
- package/source/utils/logging/health-monitor/checks/request-check.ts +76 -0
- package/source/utils/logging/health-monitor/core/health-check-runner.spec.ts +70 -0
- package/source/utils/logging/health-monitor/core/health-check-runner.ts +138 -0
- package/source/utils/logging/health-monitor/core/health-monitor.spec.ts +58 -0
- package/source/utils/logging/health-monitor/core/health-monitor.ts +344 -0
- package/source/utils/logging/health-monitor/core/scoring.spec.ts +65 -0
- package/source/utils/logging/health-monitor/core/scoring.ts +91 -0
- package/source/utils/logging/health-monitor/index.ts +15 -0
- package/source/utils/logging/health-monitor/instances.ts +48 -0
- package/source/utils/logging/health-monitor/middleware/http-middleware.spec.ts +141 -0
- package/source/utils/logging/health-monitor/middleware/http-middleware.ts +75 -0
- package/source/utils/logging/health-monitor/types.ts +126 -0
- package/source/utils/logging/index.spec.ts +284 -0
- package/source/utils/logging/index.ts +236 -0
- package/source/utils/logging/integration.spec.ts +441 -0
- package/source/utils/logging/log-method-factory.spec.ts +573 -0
- package/source/utils/logging/log-method-factory.ts +233 -0
- package/source/utils/logging/log-query/aggregation/aggregator.spec.ts +277 -0
- package/source/utils/logging/log-query/aggregation/aggregator.ts +159 -0
- package/source/utils/logging/log-query/aggregation/facet-generator.spec.ts +159 -0
- package/source/utils/logging/log-query/aggregation/facet-generator.ts +47 -0
- package/source/utils/logging/log-query/index.ts +23 -0
- package/source/utils/logging/log-query/query/filter-predicates.spec.ts +247 -0
- package/source/utils/logging/log-query/query/filter-predicates.ts +154 -0
- package/source/utils/logging/log-query/query/query-builder.spec.ts +182 -0
- package/source/utils/logging/log-query/query/query-builder.ts +151 -0
- package/source/utils/logging/log-query/query/query-engine.spec.ts +214 -0
- package/source/utils/logging/log-query/query/query-engine.ts +45 -0
- package/source/utils/logging/log-query/storage/circular-buffer.spec.ts +143 -0
- package/source/utils/logging/log-query/storage/circular-buffer.ts +75 -0
- package/source/utils/logging/log-query/storage/index-manager.spec.ts +150 -0
- package/source/utils/logging/log-query/storage/index-manager.ts +71 -0
- package/source/utils/logging/log-query/storage/log-storage.spec.ts +257 -0
- package/source/utils/logging/log-query/storage/log-storage.ts +80 -0
- package/source/utils/logging/log-query/types.ts +163 -0
- package/source/utils/logging/log-query/utils/helpers.spec.ts +263 -0
- package/source/utils/logging/log-query/utils/helpers.ts +72 -0
- package/source/utils/logging/log-query/utils/sorting.spec.ts +182 -0
- package/source/utils/logging/log-query/utils/sorting.ts +61 -0
- package/source/utils/logging/logger-provider.spec.ts +262 -0
- package/source/utils/logging/logger-provider.ts +362 -0
- package/source/utils/logging/performance.spec.ts +209 -0
- package/source/utils/logging/performance.ts +757 -0
- package/source/utils/logging/pino-logger.spec.ts +425 -0
- package/source/utils/logging/pino-logger.ts +514 -0
- package/source/utils/logging/redaction.spec.ts +490 -0
- package/source/utils/logging/redaction.ts +267 -0
- package/source/utils/logging/request-tracker.spec.ts +1198 -0
- package/source/utils/logging/request-tracker.ts +803 -0
- package/source/utils/logging/transports.spec.ts +505 -0
- package/source/utils/logging/transports.ts +305 -0
- package/source/utils/logging/types.ts +216 -0
- package/source/utils/message-builder.spec.ts +179 -0
- package/source/utils/message-builder.ts +101 -0
- package/source/utils/message-queue.tsx +486 -0
- package/source/utils/paste-detection.spec.ts +69 -0
- package/source/utils/paste-detection.ts +124 -0
- package/source/utils/paste-roundtrip.spec.ts +442 -0
- package/source/utils/paste-utils.spec.ts +128 -0
- package/source/utils/paste-utils.ts +52 -0
- package/source/utils/programming-language-helper.spec.ts +74 -0
- package/source/utils/programming-language-helper.ts +32 -0
- package/source/utils/prompt-assembly.spec.ts +221 -0
- package/source/utils/prompt-processor.ts +173 -0
- package/source/utils/tool-args-parser.spec.ts +136 -0
- package/source/utils/tool-args-parser.ts +54 -0
- package/source/utils/tool-cancellation.spec.ts +230 -0
- package/source/utils/tool-cancellation.ts +28 -0
- package/source/utils/tool-result-display.spec.tsx +469 -0
- package/source/utils/tool-result-display.tsx +90 -0
- package/source/utils/update-checker.spec.ts +383 -0
- package/source/utils/update-checker.ts +183 -0
- package/source/wizard/config-wizard.spec.tsx +103 -0
- package/source/wizard/config-wizard.tsx +382 -0
- package/source/wizard/steps/location-step.spec.tsx +186 -0
- package/source/wizard/steps/location-step.tsx +147 -0
- package/source/wizard/steps/mcp-step.spec.tsx +607 -0
- package/source/wizard/steps/mcp-step.tsx +632 -0
- package/source/wizard/steps/provider-step.spec.tsx +342 -0
- package/source/wizard/steps/provider-step.tsx +957 -0
- package/source/wizard/steps/summary-step.spec.tsx +749 -0
- package/source/wizard/steps/summary-step.tsx +228 -0
- package/source/wizard/templates/mcp-templates.spec.ts +613 -0
- package/source/wizard/templates/mcp-templates.ts +570 -0
- package/source/wizard/templates/provider-templates.spec.ts +152 -0
- package/source/wizard/templates/provider-templates.ts +485 -0
- package/source/wizard/utils/fetch-cloud-models.spec.ts +428 -0
- package/source/wizard/utils/fetch-cloud-models.ts +223 -0
- package/source/wizard/utils/fetch-local-models.spec.ts +297 -0
- package/source/wizard/utils/fetch-local-models.ts +192 -0
- package/source/wizard/validation-array.spec.ts +264 -0
- package/source/wizard/validation.spec.ts +373 -0
- package/source/wizard/validation.ts +232 -0
- package/source/app/prompts/main-prompt.md +0 -122
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PASTE_CHUNK_BASE_WINDOW_MS,
|
|
3
|
+
PASTE_CHUNK_MAX_WINDOW_MS,
|
|
4
|
+
PASTE_LARGE_CONTENT_THRESHOLD_CHARS,
|
|
5
|
+
PASTE_RAPID_DETECTION_MS,
|
|
6
|
+
} from '@/constants';
|
|
7
|
+
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
|
8
|
+
import {InputState, PlaceholderType} from '../types/hooks';
|
|
9
|
+
import {handleAtomicDeletion} from '../utils/atomic-deletion';
|
|
10
|
+
import {PasteDetector} from '../utils/paste-detection';
|
|
11
|
+
import {handlePaste} from '../utils/paste-utils';
|
|
12
|
+
|
|
13
|
+
// Scales the paste window size based on content length.
|
|
14
|
+
// Prevents truncation on slow terminals while keeping small pastes snappy
|
|
15
|
+
function getDynamicPasteWindow(contentLength: number): number {
|
|
16
|
+
// Add ~1ms buffer per 10 chars, capped at max window
|
|
17
|
+
const dynamicExtension = Math.floor(contentLength / 10);
|
|
18
|
+
return Math.min(
|
|
19
|
+
PASTE_CHUNK_BASE_WINDOW_MS + dynamicExtension,
|
|
20
|
+
PASTE_CHUNK_MAX_WINDOW_MS,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Helper functions
|
|
25
|
+
function createEmptyInputState(): InputState {
|
|
26
|
+
return {
|
|
27
|
+
displayValue: '',
|
|
28
|
+
placeholderContent: {},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function useInputState() {
|
|
33
|
+
// Core state following the spec
|
|
34
|
+
const [currentState, setCurrentState] = useState<InputState>(
|
|
35
|
+
createEmptyInputState(),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const [undoStack, setUndoStack] = useState<InputState[]>([]);
|
|
39
|
+
const [redoStack, setRedoStack] = useState<InputState[]>([]);
|
|
40
|
+
|
|
41
|
+
// Legacy compatibility - these are derived from currentState
|
|
42
|
+
const [historyIndex, setHistoryIndex] = useState(-1);
|
|
43
|
+
const [_hasLargeContent, setHasLargeContent] = useState(false);
|
|
44
|
+
const [originalInput, setOriginalInput] = useState('');
|
|
45
|
+
|
|
46
|
+
// Paste detection
|
|
47
|
+
const pasteDetectorRef = useRef(new PasteDetector());
|
|
48
|
+
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
49
|
+
|
|
50
|
+
// Track recent paste for chunked paste handling (VS Code terminal issue)
|
|
51
|
+
const lastPasteTimeRef = useRef<number>(0);
|
|
52
|
+
const lastPasteIdRef = useRef<string | null>(null);
|
|
53
|
+
|
|
54
|
+
// Cached line count for performance
|
|
55
|
+
const [cachedLineCount, setCachedLineCount] = useState(1);
|
|
56
|
+
|
|
57
|
+
// Helper to push current state to undo stack
|
|
58
|
+
const pushToUndoStack = useCallback(
|
|
59
|
+
(newState: InputState) => {
|
|
60
|
+
setUndoStack(prev => [...prev, currentState]);
|
|
61
|
+
setRedoStack([]); // Clear redo stack on new action
|
|
62
|
+
setCurrentState(newState);
|
|
63
|
+
},
|
|
64
|
+
[currentState],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Update input with paste detection and atomic deletion
|
|
68
|
+
const updateInput = useCallback(
|
|
69
|
+
(newInput: string) => {
|
|
70
|
+
// First, check for atomic deletion (placeholder removal)
|
|
71
|
+
const atomicDeletionResult = handleAtomicDeletion(currentState, newInput);
|
|
72
|
+
if (atomicDeletionResult) {
|
|
73
|
+
// Atomic deletion occurred - apply it
|
|
74
|
+
pushToUndoStack(atomicDeletionResult);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const timeSinceLastPaste = now - lastPasteTimeRef.current;
|
|
80
|
+
|
|
81
|
+
// Check if this might be a continuation of a recent paste (chunked paste in VS Code)
|
|
82
|
+
const existingPlaceholder = lastPasteIdRef.current
|
|
83
|
+
? currentState.placeholderContent[lastPasteIdRef.current]
|
|
84
|
+
: null;
|
|
85
|
+
const dynamicWindow = existingPlaceholder
|
|
86
|
+
? getDynamicPasteWindow(existingPlaceholder.content.length)
|
|
87
|
+
: PASTE_CHUNK_BASE_WINDOW_MS;
|
|
88
|
+
|
|
89
|
+
if (
|
|
90
|
+
lastPasteIdRef.current &&
|
|
91
|
+
timeSinceLastPaste < dynamicWindow &&
|
|
92
|
+
existingPlaceholder
|
|
93
|
+
) {
|
|
94
|
+
// This looks like a chunked paste continuation
|
|
95
|
+
// Extract the new text that was added (should be at the end)
|
|
96
|
+
const placeholder =
|
|
97
|
+
currentState.placeholderContent[lastPasteIdRef.current];
|
|
98
|
+
const expectedLength = currentState.displayValue.length;
|
|
99
|
+
const addedChunk = newInput.slice(expectedLength);
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
addedChunk.length > 0 &&
|
|
103
|
+
placeholder.type === PlaceholderType.PASTE
|
|
104
|
+
) {
|
|
105
|
+
// Merge the new chunk into the existing paste placeholder
|
|
106
|
+
const updatedContent = placeholder.content + addedChunk;
|
|
107
|
+
const oldPlaceholder = placeholder.displayText;
|
|
108
|
+
const newPlaceholder = `[Paste #${lastPasteIdRef.current}: ${updatedContent.length} chars]`;
|
|
109
|
+
|
|
110
|
+
const updatedPlaceholderContent = {
|
|
111
|
+
...currentState.placeholderContent,
|
|
112
|
+
[lastPasteIdRef.current]: {
|
|
113
|
+
...placeholder,
|
|
114
|
+
content: updatedContent,
|
|
115
|
+
originalSize: updatedContent.length,
|
|
116
|
+
displayText: newPlaceholder,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Replace old placeholder with updated one in display value
|
|
121
|
+
const newDisplayValue = currentState.displayValue.replace(
|
|
122
|
+
oldPlaceholder,
|
|
123
|
+
newPlaceholder,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
pushToUndoStack({
|
|
127
|
+
displayValue: newDisplayValue,
|
|
128
|
+
placeholderContent: updatedPlaceholderContent,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Update paste detector to the new display value
|
|
132
|
+
pasteDetectorRef.current.updateState(newDisplayValue);
|
|
133
|
+
lastPasteTimeRef.current = now; // Extend the window
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Then detect if this might be a paste
|
|
139
|
+
const detection = pasteDetectorRef.current.detectPaste(newInput);
|
|
140
|
+
|
|
141
|
+
if (detection.isPaste && detection.addedText.length > 0) {
|
|
142
|
+
// If we have an active paste within a short window (even if state hasn't fully updated),
|
|
143
|
+
// treat this as a continuation to prevent duplicate placeholders
|
|
144
|
+
const isVeryRecentPaste = timeSinceLastPaste < PASTE_RAPID_DETECTION_MS;
|
|
145
|
+
|
|
146
|
+
const activePasteId = lastPasteIdRef.current;
|
|
147
|
+
const activePlaceholder = activePasteId
|
|
148
|
+
? currentState.placeholderContent[activePasteId]
|
|
149
|
+
: null;
|
|
150
|
+
const activeWindow = activePlaceholder
|
|
151
|
+
? getDynamicPasteWindow(activePlaceholder.content.length)
|
|
152
|
+
: PASTE_CHUNK_BASE_WINDOW_MS;
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
activePasteId &&
|
|
156
|
+
(isVeryRecentPaste ||
|
|
157
|
+
(timeSinceLastPaste < activeWindow && activePlaceholder))
|
|
158
|
+
) {
|
|
159
|
+
// If we don't have the placeholder in state yet, just update detector and skip
|
|
160
|
+
// This happens when multiple detections fire before React updates state
|
|
161
|
+
const placeholder = currentState.placeholderContent[activePasteId];
|
|
162
|
+
if (!placeholder) {
|
|
163
|
+
// Skip duplicate early detection
|
|
164
|
+
pasteDetectorRef.current.updateState(newInput);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Treat as chunked continuation
|
|
169
|
+
if (placeholder.type === PlaceholderType.PASTE) {
|
|
170
|
+
const updatedContent = placeholder.content + detection.addedText;
|
|
171
|
+
const oldPlaceholder = placeholder.displayText;
|
|
172
|
+
const newPlaceholder = `[Paste #${activePasteId}: ${updatedContent.length} chars]`;
|
|
173
|
+
|
|
174
|
+
const updatedPlaceholderContent = {
|
|
175
|
+
...currentState.placeholderContent,
|
|
176
|
+
[activePasteId]: {
|
|
177
|
+
...placeholder,
|
|
178
|
+
content: updatedContent,
|
|
179
|
+
originalSize: updatedContent.length,
|
|
180
|
+
displayText: newPlaceholder,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const newDisplayValue = currentState.displayValue.replace(
|
|
185
|
+
oldPlaceholder,
|
|
186
|
+
newPlaceholder,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
pushToUndoStack({
|
|
190
|
+
displayValue: newDisplayValue,
|
|
191
|
+
placeholderContent: updatedPlaceholderContent,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
pasteDetectorRef.current.updateState(newDisplayValue);
|
|
195
|
+
lastPasteTimeRef.current = now;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Try to handle as paste (new paste)
|
|
201
|
+
const pasteResult = handlePaste(
|
|
202
|
+
detection.addedText,
|
|
203
|
+
currentState.displayValue,
|
|
204
|
+
currentState.placeholderContent,
|
|
205
|
+
detection.method as 'rate' | 'size' | 'multiline',
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
if (pasteResult) {
|
|
209
|
+
// Large paste detected - create placeholder
|
|
210
|
+
pushToUndoStack(pasteResult);
|
|
211
|
+
// Update paste detector state to match the new display value (with placeholder)
|
|
212
|
+
// This prevents detection confusion on subsequent pastes
|
|
213
|
+
pasteDetectorRef.current.updateState(pasteResult.displayValue);
|
|
214
|
+
|
|
215
|
+
// Track this paste for potential chunked continuation
|
|
216
|
+
const pasteId = Object.keys(pasteResult.placeholderContent).find(
|
|
217
|
+
id =>
|
|
218
|
+
!currentState.placeholderContent[id] &&
|
|
219
|
+
pasteResult.placeholderContent[id].type === PlaceholderType.PASTE,
|
|
220
|
+
);
|
|
221
|
+
if (pasteId) {
|
|
222
|
+
lastPasteIdRef.current = pasteId;
|
|
223
|
+
lastPasteTimeRef.current = now;
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
// Small paste - treat as normal input
|
|
227
|
+
pushToUndoStack({
|
|
228
|
+
displayValue: newInput,
|
|
229
|
+
placeholderContent: currentState.placeholderContent,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
// Normal typing
|
|
234
|
+
pushToUndoStack({
|
|
235
|
+
displayValue: newInput,
|
|
236
|
+
placeholderContent: currentState.placeholderContent,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Update derived state
|
|
241
|
+
const immediateLineCount = Math.max(
|
|
242
|
+
1,
|
|
243
|
+
newInput.split(/\r\n|\r|\n/).length,
|
|
244
|
+
);
|
|
245
|
+
setCachedLineCount(immediateLineCount);
|
|
246
|
+
|
|
247
|
+
// Clear any previous debounce timer
|
|
248
|
+
if (debounceTimerRef.current) {
|
|
249
|
+
clearTimeout(debounceTimerRef.current);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
253
|
+
setHasLargeContent(
|
|
254
|
+
newInput.length > PASTE_LARGE_CONTENT_THRESHOLD_CHARS,
|
|
255
|
+
);
|
|
256
|
+
}, 50);
|
|
257
|
+
},
|
|
258
|
+
[currentState, pushToUndoStack],
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// Undo function (Ctrl+_)
|
|
262
|
+
const undo = useCallback(() => {
|
|
263
|
+
if (undoStack.length > 0) {
|
|
264
|
+
const previousState = undoStack[undoStack.length - 1];
|
|
265
|
+
const newUndoStack = undoStack.slice(0, -1);
|
|
266
|
+
|
|
267
|
+
setRedoStack(prev => [...prev, currentState]);
|
|
268
|
+
setUndoStack(newUndoStack);
|
|
269
|
+
setCurrentState(previousState);
|
|
270
|
+
|
|
271
|
+
// Update paste detector state
|
|
272
|
+
pasteDetectorRef.current.updateState(previousState.displayValue);
|
|
273
|
+
}
|
|
274
|
+
}, [undoStack, currentState]);
|
|
275
|
+
|
|
276
|
+
// Redo function (Ctrl+Y)
|
|
277
|
+
const redo = useCallback(() => {
|
|
278
|
+
if (redoStack.length > 0) {
|
|
279
|
+
const nextState = redoStack[redoStack.length - 1];
|
|
280
|
+
const newRedoStack = redoStack.slice(0, -1);
|
|
281
|
+
|
|
282
|
+
setUndoStack(prev => [...prev, currentState]);
|
|
283
|
+
setRedoStack(newRedoStack);
|
|
284
|
+
setCurrentState(nextState);
|
|
285
|
+
|
|
286
|
+
// Update paste detector state
|
|
287
|
+
pasteDetectorRef.current.updateState(nextState.displayValue);
|
|
288
|
+
}
|
|
289
|
+
}, [redoStack, currentState]);
|
|
290
|
+
|
|
291
|
+
// Delete placeholder atomically
|
|
292
|
+
const deletePlaceholder = useCallback(
|
|
293
|
+
(placeholderId: string) => {
|
|
294
|
+
// Sanitize placeholderId to ensure it only contains safe characters
|
|
295
|
+
const sanitizedPlaceholderId = placeholderId.replace(
|
|
296
|
+
/[^a-zA-Z0-9_-]/g,
|
|
297
|
+
'',
|
|
298
|
+
);
|
|
299
|
+
const placeholderPattern = `[Paste #${sanitizedPlaceholderId}: \\d+ chars]`;
|
|
300
|
+
/* nosemgrep */
|
|
301
|
+
const regex = new RegExp(
|
|
302
|
+
placeholderPattern.replace(/[[\]]/g, '\\$&'),
|
|
303
|
+
'g',
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
const newDisplayValue = currentState.displayValue.replace(regex, '');
|
|
307
|
+
const newPlaceholderContent = {...currentState.placeholderContent};
|
|
308
|
+
delete newPlaceholderContent[placeholderId];
|
|
309
|
+
|
|
310
|
+
pushToUndoStack({
|
|
311
|
+
displayValue: newDisplayValue,
|
|
312
|
+
placeholderContent: newPlaceholderContent,
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
[currentState, pushToUndoStack],
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// Reset all state
|
|
319
|
+
const resetInput = useCallback(() => {
|
|
320
|
+
if (debounceTimerRef.current) {
|
|
321
|
+
clearTimeout(debounceTimerRef.current);
|
|
322
|
+
debounceTimerRef.current = null;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
setCurrentState(createEmptyInputState());
|
|
326
|
+
setUndoStack([]);
|
|
327
|
+
setRedoStack([]);
|
|
328
|
+
setHasLargeContent(false);
|
|
329
|
+
setOriginalInput('');
|
|
330
|
+
setHistoryIndex(-1);
|
|
331
|
+
setCachedLineCount(1);
|
|
332
|
+
pasteDetectorRef.current.reset();
|
|
333
|
+
lastPasteTimeRef.current = 0;
|
|
334
|
+
lastPasteIdRef.current = null;
|
|
335
|
+
}, []);
|
|
336
|
+
|
|
337
|
+
// Cleanup on unmount
|
|
338
|
+
useEffect(() => {
|
|
339
|
+
return () => {
|
|
340
|
+
if (debounceTimerRef.current) {
|
|
341
|
+
clearTimeout(debounceTimerRef.current);
|
|
342
|
+
debounceTimerRef.current = null;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}, []);
|
|
346
|
+
|
|
347
|
+
// Set full InputState (for history navigation)
|
|
348
|
+
const setInputState = useCallback((newState: InputState) => {
|
|
349
|
+
setCurrentState(newState);
|
|
350
|
+
pasteDetectorRef.current.updateState(newState.displayValue);
|
|
351
|
+
}, []);
|
|
352
|
+
|
|
353
|
+
// Legacy setters for compatibility
|
|
354
|
+
const setInput = useCallback((newInput: string) => {
|
|
355
|
+
setCurrentState(prev => ({
|
|
356
|
+
...prev,
|
|
357
|
+
displayValue: newInput,
|
|
358
|
+
}));
|
|
359
|
+
pasteDetectorRef.current.updateState(newInput);
|
|
360
|
+
}, []);
|
|
361
|
+
|
|
362
|
+
// Compute legacy pastedContent for backward compatibility
|
|
363
|
+
const legacyPastedContent = useMemo(() => {
|
|
364
|
+
const pastedContent: Record<string, string> = {};
|
|
365
|
+
Object.entries(currentState.placeholderContent).forEach(([id, content]) => {
|
|
366
|
+
if (content.type === PlaceholderType.PASTE) {
|
|
367
|
+
pastedContent[id] = content.content;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
return pastedContent;
|
|
371
|
+
}, [currentState.placeholderContent]);
|
|
372
|
+
|
|
373
|
+
return useMemo(
|
|
374
|
+
() => ({
|
|
375
|
+
// New spec-compliant interface
|
|
376
|
+
currentState,
|
|
377
|
+
undoStack,
|
|
378
|
+
redoStack,
|
|
379
|
+
undo,
|
|
380
|
+
redo,
|
|
381
|
+
deletePlaceholder,
|
|
382
|
+
setInputState,
|
|
383
|
+
|
|
384
|
+
// Legacy interface for compatibility
|
|
385
|
+
input: currentState.displayValue,
|
|
386
|
+
originalInput,
|
|
387
|
+
historyIndex,
|
|
388
|
+
setInput,
|
|
389
|
+
setOriginalInput,
|
|
390
|
+
setHistoryIndex,
|
|
391
|
+
updateInput,
|
|
392
|
+
resetInput,
|
|
393
|
+
cachedLineCount,
|
|
394
|
+
// Computed legacy property for backward compatibility
|
|
395
|
+
pastedContent: legacyPastedContent,
|
|
396
|
+
}),
|
|
397
|
+
[
|
|
398
|
+
currentState,
|
|
399
|
+
undoStack,
|
|
400
|
+
redoStack,
|
|
401
|
+
undo,
|
|
402
|
+
redo,
|
|
403
|
+
deletePlaceholder,
|
|
404
|
+
setInputState,
|
|
405
|
+
originalInput,
|
|
406
|
+
historyIndex,
|
|
407
|
+
setInput,
|
|
408
|
+
updateInput,
|
|
409
|
+
resetInput,
|
|
410
|
+
cachedLineCount,
|
|
411
|
+
legacyPastedContent,
|
|
412
|
+
],
|
|
413
|
+
);
|
|
414
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { createLLMClient } from '@/client-factory';
|
|
2
|
+
import { ErrorMessage, SuccessMessage } from '@/components/message-box';
|
|
3
|
+
import { reloadAppConfig } from '@/config/index';
|
|
4
|
+
import {
|
|
5
|
+
loadPreferences,
|
|
6
|
+
savePreferences,
|
|
7
|
+
updateLastUsed,
|
|
8
|
+
} from '@/config/preferences';
|
|
9
|
+
import { getToolManager } from '@/message-handler';
|
|
10
|
+
import { LLMClient, Message } from '@/types/core';
|
|
11
|
+
import type { ThemePreset } from '@/types/ui';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
|
|
14
|
+
interface UseModeHandlersProps {
|
|
15
|
+
client: LLMClient | null;
|
|
16
|
+
currentModel: string;
|
|
17
|
+
currentProvider: string;
|
|
18
|
+
currentTheme: ThemePreset;
|
|
19
|
+
setClient: (client: LLMClient | null) => void;
|
|
20
|
+
setCurrentModel: (model: string) => void;
|
|
21
|
+
setCurrentProvider: (provider: string) => void;
|
|
22
|
+
setCurrentTheme: (theme: ThemePreset) => void;
|
|
23
|
+
setMessages: (messages: Message[]) => void;
|
|
24
|
+
setIsModelSelectionMode: (mode: boolean) => void;
|
|
25
|
+
setIsProviderSelectionMode: (mode: boolean) => void;
|
|
26
|
+
setIsThemeSelectionMode: (mode: boolean) => void;
|
|
27
|
+
setIsModelDatabaseMode: (mode: boolean) => void;
|
|
28
|
+
setIsConfigWizardMode: (mode: boolean) => void;
|
|
29
|
+
addToChatQueue: (component: React.ReactNode) => void;
|
|
30
|
+
componentKeyCounter: number;
|
|
31
|
+
reinitializeMCPServers: (
|
|
32
|
+
toolManager: import('@/tools/tool-manager').ToolManager,
|
|
33
|
+
) => Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function useModeHandlers({
|
|
37
|
+
client,
|
|
38
|
+
currentModel,
|
|
39
|
+
currentProvider,
|
|
40
|
+
currentTheme: _currentTheme,
|
|
41
|
+
setClient,
|
|
42
|
+
setCurrentModel,
|
|
43
|
+
setCurrentProvider,
|
|
44
|
+
setCurrentTheme,
|
|
45
|
+
setMessages,
|
|
46
|
+
setIsModelSelectionMode,
|
|
47
|
+
setIsProviderSelectionMode,
|
|
48
|
+
setIsThemeSelectionMode,
|
|
49
|
+
setIsModelDatabaseMode,
|
|
50
|
+
setIsConfigWizardMode,
|
|
51
|
+
addToChatQueue,
|
|
52
|
+
componentKeyCounter,
|
|
53
|
+
reinitializeMCPServers,
|
|
54
|
+
}: UseModeHandlersProps) {
|
|
55
|
+
// Helper function to enter model selection mode
|
|
56
|
+
const enterModelSelectionMode = () => {
|
|
57
|
+
setIsModelSelectionMode(true);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Helper function to enter provider selection mode
|
|
61
|
+
const enterProviderSelectionMode = () => {
|
|
62
|
+
setIsProviderSelectionMode(true);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Handle model selection
|
|
66
|
+
const handleModelSelect = async (selectedModel: string) => {
|
|
67
|
+
if (client && selectedModel !== currentModel) {
|
|
68
|
+
client.setModel(selectedModel);
|
|
69
|
+
setCurrentModel(selectedModel);
|
|
70
|
+
|
|
71
|
+
// Clear message history when switching models
|
|
72
|
+
setMessages([]);
|
|
73
|
+
await client.clearContext();
|
|
74
|
+
|
|
75
|
+
// Update preferences
|
|
76
|
+
updateLastUsed(currentProvider, selectedModel);
|
|
77
|
+
|
|
78
|
+
// Add success message to chat queue
|
|
79
|
+
addToChatQueue(
|
|
80
|
+
<SuccessMessage
|
|
81
|
+
key={`model-changed-${componentKeyCounter}`}
|
|
82
|
+
message={`Model changed to: ${selectedModel}. Chat history cleared.`}
|
|
83
|
+
hideBox={true}
|
|
84
|
+
/>,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
setIsModelSelectionMode(false);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Handle model selection cancel
|
|
91
|
+
const handleModelSelectionCancel = () => {
|
|
92
|
+
setIsModelSelectionMode(false);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Handle provider selection
|
|
96
|
+
const handleProviderSelect = async (selectedProvider: string) => {
|
|
97
|
+
if (selectedProvider !== currentProvider) {
|
|
98
|
+
try {
|
|
99
|
+
// Create new client for the selected provider
|
|
100
|
+
const { client: newClient, actualProvider } =
|
|
101
|
+
await createLLMClient(selectedProvider);
|
|
102
|
+
|
|
103
|
+
// Check if we got the provider we requested
|
|
104
|
+
if (actualProvider !== selectedProvider) {
|
|
105
|
+
// Provider was forced to a different one (likely due to missing config)
|
|
106
|
+
addToChatQueue(
|
|
107
|
+
<ErrorMessage
|
|
108
|
+
key={`provider-forced-${componentKeyCounter}`}
|
|
109
|
+
message={`${selectedProvider} is not available. Please ensure it's properly configured in coder.config.json.`}
|
|
110
|
+
hideBox={true}
|
|
111
|
+
/>,
|
|
112
|
+
);
|
|
113
|
+
return; // Don't change anything
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setClient(newClient);
|
|
117
|
+
setCurrentProvider(actualProvider);
|
|
118
|
+
|
|
119
|
+
// Set the model from the new client
|
|
120
|
+
const newModel = newClient.getCurrentModel();
|
|
121
|
+
setCurrentModel(newModel);
|
|
122
|
+
|
|
123
|
+
// Clear message history when switching providers
|
|
124
|
+
setMessages([]);
|
|
125
|
+
await newClient.clearContext();
|
|
126
|
+
|
|
127
|
+
// Update preferences - use the actualProvider (which is what was successfully created)
|
|
128
|
+
updateLastUsed(actualProvider, newModel);
|
|
129
|
+
|
|
130
|
+
// Add success message to chat queue
|
|
131
|
+
addToChatQueue(
|
|
132
|
+
<SuccessMessage
|
|
133
|
+
key={`provider-changed-${componentKeyCounter}`}
|
|
134
|
+
message={`Provider changed to: ${actualProvider}, model: ${newModel}. Chat history cleared.`}
|
|
135
|
+
hideBox={true}
|
|
136
|
+
/>,
|
|
137
|
+
);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
// Add error message if provider change fails
|
|
140
|
+
addToChatQueue(
|
|
141
|
+
<ErrorMessage
|
|
142
|
+
key={`provider-error-${componentKeyCounter}`}
|
|
143
|
+
message={`Failed to change provider to ${selectedProvider}: ${String(
|
|
144
|
+
error,
|
|
145
|
+
)}`}
|
|
146
|
+
hideBox={true}
|
|
147
|
+
/>,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
setIsProviderSelectionMode(false);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Handle provider selection cancel
|
|
155
|
+
const handleProviderSelectionCancel = () => {
|
|
156
|
+
setIsProviderSelectionMode(false);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Helper function to enter theme selection mode
|
|
160
|
+
const enterThemeSelectionMode = () => {
|
|
161
|
+
setIsThemeSelectionMode(true);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Handle theme selection
|
|
165
|
+
const handleThemeSelect = (selectedTheme: ThemePreset) => {
|
|
166
|
+
const preferences = loadPreferences();
|
|
167
|
+
preferences.selectedTheme = selectedTheme;
|
|
168
|
+
savePreferences(preferences);
|
|
169
|
+
|
|
170
|
+
// Update the theme state immediately for real-time switching
|
|
171
|
+
setCurrentTheme(selectedTheme);
|
|
172
|
+
|
|
173
|
+
// Add success message to chat queue
|
|
174
|
+
addToChatQueue(
|
|
175
|
+
<SuccessMessage
|
|
176
|
+
key={`theme-changed-${componentKeyCounter}`}
|
|
177
|
+
message={`Theme changed to: ${selectedTheme}.`}
|
|
178
|
+
hideBox={true}
|
|
179
|
+
/>,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
setIsThemeSelectionMode(false);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Handle theme selection cancel
|
|
186
|
+
const handleThemeSelectionCancel = () => {
|
|
187
|
+
setIsThemeSelectionMode(false);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Helper function to enter model database mode
|
|
191
|
+
const enterModelDatabaseMode = () => {
|
|
192
|
+
setIsModelDatabaseMode(true);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// Handle model database cancel
|
|
196
|
+
const handleModelDatabaseCancel = () => {
|
|
197
|
+
setIsModelDatabaseMode(false);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Helper function to enter config wizard mode
|
|
201
|
+
const enterConfigWizardMode = () => {
|
|
202
|
+
setIsConfigWizardMode(true);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Handle config wizard cancel/complete
|
|
206
|
+
const handleConfigWizardComplete = async (configPath?: string) => {
|
|
207
|
+
setIsConfigWizardMode(false);
|
|
208
|
+
if (configPath) {
|
|
209
|
+
addToChatQueue(
|
|
210
|
+
<SuccessMessage
|
|
211
|
+
key={`config-wizard-complete-${componentKeyCounter}`}
|
|
212
|
+
message={`Configuration saved to: ${configPath}.`}
|
|
213
|
+
hideBox={true}
|
|
214
|
+
/>,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Reload the app configuration to pick up the newly saved config
|
|
218
|
+
reloadAppConfig();
|
|
219
|
+
|
|
220
|
+
// Reinitialize client with new configuration
|
|
221
|
+
try {
|
|
222
|
+
const preferences = loadPreferences();
|
|
223
|
+
const { client: newClient, actualProvider } = await createLLMClient(
|
|
224
|
+
preferences.lastProvider,
|
|
225
|
+
);
|
|
226
|
+
setClient(newClient);
|
|
227
|
+
setCurrentProvider(actualProvider);
|
|
228
|
+
|
|
229
|
+
const newModel = newClient.getCurrentModel();
|
|
230
|
+
setCurrentModel(newModel);
|
|
231
|
+
|
|
232
|
+
// Clear message history when switching providers
|
|
233
|
+
setMessages([]);
|
|
234
|
+
await newClient.clearContext();
|
|
235
|
+
|
|
236
|
+
// Reinitialize MCP servers with the new configuration
|
|
237
|
+
const toolManager = getToolManager();
|
|
238
|
+
if (toolManager) {
|
|
239
|
+
try {
|
|
240
|
+
await reinitializeMCPServers(toolManager);
|
|
241
|
+
addToChatQueue(
|
|
242
|
+
<SuccessMessage
|
|
243
|
+
key={`mcp-reinit-${componentKeyCounter}`}
|
|
244
|
+
message="MCP servers reinitialized with new configuration."
|
|
245
|
+
hideBox={true}
|
|
246
|
+
/>,
|
|
247
|
+
);
|
|
248
|
+
} catch (mcpError) {
|
|
249
|
+
addToChatQueue(
|
|
250
|
+
<ErrorMessage
|
|
251
|
+
key={`mcp-reinit-error-${componentKeyCounter}`}
|
|
252
|
+
message={`Failed to reinitialize MCP servers: ${String(
|
|
253
|
+
mcpError,
|
|
254
|
+
)}`}
|
|
255
|
+
hideBox={true}
|
|
256
|
+
/>,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
addToChatQueue(
|
|
262
|
+
<SuccessMessage
|
|
263
|
+
key={`config-init-${componentKeyCounter}`}
|
|
264
|
+
message={`Ready! Using provider: ${actualProvider}, model: ${newModel}`}
|
|
265
|
+
hideBox={true}
|
|
266
|
+
/>,
|
|
267
|
+
);
|
|
268
|
+
} catch (error) {
|
|
269
|
+
addToChatQueue(
|
|
270
|
+
<ErrorMessage
|
|
271
|
+
key={`config-init-error-${componentKeyCounter}`}
|
|
272
|
+
message={`Failed to initialize with new configuration: ${String(
|
|
273
|
+
error,
|
|
274
|
+
)}`}
|
|
275
|
+
hideBox={true}
|
|
276
|
+
/>,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const handleConfigWizardCancel = () => {
|
|
283
|
+
setIsConfigWizardMode(false);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
enterModelSelectionMode,
|
|
288
|
+
enterProviderSelectionMode,
|
|
289
|
+
enterThemeSelectionMode,
|
|
290
|
+
enterModelDatabaseMode,
|
|
291
|
+
enterConfigWizardMode,
|
|
292
|
+
handleModelSelect,
|
|
293
|
+
handleModelSelectionCancel,
|
|
294
|
+
handleProviderSelect,
|
|
295
|
+
handleProviderSelectionCancel,
|
|
296
|
+
handleThemeSelect,
|
|
297
|
+
handleThemeSelectionCancel,
|
|
298
|
+
handleModelDatabaseCancel,
|
|
299
|
+
handleConfigWizardComplete,
|
|
300
|
+
handleConfigWizardCancel,
|
|
301
|
+
};
|
|
302
|
+
}
|