@office-ai/aioncli-core 0.8.1 → 0.18.5
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.d.ts +8 -2
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/src/agents/codebase-investigator.d.ts +36 -1
- package/dist/src/agents/codebase-investigator.js +93 -34
- package/dist/src/agents/codebase-investigator.js.map +1 -1
- package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
- package/dist/src/agents/codebase-investigator.test.js +35 -0
- package/dist/src/agents/codebase-investigator.test.js.map +1 -0
- package/dist/src/agents/executor.d.ts +37 -11
- package/dist/src/agents/executor.js +512 -150
- package/dist/src/agents/executor.js.map +1 -1
- package/dist/src/agents/executor.test.js +1188 -245
- package/dist/src/agents/executor.test.js.map +1 -1
- package/dist/src/agents/invocation.d.ts +5 -2
- package/dist/src/agents/invocation.js +4 -2
- package/dist/src/agents/invocation.js.map +1 -1
- package/dist/src/agents/invocation.test.js +9 -0
- package/dist/src/agents/invocation.test.js.map +1 -1
- package/dist/src/agents/registry.d.ts +6 -1
- package/dist/src/agents/registry.js +51 -4
- package/dist/src/agents/registry.js.map +1 -1
- package/dist/src/agents/registry.test.js +30 -16
- package/dist/src/agents/registry.test.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.d.ts +3 -1
- package/dist/src/agents/subagent-tool-wrapper.js +4 -3
- package/dist/src/agents/subagent-tool-wrapper.js.map +1 -1
- package/dist/src/agents/subagent-tool-wrapper.test.js +9 -4
- package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -1
- package/dist/src/agents/types.d.ts +37 -7
- package/dist/src/agents/types.js +2 -0
- package/dist/src/agents/types.js.map +1 -1
- package/dist/src/code_assist/codeAssist.js +1 -1
- package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
- package/dist/src/code_assist/codeAssist.test.js +99 -0
- package/dist/src/code_assist/codeAssist.test.js.map +1 -0
- package/dist/src/code_assist/converter.d.ts +1 -0
- package/dist/src/code_assist/converter.js +1 -0
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/converter.test.js +19 -0
- package/dist/src/code_assist/converter.test.js.map +1 -1
- package/dist/src/code_assist/experiments/client_metadata.d.ts +12 -0
- package/dist/src/code_assist/experiments/client_metadata.js +50 -0
- package/dist/src/code_assist/experiments/client_metadata.js.map +1 -0
- package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/client_metadata.test.js +99 -0
- package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
- package/dist/src/code_assist/experiments/experiments.d.ts +17 -0
- package/dist/src/code_assist/experiments/experiments.js +36 -0
- package/dist/src/code_assist/experiments/experiments.js.map +1 -0
- package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/experiments.test.js +92 -0
- package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
- package/dist/src/code_assist/experiments/flagNames.d.ts +13 -0
- package/dist/src/code_assist/experiments/flagNames.js +13 -0
- package/dist/src/code_assist/experiments/flagNames.js.map +1 -0
- package/dist/src/code_assist/experiments/types.d.ts +35 -0
- package/dist/src/code_assist/experiments/types.js +7 -0
- package/dist/src/code_assist/experiments/types.js.map +1 -0
- package/dist/src/code_assist/oauth-credential-storage.js +6 -5
- package/dist/src/code_assist/oauth-credential-storage.js.map +1 -1
- package/dist/src/code_assist/oauth-credential-storage.test.js +65 -3
- package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
- package/dist/src/code_assist/oauth2.d.ts +2 -2
- package/dist/src/code_assist/oauth2.js +161 -93
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +103 -57
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/code_assist/server.d.ts +6 -4
- package/dist/src/code_assist/server.js +16 -8
- package/dist/src/code_assist/server.js.map +1 -1
- package/dist/src/code_assist/server.test.js +126 -28
- package/dist/src/code_assist/server.test.js.map +1 -1
- package/dist/src/code_assist/setup.d.ts +2 -2
- package/dist/src/code_assist/setup.js +4 -2
- package/dist/src/code_assist/setup.js.map +1 -1
- package/dist/src/code_assist/types.d.ts +1 -1
- package/dist/src/code_assist/types.js.map +1 -1
- package/dist/src/commands/extensions.d.ts +7 -0
- package/dist/src/commands/extensions.js +9 -0
- package/dist/src/commands/extensions.js.map +1 -0
- package/dist/src/commands/extensions.test.d.ts +6 -0
- package/dist/src/commands/extensions.test.js +19 -0
- package/dist/src/commands/extensions.test.js.map +1 -0
- package/dist/src/config/config.d.ts +169 -43
- package/dist/src/config/config.js +418 -79
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +684 -49
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/defaultModelConfigs.d.ts +7 -0
- package/dist/src/config/defaultModelConfigs.js +185 -0
- package/dist/src/config/defaultModelConfigs.js.map +1 -0
- package/dist/src/config/models.d.ts +23 -2
- package/dist/src/config/models.js +50 -7
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/config/models.test.js +71 -10
- package/dist/src/config/models.test.js.map +1 -1
- package/dist/src/config/storage.d.ts +3 -1
- package/dist/src/config/storage.js +22 -2
- package/dist/src/config/storage.js.map +1 -1
- package/dist/src/config/storage.test.js +7 -6
- package/dist/src/config/storage.test.js.map +1 -1
- package/dist/src/confirmation-bus/message-bus.d.ts +3 -2
- package/dist/src/confirmation-bus/message-bus.js +9 -3
- package/dist/src/confirmation-bus/message-bus.js.map +1 -1
- package/dist/src/confirmation-bus/message-bus.test.js +30 -24
- package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
- package/dist/src/confirmation-bus/types.d.ts +13 -2
- package/dist/src/confirmation-bus/types.js +1 -0
- package/dist/src/confirmation-bus/types.js.map +1 -1
- package/dist/src/core/apiKeyCredentialStorage.d.ts +17 -0
- package/dist/src/core/apiKeyCredentialStorage.js +64 -0
- package/dist/src/core/apiKeyCredentialStorage.js.map +1 -0
- package/dist/src/core/apiKeyCredentialStorage.test.d.ts +6 -0
- package/dist/src/core/apiKeyCredentialStorage.test.js +71 -0
- package/dist/src/core/apiKeyCredentialStorage.test.js.map +1 -0
- package/dist/src/core/baseLlmClient.d.ts +4 -8
- package/dist/src/core/baseLlmClient.js +6 -11
- package/dist/src/core/baseLlmClient.js.map +1 -1
- package/dist/src/core/baseLlmClient.test.js +22 -27
- package/dist/src/core/baseLlmClient.test.js.map +1 -1
- package/dist/src/core/client.d.ts +12 -19
- package/dist/src/core/client.js +104 -206
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +329 -452
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +3 -2
- package/dist/src/core/contentGenerator.js +56 -41
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/contentGenerator.test.js +49 -1
- package/dist/src/core/contentGenerator.test.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +8 -4
- package/dist/src/core/coreToolScheduler.js +348 -179
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/coreToolScheduler.test.js +575 -219
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/fakeContentGenerator.d.ts +33 -0
- package/dist/src/core/fakeContentGenerator.js +58 -0
- package/dist/src/core/fakeContentGenerator.js.map +1 -0
- package/dist/src/core/fakeContentGenerator.test.d.ts +6 -0
- package/dist/src/core/fakeContentGenerator.test.js +127 -0
- package/dist/src/core/fakeContentGenerator.test.js.map +1 -0
- package/dist/src/core/geminiChat.d.ts +23 -18
- package/dist/src/core/geminiChat.js +186 -108
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +581 -270
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/logger.d.ts +7 -2
- package/dist/src/core/logger.js +35 -27
- package/dist/src/core/logger.js.map +1 -1
- package/dist/src/core/logger.test.js +45 -29
- package/dist/src/core/logger.test.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.d.ts +1 -0
- package/dist/src/core/loggingContentGenerator.js +113 -33
- package/dist/src/core/loggingContentGenerator.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
- package/dist/src/core/loggingContentGenerator.test.js +180 -0
- package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
- package/dist/src/core/nonInteractiveToolExecutor.d.ts +3 -2
- package/dist/src/core/nonInteractiveToolExecutor.js +12 -7
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +12 -8
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/openaiContentGenerator.d.ts +15 -1
- package/dist/src/core/openaiContentGenerator.js +139 -22
- package/dist/src/core/openaiContentGenerator.js.map +1 -1
- package/dist/src/core/prompts.d.ts +2 -1
- package/dist/src/core/prompts.js +135 -154
- package/dist/src/core/prompts.js.map +1 -1
- package/dist/src/core/prompts.test.js +128 -189
- package/dist/src/core/prompts.test.js.map +1 -1
- package/dist/src/core/recordingContentGenerator.d.ts +18 -0
- package/dist/src/core/recordingContentGenerator.js +77 -0
- package/dist/src/core/recordingContentGenerator.js.map +1 -0
- package/dist/src/core/recordingContentGenerator.test.d.ts +6 -0
- package/dist/src/core/recordingContentGenerator.test.js +101 -0
- package/dist/src/core/recordingContentGenerator.test.js.map +1 -0
- package/dist/src/core/tokenLimits.test.d.ts +6 -0
- package/dist/src/core/tokenLimits.test.js +26 -0
- package/dist/src/core/tokenLimits.test.js.map +1 -0
- package/dist/src/core/turn.d.ts +23 -3
- package/dist/src/core/turn.js +18 -9
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/core/turn.test.js +98 -104
- package/dist/src/core/turn.test.js.map +1 -1
- package/dist/src/fallback/handler.js +60 -8
- package/dist/src/fallback/handler.js.map +1 -1
- package/dist/src/fallback/handler.test.js +132 -17
- package/dist/src/fallback/handler.test.js.map +1 -1
- package/dist/src/fallback/types.d.ts +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/hooks/hookAggregator.d.ts +68 -0
- package/dist/src/hooks/hookAggregator.js +262 -0
- package/dist/src/hooks/hookAggregator.js.map +1 -0
- package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
- package/dist/src/hooks/hookAggregator.test.js +387 -0
- package/dist/src/hooks/hookAggregator.test.js.map +1 -0
- package/dist/src/hooks/hookPlanner.d.ts +46 -0
- package/dist/src/hooks/hookPlanner.js +108 -0
- package/dist/src/hooks/hookPlanner.js.map +1 -0
- package/dist/src/hooks/hookPlanner.test.d.ts +6 -0
- package/dist/src/hooks/hookPlanner.test.js +255 -0
- package/dist/src/hooks/hookPlanner.test.js.map +1 -0
- package/dist/src/hooks/hookRegistry.d.ts +87 -0
- package/dist/src/hooks/hookRegistry.js +198 -0
- package/dist/src/hooks/hookRegistry.js.map +1 -0
- package/dist/src/hooks/hookRegistry.test.d.ts +6 -0
- package/dist/src/hooks/hookRegistry.test.js +341 -0
- package/dist/src/hooks/hookRegistry.test.js.map +1 -0
- package/dist/src/hooks/hookRunner.d.ts +42 -0
- package/dist/src/hooks/hookRunner.js +272 -0
- package/dist/src/hooks/hookRunner.js.map +1 -0
- package/dist/src/hooks/hookRunner.test.d.ts +6 -0
- package/dist/src/hooks/hookRunner.test.js +468 -0
- package/dist/src/hooks/hookRunner.test.js.map +1 -0
- package/dist/src/hooks/hookTranslator.d.ts +113 -0
- package/dist/src/hooks/hookTranslator.js +232 -0
- package/dist/src/hooks/hookTranslator.js.map +1 -0
- package/dist/src/hooks/hookTranslator.test.d.ts +6 -0
- package/dist/src/hooks/hookTranslator.test.js +192 -0
- package/dist/src/hooks/hookTranslator.test.js.map +1 -0
- package/dist/src/hooks/types.d.ts +384 -0
- package/dist/src/hooks/types.js +284 -0
- package/dist/src/hooks/types.js.map +1 -0
- package/dist/src/hooks/types.test.d.ts +6 -0
- package/dist/src/hooks/types.test.js +313 -0
- package/dist/src/hooks/types.test.js.map +1 -0
- package/dist/src/ide/detect-ide.d.ts +4 -0
- package/dist/src/ide/detect-ide.js +6 -1
- package/dist/src/ide/detect-ide.js.map +1 -1
- package/dist/src/ide/detect-ide.test.js +16 -0
- package/dist/src/ide/detect-ide.test.js.map +1 -1
- package/dist/src/ide/ide-client.d.ts +3 -1
- package/dist/src/ide/ide-client.js +12 -10
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/ide/ide-client.test.js +163 -4
- package/dist/src/ide/ide-client.test.js.map +1 -1
- package/dist/src/ide/ide-installer.js +66 -21
- package/dist/src/ide/ide-installer.js.map +1 -1
- package/dist/src/ide/ide-installer.test.js +54 -1
- package/dist/src/ide/ide-installer.test.js.map +1 -1
- package/dist/src/ide/process-utils.js +85 -75
- package/dist/src/ide/process-utils.js.map +1 -1
- package/dist/src/ide/process-utils.test.js +83 -90
- package/dist/src/ide/process-utils.test.js.map +1 -1
- package/dist/src/ide/types.d.ts +5 -5
- package/dist/src/ide/types.js +1 -1
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.js +24 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.d.ts +2 -0
- package/dist/src/mcp/google-auth-provider.js +21 -3
- package/dist/src/mcp/google-auth-provider.js.map +1 -1
- package/dist/src/mcp/google-auth-provider.test.js +42 -9
- package/dist/src/mcp/google-auth-provider.test.js.map +1 -1
- package/dist/src/mcp/oauth-provider.d.ts +8 -5
- package/dist/src/mcp/oauth-provider.js +140 -55
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-provider.test.js +369 -2
- package/dist/src/mcp/oauth-provider.test.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.js +5 -4
- package/dist/src/mcp/oauth-token-storage.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.test.js +17 -11
- package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
- package/dist/src/mcp/oauth-utils.d.ts +7 -0
- package/dist/src/mcp/oauth-utils.js +28 -8
- package/dist/src/mcp/oauth-utils.js.map +1 -1
- package/dist/src/mcp/oauth-utils.test.js +45 -2
- package/dist/src/mcp/oauth-utils.test.js.map +1 -1
- package/dist/src/mcp/sa-impersonation-provider.d.ts +0 -6
- package/dist/src/mcp/sa-impersonation-provider.js +6 -23
- package/dist/src/mcp/sa-impersonation-provider.js.map +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.test.js +75 -84
- package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/file-token-storage.js +3 -2
- package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -1
- package/dist/src/mcp/token-storage/file-token-storage.test.js +11 -8
- package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +6 -2
- package/dist/src/mcp/token-storage/keychain-token-storage.js +63 -7
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -1
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js +54 -3
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/types.d.ts +6 -0
- package/dist/src/mcp/token-storage/types.js.map +1 -1
- package/dist/src/output/stream-json-formatter.d.ts +32 -0
- package/dist/src/output/stream-json-formatter.js +52 -0
- package/dist/src/output/stream-json-formatter.js.map +1 -0
- package/dist/src/output/stream-json-formatter.test.d.ts +6 -0
- package/dist/src/output/stream-json-formatter.test.js +479 -0
- package/dist/src/output/stream-json-formatter.test.js.map +1 -0
- package/dist/src/output/types.d.ts +63 -1
- package/dist/src/output/types.js +11 -0
- package/dist/src/output/types.js.map +1 -1
- package/dist/src/policy/config.d.ts +31 -0
- package/dist/src/policy/config.js +199 -0
- package/dist/src/policy/config.js.map +1 -0
- package/dist/src/policy/config.test.d.ts +6 -0
- package/dist/src/policy/config.test.js +538 -0
- package/dist/src/policy/config.test.js.map +1 -0
- package/dist/src/policy/index.d.ts +2 -0
- package/dist/src/policy/index.js +2 -0
- package/dist/src/policy/index.js.map +1 -1
- package/dist/src/policy/policies/discovered.toml +8 -0
- package/dist/src/policy/policies/read-only.toml +56 -0
- package/dist/src/policy/policies/write.toml +73 -0
- package/dist/src/policy/policies/yolo.toml +31 -0
- package/dist/src/policy/policy-engine.d.ts +12 -3
- package/dist/src/policy/policy-engine.js +74 -8
- package/dist/src/policy/policy-engine.js.map +1 -1
- package/dist/src/policy/policy-engine.test.js +460 -76
- package/dist/src/policy/policy-engine.test.js.map +1 -1
- package/dist/src/policy/toml-loader.d.ts +47 -0
- package/dist/src/policy/toml-loader.js +411 -0
- package/dist/src/policy/toml-loader.js.map +1 -0
- package/dist/src/policy/toml-loader.test.d.ts +6 -0
- package/dist/src/policy/toml-loader.test.js +376 -0
- package/dist/src/policy/toml-loader.test.js.map +1 -0
- package/dist/src/policy/types.d.ts +83 -0
- package/dist/src/policy/types.js +10 -0
- package/dist/src/policy/types.js.map +1 -1
- package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
- package/dist/src/prompts/mcp-prompts.test.js +39 -0
- package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
- package/dist/src/prompts/prompt-registry.js +2 -1
- package/dist/src/prompts/prompt-registry.js.map +1 -1
- package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
- package/dist/src/prompts/prompt-registry.test.js +96 -0
- package/dist/src/prompts/prompt-registry.test.js.map +1 -0
- package/dist/src/routing/modelRouterService.js +15 -0
- package/dist/src/routing/modelRouterService.js.map +1 -1
- package/dist/src/routing/modelRouterService.test.js +62 -0
- package/dist/src/routing/modelRouterService.test.js.map +1 -1
- package/dist/src/routing/strategies/classifierStrategy.d.ts +1 -1
- package/dist/src/routing/strategies/classifierStrategy.js +9 -16
- package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
- package/dist/src/routing/strategies/classifierStrategy.test.js +17 -13
- package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.js +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -1
- package/dist/src/routing/strategies/fallbackStrategy.test.js +4 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -1
- package/dist/src/routing/strategies/overrideStrategy.js +2 -2
- package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
- package/dist/src/routing/strategies/overrideStrategy.test.js +3 -0
- package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -1
- package/dist/src/safety/built-in.d.ts +21 -0
- package/dist/src/safety/built-in.js +106 -0
- package/dist/src/safety/built-in.js.map +1 -0
- package/dist/src/safety/built-in.test.d.ts +6 -0
- package/dist/src/safety/built-in.test.js +199 -0
- package/dist/src/safety/built-in.test.js.map +1 -0
- package/dist/src/safety/checker-runner.d.ts +48 -0
- package/dist/src/safety/checker-runner.js +208 -0
- package/dist/src/safety/checker-runner.js.map +1 -0
- package/dist/src/safety/checker-runner.test.d.ts +6 -0
- package/dist/src/safety/checker-runner.test.js +238 -0
- package/dist/src/safety/checker-runner.test.js.map +1 -0
- package/dist/src/safety/context-builder.d.ts +23 -0
- package/dist/src/safety/context-builder.js +47 -0
- package/dist/src/safety/context-builder.js.map +1 -0
- package/dist/src/safety/context-builder.test.d.ts +6 -0
- package/dist/src/safety/context-builder.test.js +49 -0
- package/dist/src/safety/context-builder.test.js.map +1 -0
- package/dist/src/safety/protocol.d.ts +88 -0
- package/dist/src/safety/protocol.js +15 -0
- package/dist/src/safety/protocol.js.map +1 -0
- package/dist/src/safety/registry.d.ts +26 -0
- package/dist/src/safety/registry.js +65 -0
- package/dist/src/safety/registry.js.map +1 -0
- package/dist/src/safety/registry.test.d.ts +6 -0
- package/dist/src/safety/registry.test.js +31 -0
- package/dist/src/safety/registry.test.js.map +1 -0
- package/dist/src/services/chatCompressionService.d.ts +32 -0
- package/dist/src/services/chatCompressionService.js +162 -0
- package/dist/src/services/chatCompressionService.js.map +1 -0
- package/dist/src/services/chatCompressionService.test.d.ts +6 -0
- package/dist/src/services/chatCompressionService.test.js +210 -0
- package/dist/src/services/chatCompressionService.test.js.map +1 -0
- package/dist/src/services/chatRecordingService.d.ts +3 -2
- package/dist/src/services/chatRecordingService.js +11 -9
- package/dist/src/services/chatRecordingService.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.d.ts +2 -14
- package/dist/src/services/fileDiscoveryService.js +19 -55
- package/dist/src/services/fileDiscoveryService.js.map +1 -1
- package/dist/src/services/fileDiscoveryService.test.js +91 -11
- package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
- package/dist/src/services/loopDetectionService.d.ts +4 -1
- package/dist/src/services/loopDetectionService.js +95 -42
- package/dist/src/services/loopDetectionService.js.map +1 -1
- package/dist/src/services/loopDetectionService.test.js +220 -12
- package/dist/src/services/loopDetectionService.test.js.map +1 -1
- package/dist/src/services/modelConfig.golden.test.d.ts +6 -0
- package/dist/src/services/modelConfig.golden.test.js +42 -0
- package/dist/src/services/modelConfig.golden.test.js.map +1 -0
- package/dist/src/services/modelConfig.integration.test.d.ts +6 -0
- package/dist/src/services/modelConfig.integration.test.js +247 -0
- package/dist/src/services/modelConfig.integration.test.js.map +1 -0
- package/dist/src/services/modelConfigService.d.ts +48 -0
- package/dist/src/services/modelConfigService.js +151 -0
- package/dist/src/services/modelConfigService.js.map +1 -0
- package/dist/src/services/modelConfigService.test.d.ts +6 -0
- package/dist/src/services/modelConfigService.test.js +531 -0
- package/dist/src/services/modelConfigService.test.js.map +1 -0
- package/dist/src/services/shellExecutionService.d.ts +1 -0
- package/dist/src/services/shellExecutionService.js +195 -92
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +137 -14
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/services/test-data/resolved-aliases.golden.json +202 -0
- package/dist/src/telemetry/activity-monitor.d.ts +116 -0
- package/dist/src/telemetry/activity-monitor.js +209 -0
- package/dist/src/telemetry/activity-monitor.js.map +1 -0
- package/dist/src/telemetry/activity-monitor.test.d.ts +6 -0
- package/dist/src/telemetry/activity-monitor.test.js +251 -0
- package/dist/src/telemetry/activity-monitor.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +25 -7
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +294 -76
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +192 -66
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +25 -3
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +59 -5
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/constants.d.ts +0 -28
- package/dist/src/telemetry/constants.js +0 -29
- package/dist/src/telemetry/constants.js.map +1 -1
- package/dist/src/telemetry/gcp-exporters.js +0 -1
- package/dist/src/telemetry/gcp-exporters.js.map +1 -1
- package/dist/src/telemetry/gcp-exporters.test.js +1 -1
- package/dist/src/telemetry/gcp-exporters.test.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +7 -3
- package/dist/src/telemetry/index.js +13 -4
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +14 -7
- package/dist/src/telemetry/loggers.js +197 -320
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +0 -1
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +460 -59
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/memory-monitor.d.ts +149 -0
- package/dist/src/telemetry/memory-monitor.js +335 -0
- package/dist/src/telemetry/memory-monitor.js.map +1 -0
- package/dist/src/telemetry/memory-monitor.test.d.ts +6 -0
- package/dist/src/telemetry/memory-monitor.test.js +472 -0
- package/dist/src/telemetry/memory-monitor.test.js.map +1 -0
- package/dist/src/telemetry/metrics.d.ts +180 -4
- package/dist/src/telemetry/metrics.js +270 -6
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/metrics.test.js +502 -184
- package/dist/src/telemetry/metrics.test.js.map +1 -1
- package/dist/src/telemetry/sdk.js +3 -2
- package/dist/src/telemetry/sdk.js.map +1 -1
- package/dist/src/telemetry/semantic.d.ts +82 -0
- package/dist/src/telemetry/semantic.js +269 -0
- package/dist/src/telemetry/semantic.js.map +1 -0
- package/dist/src/telemetry/semantic.test.d.ts +6 -0
- package/dist/src/telemetry/semantic.test.js +387 -0
- package/dist/src/telemetry/semantic.test.js.map +1 -0
- package/dist/src/telemetry/telemetry-utils.test.js +29 -28
- package/dist/src/telemetry/telemetry-utils.test.js.map +1 -1
- package/dist/src/telemetry/telemetryAttributes.d.ts +8 -0
- package/dist/src/telemetry/telemetryAttributes.js +19 -0
- package/dist/src/telemetry/telemetryAttributes.js.map +1 -0
- package/dist/src/telemetry/trace.d.ts +46 -0
- package/dist/src/telemetry/trace.js +121 -0
- package/dist/src/telemetry/trace.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +227 -29
- package/dist/src/telemetry/types.js +858 -72
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.d.ts +1 -1
- package/dist/src/telemetry/uiTelemetry.js +7 -7
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +89 -67
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/test-utils/config.d.ts +1 -1
- package/dist/src/test-utils/config.js +1 -1
- package/dist/src/tools/base-tool-invocation.test.d.ts +6 -0
- package/dist/src/tools/base-tool-invocation.test.js +85 -0
- package/dist/src/tools/base-tool-invocation.test.js.map +1 -0
- package/dist/src/tools/edit.d.ts +4 -3
- package/dist/src/tools/edit.js +50 -47
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +306 -216
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/glob.d.ts +4 -3
- package/dist/src/tools/glob.js +24 -27
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/glob.test.js +212 -205
- package/dist/src/tools/glob.test.js.map +1 -1
- package/dist/src/tools/grep.d.ts +4 -3
- package/dist/src/tools/grep.js +31 -25
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/grep.test.js +15 -12
- package/dist/src/tools/grep.test.js.map +1 -1
- package/dist/src/tools/ls.d.ts +4 -3
- package/dist/src/tools/ls.js +29 -35
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/ls.test.js +34 -42
- package/dist/src/tools/ls.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.d.ts +49 -11
- package/dist/src/tools/mcp-client-manager.js +191 -31
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.test.js +132 -25
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +12 -5
- package/dist/src/tools/mcp-client.js +287 -267
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +352 -45
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +6 -2
- package/dist/src/tools/mcp-tool.js +19 -8
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/mcp-tool.test.js +186 -273
- package/dist/src/tools/mcp-tool.test.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +7 -5
- package/dist/src/tools/memoryTool.js +14 -12
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/memoryTool.test.js +10 -9
- package/dist/src/tools/memoryTool.test.js.map +1 -1
- package/dist/src/tools/message-bus-integration.test.js +14 -1
- package/dist/src/tools/message-bus-integration.test.js.map +1 -1
- package/dist/src/tools/modifiable-tool.d.ts +5 -1
- package/dist/src/tools/modifiable-tool.js +38 -16
- package/dist/src/tools/modifiable-tool.js.map +1 -1
- package/dist/src/tools/modifiable-tool.test.js +66 -31
- package/dist/src/tools/modifiable-tool.test.js.map +1 -1
- package/dist/src/tools/read-file.d.ts +6 -5
- package/dist/src/tools/read-file.js +26 -32
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-file.test.js +68 -33
- package/dist/src/tools/read-file.test.js.map +1 -1
- package/dist/src/tools/read-many-files.d.ts +6 -12
- package/dist/src/tools/read-many-files.js +28 -57
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +37 -36
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/ripGrep.d.ts +28 -10
- package/dist/src/tools/ripGrep.js +195 -193
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/ripGrep.test.js +533 -204
- package/dist/src/tools/ripGrep.test.js.map +1 -1
- package/dist/src/tools/shell.d.ts +8 -6
- package/dist/src/tools/shell.js +64 -38
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +134 -43
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/smart-edit.d.ts +10 -23
- package/dist/src/tools/smart-edit.js +100 -85
- package/dist/src/tools/smart-edit.js.map +1 -1
- package/dist/src/tools/smart-edit.test.js +229 -179
- package/dist/src/tools/smart-edit.test.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +21 -0
- package/dist/src/tools/tool-error.js +27 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-names.d.ts +17 -0
- package/dist/src/tools/tool-names.js +21 -0
- package/dist/src/tools/tool-names.js.map +1 -0
- package/dist/src/tools/tool-registry.d.ts +32 -20
- package/dist/src/tools/tool-registry.js +122 -78
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tool-registry.test.js +167 -90
- package/dist/src/tools/tool-registry.test.js.map +1 -1
- package/dist/src/tools/tools.d.ts +23 -8
- package/dist/src/tools/tools.js +69 -37
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.d.ts +11 -3
- package/dist/src/tools/web-fetch.js +80 -38
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-fetch.test.js +338 -9
- package/dist/src/tools/web-fetch.test.js.map +1 -1
- package/dist/src/tools/web-search.d.ts +4 -3
- package/dist/src/tools/web-search.js +11 -9
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/web-search.test.js +6 -0
- package/dist/src/tools/web-search.test.js.map +1 -1
- package/dist/src/tools/write-file.d.ts +3 -2
- package/dist/src/tools/write-file.js +41 -40
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +130 -123
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/tools/write-todos.d.ts +34 -9
- package/dist/src/tools/write-todos.js +54 -11
- package/dist/src/tools/write-todos.js.map +1 -1
- package/dist/src/tools/write-todos.test.js +2 -2
- package/dist/src/tools/write-todos.test.js.map +1 -1
- package/dist/src/utils/bfsFileSearch.js +3 -2
- package/dist/src/utils/bfsFileSearch.js.map +1 -1
- package/dist/src/utils/channel.d.ts +19 -0
- package/dist/src/utils/channel.js +49 -0
- package/dist/src/utils/channel.js.map +1 -0
- package/dist/src/utils/channel.test.d.ts +6 -0
- package/dist/src/utils/channel.test.js +170 -0
- package/dist/src/utils/channel.test.js.map +1 -0
- package/dist/src/utils/debugLogger.d.ts +25 -0
- package/dist/src/utils/debugLogger.js +33 -0
- package/dist/src/utils/debugLogger.js.map +1 -0
- package/dist/src/utils/debugLogger.test.d.ts +6 -0
- package/dist/src/utils/debugLogger.test.js +69 -0
- package/dist/src/utils/debugLogger.test.js.map +1 -0
- package/dist/src/utils/delay.d.ts +16 -0
- package/dist/src/utils/delay.js +43 -0
- package/dist/src/utils/delay.js.map +1 -0
- package/dist/src/utils/delay.test.d.ts +6 -0
- package/dist/src/utils/delay.test.js +88 -0
- package/dist/src/utils/delay.test.js.map +1 -0
- package/dist/src/utils/editCorrector.js +10 -25
- package/dist/src/utils/editCorrector.js.map +1 -1
- package/dist/src/utils/editCorrector.test.js +19 -5
- package/dist/src/utils/editCorrector.test.js.map +1 -1
- package/dist/src/utils/editor.d.ts +4 -2
- package/dist/src/utils/editor.js +53 -39
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/editor.test.js +18 -45
- package/dist/src/utils/editor.test.js.map +1 -1
- package/dist/src/utils/environmentContext.d.ts +2 -1
- package/dist/src/utils/environmentContext.js +20 -33
- package/dist/src/utils/environmentContext.js.map +1 -1
- package/dist/src/utils/environmentContext.test.js +6 -34
- package/dist/src/utils/environmentContext.test.js.map +1 -1
- package/dist/src/utils/errorParsing.d.ts +1 -1
- package/dist/src/utils/errorParsing.js +5 -33
- package/dist/src/utils/errorParsing.js.map +1 -1
- package/dist/src/utils/errorParsing.test.js +0 -88
- package/dist/src/utils/errorParsing.test.js.map +1 -1
- package/dist/src/utils/errors.d.ts +3 -0
- package/dist/src/utils/errors.js +6 -0
- package/dist/src/utils/errors.js.map +1 -1
- package/dist/src/utils/events.d.ts +121 -0
- package/dist/src/utils/events.js +84 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/events.test.d.ts +6 -0
- package/dist/src/utils/events.test.js +212 -0
- package/dist/src/utils/events.test.js.map +1 -0
- package/dist/src/utils/extensionLoader.d.ts +86 -0
- package/dist/src/utils/extensionLoader.js +208 -0
- package/dist/src/utils/extensionLoader.js.map +1 -0
- package/dist/src/utils/extensionLoader.test.d.ts +6 -0
- package/dist/src/utils/extensionLoader.test.js +154 -0
- package/dist/src/utils/extensionLoader.test.js.map +1 -0
- package/dist/src/utils/fetch.d.ts +1 -0
- package/dist/src/utils/fetch.js +4 -0
- package/dist/src/utils/fetch.js.map +1 -1
- package/dist/src/utils/fileUtils.d.ts +4 -0
- package/dist/src/utils/fileUtils.js +34 -2
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +87 -61
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/filesearch/fileSearch.js +1 -1
- package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
- package/dist/src/utils/flashFallback.test.js +28 -47
- package/dist/src/utils/flashFallback.test.js.map +1 -1
- package/dist/src/utils/formatters.d.ts +1 -0
- package/dist/src/utils/formatters.js +2 -1
- package/dist/src/utils/formatters.js.map +1 -1
- package/dist/src/utils/formatters.test.d.ts +6 -0
- package/dist/src/utils/formatters.test.js +26 -0
- package/dist/src/utils/formatters.test.js.map +1 -0
- package/dist/src/utils/getFolderStructure.js +9 -17
- package/dist/src/utils/getFolderStructure.js.map +1 -1
- package/dist/src/utils/getFolderStructure.test.js +7 -6
- package/dist/src/utils/getFolderStructure.test.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.d.ts +4 -1
- package/dist/src/utils/gitIgnoreParser.js +28 -10
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.test.js +58 -0
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
- package/dist/src/utils/googleErrors.d.ts +104 -0
- package/dist/src/utils/googleErrors.js +152 -0
- package/dist/src/utils/googleErrors.js.map +1 -0
- package/dist/src/utils/googleErrors.test.d.ts +6 -0
- package/dist/src/utils/googleErrors.test.js +301 -0
- package/dist/src/utils/googleErrors.test.js.map +1 -0
- package/dist/src/utils/googleQuotaErrors.d.ts +37 -0
- package/dist/src/utils/googleQuotaErrors.js +157 -0
- package/dist/src/utils/googleQuotaErrors.js.map +1 -0
- package/dist/src/utils/googleQuotaErrors.test.d.ts +6 -0
- package/dist/src/utils/googleQuotaErrors.test.js +311 -0
- package/dist/src/utils/googleQuotaErrors.test.js.map +1 -0
- package/dist/src/utils/httpErrors.d.ts +18 -0
- package/dist/src/utils/httpErrors.js +36 -0
- package/dist/src/utils/httpErrors.js.map +1 -0
- package/dist/src/utils/ignorePatterns.test.js +26 -30
- package/dist/src/utils/ignorePatterns.test.js.map +1 -1
- package/dist/src/utils/installationManager.js +2 -1
- package/dist/src/utils/installationManager.js.map +1 -1
- package/dist/src/utils/installationManager.test.js +6 -4
- package/dist/src/utils/installationManager.test.js.map +1 -1
- package/dist/src/utils/llm-edit-fixer.d.ts +1 -1
- package/dist/src/utils/llm-edit-fixer.js +33 -9
- package/dist/src/utils/llm-edit-fixer.js.map +1 -1
- package/dist/src/utils/llm-edit-fixer.test.js +38 -1
- package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.d.ts +20 -1
- package/dist/src/utils/memoryDiscovery.js +176 -12
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +299 -40
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.js +4 -3
- package/dist/src/utils/memoryImportProcessor.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.test.js +8 -14
- package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.js +3 -3
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.test.js +13 -5
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
- package/dist/src/utils/package.d.ts +12 -0
- package/dist/src/utils/package.js +15 -0
- package/dist/src/utils/package.js.map +1 -0
- package/dist/src/utils/pathCorrector.d.ts +25 -0
- package/dist/src/utils/pathCorrector.js +33 -0
- package/dist/src/utils/pathCorrector.js.map +1 -0
- package/dist/src/utils/pathCorrector.test.d.ts +6 -0
- package/dist/src/utils/pathCorrector.test.js +83 -0
- package/dist/src/utils/pathCorrector.test.js.map +1 -0
- package/dist/src/utils/pathReader.js +4 -4
- package/dist/src/utils/pathReader.js.map +1 -1
- package/dist/src/utils/pathReader.test.js +44 -1
- package/dist/src/utils/pathReader.test.js.map +1 -1
- package/dist/src/utils/paths.d.ts +1 -1
- package/dist/src/utils/paths.js +131 -29
- package/dist/src/utils/paths.js.map +1 -1
- package/dist/src/utils/paths.test.js +200 -68
- package/dist/src/utils/paths.test.js.map +1 -1
- package/dist/src/utils/quotaErrorDetection.d.ts +0 -2
- package/dist/src/utils/quotaErrorDetection.js +0 -46
- package/dist/src/utils/quotaErrorDetection.js.map +1 -1
- package/dist/src/utils/retry.d.ts +3 -10
- package/dist/src/utils/retry.js +97 -195
- package/dist/src/utils/retry.js.map +1 -1
- package/dist/src/utils/retry.test.js +179 -145
- package/dist/src/utils/retry.test.js.map +1 -1
- package/dist/src/utils/safeJsonStringify.d.ts +4 -4
- package/dist/src/utils/safeJsonStringify.js +31 -7
- package/dist/src/utils/safeJsonStringify.js.map +1 -1
- package/dist/src/utils/shell-utils.d.ts +15 -2
- package/dist/src/utils/shell-utils.js +387 -140
- package/dist/src/utils/shell-utils.js.map +1 -1
- package/dist/src/utils/shell-utils.test.js +244 -62
- package/dist/src/utils/shell-utils.test.js.map +1 -1
- package/dist/src/utils/stdio.d.ts +32 -0
- package/dist/src/utils/stdio.js +85 -0
- package/dist/src/utils/stdio.js.map +1 -0
- package/dist/src/utils/stdio.test.d.ts +6 -0
- package/dist/src/utils/stdio.test.js +47 -0
- package/dist/src/utils/stdio.test.js.map +1 -0
- package/dist/src/utils/summarizer.d.ts +4 -2
- package/dist/src/utils/summarizer.js +8 -9
- package/dist/src/utils/summarizer.js.map +1 -1
- package/dist/src/utils/summarizer.test.js +32 -12
- package/dist/src/utils/summarizer.test.js.map +1 -1
- package/dist/src/utils/systemEncoding.js +5 -4
- package/dist/src/utils/systemEncoding.js.map +1 -1
- package/dist/src/utils/systemEncoding.test.js +2 -1
- package/dist/src/utils/systemEncoding.test.js.map +1 -1
- package/dist/src/utils/terminal.d.ts +14 -0
- package/dist/src/utils/terminal.js +38 -0
- package/dist/src/utils/terminal.js.map +1 -0
- package/dist/src/utils/tool-utils.d.ts +2 -2
- package/dist/src/utils/tool-utils.js +15 -6
- package/dist/src/utils/tool-utils.js.map +1 -1
- package/dist/src/utils/tool-utils.test.js +8 -0
- package/dist/src/utils/tool-utils.test.js.map +1 -1
- package/dist/src/utils/userAccountManager.js +5 -4
- package/dist/src/utils/userAccountManager.js.map +1 -1
- package/dist/src/utils/userAccountManager.test.js +9 -7
- package/dist/src/utils/userAccountManager.test.js.map +1 -1
- package/dist/src/utils/workspaceContext.d.ts +4 -3
- package/dist/src/utils/workspaceContext.js +13 -13
- package/dist/src/utils/workspaceContext.js.map +1 -1
- package/dist/src/utils/workspaceContext.test.js +8 -7
- package/dist/src/utils/workspaceContext.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -7
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
7
|
-
import { ApiError } from '@google/genai';
|
|
8
|
-
import { GeminiChat, InvalidStreamError, StreamEventType, } from './geminiChat.js';
|
|
7
|
+
import { ApiError, ThinkingLevel } from '@google/genai';
|
|
8
|
+
import { GeminiChat, InvalidStreamError, StreamEventType, SYNTHETIC_THOUGHT_SIGNATURE, } from './geminiChat.js';
|
|
9
9
|
import { setSimulate429 } from '../utils/testUtils.js';
|
|
10
|
-
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
|
|
10
|
+
import { DEFAULT_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL, DEFAULT_THINKING_MODE, PREVIEW_GEMINI_MODEL, } from '../config/models.js';
|
|
11
11
|
import { AuthType } from './contentGenerator.js';
|
|
12
|
-
import {} from '../utils/
|
|
13
|
-
import {
|
|
12
|
+
import { TerminalQuotaError } from '../utils/googleQuotaErrors.js';
|
|
13
|
+
import { retryWithBackoff } from '../utils/retry.js';
|
|
14
14
|
import { uiTelemetryService } from '../telemetry/uiTelemetry.js';
|
|
15
15
|
// Mock fs module to prevent actual file system operations during tests
|
|
16
16
|
const mockFileSystem = new Map();
|
|
@@ -65,7 +65,6 @@ describe('GeminiChat', () => {
|
|
|
65
65
|
let mockContentGenerator;
|
|
66
66
|
let chat;
|
|
67
67
|
let mockConfig;
|
|
68
|
-
const config = {};
|
|
69
68
|
beforeEach(() => {
|
|
70
69
|
vi.clearAllMocks();
|
|
71
70
|
vi.mocked(uiTelemetryService.setLastPromptTokenCount).mockClear();
|
|
@@ -84,6 +83,7 @@ describe('GeminiChat', () => {
|
|
|
84
83
|
getTelemetryLogPromptsEnabled: () => true,
|
|
85
84
|
getUsageStatisticsEnabled: () => true,
|
|
86
85
|
getDebugMode: () => false,
|
|
86
|
+
getPreviewFeatures: () => false,
|
|
87
87
|
getContentGeneratorConfig: vi.fn().mockReturnValue({
|
|
88
88
|
authType: 'oauth-personal', // Ensure this is set for fallback tests
|
|
89
89
|
model: 'test-model',
|
|
@@ -102,16 +102,55 @@ describe('GeminiChat', () => {
|
|
|
102
102
|
getTool: vi.fn(),
|
|
103
103
|
}),
|
|
104
104
|
getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
|
|
105
|
+
getRetryFetchErrors: vi.fn().mockReturnValue(false),
|
|
106
|
+
modelConfigService: {
|
|
107
|
+
getResolvedConfig: vi.fn().mockImplementation((modelConfigKey) => {
|
|
108
|
+
const thinkingConfig = modelConfigKey.model.startsWith('gemini-3')
|
|
109
|
+
? {
|
|
110
|
+
thinkingLevel: ThinkingLevel.HIGH,
|
|
111
|
+
}
|
|
112
|
+
: {
|
|
113
|
+
thinkingBudget: DEFAULT_THINKING_MODE,
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
model: modelConfigKey.model,
|
|
117
|
+
generateContentConfig: {
|
|
118
|
+
temperature: 0,
|
|
119
|
+
thinkingConfig,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
isPreviewModelBypassMode: vi.fn().mockReturnValue(false),
|
|
125
|
+
setPreviewModelBypassMode: vi.fn(),
|
|
126
|
+
isPreviewModelFallbackMode: vi.fn().mockReturnValue(false),
|
|
127
|
+
setPreviewModelFallbackMode: vi.fn(),
|
|
128
|
+
isInteractive: vi.fn().mockReturnValue(false),
|
|
105
129
|
};
|
|
106
130
|
// Disable 429 simulation for tests
|
|
107
131
|
setSimulate429(false);
|
|
108
132
|
// Reset history for each test by creating a new instance
|
|
109
|
-
chat = new GeminiChat(mockConfig
|
|
133
|
+
chat = new GeminiChat(mockConfig);
|
|
110
134
|
});
|
|
111
135
|
afterEach(() => {
|
|
112
136
|
vi.restoreAllMocks();
|
|
113
137
|
vi.resetAllMocks();
|
|
114
138
|
});
|
|
139
|
+
describe('constructor', () => {
|
|
140
|
+
it('should initialize lastPromptTokenCount based on history size', () => {
|
|
141
|
+
const history = [
|
|
142
|
+
{ role: 'user', parts: [{ text: 'Hello' }] },
|
|
143
|
+
{ role: 'model', parts: [{ text: 'Hi there' }] },
|
|
144
|
+
];
|
|
145
|
+
const chatWithHistory = new GeminiChat(mockConfig, '', [], history);
|
|
146
|
+
const estimatedTokens = Math.ceil(JSON.stringify(history).length / 4);
|
|
147
|
+
expect(chatWithHistory.getLastPromptTokenCount()).toBe(estimatedTokens);
|
|
148
|
+
});
|
|
149
|
+
it('should initialize lastPromptTokenCount for empty history', () => {
|
|
150
|
+
const chatEmpty = new GeminiChat(mockConfig);
|
|
151
|
+
expect(chatEmpty.getLastPromptTokenCount()).toBe(Math.ceil(JSON.stringify([]).length / 4));
|
|
152
|
+
});
|
|
153
|
+
});
|
|
115
154
|
describe('sendMessageStream', () => {
|
|
116
155
|
it('should succeed if a tool call is followed by an empty part', async () => {
|
|
117
156
|
// 1. Mock a stream that contains a tool call, then an invalid (empty) part.
|
|
@@ -141,7 +180,7 @@ describe('GeminiChat', () => {
|
|
|
141
180
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithToolCall);
|
|
142
181
|
// 2. Action & Assert: The stream processing should complete without throwing an error
|
|
143
182
|
// because the presence of a tool call makes the empty final chunk acceptable.
|
|
144
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
183
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-tool-call-empty-end', new AbortController().signal);
|
|
145
184
|
await expect((async () => {
|
|
146
185
|
for await (const _ of stream) {
|
|
147
186
|
/* consume stream */
|
|
@@ -181,7 +220,7 @@ describe('GeminiChat', () => {
|
|
|
181
220
|
})();
|
|
182
221
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithNoFinish);
|
|
183
222
|
// 2. Action & Assert: The stream should fail because there's no finish reason.
|
|
184
|
-
const stream = await chat.sendMessageStream('
|
|
223
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-no-finish-empty-end', new AbortController().signal);
|
|
185
224
|
await expect((async () => {
|
|
186
225
|
for await (const _ of stream) {
|
|
187
226
|
/* consume stream */
|
|
@@ -216,7 +255,7 @@ describe('GeminiChat', () => {
|
|
|
216
255
|
})();
|
|
217
256
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithInvalidEnd);
|
|
218
257
|
// 2. Action & Assert: The stream should complete without throwing an error.
|
|
219
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
258
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-valid-then-invalid-end', new AbortController().signal);
|
|
220
259
|
await expect((async () => {
|
|
221
260
|
for await (const _ of stream) {
|
|
222
261
|
/* consume stream */
|
|
@@ -251,7 +290,7 @@ describe('GeminiChat', () => {
|
|
|
251
290
|
})();
|
|
252
291
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(multiChunkStream);
|
|
253
292
|
// 2. Action: Send a message and consume the stream.
|
|
254
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
293
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-empty-chunk-consolidation', new AbortController().signal);
|
|
255
294
|
for await (const _ of stream) {
|
|
256
295
|
// Consume the stream
|
|
257
296
|
}
|
|
@@ -299,7 +338,7 @@ describe('GeminiChat', () => {
|
|
|
299
338
|
})();
|
|
300
339
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(multiChunkStream);
|
|
301
340
|
// 2. Action: Send a message and consume the stream.
|
|
302
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
341
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-multi-chunk', new AbortController().signal);
|
|
303
342
|
for await (const _ of stream) {
|
|
304
343
|
// Consume the stream to trigger history recording.
|
|
305
344
|
}
|
|
@@ -335,7 +374,7 @@ describe('GeminiChat', () => {
|
|
|
335
374
|
})();
|
|
336
375
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(mixedContentStream);
|
|
337
376
|
// 2. Action: Send a message and fully consume the stream to trigger history recording.
|
|
338
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
377
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-mixed-chunk', new AbortController().signal);
|
|
339
378
|
for await (const _ of stream) {
|
|
340
379
|
// This loop consumes the stream.
|
|
341
380
|
}
|
|
@@ -351,6 +390,84 @@ describe('GeminiChat', () => {
|
|
|
351
390
|
expect(modelTurn?.parts?.length).toBe(1);
|
|
352
391
|
expect(modelTurn?.parts[0].text).toBe('This is the visible text that should not be lost.');
|
|
353
392
|
});
|
|
393
|
+
it('should use maxAttempts=1 for retryWithBackoff when in Preview Model Fallback Mode', async () => {
|
|
394
|
+
vi.mocked(mockConfig.isPreviewModelFallbackMode).mockReturnValue(true);
|
|
395
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue((async function* () {
|
|
396
|
+
yield {
|
|
397
|
+
candidates: [
|
|
398
|
+
{
|
|
399
|
+
content: { parts: [{ text: 'Success' }] },
|
|
400
|
+
finishReason: 'STOP',
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
};
|
|
404
|
+
})());
|
|
405
|
+
const stream = await chat.sendMessageStream({ model: PREVIEW_GEMINI_MODEL }, 'test', 'prompt-id-fast-retry', new AbortController().signal);
|
|
406
|
+
for await (const _ of stream) {
|
|
407
|
+
// consume stream
|
|
408
|
+
}
|
|
409
|
+
expect(mockRetryWithBackoff).toHaveBeenCalledWith(expect.any(Function), expect.objectContaining({
|
|
410
|
+
maxAttempts: 1,
|
|
411
|
+
}));
|
|
412
|
+
});
|
|
413
|
+
it('should NOT use maxAttempts=1 for other models even in Preview Model Fallback Mode', async () => {
|
|
414
|
+
vi.mocked(mockConfig.isPreviewModelFallbackMode).mockReturnValue(true);
|
|
415
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue((async function* () {
|
|
416
|
+
yield {
|
|
417
|
+
candidates: [
|
|
418
|
+
{
|
|
419
|
+
content: { parts: [{ text: 'Success' }] },
|
|
420
|
+
finishReason: 'STOP',
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
};
|
|
424
|
+
})());
|
|
425
|
+
const stream = await chat.sendMessageStream({ model: DEFAULT_GEMINI_FLASH_MODEL }, 'test', 'prompt-id-normal-retry', new AbortController().signal);
|
|
426
|
+
for await (const _ of stream) {
|
|
427
|
+
// consume stream
|
|
428
|
+
}
|
|
429
|
+
expect(mockRetryWithBackoff).toHaveBeenCalledWith(expect.any(Function), expect.objectContaining({
|
|
430
|
+
maxAttempts: undefined, // Should use default
|
|
431
|
+
}));
|
|
432
|
+
});
|
|
433
|
+
it('should pass DEFAULT_GEMINI_MODEL to handleFallback when Preview Model is bypassed (downgraded)', async () => {
|
|
434
|
+
// ARRANGE
|
|
435
|
+
vi.mocked(mockConfig.isPreviewModelBypassMode).mockReturnValue(true);
|
|
436
|
+
// Mock retryWithBackoff to simulate catching the error and calling onPersistent429
|
|
437
|
+
vi.mocked(retryWithBackoff).mockImplementation(async (apiCall, options) => {
|
|
438
|
+
const onPersistent429 = options?.onPersistent429;
|
|
439
|
+
try {
|
|
440
|
+
await apiCall();
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
if (onPersistent429) {
|
|
444
|
+
await onPersistent429(AuthType.LOGIN_WITH_GOOGLE, error);
|
|
445
|
+
}
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
// We need the API call to fail so retryWithBackoff calls the callback.
|
|
450
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(new TerminalQuotaError('Simulated Quota Error', {
|
|
451
|
+
code: 429,
|
|
452
|
+
message: 'Simulated Quota Error',
|
|
453
|
+
details: [],
|
|
454
|
+
}));
|
|
455
|
+
// ACT
|
|
456
|
+
const consumeStream = async () => {
|
|
457
|
+
const stream = await chat.sendMessageStream({ model: PREVIEW_GEMINI_MODEL }, 'test', 'prompt-id-bypass', new AbortController().signal);
|
|
458
|
+
// Consume the stream to trigger execution
|
|
459
|
+
for await (const _ of stream) {
|
|
460
|
+
// do nothing
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
await expect(consumeStream()).rejects.toThrow('Simulated Quota Error');
|
|
464
|
+
expect(retryWithBackoff).toHaveBeenCalled();
|
|
465
|
+
// ASSERT
|
|
466
|
+
// handleFallback is called via onPersistent429Callback
|
|
467
|
+
// We verify it was called with DEFAULT_GEMINI_MODEL
|
|
468
|
+
expect(mockHandleFallback).toHaveBeenCalledWith(expect.anything(), DEFAULT_GEMINI_MODEL, // This is the key assertion
|
|
469
|
+
expect.anything(), expect.anything());
|
|
470
|
+
});
|
|
354
471
|
it('should throw an error when a tool call is followed by an empty stream response', async () => {
|
|
355
472
|
// 1. Setup: A history where the model has just made a function call.
|
|
356
473
|
const initialHistory = [
|
|
@@ -384,14 +501,12 @@ describe('GeminiChat', () => {
|
|
|
384
501
|
})();
|
|
385
502
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(emptyStreamResponse);
|
|
386
503
|
// 3. Action: Send the function response back to the model and consume the stream.
|
|
387
|
-
const stream = await chat.sendMessageStream('
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
response: { name: 'Vesuvio' },
|
|
392
|
-
},
|
|
504
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, {
|
|
505
|
+
functionResponse: {
|
|
506
|
+
name: 'find_restaurant',
|
|
507
|
+
response: { name: 'Vesuvio' },
|
|
393
508
|
},
|
|
394
|
-
}, 'prompt-id-stream-1');
|
|
509
|
+
}, 'prompt-id-stream-1', new AbortController().signal);
|
|
395
510
|
// 4. Assert: The stream processing should throw an InvalidStreamError.
|
|
396
511
|
await expect((async () => {
|
|
397
512
|
for await (const _ of stream) {
|
|
@@ -422,7 +537,7 @@ describe('GeminiChat', () => {
|
|
|
422
537
|
};
|
|
423
538
|
})();
|
|
424
539
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithToolCall);
|
|
425
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
540
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-1', new AbortController().signal);
|
|
426
541
|
// Should not throw an error
|
|
427
542
|
await expect((async () => {
|
|
428
543
|
for await (const _ of stream) {
|
|
@@ -446,7 +561,7 @@ describe('GeminiChat', () => {
|
|
|
446
561
|
};
|
|
447
562
|
})();
|
|
448
563
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithoutFinishReason);
|
|
449
|
-
const stream = await chat.sendMessageStream(
|
|
564
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-1', new AbortController().signal);
|
|
450
565
|
await expect((async () => {
|
|
451
566
|
for await (const _ of stream) {
|
|
452
567
|
// consume stream
|
|
@@ -469,7 +584,7 @@ describe('GeminiChat', () => {
|
|
|
469
584
|
};
|
|
470
585
|
})();
|
|
471
586
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithEmptyResponse);
|
|
472
|
-
const stream = await chat.sendMessageStream(
|
|
587
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-1', new AbortController().signal);
|
|
473
588
|
await expect((async () => {
|
|
474
589
|
for await (const _ of stream) {
|
|
475
590
|
// consume stream
|
|
@@ -492,7 +607,7 @@ describe('GeminiChat', () => {
|
|
|
492
607
|
};
|
|
493
608
|
})();
|
|
494
609
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(validStream);
|
|
495
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
610
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-1', new AbortController().signal);
|
|
496
611
|
// Should not throw an error
|
|
497
612
|
await expect((async () => {
|
|
498
613
|
for await (const _ of stream) {
|
|
@@ -500,6 +615,71 @@ describe('GeminiChat', () => {
|
|
|
500
615
|
}
|
|
501
616
|
})()).resolves.not.toThrow();
|
|
502
617
|
});
|
|
618
|
+
it('should throw InvalidStreamError when finishReason is MALFORMED_FUNCTION_CALL', async () => {
|
|
619
|
+
// Setup: Stream with MALFORMED_FUNCTION_CALL finish reason and empty response
|
|
620
|
+
const streamWithMalformedFunctionCall = (async function* () {
|
|
621
|
+
yield {
|
|
622
|
+
candidates: [
|
|
623
|
+
{
|
|
624
|
+
content: {
|
|
625
|
+
role: 'model',
|
|
626
|
+
parts: [], // Empty parts
|
|
627
|
+
},
|
|
628
|
+
finishReason: 'MALFORMED_FUNCTION_CALL',
|
|
629
|
+
},
|
|
630
|
+
],
|
|
631
|
+
};
|
|
632
|
+
})();
|
|
633
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithMalformedFunctionCall);
|
|
634
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.5-pro' }, 'test', 'prompt-id-malformed', new AbortController().signal);
|
|
635
|
+
// Should throw an error
|
|
636
|
+
await expect((async () => {
|
|
637
|
+
for await (const _ of stream) {
|
|
638
|
+
// consume stream
|
|
639
|
+
}
|
|
640
|
+
})()).rejects.toThrow(InvalidStreamError);
|
|
641
|
+
});
|
|
642
|
+
it('should retry when finishReason is MALFORMED_FUNCTION_CALL', async () => {
|
|
643
|
+
// 1. Mock the API to fail once with MALFORMED_FUNCTION_CALL, then succeed.
|
|
644
|
+
vi.mocked(mockContentGenerator.generateContentStream)
|
|
645
|
+
.mockImplementationOnce(async () => (async function* () {
|
|
646
|
+
yield {
|
|
647
|
+
candidates: [
|
|
648
|
+
{
|
|
649
|
+
content: { parts: [], role: 'model' },
|
|
650
|
+
finishReason: 'MALFORMED_FUNCTION_CALL',
|
|
651
|
+
},
|
|
652
|
+
],
|
|
653
|
+
};
|
|
654
|
+
})())
|
|
655
|
+
.mockImplementationOnce(async () =>
|
|
656
|
+
// Second attempt succeeds
|
|
657
|
+
(async function* () {
|
|
658
|
+
yield {
|
|
659
|
+
candidates: [
|
|
660
|
+
{
|
|
661
|
+
content: { parts: [{ text: 'Success after retry' }] },
|
|
662
|
+
finishReason: 'STOP',
|
|
663
|
+
},
|
|
664
|
+
],
|
|
665
|
+
};
|
|
666
|
+
})());
|
|
667
|
+
// 2. Send a message
|
|
668
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.5-pro' }, 'test retry', 'prompt-id-retry-malformed', new AbortController().signal);
|
|
669
|
+
const events = [];
|
|
670
|
+
for await (const event of stream) {
|
|
671
|
+
events.push(event);
|
|
672
|
+
}
|
|
673
|
+
// 3. Assertions
|
|
674
|
+
// Should be called twice (initial + retry)
|
|
675
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(2);
|
|
676
|
+
// Check for a retry event
|
|
677
|
+
expect(events.some((e) => e.type === StreamEventType.RETRY)).toBe(true);
|
|
678
|
+
// Check for the successful content chunk
|
|
679
|
+
expect(events.some((e) => e.type === StreamEventType.CHUNK &&
|
|
680
|
+
e.value.candidates?.[0]?.content?.parts?.[0]?.text ===
|
|
681
|
+
'Success after retry')).toBe(true);
|
|
682
|
+
});
|
|
503
683
|
it('should call generateContentStream with the correct parameters', async () => {
|
|
504
684
|
const response = (async function* () {
|
|
505
685
|
yield {
|
|
@@ -523,7 +703,7 @@ describe('GeminiChat', () => {
|
|
|
523
703
|
};
|
|
524
704
|
})();
|
|
525
705
|
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(response);
|
|
526
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
706
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'hello', 'prompt-id-1', new AbortController().signal);
|
|
527
707
|
for await (const _ of stream) {
|
|
528
708
|
// consume stream
|
|
529
709
|
}
|
|
@@ -535,11 +715,68 @@ describe('GeminiChat', () => {
|
|
|
535
715
|
parts: [{ text: 'hello' }],
|
|
536
716
|
},
|
|
537
717
|
],
|
|
538
|
-
config: {
|
|
718
|
+
config: {
|
|
719
|
+
systemInstruction: '',
|
|
720
|
+
tools: [],
|
|
721
|
+
temperature: 0,
|
|
722
|
+
thinkingConfig: {
|
|
723
|
+
thinkingBudget: DEFAULT_THINKING_MODE,
|
|
724
|
+
},
|
|
725
|
+
abortSignal: expect.any(AbortSignal),
|
|
726
|
+
},
|
|
539
727
|
}, 'prompt-id-1');
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
728
|
+
});
|
|
729
|
+
it('should use thinkingLevel and remove thinkingBudget for gemini-3 models', async () => {
|
|
730
|
+
const response = (async function* () {
|
|
731
|
+
yield {
|
|
732
|
+
candidates: [
|
|
733
|
+
{
|
|
734
|
+
content: { parts: [{ text: 'response' }], role: 'model' },
|
|
735
|
+
finishReason: 'STOP',
|
|
736
|
+
},
|
|
737
|
+
],
|
|
738
|
+
};
|
|
739
|
+
})();
|
|
740
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(response);
|
|
741
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-3-test-only-model-string-for-testing' }, 'hello', 'prompt-id-thinking-level', new AbortController().signal);
|
|
742
|
+
for await (const _ of stream) {
|
|
743
|
+
// consume stream
|
|
744
|
+
}
|
|
745
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledWith(expect.objectContaining({
|
|
746
|
+
model: 'gemini-3-test-only-model-string-for-testing',
|
|
747
|
+
config: expect.objectContaining({
|
|
748
|
+
thinkingConfig: {
|
|
749
|
+
thinkingBudget: undefined,
|
|
750
|
+
thinkingLevel: ThinkingLevel.HIGH,
|
|
751
|
+
},
|
|
752
|
+
}),
|
|
753
|
+
}), 'prompt-id-thinking-level');
|
|
754
|
+
});
|
|
755
|
+
it('should use thinkingBudget and remove thinkingLevel for non-gemini-3 models', async () => {
|
|
756
|
+
const response = (async function* () {
|
|
757
|
+
yield {
|
|
758
|
+
candidates: [
|
|
759
|
+
{
|
|
760
|
+
content: { parts: [{ text: 'response' }], role: 'model' },
|
|
761
|
+
finishReason: 'STOP',
|
|
762
|
+
},
|
|
763
|
+
],
|
|
764
|
+
};
|
|
765
|
+
})();
|
|
766
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(response);
|
|
767
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'hello', 'prompt-id-thinking-budget', new AbortController().signal);
|
|
768
|
+
for await (const _ of stream) {
|
|
769
|
+
// consume stream
|
|
770
|
+
}
|
|
771
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledWith(expect.objectContaining({
|
|
772
|
+
model: 'gemini-2.0-flash',
|
|
773
|
+
config: expect.objectContaining({
|
|
774
|
+
thinkingConfig: {
|
|
775
|
+
thinkingBudget: DEFAULT_THINKING_MODE,
|
|
776
|
+
thinkingLevel: undefined,
|
|
777
|
+
},
|
|
778
|
+
}),
|
|
779
|
+
}), 'prompt-id-thinking-budget');
|
|
543
780
|
});
|
|
544
781
|
});
|
|
545
782
|
describe('addHistory', () => {
|
|
@@ -571,6 +808,23 @@ describe('GeminiChat', () => {
|
|
|
571
808
|
});
|
|
572
809
|
});
|
|
573
810
|
describe('sendMessageStream with retries', () => {
|
|
811
|
+
it('should not retry on invalid content if model does not start with gemini-2', async () => {
|
|
812
|
+
// Mock the stream to fail.
|
|
813
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockImplementation(async () => (async function* () {
|
|
814
|
+
yield {
|
|
815
|
+
candidates: [{ content: { parts: [{ text: '' }] } }],
|
|
816
|
+
};
|
|
817
|
+
})());
|
|
818
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-1.5-pro' }, 'test', 'prompt-id-no-retry', new AbortController().signal);
|
|
819
|
+
await expect((async () => {
|
|
820
|
+
for await (const _ of stream) {
|
|
821
|
+
// Must loop to trigger the internal logic that throws.
|
|
822
|
+
}
|
|
823
|
+
})()).rejects.toThrow(InvalidStreamError);
|
|
824
|
+
// Should be called only 1 time (no retry)
|
|
825
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(1);
|
|
826
|
+
expect(mockLogContentRetry).not.toHaveBeenCalled();
|
|
827
|
+
});
|
|
574
828
|
it('should yield a RETRY event when an invalid stream is encountered', async () => {
|
|
575
829
|
// ARRANGE: Mock the stream to fail once, then succeed.
|
|
576
830
|
vi.mocked(mockContentGenerator.generateContentStream)
|
|
@@ -594,7 +848,7 @@ describe('GeminiChat', () => {
|
|
|
594
848
|
};
|
|
595
849
|
})());
|
|
596
850
|
// ACT: Send a message and collect all events from the stream.
|
|
597
|
-
const stream = await chat.sendMessageStream(
|
|
851
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-yield-retry', new AbortController().signal);
|
|
598
852
|
const events = [];
|
|
599
853
|
for await (const event of stream) {
|
|
600
854
|
events.push(event);
|
|
@@ -626,7 +880,7 @@ describe('GeminiChat', () => {
|
|
|
626
880
|
],
|
|
627
881
|
};
|
|
628
882
|
})());
|
|
629
|
-
const stream = await chat.sendMessageStream(
|
|
883
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test', 'prompt-id-retry-success', new AbortController().signal);
|
|
630
884
|
const chunks = [];
|
|
631
885
|
for await (const chunk of stream) {
|
|
632
886
|
chunks.push(chunk);
|
|
@@ -655,6 +909,46 @@ describe('GeminiChat', () => {
|
|
|
655
909
|
// Verify that token counting is not called when usageMetadata is missing
|
|
656
910
|
expect(uiTelemetryService.setLastPromptTokenCount).not.toHaveBeenCalled();
|
|
657
911
|
});
|
|
912
|
+
it('should set temperature to 1 on retry', async () => {
|
|
913
|
+
// Use mockImplementationOnce to provide a fresh, promise-wrapped generator for each attempt.
|
|
914
|
+
vi.mocked(mockContentGenerator.generateContentStream)
|
|
915
|
+
.mockImplementationOnce(async () =>
|
|
916
|
+
// First call returns an invalid stream
|
|
917
|
+
(async function* () {
|
|
918
|
+
yield {
|
|
919
|
+
candidates: [{ content: { parts: [{ text: '' }] } }], // Invalid empty text part
|
|
920
|
+
};
|
|
921
|
+
})())
|
|
922
|
+
.mockImplementationOnce(async () =>
|
|
923
|
+
// Second call returns a valid stream
|
|
924
|
+
(async function* () {
|
|
925
|
+
yield {
|
|
926
|
+
candidates: [
|
|
927
|
+
{
|
|
928
|
+
content: { parts: [{ text: 'Successful response' }] },
|
|
929
|
+
finishReason: 'STOP',
|
|
930
|
+
},
|
|
931
|
+
],
|
|
932
|
+
};
|
|
933
|
+
})());
|
|
934
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-retry-temperature', new AbortController().signal);
|
|
935
|
+
for await (const _ of stream) {
|
|
936
|
+
// consume stream
|
|
937
|
+
}
|
|
938
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(2);
|
|
939
|
+
// First call should have original temperature
|
|
940
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenNthCalledWith(1, expect.objectContaining({
|
|
941
|
+
config: expect.objectContaining({
|
|
942
|
+
temperature: 0,
|
|
943
|
+
}),
|
|
944
|
+
}), 'prompt-id-retry-temperature');
|
|
945
|
+
// Second call (retry) should have temperature 1
|
|
946
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenNthCalledWith(2, expect.objectContaining({
|
|
947
|
+
config: expect.objectContaining({
|
|
948
|
+
temperature: 1,
|
|
949
|
+
}),
|
|
950
|
+
}), 'prompt-id-retry-temperature');
|
|
951
|
+
});
|
|
658
952
|
it('should fail after all retries on persistent invalid content and report metrics', async () => {
|
|
659
953
|
vi.mocked(mockContentGenerator.generateContentStream).mockImplementation(async () => (async function* () {
|
|
660
954
|
yield {
|
|
@@ -668,7 +962,7 @@ describe('GeminiChat', () => {
|
|
|
668
962
|
],
|
|
669
963
|
};
|
|
670
964
|
})());
|
|
671
|
-
const stream = await chat.sendMessageStream(
|
|
965
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test', 'prompt-id-retry-fail', new AbortController().signal);
|
|
672
966
|
await expect(async () => {
|
|
673
967
|
for await (const _ of stream) {
|
|
674
968
|
// Must loop to trigger the internal logic that throws.
|
|
@@ -689,13 +983,24 @@ describe('GeminiChat', () => {
|
|
|
689
983
|
describe('API error retry behavior', () => {
|
|
690
984
|
beforeEach(() => {
|
|
691
985
|
// Use a more direct mock for retry testing
|
|
692
|
-
mockRetryWithBackoff.mockImplementation(async (apiCall
|
|
986
|
+
mockRetryWithBackoff.mockImplementation(async (apiCall) => {
|
|
693
987
|
try {
|
|
694
988
|
return await apiCall();
|
|
695
989
|
}
|
|
696
990
|
catch (error) {
|
|
697
|
-
|
|
698
|
-
|
|
991
|
+
// Simulate the logic of defaultShouldRetry for ApiError
|
|
992
|
+
let shouldRetry = false;
|
|
993
|
+
if (error instanceof ApiError && error.message) {
|
|
994
|
+
if (error.status === 429 ||
|
|
995
|
+
(error.status >= 500 && error.status < 600)) {
|
|
996
|
+
shouldRetry = true;
|
|
997
|
+
}
|
|
998
|
+
// Explicitly don't retry on these
|
|
999
|
+
if (error.status === 400) {
|
|
1000
|
+
shouldRetry = false;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (shouldRetry) {
|
|
699
1004
|
// Try again
|
|
700
1005
|
return await apiCall();
|
|
701
1006
|
}
|
|
@@ -706,7 +1011,7 @@ describe('GeminiChat', () => {
|
|
|
706
1011
|
it('should not retry on 400 Bad Request errors', async () => {
|
|
707
1012
|
const error400 = new ApiError({ message: 'Bad Request', status: 400 });
|
|
708
1013
|
vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(error400);
|
|
709
|
-
const stream = await chat.sendMessageStream(
|
|
1014
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-400', new AbortController().signal);
|
|
710
1015
|
await expect((async () => {
|
|
711
1016
|
for await (const _ of stream) {
|
|
712
1017
|
/* consume stream */
|
|
@@ -729,7 +1034,7 @@ describe('GeminiChat', () => {
|
|
|
729
1034
|
],
|
|
730
1035
|
};
|
|
731
1036
|
})());
|
|
732
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
1037
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-429-retry', new AbortController().signal);
|
|
733
1038
|
const events = [];
|
|
734
1039
|
for await (const event of stream) {
|
|
735
1040
|
events.push(event);
|
|
@@ -741,21 +1046,6 @@ describe('GeminiChat', () => {
|
|
|
741
1046
|
e.value.candidates?.[0]?.content?.parts?.[0]?.text ===
|
|
742
1047
|
'Success after retry')).toBe(true);
|
|
743
1048
|
});
|
|
744
|
-
it('should not retry on schema depth errors', async () => {
|
|
745
|
-
const schemaError = new ApiError({
|
|
746
|
-
message: 'Request failed: maximum schema depth exceeded',
|
|
747
|
-
status: 500,
|
|
748
|
-
});
|
|
749
|
-
vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(schemaError);
|
|
750
|
-
const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-schema');
|
|
751
|
-
await expect((async () => {
|
|
752
|
-
for await (const _ of stream) {
|
|
753
|
-
/* consume stream */
|
|
754
|
-
}
|
|
755
|
-
})()).rejects.toThrow(schemaError);
|
|
756
|
-
// Should only be called once (no retry)
|
|
757
|
-
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(1);
|
|
758
|
-
});
|
|
759
1049
|
it('should retry on 5xx server errors', async () => {
|
|
760
1050
|
const error500 = new ApiError({
|
|
761
1051
|
message: 'Internal Server Error 500',
|
|
@@ -773,7 +1063,7 @@ describe('GeminiChat', () => {
|
|
|
773
1063
|
],
|
|
774
1064
|
};
|
|
775
1065
|
})());
|
|
776
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
1066
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-500-retry', new AbortController().signal);
|
|
777
1067
|
const events = [];
|
|
778
1068
|
for await (const event of stream) {
|
|
779
1069
|
events.push(event);
|
|
@@ -781,6 +1071,44 @@ describe('GeminiChat', () => {
|
|
|
781
1071
|
// Should be called twice (initial + retry)
|
|
782
1072
|
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(2);
|
|
783
1073
|
});
|
|
1074
|
+
it('should retry on specific fetch errors when configured', async () => {
|
|
1075
|
+
vi.mocked(mockConfig.getRetryFetchErrors).mockReturnValue(true);
|
|
1076
|
+
const fetchError = new Error('exception TypeError: fetch failed sending request');
|
|
1077
|
+
vi.mocked(mockContentGenerator.generateContentStream)
|
|
1078
|
+
.mockRejectedValueOnce(fetchError)
|
|
1079
|
+
.mockResolvedValueOnce((async function* () {
|
|
1080
|
+
yield {
|
|
1081
|
+
candidates: [
|
|
1082
|
+
{
|
|
1083
|
+
content: { parts: [{ text: 'Success after fetch error' }] },
|
|
1084
|
+
finishReason: 'STOP',
|
|
1085
|
+
},
|
|
1086
|
+
],
|
|
1087
|
+
};
|
|
1088
|
+
})());
|
|
1089
|
+
mockRetryWithBackoff.mockImplementation(async (apiCall, options) => {
|
|
1090
|
+
try {
|
|
1091
|
+
return await apiCall();
|
|
1092
|
+
}
|
|
1093
|
+
catch (error) {
|
|
1094
|
+
if (options?.retryFetchErrors &&
|
|
1095
|
+
error instanceof Error &&
|
|
1096
|
+
error.message.includes('exception TypeError: fetch failed sending request')) {
|
|
1097
|
+
return await apiCall();
|
|
1098
|
+
}
|
|
1099
|
+
throw error;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1102
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-fetch-error-retry', new AbortController().signal);
|
|
1103
|
+
const events = [];
|
|
1104
|
+
for await (const event of stream) {
|
|
1105
|
+
events.push(event);
|
|
1106
|
+
}
|
|
1107
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(2);
|
|
1108
|
+
expect(events.some((e) => e.type === StreamEventType.CHUNK &&
|
|
1109
|
+
e.value.candidates?.[0]?.content?.parts?.[0]?.text ===
|
|
1110
|
+
'Success after fetch error')).toBe(true);
|
|
1111
|
+
});
|
|
784
1112
|
afterEach(() => {
|
|
785
1113
|
// Reset to default behavior
|
|
786
1114
|
mockRetryWithBackoff.mockImplementation(async (apiCall) => apiCall());
|
|
@@ -814,7 +1142,7 @@ describe('GeminiChat', () => {
|
|
|
814
1142
|
};
|
|
815
1143
|
})());
|
|
816
1144
|
// 3. Send a new message
|
|
817
|
-
const stream = await chat.sendMessageStream('
|
|
1145
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'Second question', 'prompt-id-retry-existing', new AbortController().signal);
|
|
818
1146
|
for await (const _ of stream) {
|
|
819
1147
|
// consume stream
|
|
820
1148
|
}
|
|
@@ -866,7 +1194,7 @@ describe('GeminiChat', () => {
|
|
|
866
1194
|
};
|
|
867
1195
|
})());
|
|
868
1196
|
// 2. Call the method and consume the stream.
|
|
869
|
-
const stream = await chat.sendMessageStream('
|
|
1197
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test empty stream', 'prompt-id-empty-stream', new AbortController().signal);
|
|
870
1198
|
const chunks = [];
|
|
871
1199
|
for await (const chunk of stream) {
|
|
872
1200
|
chunks.push(chunk);
|
|
@@ -927,11 +1255,11 @@ describe('GeminiChat', () => {
|
|
|
927
1255
|
.mockResolvedValueOnce(firstStreamGenerator)
|
|
928
1256
|
.mockResolvedValueOnce(secondStreamGenerator);
|
|
929
1257
|
// 3. Start the first stream and consume only the first chunk to pause it
|
|
930
|
-
const firstStream = await chat.sendMessageStream('test-model',
|
|
1258
|
+
const firstStream = await chat.sendMessageStream({ model: 'test-model' }, 'first', 'prompt-1', new AbortController().signal);
|
|
931
1259
|
const firstStreamIterator = firstStream[Symbol.asyncIterator]();
|
|
932
1260
|
await firstStreamIterator.next();
|
|
933
1261
|
// 4. While the first stream is paused, start the second call. It will block.
|
|
934
|
-
const secondStreamPromise = chat.sendMessageStream('test-model',
|
|
1262
|
+
const secondStreamPromise = chat.sendMessageStream({ model: 'test-model' }, 'second', 'prompt-2', new AbortController().signal);
|
|
935
1263
|
// 5. Assert that only one API call has been made so far.
|
|
936
1264
|
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(1);
|
|
937
1265
|
// 6. Unblock and fully consume the first stream to completion.
|
|
@@ -956,215 +1284,6 @@ describe('GeminiChat', () => {
|
|
|
956
1284
|
}
|
|
957
1285
|
expect(turn4.parts[0].text).toBe('second response');
|
|
958
1286
|
});
|
|
959
|
-
describe('stopBeforeSecondMutator', () => {
|
|
960
|
-
beforeEach(() => {
|
|
961
|
-
// Common setup for these tests: mock the tool registry.
|
|
962
|
-
const mockToolRegistry = {
|
|
963
|
-
getTool: vi.fn((toolName) => {
|
|
964
|
-
if (toolName === 'edit') {
|
|
965
|
-
return { kind: Kind.Edit };
|
|
966
|
-
}
|
|
967
|
-
return { kind: Kind.Other };
|
|
968
|
-
}),
|
|
969
|
-
};
|
|
970
|
-
vi.mocked(mockConfig.getToolRegistry).mockReturnValue(mockToolRegistry);
|
|
971
|
-
});
|
|
972
|
-
it('should stop streaming before a second mutator tool call', async () => {
|
|
973
|
-
const responses = [
|
|
974
|
-
{
|
|
975
|
-
candidates: [
|
|
976
|
-
{ content: { role: 'model', parts: [{ text: 'First part. ' }] } },
|
|
977
|
-
],
|
|
978
|
-
},
|
|
979
|
-
{
|
|
980
|
-
candidates: [
|
|
981
|
-
{
|
|
982
|
-
content: {
|
|
983
|
-
role: 'model',
|
|
984
|
-
parts: [{ functionCall: { name: 'edit', args: {} } }],
|
|
985
|
-
},
|
|
986
|
-
},
|
|
987
|
-
],
|
|
988
|
-
},
|
|
989
|
-
{
|
|
990
|
-
candidates: [
|
|
991
|
-
{
|
|
992
|
-
content: {
|
|
993
|
-
role: 'model',
|
|
994
|
-
parts: [{ functionCall: { name: 'fetch', args: {} } }],
|
|
995
|
-
},
|
|
996
|
-
},
|
|
997
|
-
],
|
|
998
|
-
},
|
|
999
|
-
// This chunk contains the second mutator and should be clipped.
|
|
1000
|
-
{
|
|
1001
|
-
candidates: [
|
|
1002
|
-
{
|
|
1003
|
-
content: {
|
|
1004
|
-
role: 'model',
|
|
1005
|
-
parts: [
|
|
1006
|
-
{ functionCall: { name: 'edit', args: {} } },
|
|
1007
|
-
{ text: 'some trailing text' },
|
|
1008
|
-
],
|
|
1009
|
-
},
|
|
1010
|
-
},
|
|
1011
|
-
],
|
|
1012
|
-
},
|
|
1013
|
-
// This chunk should never be reached.
|
|
1014
|
-
{
|
|
1015
|
-
candidates: [
|
|
1016
|
-
{
|
|
1017
|
-
content: {
|
|
1018
|
-
role: 'model',
|
|
1019
|
-
parts: [{ text: 'This should not appear.' }],
|
|
1020
|
-
},
|
|
1021
|
-
},
|
|
1022
|
-
],
|
|
1023
|
-
},
|
|
1024
|
-
];
|
|
1025
|
-
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue((async function* () {
|
|
1026
|
-
for (const response of responses) {
|
|
1027
|
-
yield response;
|
|
1028
|
-
}
|
|
1029
|
-
})());
|
|
1030
|
-
const stream = await chat.sendMessageStream('test-model', { message: 'test message' }, 'prompt-id-mutator-test');
|
|
1031
|
-
for await (const _ of stream) {
|
|
1032
|
-
// Consume the stream to trigger history recording.
|
|
1033
|
-
}
|
|
1034
|
-
const history = chat.getHistory();
|
|
1035
|
-
expect(history.length).toBe(2);
|
|
1036
|
-
const modelTurn = history[1];
|
|
1037
|
-
expect(modelTurn.role).toBe('model');
|
|
1038
|
-
expect(modelTurn?.parts?.length).toBe(3);
|
|
1039
|
-
expect(modelTurn?.parts[0].text).toBe('First part. ');
|
|
1040
|
-
expect(modelTurn.parts[1].functionCall?.name).toBe('edit');
|
|
1041
|
-
expect(modelTurn.parts[2].functionCall?.name).toBe('fetch');
|
|
1042
|
-
});
|
|
1043
|
-
it('should not stop streaming if only one mutator is present', async () => {
|
|
1044
|
-
const responses = [
|
|
1045
|
-
{
|
|
1046
|
-
candidates: [
|
|
1047
|
-
{ content: { role: 'model', parts: [{ text: 'Part 1. ' }] } },
|
|
1048
|
-
],
|
|
1049
|
-
},
|
|
1050
|
-
{
|
|
1051
|
-
candidates: [
|
|
1052
|
-
{
|
|
1053
|
-
content: {
|
|
1054
|
-
role: 'model',
|
|
1055
|
-
parts: [{ functionCall: { name: 'edit', args: {} } }],
|
|
1056
|
-
},
|
|
1057
|
-
},
|
|
1058
|
-
],
|
|
1059
|
-
},
|
|
1060
|
-
{
|
|
1061
|
-
candidates: [
|
|
1062
|
-
{
|
|
1063
|
-
content: {
|
|
1064
|
-
role: 'model',
|
|
1065
|
-
parts: [{ text: 'Part 2.' }],
|
|
1066
|
-
},
|
|
1067
|
-
finishReason: 'STOP',
|
|
1068
|
-
},
|
|
1069
|
-
],
|
|
1070
|
-
},
|
|
1071
|
-
];
|
|
1072
|
-
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue((async function* () {
|
|
1073
|
-
for (const response of responses) {
|
|
1074
|
-
yield response;
|
|
1075
|
-
}
|
|
1076
|
-
})());
|
|
1077
|
-
const stream = await chat.sendMessageStream('test-model', { message: 'test message' }, 'prompt-id-one-mutator');
|
|
1078
|
-
for await (const _ of stream) {
|
|
1079
|
-
/* consume */
|
|
1080
|
-
}
|
|
1081
|
-
const history = chat.getHistory();
|
|
1082
|
-
const modelTurn = history[1];
|
|
1083
|
-
expect(modelTurn?.parts?.length).toBe(3);
|
|
1084
|
-
expect(modelTurn.parts[1].functionCall?.name).toBe('edit');
|
|
1085
|
-
expect(modelTurn.parts[2].text).toBe('Part 2.');
|
|
1086
|
-
});
|
|
1087
|
-
it('should clip the chunk containing the second mutator, preserving prior parts', async () => {
|
|
1088
|
-
const responses = [
|
|
1089
|
-
{
|
|
1090
|
-
candidates: [
|
|
1091
|
-
{
|
|
1092
|
-
content: {
|
|
1093
|
-
role: 'model',
|
|
1094
|
-
parts: [{ functionCall: { name: 'edit', args: {} } }],
|
|
1095
|
-
},
|
|
1096
|
-
},
|
|
1097
|
-
],
|
|
1098
|
-
},
|
|
1099
|
-
// This chunk has a valid part before the second mutator.
|
|
1100
|
-
// The valid part should be kept, the rest of the chunk discarded.
|
|
1101
|
-
{
|
|
1102
|
-
candidates: [
|
|
1103
|
-
{
|
|
1104
|
-
content: {
|
|
1105
|
-
role: 'model',
|
|
1106
|
-
parts: [
|
|
1107
|
-
{ text: 'Keep this text. ' },
|
|
1108
|
-
{ functionCall: { name: 'edit', args: {} } },
|
|
1109
|
-
{ text: 'Discard this text.' },
|
|
1110
|
-
],
|
|
1111
|
-
},
|
|
1112
|
-
finishReason: 'STOP',
|
|
1113
|
-
},
|
|
1114
|
-
],
|
|
1115
|
-
},
|
|
1116
|
-
];
|
|
1117
|
-
const stream = (async function* () {
|
|
1118
|
-
for (const response of responses) {
|
|
1119
|
-
yield response;
|
|
1120
|
-
}
|
|
1121
|
-
})();
|
|
1122
|
-
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
|
|
1123
|
-
const resultStream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-clip-chunk');
|
|
1124
|
-
for await (const _ of resultStream) {
|
|
1125
|
-
/* consume */
|
|
1126
|
-
}
|
|
1127
|
-
const history = chat.getHistory();
|
|
1128
|
-
const modelTurn = history[1];
|
|
1129
|
-
expect(modelTurn?.parts?.length).toBe(2);
|
|
1130
|
-
expect(modelTurn.parts[0].functionCall?.name).toBe('edit');
|
|
1131
|
-
expect(modelTurn.parts[1].text).toBe('Keep this text. ');
|
|
1132
|
-
});
|
|
1133
|
-
it('should handle two mutators in the same chunk (parallel call scenario)', async () => {
|
|
1134
|
-
const responses = [
|
|
1135
|
-
{
|
|
1136
|
-
candidates: [
|
|
1137
|
-
{
|
|
1138
|
-
content: {
|
|
1139
|
-
role: 'model',
|
|
1140
|
-
parts: [
|
|
1141
|
-
{ text: 'Some text. ' },
|
|
1142
|
-
{ functionCall: { name: 'edit', args: {} } },
|
|
1143
|
-
{ functionCall: { name: 'edit', args: {} } },
|
|
1144
|
-
],
|
|
1145
|
-
},
|
|
1146
|
-
finishReason: 'STOP',
|
|
1147
|
-
},
|
|
1148
|
-
],
|
|
1149
|
-
},
|
|
1150
|
-
];
|
|
1151
|
-
const stream = (async function* () {
|
|
1152
|
-
for (const response of responses) {
|
|
1153
|
-
yield response;
|
|
1154
|
-
}
|
|
1155
|
-
})();
|
|
1156
|
-
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
|
|
1157
|
-
const resultStream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-parallel-mutators');
|
|
1158
|
-
for await (const _ of resultStream) {
|
|
1159
|
-
/* consume */
|
|
1160
|
-
}
|
|
1161
|
-
const history = chat.getHistory();
|
|
1162
|
-
const modelTurn = history[1];
|
|
1163
|
-
expect(modelTurn?.parts?.length).toBe(2);
|
|
1164
|
-
expect(modelTurn.parts[0].text).toBe('Some text. ');
|
|
1165
|
-
expect(modelTurn.parts[1].functionCall?.name).toBe('edit');
|
|
1166
|
-
});
|
|
1167
|
-
});
|
|
1168
1287
|
describe('Model Resolution', () => {
|
|
1169
1288
|
const mockResponse = {
|
|
1170
1289
|
candidates: [
|
|
@@ -1180,7 +1299,7 @@ describe('GeminiChat', () => {
|
|
|
1180
1299
|
vi.mocked(mockContentGenerator.generateContentStream).mockImplementation(async () => (async function* () {
|
|
1181
1300
|
yield mockResponse;
|
|
1182
1301
|
})());
|
|
1183
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
1302
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'test message', 'prompt-id-res3', new AbortController().signal);
|
|
1184
1303
|
for await (const _ of stream) {
|
|
1185
1304
|
// consume stream
|
|
1186
1305
|
}
|
|
@@ -1243,7 +1362,7 @@ describe('GeminiChat', () => {
|
|
|
1243
1362
|
isInFallbackModeSpy.mockReturnValue(true);
|
|
1244
1363
|
return true; // Signal retry
|
|
1245
1364
|
});
|
|
1246
|
-
const stream = await chat.sendMessageStream('test-model',
|
|
1365
|
+
const stream = await chat.sendMessageStream({ model: 'test-model' }, 'trigger 429', 'prompt-id-fb1', new AbortController().signal);
|
|
1247
1366
|
// Consume stream to trigger logic
|
|
1248
1367
|
for await (const _ of stream) {
|
|
1249
1368
|
// no-op
|
|
@@ -1255,11 +1374,69 @@ describe('GeminiChat', () => {
|
|
|
1255
1374
|
const modelTurn = history[1];
|
|
1256
1375
|
expect(modelTurn.parts[0].text).toBe('Success on retry');
|
|
1257
1376
|
});
|
|
1377
|
+
it('should switch to DEFAULT_GEMINI_FLASH_MODEL and use thinkingBudget when falling back from a gemini-3 model', async () => {
|
|
1378
|
+
// ARRANGE
|
|
1379
|
+
const authType = AuthType.LOGIN_WITH_GOOGLE;
|
|
1380
|
+
vi.mocked(mockConfig.getContentGeneratorConfig).mockReturnValue({
|
|
1381
|
+
authType,
|
|
1382
|
+
});
|
|
1383
|
+
// Initial state: Not in fallback mode
|
|
1384
|
+
const isInFallbackModeSpy = vi.spyOn(mockConfig, 'isInFallbackMode');
|
|
1385
|
+
isInFallbackModeSpy.mockReturnValue(false);
|
|
1386
|
+
// Mock API calls:
|
|
1387
|
+
// 1. Fails with 429 (simulating gemini-3 failure)
|
|
1388
|
+
// 2. Succeeds (simulating fallback success)
|
|
1389
|
+
vi.mocked(mockContentGenerator.generateContentStream)
|
|
1390
|
+
.mockRejectedValueOnce(error429)
|
|
1391
|
+
.mockResolvedValueOnce((async function* () {
|
|
1392
|
+
yield {
|
|
1393
|
+
candidates: [
|
|
1394
|
+
{
|
|
1395
|
+
content: { parts: [{ text: 'Fallback success' }] },
|
|
1396
|
+
finishReason: 'STOP',
|
|
1397
|
+
},
|
|
1398
|
+
],
|
|
1399
|
+
};
|
|
1400
|
+
})());
|
|
1401
|
+
// Mock handleFallback to enable fallback mode and signal retry
|
|
1402
|
+
mockHandleFallback.mockImplementation(async () => {
|
|
1403
|
+
isInFallbackModeSpy.mockReturnValue(true); // Next call will see fallback mode = true
|
|
1404
|
+
return true;
|
|
1405
|
+
});
|
|
1406
|
+
// ACT
|
|
1407
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-3-test-model' }, // Start with a gemini-3 model
|
|
1408
|
+
'test fallback thinking', 'prompt-id-fb3', new AbortController().signal);
|
|
1409
|
+
for await (const _ of stream) {
|
|
1410
|
+
// consume stream
|
|
1411
|
+
}
|
|
1412
|
+
// ASSERT
|
|
1413
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(2);
|
|
1414
|
+
// First call: gemini-3 model, thinkingLevel set
|
|
1415
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenNthCalledWith(1, expect.objectContaining({
|
|
1416
|
+
model: 'gemini-3-test-model',
|
|
1417
|
+
config: expect.objectContaining({
|
|
1418
|
+
thinkingConfig: {
|
|
1419
|
+
thinkingBudget: undefined,
|
|
1420
|
+
thinkingLevel: ThinkingLevel.HIGH,
|
|
1421
|
+
},
|
|
1422
|
+
}),
|
|
1423
|
+
}), 'prompt-id-fb3');
|
|
1424
|
+
// Second call: DEFAULT_GEMINI_FLASH_MODEL (due to fallback), thinkingBudget set (due to fix)
|
|
1425
|
+
expect(mockContentGenerator.generateContentStream).toHaveBeenNthCalledWith(2, expect.objectContaining({
|
|
1426
|
+
model: DEFAULT_GEMINI_FLASH_MODEL,
|
|
1427
|
+
config: expect.objectContaining({
|
|
1428
|
+
thinkingConfig: {
|
|
1429
|
+
thinkingBudget: DEFAULT_THINKING_MODE,
|
|
1430
|
+
thinkingLevel: undefined,
|
|
1431
|
+
},
|
|
1432
|
+
}),
|
|
1433
|
+
}), 'prompt-id-fb3');
|
|
1434
|
+
});
|
|
1258
1435
|
it('should stop retrying if handleFallback returns false (e.g., auth intent)', async () => {
|
|
1259
1436
|
vi.mocked(mockConfig.getModel).mockReturnValue('gemini-pro');
|
|
1260
1437
|
vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(error429);
|
|
1261
1438
|
mockHandleFallback.mockResolvedValue(false);
|
|
1262
|
-
const stream = await chat.sendMessageStream('
|
|
1439
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test stop', 'prompt-id-fb2', new AbortController().signal);
|
|
1263
1440
|
await expect((async () => {
|
|
1264
1441
|
for await (const _ of stream) {
|
|
1265
1442
|
/* consume stream */
|
|
@@ -1303,7 +1480,7 @@ describe('GeminiChat', () => {
|
|
|
1303
1480
|
};
|
|
1304
1481
|
})());
|
|
1305
1482
|
// Send a message and consume the stream
|
|
1306
|
-
const stream = await chat.sendMessageStream(
|
|
1483
|
+
const stream = await chat.sendMessageStream({ model: 'gemini-2.0-flash' }, 'test message', 'prompt-id-discard-test', new AbortController().signal);
|
|
1307
1484
|
const events = [];
|
|
1308
1485
|
for await (const event of stream) {
|
|
1309
1486
|
events.push(event);
|
|
@@ -1354,5 +1531,139 @@ describe('GeminiChat', () => {
|
|
|
1354
1531
|
]);
|
|
1355
1532
|
});
|
|
1356
1533
|
});
|
|
1534
|
+
describe('Preview Model Fallback Logic', () => {
|
|
1535
|
+
it('should reset previewModelBypassMode to false at the start of sendMessageStream', async () => {
|
|
1536
|
+
const stream = (async function* () {
|
|
1537
|
+
yield {
|
|
1538
|
+
candidates: [
|
|
1539
|
+
{
|
|
1540
|
+
content: { role: 'model', parts: [{ text: 'Success' }] },
|
|
1541
|
+
finishReason: 'STOP',
|
|
1542
|
+
},
|
|
1543
|
+
],
|
|
1544
|
+
};
|
|
1545
|
+
})();
|
|
1546
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
|
|
1547
|
+
await chat.sendMessageStream({ model: 'test-model' }, 'test', 'prompt-id-preview-model-reset', new AbortController().signal);
|
|
1548
|
+
expect(mockConfig.setPreviewModelBypassMode).toHaveBeenCalledWith(false);
|
|
1549
|
+
});
|
|
1550
|
+
it('should reset previewModelFallbackMode to false upon successful Preview Model usage', async () => {
|
|
1551
|
+
const stream = (async function* () {
|
|
1552
|
+
yield {
|
|
1553
|
+
candidates: [
|
|
1554
|
+
{
|
|
1555
|
+
content: { role: 'model', parts: [{ text: 'Success' }] },
|
|
1556
|
+
finishReason: 'STOP',
|
|
1557
|
+
},
|
|
1558
|
+
],
|
|
1559
|
+
};
|
|
1560
|
+
})();
|
|
1561
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
|
|
1562
|
+
const resultStream = await chat.sendMessageStream({ model: PREVIEW_GEMINI_MODEL }, 'test', 'prompt-id-preview-model-healing', new AbortController().signal);
|
|
1563
|
+
for await (const _ of resultStream) {
|
|
1564
|
+
// consume stream
|
|
1565
|
+
}
|
|
1566
|
+
expect(mockConfig.setPreviewModelFallbackMode).toHaveBeenCalledWith(false);
|
|
1567
|
+
});
|
|
1568
|
+
it('should NOT reset previewModelFallbackMode if Preview Model was bypassed (downgraded)', async () => {
|
|
1569
|
+
const stream = (async function* () {
|
|
1570
|
+
yield {
|
|
1571
|
+
candidates: [
|
|
1572
|
+
{
|
|
1573
|
+
content: { role: 'model', parts: [{ text: 'Success' }] },
|
|
1574
|
+
finishReason: 'STOP',
|
|
1575
|
+
},
|
|
1576
|
+
],
|
|
1577
|
+
};
|
|
1578
|
+
})();
|
|
1579
|
+
vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
|
|
1580
|
+
// Simulate bypass mode being active (downgrade happened)
|
|
1581
|
+
vi.mocked(mockConfig.isPreviewModelBypassMode).mockReturnValue(true);
|
|
1582
|
+
const resultStream = await chat.sendMessageStream({ model: PREVIEW_GEMINI_MODEL }, 'test', 'prompt-id-bypass-no-healing', new AbortController().signal);
|
|
1583
|
+
for await (const _ of resultStream) {
|
|
1584
|
+
// consume stream
|
|
1585
|
+
}
|
|
1586
|
+
expect(mockConfig.setPreviewModelFallbackMode).not.toHaveBeenCalled();
|
|
1587
|
+
});
|
|
1588
|
+
});
|
|
1589
|
+
describe('ensureActiveLoopHasThoughtSignatures', () => {
|
|
1590
|
+
it('should add thoughtSignature to the first functionCall in each model turn of the active loop', () => {
|
|
1591
|
+
const chat = new GeminiChat(mockConfig, '', [], []);
|
|
1592
|
+
const history = [
|
|
1593
|
+
{ role: 'user', parts: [{ text: 'Old message' }] },
|
|
1594
|
+
{
|
|
1595
|
+
role: 'model',
|
|
1596
|
+
parts: [{ functionCall: { name: 'old_tool', args: {} } }],
|
|
1597
|
+
},
|
|
1598
|
+
{ role: 'user', parts: [{ text: 'Find a restaurant' }] }, // active loop starts here
|
|
1599
|
+
{
|
|
1600
|
+
role: 'model',
|
|
1601
|
+
parts: [
|
|
1602
|
+
{ functionCall: { name: 'find_restaurant', args: {} } }, // This one gets a signature
|
|
1603
|
+
{ functionCall: { name: 'find_restaurant_2', args: {} } }, // This one does NOT
|
|
1604
|
+
],
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
role: 'user',
|
|
1608
|
+
parts: [
|
|
1609
|
+
{ functionResponse: { name: 'find_restaurant', response: {} } },
|
|
1610
|
+
],
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
role: 'model',
|
|
1614
|
+
parts: [
|
|
1615
|
+
{
|
|
1616
|
+
functionCall: { name: 'tool_with_sig', args: {} },
|
|
1617
|
+
thoughtSignature: 'existing-sig',
|
|
1618
|
+
},
|
|
1619
|
+
{ functionCall: { name: 'another_tool', args: {} } }, // This one does NOT get a signature
|
|
1620
|
+
],
|
|
1621
|
+
},
|
|
1622
|
+
];
|
|
1623
|
+
const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
|
|
1624
|
+
// Outside active loop - unchanged
|
|
1625
|
+
expect(newContents[1]?.parts?.[0]).not.toHaveProperty('thoughtSignature');
|
|
1626
|
+
// Inside active loop, first model turn
|
|
1627
|
+
// First function call gets a signature
|
|
1628
|
+
expect(newContents[3]?.parts?.[0]?.thoughtSignature).toBe(SYNTHETIC_THOUGHT_SIGNATURE);
|
|
1629
|
+
// Second function call does NOT
|
|
1630
|
+
expect(newContents[3]?.parts?.[1]).not.toHaveProperty('thoughtSignature');
|
|
1631
|
+
// User functionResponse part - unchanged (this is not a model turn)
|
|
1632
|
+
expect(newContents[4]?.parts?.[0]).not.toHaveProperty('thoughtSignature');
|
|
1633
|
+
// Inside active loop, second model turn
|
|
1634
|
+
// First function call already has a signature, so nothing changes
|
|
1635
|
+
expect(newContents[5]?.parts?.[0]?.thoughtSignature).toBe('existing-sig');
|
|
1636
|
+
// Second function call does NOT get a signature
|
|
1637
|
+
expect(newContents[5]?.parts?.[1]).not.toHaveProperty('thoughtSignature');
|
|
1638
|
+
});
|
|
1639
|
+
it('should not modify contents if there is no user text message', () => {
|
|
1640
|
+
const chat = new GeminiChat(mockConfig, '', [], []);
|
|
1641
|
+
const history = [
|
|
1642
|
+
{
|
|
1643
|
+
role: 'user',
|
|
1644
|
+
parts: [{ functionResponse: { name: 'tool1', response: {} } }],
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
role: 'model',
|
|
1648
|
+
parts: [{ functionCall: { name: 'tool2', args: {} } }],
|
|
1649
|
+
},
|
|
1650
|
+
];
|
|
1651
|
+
const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
|
|
1652
|
+
expect(newContents).toEqual(history);
|
|
1653
|
+
expect(newContents[1]?.parts?.[0]).not.toHaveProperty('thoughtSignature');
|
|
1654
|
+
});
|
|
1655
|
+
it('should handle an empty history', () => {
|
|
1656
|
+
const chat = new GeminiChat(mockConfig, '', []);
|
|
1657
|
+
const history = [];
|
|
1658
|
+
const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
|
|
1659
|
+
expect(newContents).toEqual([]);
|
|
1660
|
+
});
|
|
1661
|
+
it('should handle history with only a user message', () => {
|
|
1662
|
+
const chat = new GeminiChat(mockConfig, '', []);
|
|
1663
|
+
const history = [{ role: 'user', parts: [{ text: 'Hello' }] }];
|
|
1664
|
+
const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
|
|
1665
|
+
expect(newContents).toEqual(history);
|
|
1666
|
+
});
|
|
1667
|
+
});
|
|
1357
1668
|
});
|
|
1358
1669
|
//# sourceMappingURL=geminiChat.test.js.map
|