fss-link 1.0.49 → 1.0.51
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/index.js +0 -0
- package/dist/package.json +2 -2
- package/dist/src/config/auth.js +8 -5
- package/dist/src/config/auth.js.map +1 -1
- package/dist/src/config/database.d.ts +103 -11
- package/dist/src/config/database.js +301 -59
- package/dist/src/config/database.js.map +1 -1
- package/dist/src/config/databaseBackup.d.ts +114 -0
- package/dist/src/config/databaseBackup.js +334 -0
- package/dist/src/config/databaseBackup.js.map +1 -0
- package/dist/src/config/databaseMigrations.d.ts +63 -0
- package/dist/src/config/databaseMigrations.js +379 -0
- package/dist/src/config/databaseMigrations.js.map +1 -0
- package/dist/src/config/databasePool.d.ts +70 -0
- package/dist/src/config/databasePool.js +193 -0
- package/dist/src/config/databasePool.js.map +1 -0
- package/dist/src/config/queryOptimizer.d.ts +127 -0
- package/dist/src/config/queryOptimizer.js +309 -0
- package/dist/src/config/queryOptimizer.js.map +1 -0
- package/dist/src/utils/sandbox.js +2 -8
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/validateNonInterActiveAuth.js +3 -7
- package/dist/src/validateNonInterActiveAuth.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/commands/mcp/add.test.ts +0 -122
- package/dist/commands/mcp/add.ts +0 -222
- package/dist/commands/mcp/list.test.ts +0 -154
- package/dist/commands/mcp/list.ts +0 -139
- package/dist/commands/mcp/remove.test.ts +0 -69
- package/dist/commands/mcp/remove.ts +0 -60
- package/dist/commands/mcp.test.ts +0 -55
- package/dist/commands/mcp.ts +0 -27
- package/dist/config/apiValidation.test.ts +0 -118
- package/dist/config/auth.test.ts +0 -79
- package/dist/config/auth.ts +0 -100
- package/dist/config/config.integration.test.ts +0 -407
- package/dist/config/config.test.ts +0 -1952
- package/dist/config/config.ts +0 -690
- package/dist/config/database.test.ts +0 -96
- package/dist/config/database.ts +0 -824
- package/dist/config/extension.test.ts +0 -236
- package/dist/config/extension.ts +0 -180
- package/dist/config/keyBindings.test.ts +0 -62
- package/dist/config/keyBindings.ts +0 -184
- package/dist/config/modelManager.ts +0 -326
- package/dist/config/providerManager.ts +0 -244
- package/dist/config/providerPersistence.test.ts +0 -377
- package/dist/config/providerPersistence.ts +0 -105
- package/dist/config/sandboxConfig.ts +0 -107
- package/dist/config/settings.test.ts +0 -1424
- package/dist/config/settings.ts +0 -517
- package/dist/config/settingsSchema.test.ts +0 -252
- package/dist/config/settingsSchema.ts +0 -728
- package/dist/config/trustedFolders.test.ts +0 -208
- package/dist/config/trustedFolders.ts +0 -167
- package/dist/gemini.test.tsx +0 -252
- package/dist/gemini.tsx +0 -357
- package/dist/generated/git-commit.ts +0 -10
- package/dist/index.ts +0 -21
- package/dist/nonInteractiveCli.test.ts +0 -276
- package/dist/nonInteractiveCli.ts +0 -143
- package/dist/patches/is-in-ci.ts +0 -17
- package/dist/services/BuiltinCommandLoader.test.ts +0 -127
- package/dist/services/BuiltinCommandLoader.ts +0 -95
- package/dist/services/CommandService.test.ts +0 -352
- package/dist/services/CommandService.ts +0 -103
- package/dist/services/FileCommandLoader.test.ts +0 -1002
- package/dist/services/FileCommandLoader.ts +0 -289
- package/dist/services/McpPromptLoader.ts +0 -231
- package/dist/services/SearchEngineConfigProvider.ts +0 -100
- package/dist/services/prompt-processors/argumentProcessor.test.ts +0 -41
- package/dist/services/prompt-processors/argumentProcessor.ts +0 -23
- package/dist/services/prompt-processors/shellProcessor.test.ts +0 -709
- package/dist/services/prompt-processors/shellProcessor.ts +0 -248
- package/dist/services/prompt-processors/types.ts +0 -44
- package/dist/services/types.ts +0 -24
- package/dist/src/config/apiValidation.test.d.ts +0 -6
- package/dist/src/config/apiValidation.test.js +0 -99
- package/dist/src/config/apiValidation.test.js.map +0 -1
- package/dist/src/config/database.test.d.ts +0 -6
- package/dist/src/config/database.test.js +0 -80
- package/dist/src/config/database.test.js.map +0 -1
- package/dist/src/config/providerManager.d.ts +0 -74
- package/dist/src/config/providerManager.js +0 -203
- package/dist/src/config/providerManager.js.map +0 -1
- package/dist/src/config/providerPersistence.test.d.ts +0 -6
- package/dist/src/config/providerPersistence.test.js +0 -283
- package/dist/src/config/providerPersistence.test.js.map +0 -1
- package/dist/src/ui/components/GeminiKeyDialog.d.ts +0 -11
- package/dist/src/ui/components/GeminiKeyDialog.js +0 -156
- package/dist/src/ui/components/GeminiKeyDialog.js.map +0 -1
- package/dist/src/ui/components/OpenAIEndpointDialog.d.ts +0 -19
- package/dist/src/ui/components/OpenAIEndpointDialog.js +0 -163
- package/dist/src/ui/components/OpenAIEndpointDialog.js.map +0 -1
- package/dist/test-setup.ts +0 -12
- package/dist/test-utils/customMatchers.ts +0 -65
- package/dist/test-utils/mockCommandContext.test.ts +0 -62
- package/dist/test-utils/mockCommandContext.ts +0 -105
- package/dist/test-utils/render.tsx +0 -18
- package/dist/ui/App.test.tsx +0 -2181
- package/dist/ui/App.tsx +0 -1344
- package/dist/ui/IdeIntegrationNudge.tsx +0 -98
- package/dist/ui/__snapshots__/App.test.tsx.snap +0 -124
- package/dist/ui/colors.ts +0 -56
- package/dist/ui/commands/aboutCommand.test.ts +0 -153
- package/dist/ui/commands/aboutCommand.ts +0 -49
- package/dist/ui/commands/authCommand.test.ts +0 -36
- package/dist/ui/commands/authCommand.ts +0 -17
- package/dist/ui/commands/bugCommand.test.ts +0 -114
- package/dist/ui/commands/bugCommand.ts +0 -92
- package/dist/ui/commands/chatCommand.test.ts +0 -414
- package/dist/ui/commands/chatCommand.ts +0 -280
- package/dist/ui/commands/clearCommand.test.ts +0 -100
- package/dist/ui/commands/clearCommand.ts +0 -29
- package/dist/ui/commands/compressCommand.test.ts +0 -129
- package/dist/ui/commands/compressCommand.ts +0 -78
- package/dist/ui/commands/contextCommand.ts +0 -132
- package/dist/ui/commands/copyCommand.test.ts +0 -296
- package/dist/ui/commands/copyCommand.ts +0 -67
- package/dist/ui/commands/corgiCommand.test.ts +0 -34
- package/dist/ui/commands/corgiCommand.ts +0 -16
- package/dist/ui/commands/directoryCommand.test.tsx +0 -185
- package/dist/ui/commands/directoryCommand.tsx +0 -179
- package/dist/ui/commands/docsCommand.test.ts +0 -99
- package/dist/ui/commands/docsCommand.ts +0 -42
- package/dist/ui/commands/editorCommand.test.ts +0 -30
- package/dist/ui/commands/editorCommand.ts +0 -21
- package/dist/ui/commands/extensionsCommand.test.ts +0 -67
- package/dist/ui/commands/extensionsCommand.ts +0 -46
- package/dist/ui/commands/helpCommand.test.ts +0 -52
- package/dist/ui/commands/helpCommand.ts +0 -23
- package/dist/ui/commands/ideCommand.test.ts +0 -255
- package/dist/ui/commands/ideCommand.ts +0 -283
- package/dist/ui/commands/initCommand.test.ts +0 -127
- package/dist/ui/commands/initCommand.ts +0 -117
- package/dist/ui/commands/mcpCommand.test.ts +0 -1057
- package/dist/ui/commands/mcpCommand.ts +0 -531
- package/dist/ui/commands/memoryCommand.test.ts +0 -344
- package/dist/ui/commands/memoryCommand.ts +0 -305
- package/dist/ui/commands/privacyCommand.test.ts +0 -38
- package/dist/ui/commands/privacyCommand.ts +0 -17
- package/dist/ui/commands/quitCommand.test.ts +0 -55
- package/dist/ui/commands/quitCommand.ts +0 -36
- package/dist/ui/commands/restoreCommand.test.ts +0 -250
- package/dist/ui/commands/restoreCommand.ts +0 -157
- package/dist/ui/commands/searchEngineSetupCommand.ts +0 -18
- package/dist/ui/commands/settingsCommand.test.ts +0 -36
- package/dist/ui/commands/settingsCommand.ts +0 -17
- package/dist/ui/commands/setupGithubCommand.test.ts +0 -238
- package/dist/ui/commands/setupGithubCommand.ts +0 -212
- package/dist/ui/commands/speakCommand.ts +0 -175
- package/dist/ui/commands/statsCommand.test.ts +0 -78
- package/dist/ui/commands/statsCommand.ts +0 -70
- package/dist/ui/commands/terminalSetupCommand.test.ts +0 -85
- package/dist/ui/commands/terminalSetupCommand.ts +0 -45
- package/dist/ui/commands/themeCommand.test.ts +0 -38
- package/dist/ui/commands/themeCommand.ts +0 -17
- package/dist/ui/commands/toolsCommand.test.ts +0 -105
- package/dist/ui/commands/toolsCommand.ts +0 -71
- package/dist/ui/commands/ttsCommand.ts +0 -143
- package/dist/ui/commands/types.ts +0 -204
- package/dist/ui/commands/vimCommand.ts +0 -25
- package/dist/ui/commands/voiceCommand.ts +0 -125
- package/dist/ui/components/AboutBox.tsx +0 -133
- package/dist/ui/components/AsciiArt.ts +0 -54
- package/dist/ui/components/AuthDialog.test.tsx +0 -334
- package/dist/ui/components/AuthDialog.tsx +0 -289
- package/dist/ui/components/AuthInProgress.tsx +0 -62
- package/dist/ui/components/AutoAcceptIndicator.tsx +0 -47
- package/dist/ui/components/ConsoleSummaryDisplay.tsx +0 -35
- package/dist/ui/components/ContextSummaryDisplay.test.tsx +0 -85
- package/dist/ui/components/ContextSummaryDisplay.tsx +0 -120
- package/dist/ui/components/ContextUsageDisplay.tsx +0 -77
- package/dist/ui/components/DebugProfiler.tsx +0 -36
- package/dist/ui/components/DetailedMessagesDisplay.tsx +0 -82
- package/dist/ui/components/EditorSettingsDialog.tsx +0 -172
- package/dist/ui/components/FolderTrustDialog.test.tsx +0 -36
- package/dist/ui/components/FolderTrustDialog.tsx +0 -74
- package/dist/ui/components/Footer.test.tsx +0 -159
- package/dist/ui/components/Footer.tsx +0 -158
- package/dist/ui/components/GeminiKeyDialog.tsx +0 -252
- package/dist/ui/components/GeminiRespondingSpinner.tsx +0 -34
- package/dist/ui/components/Header.test.tsx +0 -44
- package/dist/ui/components/Header.tsx +0 -70
- package/dist/ui/components/Help.tsx +0 -174
- package/dist/ui/components/HistoryItemDisplay.test.tsx +0 -125
- package/dist/ui/components/HistoryItemDisplay.tsx +0 -98
- package/dist/ui/components/InputPrompt.test.tsx +0 -1467
- package/dist/ui/components/InputPrompt.tsx +0 -641
- package/dist/ui/components/LMStudioModelPrompt.tsx +0 -215
- package/dist/ui/components/LoadingIndicator.test.tsx +0 -296
- package/dist/ui/components/LoadingIndicator.tsx +0 -82
- package/dist/ui/components/MemoryUsageDisplay.tsx +0 -36
- package/dist/ui/components/ModelStatsDisplay.test.tsx +0 -252
- package/dist/ui/components/ModelStatsDisplay.tsx +0 -197
- package/dist/ui/components/OllamaModelPrompt.tsx +0 -206
- package/dist/ui/components/OpenAIEndpointDialog.tsx +0 -261
- package/dist/ui/components/OpenAIKeyPrompt.test.tsx +0 -64
- package/dist/ui/components/OpenAIKeyPrompt.tsx +0 -197
- package/dist/ui/components/PrepareLabel.tsx +0 -48
- package/dist/ui/components/SearchEngineConfigDialog.tsx +0 -280
- package/dist/ui/components/SessionSummaryDisplay.test.tsx +0 -75
- package/dist/ui/components/SessionSummaryDisplay.tsx +0 -18
- package/dist/ui/components/SettingsDialog.test.tsx +0 -865
- package/dist/ui/components/SettingsDialog.tsx +0 -753
- package/dist/ui/components/ShellConfirmationDialog.test.tsx +0 -53
- package/dist/ui/components/ShellConfirmationDialog.tsx +0 -103
- package/dist/ui/components/ShellModeIndicator.tsx +0 -18
- package/dist/ui/components/ShowMoreLines.tsx +0 -40
- package/dist/ui/components/StatsDisplay.test.tsx +0 -401
- package/dist/ui/components/StatsDisplay.tsx +0 -273
- package/dist/ui/components/SuggestionsDisplay.tsx +0 -102
- package/dist/ui/components/ThemeDialog.tsx +0 -310
- package/dist/ui/components/Tips.tsx +0 -45
- package/dist/ui/components/TodoDisplay.test.tsx +0 -97
- package/dist/ui/components/TodoDisplay.tsx +0 -72
- package/dist/ui/components/ToolStatsDisplay.test.tsx +0 -180
- package/dist/ui/components/ToolStatsDisplay.tsx +0 -208
- package/dist/ui/components/UpdateNotification.tsx +0 -23
- package/dist/ui/components/WelcomeBackDialog.tsx +0 -290
- package/dist/ui/components/__snapshots__/IDEContextDetailDisplay.test.tsx.snap +0 -24
- package/dist/ui/components/__snapshots__/ModelStatsDisplay.test.tsx.snap +0 -121
- package/dist/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap +0 -30
- package/dist/ui/components/__snapshots__/ShellConfirmationDialog.test.tsx.snap +0 -21
- package/dist/ui/components/__snapshots__/StatsDisplay.test.tsx.snap +0 -264
- package/dist/ui/components/__snapshots__/ToolStatsDisplay.test.tsx.snap +0 -91
- package/dist/ui/components/messages/CompressionMessage.tsx +0 -49
- package/dist/ui/components/messages/DiffRenderer.test.tsx +0 -365
- package/dist/ui/components/messages/DiffRenderer.tsx +0 -358
- package/dist/ui/components/messages/ErrorMessage.tsx +0 -31
- package/dist/ui/components/messages/GeminiMessage.tsx +0 -43
- package/dist/ui/components/messages/GeminiMessageContent.tsx +0 -43
- package/dist/ui/components/messages/InfoMessage.tsx +0 -32
- package/dist/ui/components/messages/ToolConfirmationMessage.test.tsx +0 -58
- package/dist/ui/components/messages/ToolConfirmationMessage.tsx +0 -297
- package/dist/ui/components/messages/ToolGroupMessage.tsx +0 -126
- package/dist/ui/components/messages/ToolMessage.test.tsx +0 -183
- package/dist/ui/components/messages/ToolMessage.tsx +0 -296
- package/dist/ui/components/messages/UserMessage.tsx +0 -43
- package/dist/ui/components/messages/UserShellMessage.tsx +0 -25
- package/dist/ui/components/shared/MaxSizedBox.test.tsx +0 -425
- package/dist/ui/components/shared/MaxSizedBox.tsx +0 -624
- package/dist/ui/components/shared/RadioButtonSelect.test.tsx +0 -181
- package/dist/ui/components/shared/RadioButtonSelect.tsx +0 -234
- package/dist/ui/components/shared/__snapshots__/RadioButtonSelect.test.tsx.snap +0 -47
- package/dist/ui/components/shared/text-buffer.test.ts +0 -1728
- package/dist/ui/components/shared/text-buffer.ts +0 -2227
- package/dist/ui/components/shared/vim-buffer-actions.test.ts +0 -1119
- package/dist/ui/components/shared/vim-buffer-actions.ts +0 -814
- package/dist/ui/constants.ts +0 -17
- package/dist/ui/contexts/KeypressContext.test.tsx +0 -391
- package/dist/ui/contexts/KeypressContext.tsx +0 -440
- package/dist/ui/contexts/OverflowContext.tsx +0 -87
- package/dist/ui/contexts/SessionContext.test.tsx +0 -132
- package/dist/ui/contexts/SessionContext.tsx +0 -143
- package/dist/ui/contexts/SettingsContext.tsx +0 -20
- package/dist/ui/contexts/StreamingContext.tsx +0 -22
- package/dist/ui/contexts/VimModeContext.tsx +0 -79
- package/dist/ui/editors/editorSettingsManager.ts +0 -66
- package/dist/ui/hooks/atCommandProcessor.test.ts +0 -1102
- package/dist/ui/hooks/atCommandProcessor.ts +0 -485
- package/dist/ui/hooks/shellCommandProcessor.test.ts +0 -481
- package/dist/ui/hooks/shellCommandProcessor.ts +0 -314
- package/dist/ui/hooks/slashCommandProcessor.test.ts +0 -1044
- package/dist/ui/hooks/slashCommandProcessor.ts +0 -595
- package/dist/ui/hooks/useAtCompletion.test.ts +0 -497
- package/dist/ui/hooks/useAtCompletion.ts +0 -244
- package/dist/ui/hooks/useAuthCommand.ts +0 -129
- package/dist/ui/hooks/useAutoAcceptIndicator.test.ts +0 -300
- package/dist/ui/hooks/useAutoAcceptIndicator.ts +0 -52
- package/dist/ui/hooks/useBracketedPaste.ts +0 -37
- package/dist/ui/hooks/useCommandCompletion.test.ts +0 -518
- package/dist/ui/hooks/useCommandCompletion.tsx +0 -238
- package/dist/ui/hooks/useCompletion.ts +0 -128
- package/dist/ui/hooks/useConsoleMessages.test.ts +0 -147
- package/dist/ui/hooks/useConsoleMessages.ts +0 -110
- package/dist/ui/hooks/useEditorSettings.test.ts +0 -283
- package/dist/ui/hooks/useEditorSettings.ts +0 -75
- package/dist/ui/hooks/useFocus.test.ts +0 -119
- package/dist/ui/hooks/useFocus.ts +0 -48
- package/dist/ui/hooks/useFolderTrust.test.ts +0 -159
- package/dist/ui/hooks/useFolderTrust.ts +0 -72
- package/dist/ui/hooks/useGeminiStream.test.tsx +0 -1998
- package/dist/ui/hooks/useGeminiStream.ts +0 -1017
- package/dist/ui/hooks/useGitBranchName.test.ts +0 -280
- package/dist/ui/hooks/useGitBranchName.ts +0 -79
- package/dist/ui/hooks/useHistoryManager.test.ts +0 -202
- package/dist/ui/hooks/useHistoryManager.ts +0 -111
- package/dist/ui/hooks/useInputHistory.test.ts +0 -261
- package/dist/ui/hooks/useInputHistory.ts +0 -111
- package/dist/ui/hooks/useKeypress.test.ts +0 -280
- package/dist/ui/hooks/useKeypress.ts +0 -39
- package/dist/ui/hooks/useKittyKeyboardProtocol.ts +0 -31
- package/dist/ui/hooks/useLoadingIndicator.test.ts +0 -139
- package/dist/ui/hooks/useLoadingIndicator.ts +0 -57
- package/dist/ui/hooks/useLogger.ts +0 -32
- package/dist/ui/hooks/useMessageQueue.test.ts +0 -226
- package/dist/ui/hooks/useMessageQueue.ts +0 -69
- package/dist/ui/hooks/usePhraseCycler.test.ts +0 -145
- package/dist/ui/hooks/usePhraseCycler.ts +0 -198
- package/dist/ui/hooks/usePrivacySettings.test.ts +0 -242
- package/dist/ui/hooks/usePrivacySettings.ts +0 -150
- package/dist/ui/hooks/useReactToolScheduler.ts +0 -309
- package/dist/ui/hooks/useRefreshMemoryCommand.ts +0 -7
- package/dist/ui/hooks/useReverseSearchCompletion.test.tsx +0 -260
- package/dist/ui/hooks/useReverseSearchCompletion.tsx +0 -95
- package/dist/ui/hooks/useSettingsCommand.ts +0 -25
- package/dist/ui/hooks/useShellHistory.test.ts +0 -219
- package/dist/ui/hooks/useShellHistory.ts +0 -133
- package/dist/ui/hooks/useShowMemoryCommand.ts +0 -75
- package/dist/ui/hooks/useSlashCompletion.test.ts +0 -434
- package/dist/ui/hooks/useSlashCompletion.ts +0 -187
- package/dist/ui/hooks/useStateAndRef.ts +0 -36
- package/dist/ui/hooks/useTerminalSize.ts +0 -32
- package/dist/ui/hooks/useThemeCommand.ts +0 -110
- package/dist/ui/hooks/useTimer.test.ts +0 -120
- package/dist/ui/hooks/useTimer.ts +0 -65
- package/dist/ui/hooks/useToolScheduler.test.ts +0 -1123
- package/dist/ui/hooks/useWelcomeBack.ts +0 -253
- package/dist/ui/hooks/vim.test.ts +0 -1691
- package/dist/ui/hooks/vim.ts +0 -784
- package/dist/ui/keyMatchers.test.ts +0 -337
- package/dist/ui/keyMatchers.ts +0 -105
- package/dist/ui/privacy/CloudFreePrivacyNotice.tsx +0 -117
- package/dist/ui/privacy/CloudPaidPrivacyNotice.tsx +0 -59
- package/dist/ui/privacy/GeminiPrivacyNotice.tsx +0 -62
- package/dist/ui/privacy/PrivacyNotice.tsx +0 -42
- package/dist/ui/semantic-colors.ts +0 -26
- package/dist/ui/themes/ansi-light.ts +0 -150
- package/dist/ui/themes/ansi.ts +0 -159
- package/dist/ui/themes/atom-one-dark.ts +0 -147
- package/dist/ui/themes/ayu-light.ts +0 -139
- package/dist/ui/themes/ayu.ts +0 -113
- package/dist/ui/themes/color-utils.test.ts +0 -221
- package/dist/ui/themes/color-utils.ts +0 -231
- package/dist/ui/themes/default-light.ts +0 -108
- package/dist/ui/themes/default.ts +0 -151
- package/dist/ui/themes/dracula.ts +0 -124
- package/dist/ui/themes/fss-code-dark.ts +0 -156
- package/dist/ui/themes/fss-dark.ts +0 -113
- package/dist/ui/themes/fss-light.ts +0 -139
- package/dist/ui/themes/github-dark.ts +0 -147
- package/dist/ui/themes/github-light.ts +0 -149
- package/dist/ui/themes/googlecode.ts +0 -146
- package/dist/ui/themes/no-color.ts +0 -125
- package/dist/ui/themes/qwen-dark.ts +0 -118
- package/dist/ui/themes/qwen-light.ts +0 -144
- package/dist/ui/themes/semantic-tokens.ts +0 -127
- package/dist/ui/themes/shades-of-purple.ts +0 -352
- package/dist/ui/themes/theme-manager.test.ts +0 -99
- package/dist/ui/themes/theme-manager.ts +0 -257
- package/dist/ui/themes/theme.test.ts +0 -97
- package/dist/ui/themes/theme.ts +0 -451
- package/dist/ui/themes/xcode.ts +0 -154
- package/dist/ui/types.ts +0 -255
- package/dist/ui/utils/CodeColorizer.tsx +0 -217
- package/dist/ui/utils/ConsolePatcher.ts +0 -71
- package/dist/ui/utils/InlineMarkdownRenderer.tsx +0 -173
- package/dist/ui/utils/MarkdownDisplay.test.tsx +0 -244
- package/dist/ui/utils/MarkdownDisplay.tsx +0 -415
- package/dist/ui/utils/TableRenderer.tsx +0 -159
- package/dist/ui/utils/__snapshots__/MarkdownDisplay.test.tsx.snap +0 -93
- package/dist/ui/utils/clipboardUtils.test.ts +0 -76
- package/dist/ui/utils/clipboardUtils.ts +0 -149
- package/dist/ui/utils/commandUtils.test.ts +0 -384
- package/dist/ui/utils/commandUtils.ts +0 -106
- package/dist/ui/utils/computeStats.test.ts +0 -292
- package/dist/ui/utils/computeStats.ts +0 -86
- package/dist/ui/utils/displayUtils.test.ts +0 -58
- package/dist/ui/utils/displayUtils.ts +0 -32
- package/dist/ui/utils/formatters.test.ts +0 -72
- package/dist/ui/utils/formatters.ts +0 -63
- package/dist/ui/utils/isNarrowWidth.ts +0 -9
- package/dist/ui/utils/kittyProtocolDetector.ts +0 -105
- package/dist/ui/utils/markdownUtilities.test.ts +0 -50
- package/dist/ui/utils/markdownUtilities.ts +0 -125
- package/dist/ui/utils/platformConstants.ts +0 -52
- package/dist/ui/utils/terminalSetup.ts +0 -342
- package/dist/ui/utils/textUtils.ts +0 -40
- package/dist/ui/utils/updateCheck.test.ts +0 -163
- package/dist/ui/utils/updateCheck.ts +0 -100
- package/dist/utils/checks.ts +0 -28
- package/dist/utils/cleanup.test.ts +0 -68
- package/dist/utils/cleanup.ts +0 -36
- package/dist/utils/dialogScopeUtils.ts +0 -64
- package/dist/utils/events.ts +0 -14
- package/dist/utils/gitUtils.test.ts +0 -149
- package/dist/utils/gitUtils.ts +0 -116
- package/dist/utils/handleAutoUpdate.test.ts +0 -272
- package/dist/utils/handleAutoUpdate.ts +0 -145
- package/dist/utils/installationInfo.test.ts +0 -315
- package/dist/utils/installationInfo.ts +0 -176
- package/dist/utils/package.ts +0 -38
- package/dist/utils/readStdin.ts +0 -51
- package/dist/utils/resolvePath.ts +0 -21
- package/dist/utils/sandbox-macos-permissive-closed.sb +0 -32
- package/dist/utils/sandbox-macos-permissive-open.sb +0 -25
- package/dist/utils/sandbox-macos-permissive-proxied.sb +0 -37
- package/dist/utils/sandbox-macos-restrictive-closed.sb +0 -93
- package/dist/utils/sandbox-macos-restrictive-open.sb +0 -96
- package/dist/utils/sandbox-macos-restrictive-proxied.sb +0 -98
- package/dist/utils/sandbox.ts +0 -962
- package/dist/utils/settingsUtils.test.ts +0 -797
- package/dist/utils/settingsUtils.ts +0 -489
- package/dist/utils/spawnWrapper.ts +0 -9
- package/dist/utils/startupWarnings.test.ts +0 -83
- package/dist/utils/startupWarnings.ts +0 -40
- package/dist/utils/updateEventEmitter.ts +0 -13
- package/dist/utils/userStartupWarnings.test.ts +0 -87
- package/dist/utils/userStartupWarnings.ts +0 -69
- package/dist/utils/version.ts +0 -12
- package/dist/validateNonInterActiveAuth.test.ts +0 -260
- package/dist/validateNonInterActiveAuth.ts +0 -51
- package/dist/vitest.config.ts +0 -37
- package/dist/zed-integration/acp.ts +0 -366
- package/dist/zed-integration/fileSystemService.ts +0 -47
- package/dist/zed-integration/schema.ts +0 -466
- package/dist/zed-integration/zedIntegration.ts +0 -944
|
@@ -1,1017 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { type Part, type PartListUnion, FinishReason } from '@google/genai';
|
|
8
|
-
import {
|
|
9
|
-
Config,
|
|
10
|
-
ServerGeminiContentEvent as ContentEvent,
|
|
11
|
-
DEFAULT_GEMINI_FLASH_MODEL,
|
|
12
|
-
EditorType,
|
|
13
|
-
ServerGeminiErrorEvent as ErrorEvent,
|
|
14
|
-
GeminiClient,
|
|
15
|
-
ServerGeminiStreamEvent as GeminiEvent,
|
|
16
|
-
getErrorMessage,
|
|
17
|
-
GitService,
|
|
18
|
-
isNodeError,
|
|
19
|
-
logUserPrompt,
|
|
20
|
-
MessageSenderType,
|
|
21
|
-
parseAndFormatApiError,
|
|
22
|
-
ServerGeminiChatCompressedEvent,
|
|
23
|
-
GeminiEventType as ServerGeminiEventType,
|
|
24
|
-
ServerGeminiFinishedEvent,
|
|
25
|
-
ThoughtSummary,
|
|
26
|
-
ToolCallRequestInfo,
|
|
27
|
-
UnauthorizedError,
|
|
28
|
-
UserPromptEvent,
|
|
29
|
-
} from 'fss-link-core';
|
|
30
|
-
import { promises as fs } from 'fs';
|
|
31
|
-
import path from 'path';
|
|
32
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
33
|
-
import { useSessionStats } from '../contexts/SessionContext.js';
|
|
34
|
-
import {
|
|
35
|
-
HistoryItem,
|
|
36
|
-
HistoryItemToolGroup,
|
|
37
|
-
HistoryItemWithoutId,
|
|
38
|
-
MessageType,
|
|
39
|
-
SlashCommandProcessorResult,
|
|
40
|
-
StreamingState,
|
|
41
|
-
ToolCallStatus,
|
|
42
|
-
} from '../types.js';
|
|
43
|
-
import { isAtCommand } from '../utils/commandUtils.js';
|
|
44
|
-
import { findLastSafeSplitPoint } from '../utils/markdownUtilities.js';
|
|
45
|
-
import { handleAtCommand } from './atCommandProcessor.js';
|
|
46
|
-
import { useShellCommandProcessor } from './shellCommandProcessor.js';
|
|
47
|
-
import { UseHistoryManagerReturn } from './useHistoryManager.js';
|
|
48
|
-
import { useKeypress } from './useKeypress.js';
|
|
49
|
-
import { useLogger } from './useLogger.js';
|
|
50
|
-
import {
|
|
51
|
-
mapToDisplay as mapTrackedToolCallsToDisplay,
|
|
52
|
-
TrackedCancelledToolCall,
|
|
53
|
-
TrackedCompletedToolCall,
|
|
54
|
-
TrackedToolCall,
|
|
55
|
-
useReactToolScheduler,
|
|
56
|
-
} from './useReactToolScheduler.js';
|
|
57
|
-
import { useStateAndRef } from './useStateAndRef.js';
|
|
58
|
-
|
|
59
|
-
export function mergePartListUnions(list: PartListUnion[]): PartListUnion {
|
|
60
|
-
const resultParts: PartListUnion = [];
|
|
61
|
-
for (const item of list) {
|
|
62
|
-
if (Array.isArray(item)) {
|
|
63
|
-
resultParts.push(...item);
|
|
64
|
-
} else {
|
|
65
|
-
resultParts.push(item);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return resultParts;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
enum StreamProcessingStatus {
|
|
72
|
-
Completed,
|
|
73
|
-
UserCancelled,
|
|
74
|
-
Error,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Manages the Gemini stream, including user input, command processing,
|
|
79
|
-
* API interaction, and tool call lifecycle.
|
|
80
|
-
*/
|
|
81
|
-
export const useGeminiStream = (
|
|
82
|
-
geminiClient: GeminiClient,
|
|
83
|
-
history: HistoryItem[],
|
|
84
|
-
addItem: UseHistoryManagerReturn['addItem'],
|
|
85
|
-
config: Config,
|
|
86
|
-
onDebugMessage: (message: string) => void,
|
|
87
|
-
handleSlashCommand: (
|
|
88
|
-
cmd: PartListUnion,
|
|
89
|
-
) => Promise<SlashCommandProcessorResult | false>,
|
|
90
|
-
shellModeActive: boolean,
|
|
91
|
-
getPreferredEditor: () => EditorType | undefined,
|
|
92
|
-
onAuthError: () => void,
|
|
93
|
-
performMemoryRefresh: () => Promise<void>,
|
|
94
|
-
modelSwitchedFromQuotaError: boolean,
|
|
95
|
-
setModelSwitchedFromQuotaError: React.Dispatch<React.SetStateAction<boolean>>,
|
|
96
|
-
onEditorClose: () => void,
|
|
97
|
-
onCancelSubmit: () => void,
|
|
98
|
-
) => {
|
|
99
|
-
const [initError, setInitError] = useState<string | null>(null);
|
|
100
|
-
const abortControllerRef = useRef<AbortController | null>(null);
|
|
101
|
-
const turnCancelledRef = useRef(false);
|
|
102
|
-
const isSubmittingQueryRef = useRef(false);
|
|
103
|
-
const [isResponding, setIsResponding] = useState<boolean>(false);
|
|
104
|
-
const [thought, setThought] = useState<ThoughtSummary | null>(null);
|
|
105
|
-
const [pendingHistoryItemRef, setPendingHistoryItem] =
|
|
106
|
-
useStateAndRef<HistoryItemWithoutId | null>(null);
|
|
107
|
-
const processedMemoryToolsRef = useRef<Set<string>>(new Set());
|
|
108
|
-
const { startNewPrompt, getPromptCount } = useSessionStats();
|
|
109
|
-
const logger = useLogger();
|
|
110
|
-
const gitService = useMemo(() => {
|
|
111
|
-
if (!config.getProjectRoot()) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
return new GitService(config.getProjectRoot());
|
|
115
|
-
}, [config]);
|
|
116
|
-
|
|
117
|
-
const [toolCalls, scheduleToolCalls, markToolsAsSubmitted] =
|
|
118
|
-
useReactToolScheduler(
|
|
119
|
-
async (completedToolCallsFromScheduler) => {
|
|
120
|
-
// This onComplete is called when ALL scheduled tools for a given batch are done.
|
|
121
|
-
if (completedToolCallsFromScheduler.length > 0) {
|
|
122
|
-
// Add the final state of these tools to the history for display.
|
|
123
|
-
addItem(
|
|
124
|
-
mapTrackedToolCallsToDisplay(
|
|
125
|
-
completedToolCallsFromScheduler as TrackedToolCall[],
|
|
126
|
-
),
|
|
127
|
-
Date.now(),
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
// Handle tool response submission immediately when tools complete
|
|
131
|
-
await handleCompletedTools(
|
|
132
|
-
completedToolCallsFromScheduler as TrackedToolCall[],
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
config,
|
|
137
|
-
setPendingHistoryItem,
|
|
138
|
-
getPreferredEditor,
|
|
139
|
-
onEditorClose,
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const pendingToolCallGroupDisplay = useMemo(
|
|
143
|
-
() =>
|
|
144
|
-
toolCalls.length ? mapTrackedToolCallsToDisplay(toolCalls) : undefined,
|
|
145
|
-
[toolCalls],
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
const loopDetectedRef = useRef(false);
|
|
149
|
-
|
|
150
|
-
const onExec = useCallback(async (done: Promise<void>) => {
|
|
151
|
-
setIsResponding(true);
|
|
152
|
-
await done;
|
|
153
|
-
setIsResponding(false);
|
|
154
|
-
}, []);
|
|
155
|
-
const { handleShellCommand } = useShellCommandProcessor(
|
|
156
|
-
addItem,
|
|
157
|
-
setPendingHistoryItem,
|
|
158
|
-
onExec,
|
|
159
|
-
onDebugMessage,
|
|
160
|
-
config,
|
|
161
|
-
geminiClient,
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
const streamingState = useMemo(() => {
|
|
165
|
-
if (toolCalls.some((tc) => tc.status === 'awaiting_approval')) {
|
|
166
|
-
return StreamingState.WaitingForConfirmation;
|
|
167
|
-
}
|
|
168
|
-
if (
|
|
169
|
-
isResponding ||
|
|
170
|
-
toolCalls.some(
|
|
171
|
-
(tc) =>
|
|
172
|
-
tc.status === 'executing' ||
|
|
173
|
-
tc.status === 'scheduled' ||
|
|
174
|
-
tc.status === 'validating' ||
|
|
175
|
-
((tc.status === 'success' ||
|
|
176
|
-
tc.status === 'error' ||
|
|
177
|
-
tc.status === 'cancelled') &&
|
|
178
|
-
!(tc as TrackedCompletedToolCall | TrackedCancelledToolCall)
|
|
179
|
-
.responseSubmittedToGemini),
|
|
180
|
-
)
|
|
181
|
-
) {
|
|
182
|
-
return StreamingState.Responding;
|
|
183
|
-
}
|
|
184
|
-
return StreamingState.Idle;
|
|
185
|
-
}, [isResponding, toolCalls]);
|
|
186
|
-
|
|
187
|
-
const cancelOngoingRequest = useCallback(() => {
|
|
188
|
-
if (streamingState !== StreamingState.Responding) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (turnCancelledRef.current) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
turnCancelledRef.current = true;
|
|
195
|
-
isSubmittingQueryRef.current = false;
|
|
196
|
-
abortControllerRef.current?.abort();
|
|
197
|
-
if (pendingHistoryItemRef.current) {
|
|
198
|
-
addItem(pendingHistoryItemRef.current, Date.now());
|
|
199
|
-
}
|
|
200
|
-
addItem(
|
|
201
|
-
{
|
|
202
|
-
type: MessageType.INFO,
|
|
203
|
-
text: 'Request cancelled.',
|
|
204
|
-
},
|
|
205
|
-
Date.now(),
|
|
206
|
-
);
|
|
207
|
-
setPendingHistoryItem(null);
|
|
208
|
-
onCancelSubmit();
|
|
209
|
-
setIsResponding(false);
|
|
210
|
-
}, [
|
|
211
|
-
streamingState,
|
|
212
|
-
addItem,
|
|
213
|
-
setPendingHistoryItem,
|
|
214
|
-
onCancelSubmit,
|
|
215
|
-
pendingHistoryItemRef,
|
|
216
|
-
]);
|
|
217
|
-
|
|
218
|
-
useKeypress(
|
|
219
|
-
(key) => {
|
|
220
|
-
if (key.name === 'escape') {
|
|
221
|
-
cancelOngoingRequest();
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
{ isActive: streamingState === StreamingState.Responding },
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
const prepareQueryForGemini = useCallback(
|
|
228
|
-
async (
|
|
229
|
-
query: PartListUnion,
|
|
230
|
-
userMessageTimestamp: number,
|
|
231
|
-
abortSignal: AbortSignal,
|
|
232
|
-
prompt_id: string,
|
|
233
|
-
): Promise<{
|
|
234
|
-
queryToSend: PartListUnion | null;
|
|
235
|
-
shouldProceed: boolean;
|
|
236
|
-
}> => {
|
|
237
|
-
if (turnCancelledRef.current) {
|
|
238
|
-
return { queryToSend: null, shouldProceed: false };
|
|
239
|
-
}
|
|
240
|
-
if (typeof query === 'string' && query.trim().length === 0) {
|
|
241
|
-
return { queryToSend: null, shouldProceed: false };
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
let localQueryToSendToGemini: PartListUnion | null = null;
|
|
245
|
-
|
|
246
|
-
if (typeof query === 'string') {
|
|
247
|
-
const trimmedQuery = query.trim();
|
|
248
|
-
logUserPrompt(
|
|
249
|
-
config,
|
|
250
|
-
new UserPromptEvent(
|
|
251
|
-
trimmedQuery.length,
|
|
252
|
-
prompt_id,
|
|
253
|
-
config.getContentGeneratorConfig()?.authType,
|
|
254
|
-
trimmedQuery,
|
|
255
|
-
),
|
|
256
|
-
);
|
|
257
|
-
onDebugMessage(`User query: '${trimmedQuery}'`);
|
|
258
|
-
await logger?.logMessage(MessageSenderType.USER, trimmedQuery);
|
|
259
|
-
|
|
260
|
-
// Handle UI-only commands first
|
|
261
|
-
const slashCommandResult = await handleSlashCommand(trimmedQuery);
|
|
262
|
-
|
|
263
|
-
if (slashCommandResult) {
|
|
264
|
-
switch (slashCommandResult.type) {
|
|
265
|
-
case 'schedule_tool': {
|
|
266
|
-
const { toolName, toolArgs } = slashCommandResult;
|
|
267
|
-
const toolCallRequest: ToolCallRequestInfo = {
|
|
268
|
-
callId: `${toolName}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
269
|
-
name: toolName,
|
|
270
|
-
args: toolArgs,
|
|
271
|
-
isClientInitiated: true,
|
|
272
|
-
prompt_id,
|
|
273
|
-
};
|
|
274
|
-
scheduleToolCalls([toolCallRequest], abortSignal);
|
|
275
|
-
return { queryToSend: null, shouldProceed: false };
|
|
276
|
-
}
|
|
277
|
-
case 'submit_prompt': {
|
|
278
|
-
localQueryToSendToGemini = slashCommandResult.content;
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
queryToSend: localQueryToSendToGemini,
|
|
282
|
-
shouldProceed: true,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
case 'handled': {
|
|
286
|
-
return { queryToSend: null, shouldProceed: false };
|
|
287
|
-
}
|
|
288
|
-
default: {
|
|
289
|
-
const unreachable: never = slashCommandResult;
|
|
290
|
-
throw new Error(
|
|
291
|
-
`Unhandled slash command result type: ${unreachable}`,
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (shellModeActive && handleShellCommand(trimmedQuery, abortSignal)) {
|
|
298
|
-
return { queryToSend: null, shouldProceed: false };
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Handle @-commands (which might involve tool calls)
|
|
302
|
-
if (isAtCommand(trimmedQuery)) {
|
|
303
|
-
const atCommandResult = await handleAtCommand({
|
|
304
|
-
query: trimmedQuery,
|
|
305
|
-
config,
|
|
306
|
-
addItem,
|
|
307
|
-
onDebugMessage,
|
|
308
|
-
messageId: userMessageTimestamp,
|
|
309
|
-
signal: abortSignal,
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// Add user's turn after @ command processing is done.
|
|
313
|
-
addItem(
|
|
314
|
-
{ type: MessageType.USER, text: trimmedQuery },
|
|
315
|
-
userMessageTimestamp,
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
if (!atCommandResult.shouldProceed) {
|
|
319
|
-
return { queryToSend: null, shouldProceed: false };
|
|
320
|
-
}
|
|
321
|
-
localQueryToSendToGemini = atCommandResult.processedQuery;
|
|
322
|
-
} else {
|
|
323
|
-
// Normal query for Gemini
|
|
324
|
-
addItem(
|
|
325
|
-
{ type: MessageType.USER, text: trimmedQuery },
|
|
326
|
-
userMessageTimestamp,
|
|
327
|
-
);
|
|
328
|
-
localQueryToSendToGemini = trimmedQuery;
|
|
329
|
-
}
|
|
330
|
-
} else {
|
|
331
|
-
// It's a function response (PartListUnion that isn't a string)
|
|
332
|
-
localQueryToSendToGemini = query;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
if (localQueryToSendToGemini === null) {
|
|
336
|
-
onDebugMessage(
|
|
337
|
-
'Query processing resulted in null, not sending to Gemini.',
|
|
338
|
-
);
|
|
339
|
-
return { queryToSend: null, shouldProceed: false };
|
|
340
|
-
}
|
|
341
|
-
return { queryToSend: localQueryToSendToGemini, shouldProceed: true };
|
|
342
|
-
},
|
|
343
|
-
[
|
|
344
|
-
config,
|
|
345
|
-
addItem,
|
|
346
|
-
onDebugMessage,
|
|
347
|
-
handleShellCommand,
|
|
348
|
-
handleSlashCommand,
|
|
349
|
-
logger,
|
|
350
|
-
shellModeActive,
|
|
351
|
-
scheduleToolCalls,
|
|
352
|
-
],
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
// --- Stream Event Handlers ---
|
|
356
|
-
|
|
357
|
-
const handleContentEvent = useCallback(
|
|
358
|
-
(
|
|
359
|
-
eventValue: ContentEvent['value'],
|
|
360
|
-
currentGeminiMessageBuffer: string,
|
|
361
|
-
userMessageTimestamp: number,
|
|
362
|
-
): string => {
|
|
363
|
-
if (turnCancelledRef.current) {
|
|
364
|
-
// Prevents additional output after a user initiated cancel.
|
|
365
|
-
return '';
|
|
366
|
-
}
|
|
367
|
-
let newGeminiMessageBuffer = currentGeminiMessageBuffer + eventValue;
|
|
368
|
-
if (
|
|
369
|
-
pendingHistoryItemRef.current?.type !== 'gemini' &&
|
|
370
|
-
pendingHistoryItemRef.current?.type !== 'gemini_content'
|
|
371
|
-
) {
|
|
372
|
-
if (pendingHistoryItemRef.current) {
|
|
373
|
-
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
|
374
|
-
}
|
|
375
|
-
setPendingHistoryItem({ type: 'gemini', text: '' });
|
|
376
|
-
newGeminiMessageBuffer = eventValue;
|
|
377
|
-
}
|
|
378
|
-
// Split large messages for better rendering performance. Ideally,
|
|
379
|
-
// we should maximize the amount of output sent to <Static />.
|
|
380
|
-
const splitPoint = findLastSafeSplitPoint(newGeminiMessageBuffer);
|
|
381
|
-
if (splitPoint === newGeminiMessageBuffer.length) {
|
|
382
|
-
// Update the existing message with accumulated content
|
|
383
|
-
setPendingHistoryItem((item) => ({
|
|
384
|
-
type: item?.type as 'gemini' | 'gemini_content',
|
|
385
|
-
text: newGeminiMessageBuffer,
|
|
386
|
-
}));
|
|
387
|
-
} else {
|
|
388
|
-
// This indicates that we need to split up this Gemini Message.
|
|
389
|
-
// Splitting a message is primarily a performance consideration. There is a
|
|
390
|
-
// <Static> component at the root of App.tsx which takes care of rendering
|
|
391
|
-
// content statically or dynamically. Everything but the last message is
|
|
392
|
-
// treated as static in order to prevent re-rendering an entire message history
|
|
393
|
-
// multiple times per-second (as streaming occurs). Prior to this change you'd
|
|
394
|
-
// see heavy flickering of the terminal. This ensures that larger messages get
|
|
395
|
-
// broken up so that there are more "statically" rendered.
|
|
396
|
-
const beforeText = newGeminiMessageBuffer.substring(0, splitPoint);
|
|
397
|
-
const afterText = newGeminiMessageBuffer.substring(splitPoint);
|
|
398
|
-
addItem(
|
|
399
|
-
{
|
|
400
|
-
type: pendingHistoryItemRef.current?.type as
|
|
401
|
-
| 'gemini'
|
|
402
|
-
| 'gemini_content',
|
|
403
|
-
text: beforeText,
|
|
404
|
-
},
|
|
405
|
-
userMessageTimestamp,
|
|
406
|
-
);
|
|
407
|
-
setPendingHistoryItem({ type: 'gemini_content', text: afterText });
|
|
408
|
-
newGeminiMessageBuffer = afterText;
|
|
409
|
-
}
|
|
410
|
-
return newGeminiMessageBuffer;
|
|
411
|
-
},
|
|
412
|
-
[addItem, pendingHistoryItemRef, setPendingHistoryItem],
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
const handleUserCancelledEvent = useCallback(
|
|
416
|
-
(userMessageTimestamp: number) => {
|
|
417
|
-
if (turnCancelledRef.current) {
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
if (pendingHistoryItemRef.current) {
|
|
421
|
-
if (pendingHistoryItemRef.current.type === 'tool_group') {
|
|
422
|
-
const updatedTools = pendingHistoryItemRef.current.tools.map(
|
|
423
|
-
(tool) =>
|
|
424
|
-
tool.status === ToolCallStatus.Pending ||
|
|
425
|
-
tool.status === ToolCallStatus.Confirming ||
|
|
426
|
-
tool.status === ToolCallStatus.Executing
|
|
427
|
-
? { ...tool, status: ToolCallStatus.Canceled }
|
|
428
|
-
: tool,
|
|
429
|
-
);
|
|
430
|
-
const pendingItem: HistoryItemToolGroup = {
|
|
431
|
-
...pendingHistoryItemRef.current,
|
|
432
|
-
tools: updatedTools,
|
|
433
|
-
};
|
|
434
|
-
addItem(pendingItem, userMessageTimestamp);
|
|
435
|
-
} else {
|
|
436
|
-
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
|
437
|
-
}
|
|
438
|
-
setPendingHistoryItem(null);
|
|
439
|
-
}
|
|
440
|
-
addItem(
|
|
441
|
-
{ type: MessageType.INFO, text: 'User cancelled the request.' },
|
|
442
|
-
userMessageTimestamp,
|
|
443
|
-
);
|
|
444
|
-
setIsResponding(false);
|
|
445
|
-
setThought(null); // Reset thought when user cancels
|
|
446
|
-
},
|
|
447
|
-
[addItem, pendingHistoryItemRef, setPendingHistoryItem, setThought],
|
|
448
|
-
);
|
|
449
|
-
|
|
450
|
-
const handleErrorEvent = useCallback(
|
|
451
|
-
(eventValue: ErrorEvent['value'], userMessageTimestamp: number) => {
|
|
452
|
-
if (pendingHistoryItemRef.current) {
|
|
453
|
-
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
|
454
|
-
setPendingHistoryItem(null);
|
|
455
|
-
}
|
|
456
|
-
addItem(
|
|
457
|
-
{
|
|
458
|
-
type: MessageType.ERROR,
|
|
459
|
-
text: parseAndFormatApiError(
|
|
460
|
-
eventValue.error,
|
|
461
|
-
config.getContentGeneratorConfig()?.authType,
|
|
462
|
-
undefined,
|
|
463
|
-
config.getModel(),
|
|
464
|
-
DEFAULT_GEMINI_FLASH_MODEL,
|
|
465
|
-
),
|
|
466
|
-
},
|
|
467
|
-
userMessageTimestamp,
|
|
468
|
-
);
|
|
469
|
-
setThought(null); // Reset thought when there's an error
|
|
470
|
-
},
|
|
471
|
-
[addItem, pendingHistoryItemRef, setPendingHistoryItem, config, setThought],
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
const handleFinishedEvent = useCallback(
|
|
475
|
-
(event: ServerGeminiFinishedEvent, userMessageTimestamp: number) => {
|
|
476
|
-
const finishReason = event.value;
|
|
477
|
-
|
|
478
|
-
const finishReasonMessages: Record<FinishReason, string | undefined> = {
|
|
479
|
-
[FinishReason.FINISH_REASON_UNSPECIFIED]: undefined,
|
|
480
|
-
[FinishReason.STOP]: undefined,
|
|
481
|
-
[FinishReason.MAX_TOKENS]: 'Response truncated due to token limits.',
|
|
482
|
-
[FinishReason.SAFETY]: 'Response stopped due to safety reasons.',
|
|
483
|
-
[FinishReason.RECITATION]: 'Response stopped due to recitation policy.',
|
|
484
|
-
[FinishReason.LANGUAGE]:
|
|
485
|
-
'Response stopped due to unsupported language.',
|
|
486
|
-
[FinishReason.BLOCKLIST]: 'Response stopped due to forbidden terms.',
|
|
487
|
-
[FinishReason.PROHIBITED_CONTENT]:
|
|
488
|
-
'Response stopped due to prohibited content.',
|
|
489
|
-
[FinishReason.SPII]:
|
|
490
|
-
'Response stopped due to sensitive personally identifiable information.',
|
|
491
|
-
[FinishReason.OTHER]: 'Response stopped for other reasons.',
|
|
492
|
-
[FinishReason.MALFORMED_FUNCTION_CALL]:
|
|
493
|
-
'Response stopped due to malformed function call.',
|
|
494
|
-
[FinishReason.IMAGE_SAFETY]:
|
|
495
|
-
'Response stopped due to image safety violations.',
|
|
496
|
-
[FinishReason.UNEXPECTED_TOOL_CALL]:
|
|
497
|
-
'Response stopped due to unexpected tool call.',
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
const message = finishReasonMessages[finishReason];
|
|
501
|
-
if (message) {
|
|
502
|
-
addItem(
|
|
503
|
-
{
|
|
504
|
-
type: 'info',
|
|
505
|
-
text: `⚠️ ${message}`,
|
|
506
|
-
},
|
|
507
|
-
userMessageTimestamp,
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
},
|
|
511
|
-
[addItem],
|
|
512
|
-
);
|
|
513
|
-
|
|
514
|
-
const handleChatCompressionEvent = useCallback(
|
|
515
|
-
(eventValue: ServerGeminiChatCompressedEvent['value']) =>
|
|
516
|
-
addItem(
|
|
517
|
-
{
|
|
518
|
-
type: 'info',
|
|
519
|
-
text:
|
|
520
|
-
`IMPORTANT: This conversation approached the input token limit for ${config.getModel()}. ` +
|
|
521
|
-
`A compressed context will be sent for future messages (compressed from: ` +
|
|
522
|
-
`${eventValue?.originalTokenCount ?? 'unknown'} to ` +
|
|
523
|
-
`${eventValue?.newTokenCount ?? 'unknown'} tokens).`,
|
|
524
|
-
},
|
|
525
|
-
Date.now(),
|
|
526
|
-
),
|
|
527
|
-
[addItem, config],
|
|
528
|
-
);
|
|
529
|
-
|
|
530
|
-
const handleMaxSessionTurnsEvent = useCallback(
|
|
531
|
-
() =>
|
|
532
|
-
addItem(
|
|
533
|
-
{
|
|
534
|
-
type: 'info',
|
|
535
|
-
text:
|
|
536
|
-
`The session has reached the maximum number of turns: ${config.getMaxSessionTurns()}. ` +
|
|
537
|
-
`Please update this limit in your setting.json file.`,
|
|
538
|
-
},
|
|
539
|
-
Date.now(),
|
|
540
|
-
),
|
|
541
|
-
[addItem, config],
|
|
542
|
-
);
|
|
543
|
-
|
|
544
|
-
const handleSessionTokenLimitExceededEvent = useCallback(
|
|
545
|
-
(value: { currentTokens: number; limit: number; message: string }) =>
|
|
546
|
-
addItem(
|
|
547
|
-
{
|
|
548
|
-
type: 'error',
|
|
549
|
-
text:
|
|
550
|
-
`🚫 Session token limit exceeded: ${value.currentTokens.toLocaleString()} tokens > ${value.limit.toLocaleString()} limit.\n\n` +
|
|
551
|
-
`💡 Solutions:\n` +
|
|
552
|
-
` • Start a new session: Use /clear command\n` +
|
|
553
|
-
` • Increase limit: Add "sessionTokenLimit": (e.g., 128000) to your settings.json\n` +
|
|
554
|
-
` • Compress history: Use /compress command to compress history`,
|
|
555
|
-
},
|
|
556
|
-
Date.now(),
|
|
557
|
-
),
|
|
558
|
-
[addItem],
|
|
559
|
-
);
|
|
560
|
-
|
|
561
|
-
const handleLoopDetectedEvent = useCallback(() => {
|
|
562
|
-
addItem(
|
|
563
|
-
{
|
|
564
|
-
type: 'info',
|
|
565
|
-
text: `A potential loop was detected. This can happen due to repetitive tool calls or other model behavior. The request has been halted.`,
|
|
566
|
-
},
|
|
567
|
-
Date.now(),
|
|
568
|
-
);
|
|
569
|
-
}, [addItem]);
|
|
570
|
-
|
|
571
|
-
const processGeminiStreamEvents = useCallback(
|
|
572
|
-
async (
|
|
573
|
-
stream: AsyncIterable<GeminiEvent>,
|
|
574
|
-
userMessageTimestamp: number,
|
|
575
|
-
signal: AbortSignal,
|
|
576
|
-
): Promise<StreamProcessingStatus> => {
|
|
577
|
-
let geminiMessageBuffer = '';
|
|
578
|
-
const toolCallRequests: ToolCallRequestInfo[] = [];
|
|
579
|
-
for await (const event of stream) {
|
|
580
|
-
switch (event.type) {
|
|
581
|
-
case ServerGeminiEventType.Thought:
|
|
582
|
-
setThought(event.value);
|
|
583
|
-
break;
|
|
584
|
-
case ServerGeminiEventType.Content:
|
|
585
|
-
geminiMessageBuffer = handleContentEvent(
|
|
586
|
-
event.value,
|
|
587
|
-
geminiMessageBuffer,
|
|
588
|
-
userMessageTimestamp,
|
|
589
|
-
);
|
|
590
|
-
break;
|
|
591
|
-
case ServerGeminiEventType.ToolCallRequest:
|
|
592
|
-
toolCallRequests.push(event.value);
|
|
593
|
-
break;
|
|
594
|
-
case ServerGeminiEventType.UserCancelled:
|
|
595
|
-
handleUserCancelledEvent(userMessageTimestamp);
|
|
596
|
-
break;
|
|
597
|
-
case ServerGeminiEventType.Error:
|
|
598
|
-
handleErrorEvent(event.value, userMessageTimestamp);
|
|
599
|
-
break;
|
|
600
|
-
case ServerGeminiEventType.ChatCompressed:
|
|
601
|
-
handleChatCompressionEvent(event.value);
|
|
602
|
-
break;
|
|
603
|
-
case ServerGeminiEventType.ToolCallConfirmation:
|
|
604
|
-
case ServerGeminiEventType.ToolCallResponse:
|
|
605
|
-
// do nothing
|
|
606
|
-
break;
|
|
607
|
-
case ServerGeminiEventType.MaxSessionTurns:
|
|
608
|
-
handleMaxSessionTurnsEvent();
|
|
609
|
-
break;
|
|
610
|
-
case ServerGeminiEventType.SessionTokenLimitExceeded:
|
|
611
|
-
handleSessionTokenLimitExceededEvent(event.value);
|
|
612
|
-
break;
|
|
613
|
-
case ServerGeminiEventType.Finished:
|
|
614
|
-
handleFinishedEvent(
|
|
615
|
-
event as ServerGeminiFinishedEvent,
|
|
616
|
-
userMessageTimestamp,
|
|
617
|
-
);
|
|
618
|
-
break;
|
|
619
|
-
case ServerGeminiEventType.LoopDetected:
|
|
620
|
-
// handle later because we want to move pending history to history
|
|
621
|
-
// before we add loop detected message to history
|
|
622
|
-
loopDetectedRef.current = true;
|
|
623
|
-
break;
|
|
624
|
-
default: {
|
|
625
|
-
// enforces exhaustive switch-case
|
|
626
|
-
const unreachable: never = event;
|
|
627
|
-
return unreachable;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (toolCallRequests.length > 0) {
|
|
632
|
-
scheduleToolCalls(toolCallRequests, signal);
|
|
633
|
-
}
|
|
634
|
-
return StreamProcessingStatus.Completed;
|
|
635
|
-
},
|
|
636
|
-
[
|
|
637
|
-
handleContentEvent,
|
|
638
|
-
handleUserCancelledEvent,
|
|
639
|
-
handleErrorEvent,
|
|
640
|
-
scheduleToolCalls,
|
|
641
|
-
handleChatCompressionEvent,
|
|
642
|
-
handleFinishedEvent,
|
|
643
|
-
handleMaxSessionTurnsEvent,
|
|
644
|
-
handleSessionTokenLimitExceededEvent,
|
|
645
|
-
],
|
|
646
|
-
);
|
|
647
|
-
|
|
648
|
-
const submitQuery = useCallback(
|
|
649
|
-
async (
|
|
650
|
-
query: PartListUnion,
|
|
651
|
-
options?: { isContinuation: boolean },
|
|
652
|
-
prompt_id?: string,
|
|
653
|
-
) => {
|
|
654
|
-
// Prevent concurrent executions of submitQuery, but allow continuations
|
|
655
|
-
// which are part of the same logical flow (tool responses)
|
|
656
|
-
if (isSubmittingQueryRef.current && !options?.isContinuation) {
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
if (
|
|
661
|
-
(streamingState === StreamingState.Responding ||
|
|
662
|
-
streamingState === StreamingState.WaitingForConfirmation) &&
|
|
663
|
-
!options?.isContinuation
|
|
664
|
-
)
|
|
665
|
-
return;
|
|
666
|
-
|
|
667
|
-
// Set the flag to indicate we're now executing
|
|
668
|
-
isSubmittingQueryRef.current = true;
|
|
669
|
-
|
|
670
|
-
const userMessageTimestamp = Date.now();
|
|
671
|
-
|
|
672
|
-
// Reset quota error flag when starting a new query (not a continuation)
|
|
673
|
-
if (!options?.isContinuation) {
|
|
674
|
-
setModelSwitchedFromQuotaError(false);
|
|
675
|
-
config.setQuotaErrorOccurred(false);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
abortControllerRef.current = new AbortController();
|
|
679
|
-
const abortSignal = abortControllerRef.current.signal;
|
|
680
|
-
turnCancelledRef.current = false;
|
|
681
|
-
|
|
682
|
-
if (!prompt_id) {
|
|
683
|
-
prompt_id = config.getSessionId() + '########' + getPromptCount();
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
const { queryToSend, shouldProceed } = await prepareQueryForGemini(
|
|
687
|
-
query,
|
|
688
|
-
userMessageTimestamp,
|
|
689
|
-
abortSignal,
|
|
690
|
-
prompt_id!,
|
|
691
|
-
);
|
|
692
|
-
|
|
693
|
-
if (!shouldProceed || queryToSend === null) {
|
|
694
|
-
isSubmittingQueryRef.current = false;
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
if (!options?.isContinuation) {
|
|
699
|
-
startNewPrompt();
|
|
700
|
-
setThought(null); // Reset thought when starting a new prompt
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
setIsResponding(true);
|
|
704
|
-
setInitError(null);
|
|
705
|
-
|
|
706
|
-
try {
|
|
707
|
-
const stream = geminiClient.sendMessageStream(
|
|
708
|
-
queryToSend,
|
|
709
|
-
abortSignal,
|
|
710
|
-
prompt_id!,
|
|
711
|
-
);
|
|
712
|
-
const processingStatus = await processGeminiStreamEvents(
|
|
713
|
-
stream,
|
|
714
|
-
userMessageTimestamp,
|
|
715
|
-
abortSignal,
|
|
716
|
-
);
|
|
717
|
-
|
|
718
|
-
if (processingStatus === StreamProcessingStatus.UserCancelled) {
|
|
719
|
-
isSubmittingQueryRef.current = false;
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
if (pendingHistoryItemRef.current) {
|
|
724
|
-
addItem(pendingHistoryItemRef.current, userMessageTimestamp);
|
|
725
|
-
setPendingHistoryItem(null);
|
|
726
|
-
}
|
|
727
|
-
if (loopDetectedRef.current) {
|
|
728
|
-
loopDetectedRef.current = false;
|
|
729
|
-
handleLoopDetectedEvent();
|
|
730
|
-
}
|
|
731
|
-
} catch (error: unknown) {
|
|
732
|
-
if (error instanceof UnauthorizedError) {
|
|
733
|
-
onAuthError();
|
|
734
|
-
} else if (!isNodeError(error) || error.name !== 'AbortError') {
|
|
735
|
-
addItem(
|
|
736
|
-
{
|
|
737
|
-
type: MessageType.ERROR,
|
|
738
|
-
text: parseAndFormatApiError(
|
|
739
|
-
getErrorMessage(error) || 'Unknown error',
|
|
740
|
-
config.getContentGeneratorConfig()?.authType,
|
|
741
|
-
undefined,
|
|
742
|
-
config.getModel(),
|
|
743
|
-
DEFAULT_GEMINI_FLASH_MODEL,
|
|
744
|
-
),
|
|
745
|
-
},
|
|
746
|
-
userMessageTimestamp,
|
|
747
|
-
);
|
|
748
|
-
}
|
|
749
|
-
} finally {
|
|
750
|
-
setIsResponding(false);
|
|
751
|
-
isSubmittingQueryRef.current = false;
|
|
752
|
-
}
|
|
753
|
-
},
|
|
754
|
-
[
|
|
755
|
-
streamingState,
|
|
756
|
-
setModelSwitchedFromQuotaError,
|
|
757
|
-
prepareQueryForGemini,
|
|
758
|
-
processGeminiStreamEvents,
|
|
759
|
-
pendingHistoryItemRef,
|
|
760
|
-
addItem,
|
|
761
|
-
setPendingHistoryItem,
|
|
762
|
-
setInitError,
|
|
763
|
-
geminiClient,
|
|
764
|
-
onAuthError,
|
|
765
|
-
config,
|
|
766
|
-
startNewPrompt,
|
|
767
|
-
getPromptCount,
|
|
768
|
-
handleLoopDetectedEvent,
|
|
769
|
-
],
|
|
770
|
-
);
|
|
771
|
-
|
|
772
|
-
const handleCompletedTools = useCallback(
|
|
773
|
-
async (completedToolCallsFromScheduler: TrackedToolCall[]) => {
|
|
774
|
-
if (isResponding) {
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
const completedAndReadyToSubmitTools =
|
|
779
|
-
completedToolCallsFromScheduler.filter(
|
|
780
|
-
(
|
|
781
|
-
tc: TrackedToolCall,
|
|
782
|
-
): tc is TrackedCompletedToolCall | TrackedCancelledToolCall => {
|
|
783
|
-
const isTerminalState =
|
|
784
|
-
tc.status === 'success' ||
|
|
785
|
-
tc.status === 'error' ||
|
|
786
|
-
tc.status === 'cancelled';
|
|
787
|
-
|
|
788
|
-
if (isTerminalState) {
|
|
789
|
-
const completedOrCancelledCall = tc as
|
|
790
|
-
| TrackedCompletedToolCall
|
|
791
|
-
| TrackedCancelledToolCall;
|
|
792
|
-
return (
|
|
793
|
-
completedOrCancelledCall.response?.responseParts !== undefined
|
|
794
|
-
);
|
|
795
|
-
}
|
|
796
|
-
return false;
|
|
797
|
-
},
|
|
798
|
-
);
|
|
799
|
-
|
|
800
|
-
// Finalize any client-initiated tools as soon as they are done.
|
|
801
|
-
const clientTools = completedAndReadyToSubmitTools.filter(
|
|
802
|
-
(t) => t.request.isClientInitiated,
|
|
803
|
-
);
|
|
804
|
-
if (clientTools.length > 0) {
|
|
805
|
-
markToolsAsSubmitted(clientTools.map((t) => t.request.callId));
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
// Identify new, successful save_memory calls that we haven't processed yet.
|
|
809
|
-
const newSuccessfulMemorySaves = completedAndReadyToSubmitTools.filter(
|
|
810
|
-
(t) =>
|
|
811
|
-
t.request.name === 'save_memory' &&
|
|
812
|
-
t.status === 'success' &&
|
|
813
|
-
!processedMemoryToolsRef.current.has(t.request.callId),
|
|
814
|
-
);
|
|
815
|
-
|
|
816
|
-
if (newSuccessfulMemorySaves.length > 0) {
|
|
817
|
-
// Perform the refresh only if there are new ones.
|
|
818
|
-
void performMemoryRefresh();
|
|
819
|
-
// Mark them as processed so we don't do this again on the next render.
|
|
820
|
-
newSuccessfulMemorySaves.forEach((t) =>
|
|
821
|
-
processedMemoryToolsRef.current.add(t.request.callId),
|
|
822
|
-
);
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
const geminiTools = completedAndReadyToSubmitTools.filter(
|
|
826
|
-
(t) => !t.request.isClientInitiated,
|
|
827
|
-
);
|
|
828
|
-
|
|
829
|
-
if (geminiTools.length === 0) {
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// If all the tools were cancelled, don't submit a response to Gemini.
|
|
834
|
-
const allToolsCancelled = geminiTools.every(
|
|
835
|
-
(tc) => tc.status === 'cancelled',
|
|
836
|
-
);
|
|
837
|
-
|
|
838
|
-
if (allToolsCancelled) {
|
|
839
|
-
if (geminiClient) {
|
|
840
|
-
// We need to manually add the function responses to the history
|
|
841
|
-
// so the model knows the tools were cancelled.
|
|
842
|
-
const responsesToAdd = geminiTools.flatMap(
|
|
843
|
-
(toolCall) => toolCall.response.responseParts,
|
|
844
|
-
);
|
|
845
|
-
const combinedParts: Part[] = [];
|
|
846
|
-
for (const response of responsesToAdd) {
|
|
847
|
-
if (Array.isArray(response)) {
|
|
848
|
-
combinedParts.push(...response);
|
|
849
|
-
} else if (typeof response === 'string') {
|
|
850
|
-
combinedParts.push({ text: response });
|
|
851
|
-
} else {
|
|
852
|
-
combinedParts.push(response);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
geminiClient.addHistory({
|
|
856
|
-
role: 'user',
|
|
857
|
-
parts: combinedParts,
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
const callIdsToMarkAsSubmitted = geminiTools.map(
|
|
862
|
-
(toolCall) => toolCall.request.callId,
|
|
863
|
-
);
|
|
864
|
-
markToolsAsSubmitted(callIdsToMarkAsSubmitted);
|
|
865
|
-
return;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
const responsesToSend: PartListUnion[] = geminiTools.map(
|
|
869
|
-
(toolCall) => toolCall.response.responseParts,
|
|
870
|
-
);
|
|
871
|
-
const callIdsToMarkAsSubmitted = geminiTools.map(
|
|
872
|
-
(toolCall) => toolCall.request.callId,
|
|
873
|
-
);
|
|
874
|
-
|
|
875
|
-
const prompt_ids = geminiTools.map(
|
|
876
|
-
(toolCall) => toolCall.request.prompt_id,
|
|
877
|
-
);
|
|
878
|
-
|
|
879
|
-
markToolsAsSubmitted(callIdsToMarkAsSubmitted);
|
|
880
|
-
|
|
881
|
-
// Don't continue if model was switched due to quota error
|
|
882
|
-
if (modelSwitchedFromQuotaError) {
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
submitQuery(
|
|
887
|
-
mergePartListUnions(responsesToSend),
|
|
888
|
-
{
|
|
889
|
-
isContinuation: true,
|
|
890
|
-
},
|
|
891
|
-
prompt_ids[0],
|
|
892
|
-
);
|
|
893
|
-
},
|
|
894
|
-
[
|
|
895
|
-
isResponding,
|
|
896
|
-
submitQuery,
|
|
897
|
-
markToolsAsSubmitted,
|
|
898
|
-
geminiClient,
|
|
899
|
-
performMemoryRefresh,
|
|
900
|
-
modelSwitchedFromQuotaError,
|
|
901
|
-
],
|
|
902
|
-
);
|
|
903
|
-
|
|
904
|
-
const pendingHistoryItems = [
|
|
905
|
-
pendingHistoryItemRef.current,
|
|
906
|
-
pendingToolCallGroupDisplay,
|
|
907
|
-
].filter((i) => i !== undefined && i !== null);
|
|
908
|
-
|
|
909
|
-
useEffect(() => {
|
|
910
|
-
const saveRestorableToolCalls = async () => {
|
|
911
|
-
if (!config.getCheckpointingEnabled()) {
|
|
912
|
-
return;
|
|
913
|
-
}
|
|
914
|
-
const restorableToolCalls = toolCalls.filter(
|
|
915
|
-
(toolCall) =>
|
|
916
|
-
(toolCall.request.name === 'replace' ||
|
|
917
|
-
toolCall.request.name === 'write_file') &&
|
|
918
|
-
toolCall.status === 'awaiting_approval',
|
|
919
|
-
);
|
|
920
|
-
|
|
921
|
-
if (restorableToolCalls.length > 0) {
|
|
922
|
-
const checkpointDir = config.getProjectTempDir()
|
|
923
|
-
? path.join(config.getProjectTempDir(), 'checkpoints')
|
|
924
|
-
: undefined;
|
|
925
|
-
|
|
926
|
-
if (!checkpointDir) {
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
try {
|
|
931
|
-
await fs.mkdir(checkpointDir, { recursive: true });
|
|
932
|
-
} catch (error) {
|
|
933
|
-
if (!isNodeError(error) || error.code !== 'EEXIST') {
|
|
934
|
-
onDebugMessage(
|
|
935
|
-
`Failed to create checkpoint directory: ${getErrorMessage(error)}`,
|
|
936
|
-
);
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
for (const toolCall of restorableToolCalls) {
|
|
942
|
-
const filePath = toolCall.request.args['file_path'] as string;
|
|
943
|
-
if (!filePath) {
|
|
944
|
-
onDebugMessage(
|
|
945
|
-
`Skipping restorable tool call due to missing file_path: ${toolCall.request.name}`,
|
|
946
|
-
);
|
|
947
|
-
continue;
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
try {
|
|
951
|
-
let commitHash = await gitService?.createFileSnapshot(
|
|
952
|
-
`Snapshot for ${toolCall.request.name}`,
|
|
953
|
-
);
|
|
954
|
-
|
|
955
|
-
if (!commitHash) {
|
|
956
|
-
commitHash = await gitService?.getCurrentCommitHash();
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
if (!commitHash) {
|
|
960
|
-
onDebugMessage(
|
|
961
|
-
`Failed to create snapshot for ${filePath}. Skipping restorable tool call.`,
|
|
962
|
-
);
|
|
963
|
-
continue;
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
const timestamp = new Date()
|
|
967
|
-
.toISOString()
|
|
968
|
-
.replace(/:/g, '-')
|
|
969
|
-
.replace(/\./g, '_');
|
|
970
|
-
const toolName = toolCall.request.name;
|
|
971
|
-
const fileName = path.basename(filePath);
|
|
972
|
-
const toolCallWithSnapshotFileName = `${timestamp}-${fileName}-${toolName}.json`;
|
|
973
|
-
const clientHistory = await geminiClient?.getHistory();
|
|
974
|
-
const toolCallWithSnapshotFilePath = path.join(
|
|
975
|
-
checkpointDir,
|
|
976
|
-
toolCallWithSnapshotFileName,
|
|
977
|
-
);
|
|
978
|
-
|
|
979
|
-
await fs.writeFile(
|
|
980
|
-
toolCallWithSnapshotFilePath,
|
|
981
|
-
JSON.stringify(
|
|
982
|
-
{
|
|
983
|
-
history,
|
|
984
|
-
clientHistory,
|
|
985
|
-
toolCall: {
|
|
986
|
-
name: toolCall.request.name,
|
|
987
|
-
args: toolCall.request.args,
|
|
988
|
-
},
|
|
989
|
-
commitHash,
|
|
990
|
-
filePath,
|
|
991
|
-
},
|
|
992
|
-
null,
|
|
993
|
-
2,
|
|
994
|
-
),
|
|
995
|
-
);
|
|
996
|
-
} catch (error) {
|
|
997
|
-
onDebugMessage(
|
|
998
|
-
`Failed to write restorable tool call file: ${getErrorMessage(
|
|
999
|
-
error,
|
|
1000
|
-
)}`,
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
};
|
|
1006
|
-
saveRestorableToolCalls();
|
|
1007
|
-
}, [toolCalls, config, onDebugMessage, gitService, history, geminiClient]);
|
|
1008
|
-
|
|
1009
|
-
return {
|
|
1010
|
-
streamingState,
|
|
1011
|
-
submitQuery,
|
|
1012
|
-
initError,
|
|
1013
|
-
pendingHistoryItems,
|
|
1014
|
-
thought,
|
|
1015
|
-
cancelOngoingRequest,
|
|
1016
|
-
};
|
|
1017
|
-
};
|