centaurus-cli 3.0.1 → 3.1.0
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/dist/ai/types.js +0 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/cli-adapter.js +5047 -5158
- package/dist/cli-adapter.js.map +1 -1
- package/dist/commands/CommandParser.js +372 -315
- package/dist/commands/CommandParser.js.map +1 -1
- package/dist/config/build-config.js +11 -42
- package/dist/config/build-config.js.map +1 -1
- package/dist/config/defaultConfig.js +94 -82
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/manager.js +144 -160
- package/dist/config/manager.js.map +1 -1
- package/dist/config/mcp-config-manager.js +411 -364
- package/dist/config/mcp-config-manager.js.map +1 -1
- package/dist/config/models.js +118 -185
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +186 -184
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +33 -26
- package/dist/config/types.js.map +1 -1
- package/dist/context/command-detector.js +63 -67
- package/dist/context/command-detector.js.map +1 -1
- package/dist/context/context-manager.js +533 -518
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/handlers/docker-handler.js +518 -576
- package/dist/context/handlers/docker-handler.js.map +1 -1
- package/dist/context/handlers/ssh-handler.js +1050 -1109
- package/dist/context/handlers/ssh-handler.js.map +1 -1
- package/dist/context/handlers/wsl-handler.js +558 -630
- package/dist/context/handlers/wsl-handler.js.map +1 -1
- package/dist/context/index.js +42 -6
- package/dist/context/index.js.map +1 -1
- package/dist/context/subshell-handler.js +0 -4
- package/dist/context/subshell-handler.js.map +1 -1
- package/dist/context/types.js +20 -31
- package/dist/context/types.js.map +1 -1
- package/dist/hooks/useConnectivity.js +13 -10
- package/dist/hooks/useConnectivity.js.map +1 -1
- package/dist/hooks/useTerminalDimensions.js +67 -79
- package/dist/hooks/useTerminalDimensions.js.map +1 -1
- package/dist/index.js +228 -251
- package/dist/index.js.map +1 -1
- package/dist/mcp/mcp-command-handler.js +297 -260
- package/dist/mcp/mcp-command-handler.js.map +1 -1
- package/dist/mcp/mcp-server-manager.js +139 -155
- package/dist/mcp/mcp-server-manager.js.map +1 -1
- package/dist/mcp/mcp-tool-wrapper.js +74 -94
- package/dist/mcp/mcp-tool-wrapper.js.map +1 -1
- package/dist/services/ai-autocomplete-agent.js +169 -181
- package/dist/services/ai-autocomplete-agent.js.map +1 -1
- package/dist/services/ai-context-injector.js +180 -93
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/ai-service-client.js +513 -456
- package/dist/services/ai-service-client.js.map +1 -1
- package/dist/services/api-client.js +443 -441
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/auth-handler.js +162 -198
- package/dist/services/auth-handler.js.map +1 -1
- package/dist/services/background-task-manager.js +258 -282
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/checkpoint-manager.js +1526 -1512
- package/dist/services/checkpoint-manager.js.map +1 -1
- package/dist/services/clipboard-service.js +151 -200
- package/dist/services/clipboard-service.js.map +1 -1
- package/dist/services/connectivity-manager.js +63 -65
- package/dist/services/connectivity-manager.js.map +1 -1
- package/dist/services/conversation-manager.js +118 -121
- package/dist/services/conversation-manager.js.map +1 -1
- package/dist/services/environment-context-injector.js +160 -187
- package/dist/services/environment-context-injector.js.map +1 -1
- package/dist/services/fast-context-agent.js +203 -243
- package/dist/services/fast-context-agent.js.map +1 -1
- package/dist/services/input-detection-agent.js +190 -202
- package/dist/services/input-detection-agent.js.map +1 -1
- package/dist/services/input-requirement-detector.js +155 -189
- package/dist/services/input-requirement-detector.js.map +1 -1
- package/dist/services/local-chat-storage.js +342 -365
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/monitored-shell-manager.js +225 -233
- package/dist/services/monitored-shell-manager.js.map +1 -1
- package/dist/services/ollama-service.js +293 -310
- package/dist/services/ollama-service.js.map +1 -1
- package/dist/services/rules-storage.js +142 -0
- package/dist/services/rules-storage.js.map +1 -0
- package/dist/services/session-quota-manager.js +219 -235
- package/dist/services/session-quota-manager.js.map +1 -1
- package/dist/services/shell-input-agent.js +299 -334
- package/dist/services/shell-input-agent.js.map +1 -1
- package/dist/services/sub-agent-manager.js +459 -501
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +133 -183
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/services/workflow-storage.js +202 -217
- package/dist/services/workflow-storage.js.map +1 -1
- package/dist/test-ssh-handler.js +148 -193
- package/dist/test-ssh-handler.js.map +1 -1
- package/dist/tools/add-mcp.js +161 -0
- package/dist/tools/add-mcp.js.map +1 -0
- package/dist/tools/background-command.js +240 -273
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +447 -440
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/create-image.js +172 -202
- package/dist/tools/create-image.js.map +1 -1
- package/dist/tools/enter-remote-session.js +169 -215
- package/dist/tools/enter-remote-session.js.map +1 -1
- package/dist/tools/fast-context.js +60 -67
- package/dist/tools/fast-context.js.map +1 -1
- package/dist/tools/file-ops.js +601 -572
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/find-files.js +262 -303
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/get-diff.js +423 -406
- package/dist/tools/get-diff.js.map +1 -1
- package/dist/tools/grep-search.js +966 -948
- package/dist/tools/grep-search.js.map +1 -1
- package/dist/tools/inspect-symbol.js +308 -323
- package/dist/tools/inspect-symbol.js.map +1 -1
- package/dist/tools/plan-mode.js +459 -503
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/read-binary-file.js +160 -190
- package/dist/tools/read-binary-file.js.map +1 -1
- package/dist/tools/registry.js +100 -84
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/reproduce_issue.js +170 -151
- package/dist/tools/reproduce_issue.js.map +1 -1
- package/dist/tools/sub-agent.js +223 -228
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/task-complete.js +28 -27
- package/dist/tools/task-complete.js.map +1 -1
- package/dist/tools/types.js +0 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/validation.js +96 -118
- package/dist/tools/validation.js.map +1 -1
- package/dist/tools/web-search.js +194 -194
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools/workflow-tool.js +77 -82
- package/dist/tools/workflow-tool.js.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/rule.js +1 -0
- package/dist/types/rule.js.map +1 -0
- package/dist/types/workflow.js +0 -7
- package/dist/types/workflow.js.map +1 -1
- package/dist/ui/components/AgentTimer.js +24 -25
- package/dist/ui/components/AgentTimer.js.map +1 -1
- package/dist/ui/components/App.js +3266 -3263
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +22 -34
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +30 -24
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/Breadcrumbs.js +53 -82
- package/dist/ui/components/Breadcrumbs.js.map +1 -1
- package/dist/ui/components/CircularSelectInput.js +59 -67
- package/dist/ui/components/CircularSelectInput.js.map +1 -1
- package/dist/ui/components/ClipboardFileAutocomplete.js +78 -39
- package/dist/ui/components/ClipboardFileAutocomplete.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +24 -42
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/ConfigViewer.js +18 -25
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +49 -71
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +32 -83
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/ContextWindowIndicator.js +34 -49
- package/dist/ui/components/ContextWindowIndicator.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +104 -106
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +68 -121
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/ErrorBoundary.js +40 -48
- package/dist/ui/components/ErrorBoundary.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js +29 -60
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileOperation.js +34 -29
- package/dist/ui/components/FileOperation.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +55 -25
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/FontRecommendation.js.map +1 -1
- package/dist/ui/components/GitDiffBreadcrumb.js +29 -0
- package/dist/ui/components/GitDiffBreadcrumb.js.map +1 -0
- package/dist/ui/components/InputBox.js +1620 -2150
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +234 -352
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +34 -35
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +22 -25
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +40 -51
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MCPListScreen.js +40 -48
- package/dist/ui/components/MCPListScreen.js.map +1 -1
- package/dist/ui/components/MCPServerListScreen.js +49 -56
- package/dist/ui/components/MCPServerListScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +69 -96
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageBox.js +66 -48
- package/dist/ui/components/MessageBox.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +150 -142
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/MonitorModeAIPanel.js +46 -65
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/MultiLineInput.js +243 -277
- package/dist/ui/components/MultiLineInput.js.map +1 -1
- package/dist/ui/components/PasswordPrompt.js +37 -18
- package/dist/ui/components/PasswordPrompt.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +27 -38
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanReviewScreen.js +46 -50
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +81 -0
- package/dist/ui/components/RulesEditorScreen.js.map +1 -0
- package/dist/ui/components/SelectPrompt.js +19 -8
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/ShimmerText.js +44 -0
- package/dist/ui/components/ShimmerText.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +49 -22
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +56 -87
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +116 -99
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/TaskCompletedMessage.js +28 -23
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +44 -70
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/ThinkingDisplay.js +44 -41
- package/dist/ui/components/ThinkingDisplay.js.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.js +772 -1326
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +53 -84
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/ToolResult.js +22 -15
- package/dist/ui/components/ToolResult.js.map +1 -1
- package/dist/ui/components/VersionUpdatePrompt.js +88 -120
- package/dist/ui/components/VersionUpdatePrompt.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +176 -26
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +94 -161
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/utils/ansi-encoder.js +30 -61
- package/dist/utils/ansi-encoder.js.map +1 -1
- package/dist/utils/chat-formatter.js +327 -305
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/command-history.js +152 -174
- package/dist/utils/command-history.js.map +1 -1
- package/dist/utils/context-sanitizer.js +49 -112
- package/dist/utils/context-sanitizer.js.map +1 -1
- package/dist/utils/conversation-logger.js +292 -324
- package/dist/utils/conversation-logger.js.map +1 -1
- package/dist/utils/custom-commands-manager.js +126 -131
- package/dist/utils/custom-commands-manager.js.map +1 -1
- package/dist/utils/editor-utils.js +732 -837
- package/dist/utils/editor-utils.js.map +1 -1
- package/dist/utils/file.js +174 -213
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/git-stats.js +169 -0
- package/dist/utils/git-stats.js.map +1 -0
- package/dist/utils/input-classifier.js +960 -482
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/logger.js +48 -73
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/markdown-parser.js +277 -310
- package/dist/utils/markdown-parser.js.map +1 -1
- package/dist/utils/rule-reference-resolver.js +54 -0
- package/dist/utils/rule-reference-resolver.js.map +1 -0
- package/dist/utils/shell.js +144 -156
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/state.js +23 -22
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/syntax-checker.js +279 -327
- package/dist/utils/syntax-checker.js.map +1 -1
- package/dist/utils/terminal-output.js +199 -302
- package/dist/utils/terminal-output.js.map +1 -1
- package/dist/utils/text-clipboard.js +47 -70
- package/dist/utils/text-clipboard.js.map +1 -1
- package/dist/utils/unicode-sanitizer.js +134 -197
- package/dist/utils/unicode-sanitizer.js.map +1 -1
- package/dist/utils/version-checker.js +46 -56
- package/dist/utils/version-checker.js.map +1 -1
- package/package.json +6 -4
- package/dist/ai/types.d.ts +0 -20
- package/dist/ai/types.d.ts.map +0 -1
- package/dist/cli-adapter.d.ts +0 -514
- package/dist/cli-adapter.d.ts.map +0 -1
- package/dist/commands/CommandParser.d.ts +0 -27
- package/dist/commands/CommandParser.d.ts.map +0 -1
- package/dist/config/build-config.d.ts +0 -42
- package/dist/config/build-config.d.ts.map +0 -1
- package/dist/config/defaultConfig.d.ts +0 -79
- package/dist/config/defaultConfig.d.ts.map +0 -1
- package/dist/config/manager.d.ts +0 -62
- package/dist/config/manager.d.ts.map +0 -1
- package/dist/config/mcp-config-manager.d.ts +0 -79
- package/dist/config/mcp-config-manager.d.ts.map +0 -1
- package/dist/config/models.d.ts +0 -83
- package/dist/config/models.d.ts.map +0 -1
- package/dist/config/slash-commands.d.ts +0 -23
- package/dist/config/slash-commands.d.ts.map +0 -1
- package/dist/config/types.d.ts +0 -35
- package/dist/config/types.d.ts.map +0 -1
- package/dist/context/command-detector.d.ts +0 -50
- package/dist/context/command-detector.d.ts.map +0 -1
- package/dist/context/context-manager.d.ts +0 -157
- package/dist/context/context-manager.d.ts.map +0 -1
- package/dist/context/handlers/docker-handler.d.ts +0 -130
- package/dist/context/handlers/docker-handler.d.ts.map +0 -1
- package/dist/context/handlers/ssh-handler.d.ts +0 -201
- package/dist/context/handlers/ssh-handler.d.ts.map +0 -1
- package/dist/context/handlers/wsl-handler.d.ts +0 -146
- package/dist/context/handlers/wsl-handler.d.ts.map +0 -1
- package/dist/context/index.d.ts +0 -8
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/subshell-handler.d.ts +0 -165
- package/dist/context/subshell-handler.d.ts.map +0 -1
- package/dist/context/types.d.ts +0 -70
- package/dist/context/types.d.ts.map +0 -1
- package/dist/hooks/useConnectivity.d.ts +0 -2
- package/dist/hooks/useConnectivity.d.ts.map +0 -1
- package/dist/hooks/useTerminalDimensions.d.ts +0 -41
- package/dist/hooks/useTerminalDimensions.d.ts.map +0 -1
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +0 -1
- package/dist/mcp/mcp-command-handler.d.ts +0 -47
- package/dist/mcp/mcp-command-handler.d.ts.map +0 -1
- package/dist/mcp/mcp-server-manager.d.ts +0 -30
- package/dist/mcp/mcp-server-manager.d.ts.map +0 -1
- package/dist/mcp/mcp-tool-wrapper.d.ts +0 -12
- package/dist/mcp/mcp-tool-wrapper.d.ts.map +0 -1
- package/dist/services/ai-autocomplete-agent.d.ts +0 -39
- package/dist/services/ai-autocomplete-agent.d.ts.map +0 -1
- package/dist/services/ai-context-injector.d.ts +0 -41
- package/dist/services/ai-context-injector.d.ts.map +0 -1
- package/dist/services/ai-service-client.d.ts +0 -128
- package/dist/services/ai-service-client.d.ts.map +0 -1
- package/dist/services/api-client.d.ts +0 -353
- package/dist/services/api-client.d.ts.map +0 -1
- package/dist/services/auth-handler.d.ts +0 -30
- package/dist/services/auth-handler.d.ts.map +0 -1
- package/dist/services/background-task-manager.d.ts +0 -114
- package/dist/services/background-task-manager.d.ts.map +0 -1
- package/dist/services/checkpoint-manager.d.ts +0 -204
- package/dist/services/checkpoint-manager.d.ts.map +0 -1
- package/dist/services/clipboard-service.d.ts +0 -37
- package/dist/services/clipboard-service.d.ts.map +0 -1
- package/dist/services/connectivity-manager.d.ts +0 -18
- package/dist/services/connectivity-manager.d.ts.map +0 -1
- package/dist/services/conversation-manager.d.ts +0 -73
- package/dist/services/conversation-manager.d.ts.map +0 -1
- package/dist/services/environment-context-injector.d.ts +0 -69
- package/dist/services/environment-context-injector.d.ts.map +0 -1
- package/dist/services/fast-context-agent.d.ts +0 -12
- package/dist/services/fast-context-agent.d.ts.map +0 -1
- package/dist/services/input-detection-agent.d.ts +0 -40
- package/dist/services/input-detection-agent.d.ts.map +0 -1
- package/dist/services/input-requirement-detector.d.ts +0 -28
- package/dist/services/input-requirement-detector.d.ts.map +0 -1
- package/dist/services/local-chat-storage.d.ts +0 -182
- package/dist/services/local-chat-storage.d.ts.map +0 -1
- package/dist/services/monitored-shell-manager.d.ts +0 -120
- package/dist/services/monitored-shell-manager.d.ts.map +0 -1
- package/dist/services/ollama-service.d.ts +0 -197
- package/dist/services/ollama-service.d.ts.map +0 -1
- package/dist/services/session-quota-manager.d.ts +0 -101
- package/dist/services/session-quota-manager.d.ts.map +0 -1
- package/dist/services/shell-input-agent.d.ts +0 -89
- package/dist/services/shell-input-agent.d.ts.map +0 -1
- package/dist/services/sub-agent-manager.d.ts +0 -140
- package/dist/services/sub-agent-manager.d.ts.map +0 -1
- package/dist/services/warpify-detector.d.ts +0 -43
- package/dist/services/warpify-detector.d.ts.map +0 -1
- package/dist/services/workflow-storage.d.ts +0 -72
- package/dist/services/workflow-storage.d.ts.map +0 -1
- package/dist/test-ssh-handler.d.ts +0 -8
- package/dist/test-ssh-handler.d.ts.map +0 -1
- package/dist/tools/background-command.d.ts +0 -11
- package/dist/tools/background-command.d.ts.map +0 -1
- package/dist/tools/command.d.ts +0 -3
- package/dist/tools/command.d.ts.map +0 -1
- package/dist/tools/create-image.d.ts +0 -10
- package/dist/tools/create-image.d.ts.map +0 -1
- package/dist/tools/enter-remote-session.d.ts +0 -48
- package/dist/tools/enter-remote-session.d.ts.map +0 -1
- package/dist/tools/fast-context.d.ts +0 -3
- package/dist/tools/fast-context.d.ts.map +0 -1
- package/dist/tools/file-ops.d.ts +0 -7
- package/dist/tools/file-ops.d.ts.map +0 -1
- package/dist/tools/find-files.d.ts +0 -49
- package/dist/tools/find-files.d.ts.map +0 -1
- package/dist/tools/get-diff.d.ts +0 -14
- package/dist/tools/get-diff.d.ts.map +0 -1
- package/dist/tools/grep-search.d.ts +0 -155
- package/dist/tools/grep-search.d.ts.map +0 -1
- package/dist/tools/inspect-symbol.d.ts +0 -32
- package/dist/tools/inspect-symbol.d.ts.map +0 -1
- package/dist/tools/plan-mode.d.ts +0 -140
- package/dist/tools/plan-mode.d.ts.map +0 -1
- package/dist/tools/read-binary-file.d.ts +0 -10
- package/dist/tools/read-binary-file.d.ts.map +0 -1
- package/dist/tools/registry.d.ts +0 -31
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/reproduce_issue.d.ts +0 -2
- package/dist/tools/reproduce_issue.d.ts.map +0 -1
- package/dist/tools/sub-agent.d.ts +0 -9
- package/dist/tools/sub-agent.d.ts.map +0 -1
- package/dist/tools/task-complete.d.ts +0 -3
- package/dist/tools/task-complete.d.ts.map +0 -1
- package/dist/tools/types.d.ts +0 -40
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/validation.d.ts +0 -47
- package/dist/tools/validation.d.ts.map +0 -1
- package/dist/tools/web-search.d.ts +0 -24
- package/dist/tools/web-search.d.ts.map +0 -1
- package/dist/tools/workflow-tool.d.ts +0 -11
- package/dist/tools/workflow-tool.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -123
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/workflow.d.ts +0 -110
- package/dist/types/workflow.d.ts.map +0 -1
- package/dist/ui/components/AgentTimer.d.ts +0 -7
- package/dist/ui/components/AgentTimer.d.ts.map +0 -1
- package/dist/ui/components/App.d.ts +0 -197
- package/dist/ui/components/App.d.ts.map +0 -1
- package/dist/ui/components/AuthScreen.d.ts +0 -8
- package/dist/ui/components/AuthScreen.d.ts.map +0 -1
- package/dist/ui/components/AuthWelcomeScreen.d.ts +0 -8
- package/dist/ui/components/AuthWelcomeScreen.d.ts.map +0 -1
- package/dist/ui/components/Breadcrumbs.d.ts +0 -13
- package/dist/ui/components/Breadcrumbs.d.ts.map +0 -1
- package/dist/ui/components/CircularSelectInput.d.ts +0 -24
- package/dist/ui/components/CircularSelectInput.d.ts.map +0 -1
- package/dist/ui/components/ClipboardFileAutocomplete.d.ts +0 -10
- package/dist/ui/components/ClipboardFileAutocomplete.d.ts.map +0 -1
- package/dist/ui/components/CodeBlock.d.ts +0 -9
- package/dist/ui/components/CodeBlock.d.ts.map +0 -1
- package/dist/ui/components/ConfigViewer.d.ts +0 -11
- package/dist/ui/components/ConfigViewer.d.ts.map +0 -1
- package/dist/ui/components/ConfirmPrompt.d.ts +0 -13
- package/dist/ui/components/ConfirmPrompt.d.ts.map +0 -1
- package/dist/ui/components/ConnectionStatusMessage.d.ts +0 -17
- package/dist/ui/components/ConnectionStatusMessage.d.ts.map +0 -1
- package/dist/ui/components/ContextWindowIndicator.d.ts +0 -8
- package/dist/ui/components/ContextWindowIndicator.d.ts.map +0 -1
- package/dist/ui/components/DetailedPlanReviewScreen.d.ts +0 -17
- package/dist/ui/components/DetailedPlanReviewScreen.d.ts.map +0 -1
- package/dist/ui/components/DiffViewer.d.ts +0 -9
- package/dist/ui/components/DiffViewer.d.ts.map +0 -1
- package/dist/ui/components/ErrorBoundary.d.ts +0 -17
- package/dist/ui/components/ErrorBoundary.d.ts.map +0 -1
- package/dist/ui/components/FileCreationPreview.d.ts +0 -8
- package/dist/ui/components/FileCreationPreview.d.ts.map +0 -1
- package/dist/ui/components/FileOperation.d.ts +0 -10
- package/dist/ui/components/FileOperation.d.ts.map +0 -1
- package/dist/ui/components/FileTagAutocomplete.d.ts +0 -11
- package/dist/ui/components/FileTagAutocomplete.d.ts.map +0 -1
- package/dist/ui/components/FontRecommendation.d.ts +0 -1
- package/dist/ui/components/FontRecommendation.d.ts.map +0 -1
- package/dist/ui/components/InputBox.d.ts +0 -42
- package/dist/ui/components/InputBox.d.ts.map +0 -1
- package/dist/ui/components/InteractiveShell.d.ts +0 -30
- package/dist/ui/components/InteractiveShell.d.ts.map +0 -1
- package/dist/ui/components/KeyboardHelp.d.ts +0 -7
- package/dist/ui/components/KeyboardHelp.d.ts.map +0 -1
- package/dist/ui/components/LoadingIndicator.d.ts +0 -3
- package/dist/ui/components/LoadingIndicator.d.ts.map +0 -1
- package/dist/ui/components/MCPAddScreen.d.ts +0 -13
- package/dist/ui/components/MCPAddScreen.d.ts.map +0 -1
- package/dist/ui/components/MCPListScreen.d.ts +0 -17
- package/dist/ui/components/MCPListScreen.d.ts.map +0 -1
- package/dist/ui/components/MCPServerListScreen.d.ts +0 -16
- package/dist/ui/components/MCPServerListScreen.d.ts.map +0 -1
- package/dist/ui/components/MarkdownRenderer.d.ts +0 -8
- package/dist/ui/components/MarkdownRenderer.d.ts.map +0 -1
- package/dist/ui/components/MessageBox.d.ts +0 -10
- package/dist/ui/components/MessageBox.d.ts.map +0 -1
- package/dist/ui/components/MessageDisplay.d.ts +0 -14
- package/dist/ui/components/MessageDisplay.d.ts.map +0 -1
- package/dist/ui/components/MonitorModeAIPanel.d.ts +0 -23
- package/dist/ui/components/MonitorModeAIPanel.d.ts.map +0 -1
- package/dist/ui/components/MultiLineInput.d.ts +0 -13
- package/dist/ui/components/MultiLineInput.d.ts.map +0 -1
- package/dist/ui/components/PasswordPrompt.d.ts +0 -9
- package/dist/ui/components/PasswordPrompt.d.ts.map +0 -1
- package/dist/ui/components/PlanAcceptedMessage.d.ts +0 -20
- package/dist/ui/components/PlanAcceptedMessage.d.ts.map +0 -1
- package/dist/ui/components/PlanReviewScreen.d.ts +0 -14
- package/dist/ui/components/PlanReviewScreen.d.ts.map +0 -1
- package/dist/ui/components/SelectPrompt.d.ts +0 -12
- package/dist/ui/components/SelectPrompt.d.ts.map +0 -1
- package/dist/ui/components/SlashCommandAutocomplete.d.ts +0 -13
- package/dist/ui/components/SlashCommandAutocomplete.d.ts.map +0 -1
- package/dist/ui/components/StatusBar.d.ts +0 -14
- package/dist/ui/components/StatusBar.d.ts.map +0 -1
- package/dist/ui/components/StreamingMessageDisplay.d.ts +0 -15
- package/dist/ui/components/StreamingMessageDisplay.d.ts.map +0 -1
- package/dist/ui/components/TaskCompletedMessage.d.ts +0 -14
- package/dist/ui/components/TaskCompletedMessage.d.ts.map +0 -1
- package/dist/ui/components/TaskProgressIndicator.d.ts +0 -18
- package/dist/ui/components/TaskProgressIndicator.d.ts.map +0 -1
- package/dist/ui/components/ThinkingDisplay.d.ts +0 -15
- package/dist/ui/components/ThinkingDisplay.d.ts.map +0 -1
- package/dist/ui/components/ToolExecutionMessage.d.ts +0 -8
- package/dist/ui/components/ToolExecutionMessage.d.ts.map +0 -1
- package/dist/ui/components/ToolExecutionStatus.d.ts +0 -10
- package/dist/ui/components/ToolExecutionStatus.d.ts.map +0 -1
- package/dist/ui/components/ToolResult.d.ts +0 -10
- package/dist/ui/components/ToolResult.d.ts.map +0 -1
- package/dist/ui/components/VersionUpdatePrompt.d.ts +0 -9
- package/dist/ui/components/VersionUpdatePrompt.d.ts.map +0 -1
- package/dist/ui/components/WelcomeBanner.d.ts +0 -3
- package/dist/ui/components/WelcomeBanner.d.ts.map +0 -1
- package/dist/ui/components/WorkflowCreatorScreen.d.ts +0 -25
- package/dist/ui/components/WorkflowCreatorScreen.d.ts.map +0 -1
- package/dist/utils/ansi-encoder.d.ts +0 -7
- package/dist/utils/ansi-encoder.d.ts.map +0 -1
- package/dist/utils/chat-formatter.d.ts +0 -12
- package/dist/utils/chat-formatter.d.ts.map +0 -1
- package/dist/utils/command-history.d.ts +0 -24
- package/dist/utils/command-history.d.ts.map +0 -1
- package/dist/utils/context-sanitizer.d.ts +0 -50
- package/dist/utils/context-sanitizer.d.ts.map +0 -1
- package/dist/utils/conversation-logger.d.ts +0 -142
- package/dist/utils/conversation-logger.d.ts.map +0 -1
- package/dist/utils/custom-commands-manager.d.ts +0 -59
- package/dist/utils/custom-commands-manager.d.ts.map +0 -1
- package/dist/utils/editor-utils.d.ts +0 -101
- package/dist/utils/editor-utils.d.ts.map +0 -1
- package/dist/utils/file.d.ts +0 -61
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/input-classifier.d.ts +0 -25
- package/dist/utils/input-classifier.d.ts.map +0 -1
- package/dist/utils/logger.d.ts +0 -17
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/markdown-parser.d.ts +0 -60
- package/dist/utils/markdown-parser.d.ts.map +0 -1
- package/dist/utils/shell.d.ts +0 -47
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/state.d.ts +0 -13
- package/dist/utils/state.d.ts.map +0 -1
- package/dist/utils/syntax-checker.d.ts +0 -24
- package/dist/utils/syntax-checker.d.ts.map +0 -1
- package/dist/utils/terminal-output.d.ts +0 -25
- package/dist/utils/terminal-output.d.ts.map +0 -1
- package/dist/utils/text-clipboard.d.ts +0 -12
- package/dist/utils/text-clipboard.d.ts.map +0 -1
- package/dist/utils/unicode-sanitizer.d.ts +0 -44
- package/dist/utils/unicode-sanitizer.d.ts.map +0 -1
- package/dist/utils/version-checker.d.ts +0 -14
- package/dist/utils/version-checker.d.ts.map +0 -1
|
@@ -1,484 +1,541 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
import { apiClient } from "./api-client.js";
|
|
2
|
+
import { readFileSync, existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { IS_DEV_BUILD, DEV_BACKEND_URL, PRODUCTION_BACKEND_URL } from "../config/build-config.js";
|
|
6
|
+
import { logWarning } from "../utils/logger.js";
|
|
7
|
+
import { ollamaService, OllamaService } from "./ollama-service.js";
|
|
8
|
+
import { quickLog } from "../utils/conversation-logger.js";
|
|
9
|
+
class AIServiceClient {
|
|
10
|
+
baseURL;
|
|
11
|
+
maxRetries = 5;
|
|
12
|
+
retryDelay = 1e3;
|
|
13
|
+
// Start with 1 second
|
|
14
|
+
maxRetryDelay = 3e4;
|
|
15
|
+
maxRetryAfterDelay = 6e4;
|
|
16
|
+
highDemandMessage = "Very high demand right now. Please wait and retry after some time.";
|
|
17
|
+
constructor() {
|
|
18
|
+
this.baseURL = "";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the base URL for API requests
|
|
22
|
+
* Lazy-loaded to ensure environment variables are loaded first
|
|
23
|
+
*/
|
|
24
|
+
getBaseURL() {
|
|
25
|
+
if (!this.baseURL) {
|
|
26
|
+
this.baseURL = IS_DEV_BUILD ? DEV_BACKEND_URL : PRODUCTION_BACKEND_URL;
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Check if using a local Ollama model
|
|
52
|
-
if (this.isUsingLocalModel()) {
|
|
53
|
-
const localModel = this.getCurrentModel();
|
|
54
|
-
const supportsTools = OllamaService.modelSupportsTools(localModel);
|
|
55
|
-
quickLog(`[${new Date().toISOString()}] [AIServiceClient] Routing to local Ollama model: ${localModel}, supportsTools: ${supportsTools}\n`);
|
|
56
|
-
// Show warning only if tools are provided but model doesn't support them
|
|
57
|
-
if (tools.length > 0 && !supportsTools) {
|
|
58
|
-
yield {
|
|
59
|
-
type: 'text',
|
|
60
|
-
content: `⚠️ Note: Model "${localModel}" does not support tool calling. Running in text-only mode.\n\n`,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
// Route to local Ollama with tools
|
|
64
|
-
yield* this.streamLocalChat(localModel, messages, tools);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// Build request payload for cloud backend
|
|
68
|
-
const payload = {
|
|
69
|
-
model,
|
|
70
|
-
messages,
|
|
71
|
-
tools,
|
|
72
|
-
stream: true,
|
|
73
|
-
clientType: 'cli', // Tell backend this is a CLI request
|
|
74
|
-
environmentContext,
|
|
75
|
-
mode,
|
|
76
|
-
thinkingConfig,
|
|
28
|
+
return this.baseURL;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Stream chat request to backend AI proxy
|
|
32
|
+
*
|
|
33
|
+
* @param model - The AI model to use (e.g., 'gemini-2.5-flash')
|
|
34
|
+
* @param messages - Conversation history including system, user, assistant, and tool messages
|
|
35
|
+
* @param tools - Available tool schemas for the AI to use
|
|
36
|
+
* @param environmentContext - Optional environment context (OS, shell, cwd, etc.)
|
|
37
|
+
* @param mode - Optional mode (default, plan, command)
|
|
38
|
+
* @yields Stream chunks (text, tool calls, done, or error events)
|
|
39
|
+
*/
|
|
40
|
+
async *streamChat(model, messages, tools, environmentContext, mode, thinkingConfig, abortSignal) {
|
|
41
|
+
if (this.isUsingLocalModel()) {
|
|
42
|
+
const localModel = this.getCurrentModel();
|
|
43
|
+
const supportsTools = OllamaService.modelSupportsTools(localModel);
|
|
44
|
+
quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Routing to local Ollama model: ${localModel}, supportsTools: ${supportsTools}
|
|
45
|
+
`);
|
|
46
|
+
if (tools.length > 0 && !supportsTools) {
|
|
47
|
+
yield {
|
|
48
|
+
type: "text",
|
|
49
|
+
content: `\u26A0\uFE0F Note: Model "${localModel}" does not support tool calling. Running in text-only mode.
|
|
50
|
+
|
|
51
|
+
`
|
|
77
52
|
};
|
|
78
|
-
|
|
79
|
-
|
|
53
|
+
}
|
|
54
|
+
yield* this.streamLocalChat(localModel, messages, tools);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const payload = {
|
|
58
|
+
model,
|
|
59
|
+
messages,
|
|
60
|
+
tools,
|
|
61
|
+
stream: true,
|
|
62
|
+
clientType: "cli",
|
|
63
|
+
// Tell backend this is a CLI request
|
|
64
|
+
environmentContext,
|
|
65
|
+
mode,
|
|
66
|
+
thinkingConfig
|
|
67
|
+
};
|
|
68
|
+
if (!apiClient.isAuthenticated()) {
|
|
69
|
+
yield {
|
|
70
|
+
type: "error",
|
|
71
|
+
message: "Authentication required. Please sign in.",
|
|
72
|
+
code: "AUTH_REQUIRED"
|
|
73
|
+
};
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let lastError = null;
|
|
77
|
+
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
|
|
78
|
+
try {
|
|
79
|
+
const response = await fetch(`${this.getBaseURL()}/chat/completions`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
"Authorization": `Bearer ${this.getSessionToken()}`
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify(payload),
|
|
86
|
+
signal: abortSignal
|
|
87
|
+
// Only abort when user explicitly cancels
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const errorText = await response.text();
|
|
91
|
+
const parsedHttpError = this.parseHttpError(response.status, response.statusText, errorText);
|
|
92
|
+
if (response.status === 401) {
|
|
80
93
|
yield {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
type: "error",
|
|
95
|
+
message: "Session expired. Please sign in again.",
|
|
96
|
+
code: "AUTH_REQUIRED"
|
|
84
97
|
};
|
|
85
98
|
return;
|
|
99
|
+
}
|
|
100
|
+
lastError = parsedHttpError;
|
|
101
|
+
if (this.isRetryableError(parsedHttpError.code, parsedHttpError.message, response.status) && attempt < this.maxRetries - 1) {
|
|
102
|
+
const retryAfterMs = this.getRetryAfterMs(response.headers);
|
|
103
|
+
await this.sleep(this.getRetryDelayMs(attempt, retryAfterMs));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (this.isRateLimitError(parsedHttpError.code, parsedHttpError.message, response.status)) {
|
|
107
|
+
yield this.createHighDemandError();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
yield parsedHttpError;
|
|
111
|
+
return;
|
|
86
112
|
}
|
|
87
|
-
|
|
88
|
-
let
|
|
89
|
-
for (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// Connection issues will manifest as network errors, not timeouts
|
|
97
|
-
const response = await fetch(`${this.getBaseURL()}/ai/chat`, {
|
|
98
|
-
method: 'POST',
|
|
99
|
-
headers: {
|
|
100
|
-
'Content-Type': 'application/json',
|
|
101
|
-
'Authorization': `Bearer ${this.getSessionToken()}`,
|
|
102
|
-
},
|
|
103
|
-
body: JSON.stringify(payload),
|
|
104
|
-
signal: abortSignal, // Only abort when user explicitly cancels
|
|
105
|
-
});
|
|
106
|
-
// Check for HTTP errors
|
|
107
|
-
if (!response.ok) {
|
|
108
|
-
const errorText = await response.text();
|
|
109
|
-
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
110
|
-
let errorCode = 'HTTP_ERROR';
|
|
111
|
-
try {
|
|
112
|
-
const errorData = JSON.parse(errorText);
|
|
113
|
-
if (errorData.error) {
|
|
114
|
-
errorMessage = errorData.error.message || errorMessage;
|
|
115
|
-
errorCode = errorData.error.code || errorCode;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// If response is not JSON, use the text as message
|
|
120
|
-
if (errorText) {
|
|
121
|
-
errorMessage = errorText;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
// Handle specific error codes
|
|
125
|
-
if (response.status === 401) {
|
|
126
|
-
yield {
|
|
127
|
-
type: 'error',
|
|
128
|
-
message: 'Session expired. Please sign in again.',
|
|
129
|
-
code: 'AUTH_REQUIRED',
|
|
130
|
-
};
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (response.status === 429) {
|
|
134
|
-
// Rate limit - don't retry immediately
|
|
135
|
-
yield {
|
|
136
|
-
type: 'error',
|
|
137
|
-
message: 'Service temporarily unavailable due to high demand. Please try again in a moment.',
|
|
138
|
-
code: 'RATE_LIMIT',
|
|
139
|
-
};
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
if (response.status === 504) {
|
|
143
|
-
// Timeout error - retryable
|
|
144
|
-
lastError = {
|
|
145
|
-
type: 'error',
|
|
146
|
-
message: 'Request timed out. Retrying...',
|
|
147
|
-
code: 'TIMEOUT',
|
|
148
|
-
};
|
|
149
|
-
if (attempt < this.maxRetries - 1) {
|
|
150
|
-
await this.sleep(this.retryDelay * Math.pow(2, attempt));
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// For other errors, yield and return
|
|
155
|
-
yield {
|
|
156
|
-
type: 'error',
|
|
157
|
-
message: errorMessage,
|
|
158
|
-
code: errorCode,
|
|
159
|
-
};
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
// Parse SSE stream
|
|
163
|
-
// We iterate manually to catch retryable errors from the stream
|
|
164
|
-
let contentReceived = false;
|
|
165
|
-
let shouldRetry = false;
|
|
166
|
-
for await (const chunk of this.parseSSEStream(response.body)) {
|
|
167
|
-
if (chunk.type === 'error') {
|
|
168
|
-
// Check if this is a retryable error (like rate limit) AND we haven't sent partial content yet
|
|
169
|
-
if (this.isRetryableError(chunk.code) && !contentReceived) {
|
|
170
|
-
lastError = chunk;
|
|
171
|
-
shouldRetry = true;
|
|
172
|
-
break; // Break the stream loop to trigger retry
|
|
173
|
-
}
|
|
174
|
-
// Not retryable or content already sent - yield error and stop
|
|
175
|
-
yield chunk;
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
// Mark that we've received content
|
|
179
|
-
if (chunk.type !== 'done' && chunk.type !== 'thought' && chunk.type !== 'thinking_signature') {
|
|
180
|
-
contentReceived = true;
|
|
181
|
-
}
|
|
182
|
-
yield chunk;
|
|
183
|
-
}
|
|
184
|
-
// If stream finished cleanly (without error chunk), we are done
|
|
185
|
-
if (!shouldRetry) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
// If we need to retry, check attempts and wait
|
|
189
|
-
if (attempt < this.maxRetries - 1) {
|
|
190
|
-
// We're going to retry, so we need to wait for the backoff period
|
|
191
|
-
await this.sleep(this.retryDelay * Math.pow(2, attempt));
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
// If we've exhausted retries, we'll fall through to the end of the loop
|
|
195
|
-
// and yield the lastError below
|
|
196
|
-
}
|
|
197
|
-
catch (error) {
|
|
198
|
-
// Handle network errors
|
|
199
|
-
if (error.name === 'TypeError' && error.message.includes('fetch')) {
|
|
200
|
-
lastError = {
|
|
201
|
-
type: 'error',
|
|
202
|
-
message: 'Backend service is unreachable. Please check your connection.',
|
|
203
|
-
code: 'NETWORK_ERROR',
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
else if (error.name === 'AbortError' || error.name === 'TimeoutError') {
|
|
207
|
-
lastError = {
|
|
208
|
-
type: 'error',
|
|
209
|
-
message: 'Request timed out. Please try again.',
|
|
210
|
-
code: 'TIMEOUT',
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
lastError = {
|
|
215
|
-
type: 'error',
|
|
216
|
-
message: error.message || 'Unknown error occurred',
|
|
217
|
-
code: error.code || 'UNKNOWN_ERROR',
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
// Retry for transient errors
|
|
221
|
-
if (this.isRetryableError(lastError.code) && attempt < this.maxRetries - 1) {
|
|
222
|
-
await this.sleep(this.retryDelay * Math.pow(2, attempt));
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
// If not retryable or max retries reached, yield error and return
|
|
226
|
-
break;
|
|
113
|
+
let contentReceived = false;
|
|
114
|
+
let shouldRetry = false;
|
|
115
|
+
for await (const chunk of this.parseSSEStream(response.body)) {
|
|
116
|
+
if (chunk.type === "error") {
|
|
117
|
+
const normalizedChunk = this.normalizeErrorChunk(chunk);
|
|
118
|
+
if (this.isRetryableError(normalizedChunk.code, normalizedChunk.message) && !contentReceived) {
|
|
119
|
+
lastError = normalizedChunk;
|
|
120
|
+
shouldRetry = true;
|
|
121
|
+
break;
|
|
227
122
|
}
|
|
123
|
+
yield normalizedChunk;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (chunk.type !== "done" && chunk.type !== "thought" && chunk.type !== "thinking_signature" && chunk.type !== "file_descriptions") {
|
|
127
|
+
contentReceived = true;
|
|
128
|
+
}
|
|
129
|
+
yield chunk;
|
|
228
130
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
yield lastError;
|
|
131
|
+
if (!shouldRetry) {
|
|
132
|
+
return;
|
|
232
133
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
*/
|
|
237
|
-
isRetryableError(code) {
|
|
238
|
-
const retryableCodes = ['NETWORK_ERROR', 'TIMEOUT', 'UNKNOWN_ERROR', 'RATE_LIMIT'];
|
|
239
|
-
return retryableCodes.includes(code);
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Sleep for specified milliseconds
|
|
243
|
-
*/
|
|
244
|
-
sleep(ms) {
|
|
245
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Get session token from apiClient
|
|
249
|
-
* This is a workaround since sessionToken is private
|
|
250
|
-
*/
|
|
251
|
-
getSessionToken() {
|
|
252
|
-
// Read session token from the same location apiClient uses
|
|
253
|
-
const configPath = join(homedir(), '.centaurus', 'session.json');
|
|
254
|
-
try {
|
|
255
|
-
if (existsSync(configPath)) {
|
|
256
|
-
const data = readFileSync(configPath, 'utf-8');
|
|
257
|
-
const session = JSON.parse(data);
|
|
258
|
-
return session.sessionToken || '';
|
|
259
|
-
}
|
|
134
|
+
if (attempt < this.maxRetries - 1) {
|
|
135
|
+
await this.sleep(this.getRetryDelayMs(attempt));
|
|
136
|
+
continue;
|
|
260
137
|
}
|
|
261
|
-
|
|
262
|
-
|
|
138
|
+
} catch (error) {
|
|
139
|
+
lastError = this.normalizeThrownError(error);
|
|
140
|
+
const wasIntentionalAbort = (error?.name === "AbortError" || error?.name === "TimeoutError") && !!abortSignal?.aborted;
|
|
141
|
+
if (wasIntentionalAbort) {
|
|
142
|
+
break;
|
|
263
143
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
* Check if the current configuration is using a local Ollama model
|
|
268
|
-
*/
|
|
269
|
-
isUsingLocalModel() {
|
|
270
|
-
const configPath = join(homedir(), '.centaurus', 'config.json');
|
|
271
|
-
try {
|
|
272
|
-
if (existsSync(configPath)) {
|
|
273
|
-
const data = readFileSync(configPath, 'utf-8');
|
|
274
|
-
const config = JSON.parse(data);
|
|
275
|
-
return config.isLocalModel === true;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
// Return false if unable to read
|
|
144
|
+
if (this.isRetryableError(lastError.code, lastError.message) && attempt < this.maxRetries - 1) {
|
|
145
|
+
await this.sleep(this.getRetryDelayMs(attempt));
|
|
146
|
+
continue;
|
|
280
147
|
}
|
|
281
|
-
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
282
150
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
151
|
+
if (lastError) {
|
|
152
|
+
if (this.isRateLimitError(lastError.code, lastError.message)) {
|
|
153
|
+
yield this.createHighDemandError();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
yield lastError;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Create a normalized high-demand error response.
|
|
161
|
+
*/
|
|
162
|
+
createHighDemandError() {
|
|
163
|
+
return {
|
|
164
|
+
type: "error",
|
|
165
|
+
message: this.highDemandMessage,
|
|
166
|
+
code: "RATE_LIMIT"
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Parse backend HTTP error body into a normalized error chunk.
|
|
171
|
+
*/
|
|
172
|
+
parseHttpError(status, statusText, errorText) {
|
|
173
|
+
let errorMessage = `HTTP ${status}: ${statusText}`;
|
|
174
|
+
let errorCode = "HTTP_ERROR";
|
|
175
|
+
if (errorText) {
|
|
176
|
+
try {
|
|
177
|
+
const parsed = JSON.parse(errorText);
|
|
178
|
+
const rootError = Array.isArray(parsed) ? parsed[0]?.error ?? parsed[0] : parsed?.error ?? parsed;
|
|
179
|
+
if (rootError) {
|
|
180
|
+
if (typeof rootError.message === "string" && rootError.message.trim()) {
|
|
181
|
+
errorMessage = rootError.message;
|
|
182
|
+
}
|
|
183
|
+
if (typeof rootError.code === "string" || typeof rootError.code === "number") {
|
|
184
|
+
errorCode = String(rootError.code);
|
|
185
|
+
} else if (typeof rootError.status === "string") {
|
|
186
|
+
errorCode = rootError.status;
|
|
187
|
+
}
|
|
297
188
|
}
|
|
298
|
-
|
|
189
|
+
} catch {
|
|
190
|
+
errorMessage = errorText;
|
|
191
|
+
}
|
|
299
192
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
// Tool results - convert to Ollama's tool message format
|
|
307
|
-
return {
|
|
308
|
-
role: 'tool',
|
|
309
|
-
content: msg.content,
|
|
310
|
-
tool_name: msg.tool_call_id || 'unknown', // Use tool_call_id as tool_name
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
if (msg.role === 'assistant' && msg.tool_calls?.length) {
|
|
314
|
-
// Assistant message with tool calls
|
|
315
|
-
return {
|
|
316
|
-
role: 'assistant',
|
|
317
|
-
content: msg.content || '',
|
|
318
|
-
tool_calls: msg.tool_calls.map(tc => ({
|
|
319
|
-
function: {
|
|
320
|
-
name: tc.name,
|
|
321
|
-
arguments: tc.arguments,
|
|
322
|
-
}
|
|
323
|
-
})),
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
// Regular message
|
|
327
|
-
return {
|
|
328
|
-
role: msg.role,
|
|
329
|
-
content: msg.content,
|
|
330
|
-
};
|
|
331
|
-
});
|
|
193
|
+
if (status === 504) {
|
|
194
|
+
return {
|
|
195
|
+
type: "error",
|
|
196
|
+
message: "Request timed out. Please try again.",
|
|
197
|
+
code: "TIMEOUT"
|
|
198
|
+
};
|
|
332
199
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
*/
|
|
336
|
-
convertToolsToOllamaFormat(tools) {
|
|
337
|
-
return tools.map(tool => ({
|
|
338
|
-
type: 'function',
|
|
339
|
-
function: {
|
|
340
|
-
name: tool.name,
|
|
341
|
-
description: tool.description,
|
|
342
|
-
parameters: {
|
|
343
|
-
type: 'object',
|
|
344
|
-
properties: tool.parameters.properties,
|
|
345
|
-
required: tool.parameters.required,
|
|
346
|
-
},
|
|
347
|
-
},
|
|
348
|
-
}));
|
|
200
|
+
if (this.isRateLimitError(errorCode, errorMessage, status)) {
|
|
201
|
+
return this.createHighDemandError();
|
|
349
202
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
203
|
+
return {
|
|
204
|
+
type: "error",
|
|
205
|
+
message: errorMessage,
|
|
206
|
+
code: errorCode
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Normalize streamed error chunks to stable internal codes/messages.
|
|
211
|
+
*/
|
|
212
|
+
normalizeErrorChunk(chunk) {
|
|
213
|
+
const normalizedCode = chunk.code ? String(chunk.code) : "UNKNOWN_ERROR";
|
|
214
|
+
const normalizedMessage = chunk.message || "Unknown error occurred";
|
|
215
|
+
if (this.isRateLimitError(normalizedCode, normalizedMessage)) {
|
|
216
|
+
return this.createHighDemandError();
|
|
217
|
+
}
|
|
218
|
+
if (normalizedCode === "504") {
|
|
219
|
+
return {
|
|
220
|
+
type: "error",
|
|
221
|
+
message: "Request timed out. Please try again.",
|
|
222
|
+
code: "TIMEOUT"
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
type: "error",
|
|
227
|
+
message: normalizedMessage,
|
|
228
|
+
code: normalizedCode
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Normalize thrown errors from fetch/network/runtime paths.
|
|
233
|
+
*/
|
|
234
|
+
normalizeThrownError(error) {
|
|
235
|
+
const rawMessage = error?.message || "Unknown error occurred";
|
|
236
|
+
const rawCode = error?.code ? String(error.code) : "UNKNOWN_ERROR";
|
|
237
|
+
if (this.isRateLimitError(rawCode, rawMessage, error?.status)) {
|
|
238
|
+
return this.createHighDemandError();
|
|
239
|
+
}
|
|
240
|
+
if (error?.name === "TypeError" && rawMessage.includes("fetch")) {
|
|
241
|
+
return {
|
|
242
|
+
type: "error",
|
|
243
|
+
message: "Backend service is unreachable. Please check your connection.",
|
|
244
|
+
code: "NETWORK_ERROR"
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (error?.name === "AbortError" || error?.name === "TimeoutError") {
|
|
248
|
+
return {
|
|
249
|
+
type: "error",
|
|
250
|
+
message: "Request timed out. Please try again.",
|
|
251
|
+
code: "TIMEOUT"
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
type: "error",
|
|
256
|
+
message: rawMessage,
|
|
257
|
+
code: rawCode
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Check if an error is a rate-limit/resource-exhausted signal.
|
|
262
|
+
*/
|
|
263
|
+
isRateLimitError(code, message = "", status) {
|
|
264
|
+
const normalizedCode = (code || "").toString().toLowerCase();
|
|
265
|
+
const normalizedMessage = message.toLowerCase();
|
|
266
|
+
return status === 429 || normalizedCode === "429" || normalizedCode === "8" || normalizedCode === "rate_limit" || normalizedCode === "resource_exhausted" || normalizedMessage.includes("rate limit") || normalizedMessage.includes("too many requests") || normalizedMessage.includes("quota") || normalizedMessage.includes("resource exhausted") || normalizedMessage.includes("resource_exhausted") || normalizedMessage.includes("maas api returned 429");
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Check if HTTP status is retryable.
|
|
270
|
+
*/
|
|
271
|
+
isRetryableStatus(status) {
|
|
272
|
+
if (typeof status !== "number") {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
return [408, 425, 429, 500, 502, 503, 504].includes(status);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Check if an error should be retried.
|
|
279
|
+
*/
|
|
280
|
+
isRetryableError(code, message = "", status) {
|
|
281
|
+
if (this.isRateLimitError(code, message, status)) {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
if (this.isRetryableStatus(status)) {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
const retryableCodes = ["NETWORK_ERROR", "TIMEOUT", "UNKNOWN_ERROR", "RATE_LIMIT"];
|
|
288
|
+
if (retryableCodes.includes(code)) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
const normalizedMessage = message.toLowerCase();
|
|
292
|
+
return normalizedMessage.includes("timeout") || normalizedMessage.includes("timed out") || normalizedMessage.includes("temporarily unavailable") || normalizedMessage.includes("network error");
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Parse Retry-After from response headers.
|
|
296
|
+
*/
|
|
297
|
+
getRetryAfterMs(headers) {
|
|
298
|
+
const retryAfterValue = headers.get("retry-after");
|
|
299
|
+
if (!retryAfterValue) {
|
|
300
|
+
return void 0;
|
|
301
|
+
}
|
|
302
|
+
const seconds = Number(retryAfterValue);
|
|
303
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
304
|
+
return seconds * 1e3;
|
|
305
|
+
}
|
|
306
|
+
const retryAfterDate = Date.parse(retryAfterValue);
|
|
307
|
+
if (!Number.isNaN(retryAfterDate)) {
|
|
308
|
+
return Math.max(0, retryAfterDate - Date.now());
|
|
309
|
+
}
|
|
310
|
+
return void 0;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Compute retry delay with exponential backoff + jitter.
|
|
314
|
+
*/
|
|
315
|
+
getRetryDelayMs(attempt, retryAfterMs) {
|
|
316
|
+
const exponentialDelay = this.retryDelay * Math.pow(2, attempt);
|
|
317
|
+
const cappedDelay = Math.min(exponentialDelay, this.maxRetryDelay);
|
|
318
|
+
const jitteredDelay = Math.round(Math.min(cappedDelay * (0.5 + Math.random()), this.maxRetryDelay));
|
|
319
|
+
if (retryAfterMs === void 0) {
|
|
320
|
+
return jitteredDelay;
|
|
321
|
+
}
|
|
322
|
+
const cappedRetryAfter = Math.min(Math.max(0, retryAfterMs), this.maxRetryAfterDelay);
|
|
323
|
+
return Math.max(jitteredDelay, cappedRetryAfter);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Sleep for specified milliseconds
|
|
327
|
+
*/
|
|
328
|
+
sleep(ms) {
|
|
329
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get session token from apiClient
|
|
333
|
+
* This is a workaround since sessionToken is private
|
|
334
|
+
*/
|
|
335
|
+
getSessionToken() {
|
|
336
|
+
const configPath = join(homedir(), ".centaurus", "session.json");
|
|
337
|
+
try {
|
|
338
|
+
if (existsSync(configPath)) {
|
|
339
|
+
const data = readFileSync(configPath, "utf-8");
|
|
340
|
+
const session = JSON.parse(data);
|
|
341
|
+
return session.sessionToken || "";
|
|
342
|
+
}
|
|
343
|
+
} catch (error) {
|
|
344
|
+
}
|
|
345
|
+
return "";
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Check if the current configuration is using a local Ollama model
|
|
349
|
+
*/
|
|
350
|
+
isUsingLocalModel() {
|
|
351
|
+
const configPath = join(homedir(), ".centaurus", "config.json");
|
|
352
|
+
try {
|
|
353
|
+
if (existsSync(configPath)) {
|
|
354
|
+
const data = readFileSync(configPath, "utf-8");
|
|
355
|
+
const config = JSON.parse(data);
|
|
356
|
+
return config.isLocalModel === true;
|
|
357
|
+
}
|
|
358
|
+
} catch (error) {
|
|
359
|
+
}
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Get the current model name from config
|
|
364
|
+
*/
|
|
365
|
+
getCurrentModel() {
|
|
366
|
+
const configPath = join(homedir(), ".centaurus", "config.json");
|
|
367
|
+
try {
|
|
368
|
+
if (existsSync(configPath)) {
|
|
369
|
+
const data = readFileSync(configPath, "utf-8");
|
|
370
|
+
const config = JSON.parse(data);
|
|
371
|
+
return config.model || "gemini-2.5-flash";
|
|
372
|
+
}
|
|
373
|
+
} catch (error) {
|
|
374
|
+
}
|
|
375
|
+
return "gemini-2.5-flash";
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Convert internal message format to Ollama format (with tool support)
|
|
379
|
+
*/
|
|
380
|
+
convertToOllamaMessages(messages) {
|
|
381
|
+
return messages.map((msg) => {
|
|
382
|
+
if (msg.role === "tool") {
|
|
383
|
+
return {
|
|
384
|
+
role: "tool",
|
|
385
|
+
content: msg.content,
|
|
386
|
+
tool_name: msg.tool_call_id || "unknown"
|
|
387
|
+
// Use tool_call_id as tool_name
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
if (msg.role === "assistant" && msg.tool_calls?.length) {
|
|
391
|
+
return {
|
|
392
|
+
role: "assistant",
|
|
393
|
+
content: msg.content || "",
|
|
394
|
+
tool_calls: msg.tool_calls.map((tc) => ({
|
|
395
|
+
function: {
|
|
396
|
+
name: tc.name,
|
|
397
|
+
arguments: tc.arguments
|
|
395
398
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
+
}))
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
role: msg.role,
|
|
404
|
+
content: msg.content
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Convert ToolSchema array to Ollama tool format
|
|
410
|
+
*/
|
|
411
|
+
convertToolsToOllamaFormat(tools) {
|
|
412
|
+
return tools.map((tool) => ({
|
|
413
|
+
type: "function",
|
|
414
|
+
function: {
|
|
415
|
+
name: tool.name,
|
|
416
|
+
description: tool.description,
|
|
417
|
+
parameters: {
|
|
418
|
+
type: "object",
|
|
419
|
+
properties: tool.parameters.properties,
|
|
420
|
+
required: tool.parameters.required
|
|
399
421
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
422
|
+
}
|
|
423
|
+
}));
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Stream chat request to local Ollama instance with tool calling support
|
|
427
|
+
*
|
|
428
|
+
* @param model - The local Ollama model to use (e.g., 'llama3.2:latest')
|
|
429
|
+
* @param messages - Conversation history
|
|
430
|
+
* @param tools - Available tools (will be converted to Ollama format)
|
|
431
|
+
* @yields Stream chunks (text, tool_call, or done events)
|
|
432
|
+
*/
|
|
433
|
+
async *streamLocalChat(model, messages, tools = []) {
|
|
434
|
+
try {
|
|
435
|
+
const supportsTools = OllamaService.modelSupportsTools(model);
|
|
436
|
+
const effectiveTools = supportsTools ? tools : [];
|
|
437
|
+
quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Starting local chat with model: ${model}, tools: ${effectiveTools.length}, supportsTools: ${supportsTools}
|
|
438
|
+
`);
|
|
439
|
+
const ollamaMessages = this.convertToOllamaMessages(messages);
|
|
440
|
+
const ollamaTools = effectiveTools.length > 0 ? this.convertToolsToOllamaFormat(effectiveTools) : void 0;
|
|
441
|
+
const response = await ollamaService.sendChatMessage(model, ollamaMessages, ollamaTools);
|
|
442
|
+
if (response.message?.tool_calls?.length) {
|
|
443
|
+
quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Received ${response.message.tool_calls.length} tool calls from Ollama
|
|
444
|
+
`);
|
|
445
|
+
for (const toolCall of response.message.tool_calls) {
|
|
446
|
+
yield {
|
|
447
|
+
type: "tool_call",
|
|
448
|
+
toolCall: {
|
|
449
|
+
id: `ollama-${Date.now()}-${toolCall.function.name}`,
|
|
450
|
+
// Generate unique ID
|
|
451
|
+
name: toolCall.function.name,
|
|
452
|
+
arguments: toolCall.function.arguments
|
|
453
|
+
}
|
|
454
|
+
};
|
|
407
455
|
}
|
|
456
|
+
yield { type: "done" };
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (response.message.content) {
|
|
460
|
+
yield {
|
|
461
|
+
type: "text",
|
|
462
|
+
content: response.message.content
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
yield { type: "done" };
|
|
466
|
+
quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Local chat completed
|
|
467
|
+
`);
|
|
468
|
+
} catch (error) {
|
|
469
|
+
quickLog(`[${(/* @__PURE__ */ new Date()).toISOString()}] [AIServiceClient] Local chat error: ${error.message}
|
|
470
|
+
`);
|
|
471
|
+
yield {
|
|
472
|
+
type: "error",
|
|
473
|
+
message: error.message || "Failed to communicate with Ollama",
|
|
474
|
+
code: "OLLAMA_ERROR"
|
|
475
|
+
};
|
|
408
476
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
// Skip malformed JSON
|
|
437
|
-
logWarning(`Failed to parse SSE data (in buffer): ${dataStr}`);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
break;
|
|
444
|
-
}
|
|
445
|
-
// Decode chunk and add to buffer
|
|
446
|
-
buffer += decoder.decode(value, { stream: true });
|
|
447
|
-
// Process complete lines in buffer
|
|
448
|
-
const lines = buffer.split('\n');
|
|
449
|
-
// Keep the last incomplete line in buffer
|
|
450
|
-
buffer = lines.pop() || '';
|
|
451
|
-
for (const line of lines) {
|
|
452
|
-
// SSE format: "data: {json}"
|
|
453
|
-
if (line.startsWith('data: ')) {
|
|
454
|
-
const dataStr = line.slice(6); // Remove "data: " prefix
|
|
455
|
-
// Skip empty data lines
|
|
456
|
-
if (!dataStr.trim()) {
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
try {
|
|
460
|
-
const chunk = JSON.parse(dataStr);
|
|
461
|
-
yield chunk;
|
|
462
|
-
// Stop if we receive a done or error event
|
|
463
|
-
if (chunk.type === 'done' || chunk.type === 'error') {
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
catch (error) {
|
|
468
|
-
// Skip malformed JSON
|
|
469
|
-
logWarning(`Failed to parse SSE data: ${dataStr}`);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
// SSE event type line: "event: chunk"
|
|
473
|
-
// We don't need to process these separately since the data contains the type
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Parse Server-Sent Events stream from response body
|
|
480
|
+
*
|
|
481
|
+
* @param body - ReadableStream from fetch response
|
|
482
|
+
* @yields Parsed stream chunks
|
|
483
|
+
*/
|
|
484
|
+
async *parseSSEStream(body) {
|
|
485
|
+
const reader = body.getReader();
|
|
486
|
+
const decoder = new TextDecoder();
|
|
487
|
+
let buffer = "";
|
|
488
|
+
try {
|
|
489
|
+
while (true) {
|
|
490
|
+
const { done, value } = await reader.read();
|
|
491
|
+
if (done) {
|
|
492
|
+
if (buffer.trim()) {
|
|
493
|
+
const remainingLines = buffer.split("\n");
|
|
494
|
+
for (const line of remainingLines) {
|
|
495
|
+
if (line.startsWith("data: ")) {
|
|
496
|
+
const dataStr = line.slice(6);
|
|
497
|
+
if (dataStr.trim()) {
|
|
498
|
+
try {
|
|
499
|
+
const chunk = JSON.parse(dataStr);
|
|
500
|
+
yield chunk;
|
|
501
|
+
} catch (error) {
|
|
502
|
+
logWarning(`Failed to parse SSE data (in buffer): ${dataStr}`);
|
|
503
|
+
}
|
|
474
504
|
}
|
|
505
|
+
}
|
|
475
506
|
}
|
|
507
|
+
}
|
|
508
|
+
break;
|
|
476
509
|
}
|
|
477
|
-
|
|
478
|
-
|
|
510
|
+
buffer += decoder.decode(value, { stream: true });
|
|
511
|
+
const lines = buffer.split("\n");
|
|
512
|
+
buffer = lines.pop() || "";
|
|
513
|
+
for (const line of lines) {
|
|
514
|
+
if (line.startsWith("data: ")) {
|
|
515
|
+
const dataStr = line.slice(6);
|
|
516
|
+
if (!dataStr.trim()) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
try {
|
|
520
|
+
const chunk = JSON.parse(dataStr);
|
|
521
|
+
yield chunk;
|
|
522
|
+
if (chunk.type === "done" || chunk.type === "error") {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
} catch (error) {
|
|
526
|
+
logWarning(`Failed to parse SSE data: ${dataStr}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
479
529
|
}
|
|
530
|
+
}
|
|
531
|
+
} finally {
|
|
532
|
+
reader.releaseLock();
|
|
480
533
|
}
|
|
534
|
+
}
|
|
481
535
|
}
|
|
482
|
-
|
|
483
|
-
export
|
|
536
|
+
const aiServiceClient = new AIServiceClient();
|
|
537
|
+
export {
|
|
538
|
+
AIServiceClient,
|
|
539
|
+
aiServiceClient
|
|
540
|
+
};
|
|
484
541
|
//# sourceMappingURL=ai-service-client.js.map
|