@vybestack/llxprt-code 0.4.8 → 0.5.0-nightly.251102.6bb3db7a
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/package.json +5 -3
- package/dist/src/auth/__tests__/oauthManager.safety.test.d.ts +6 -0
- package/dist/src/auth/__tests__/oauthManager.safety.test.js +49 -0
- package/dist/src/auth/__tests__/oauthManager.safety.test.js.map +1 -0
- package/dist/src/auth/oauth-manager.d.ts +11 -0
- package/dist/src/auth/oauth-manager.js +62 -29
- package/dist/src/auth/oauth-manager.js.map +1 -1
- package/dist/src/auth/oauth-manager.spec.js +7 -2
- package/dist/src/auth/oauth-manager.spec.js.map +1 -1
- package/dist/src/config/__tests__/nonInteractiveTools.test.d.ts +6 -0
- package/dist/src/config/__tests__/nonInteractiveTools.test.js +13 -0
- package/dist/src/config/__tests__/nonInteractiveTools.test.js.map +1 -0
- package/dist/src/config/__tests__/profileBootstrap.test.d.ts +6 -0
- package/dist/src/config/__tests__/profileBootstrap.test.js +91 -0
- package/dist/src/config/__tests__/profileBootstrap.test.js.map +1 -0
- package/dist/src/config/config.d.ts +6 -2
- package/dist/src/config/config.js +219 -18
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/profileBootstrap.d.ts +64 -0
- package/dist/src/config/profileBootstrap.js +140 -0
- package/dist/src/config/profileBootstrap.js.map +1 -0
- package/dist/src/gemini.js +68 -23
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +1 -2
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/integration-tests/base-url-behavior.integration.test.js +110 -450
- package/dist/src/integration-tests/base-url-behavior.integration.test.js.map +1 -1
- package/dist/src/integration-tests/model-params-isolation.integration.test.js +101 -539
- package/dist/src/integration-tests/model-params-isolation.integration.test.js.map +1 -1
- package/dist/src/integration-tests/modelParams.integration.test.js +86 -761
- package/dist/src/integration-tests/modelParams.integration.test.js.map +1 -1
- package/dist/src/integration-tests/provider-multi-runtime.integration.test.d.ts +6 -0
- package/dist/src/integration-tests/provider-multi-runtime.integration.test.js +198 -0
- package/dist/src/integration-tests/provider-multi-runtime.integration.test.js.map +1 -0
- package/dist/src/integration-tests/provider-switching.integration.test.js +97 -151
- package/dist/src/integration-tests/provider-switching.integration.test.js.map +1 -1
- package/dist/src/integration-tests/runtime-isolation.test.d.ts +13 -0
- package/dist/src/integration-tests/runtime-isolation.test.js +170 -0
- package/dist/src/integration-tests/runtime-isolation.test.js.map +1 -0
- package/dist/src/integration-tests/test-utils.js +19 -2
- package/dist/src/integration-tests/test-utils.js.map +1 -1
- package/dist/src/integration-tests/test-utils.test.js +9 -8
- package/dist/src/integration-tests/test-utils.test.js.map +1 -1
- package/dist/src/integration-tests/todo-continuation.integration.test.js +5 -2
- package/dist/src/integration-tests/todo-continuation.integration.test.js.map +1 -1
- package/dist/src/integration-tests/tools-governance.integration.test.d.ts +6 -0
- package/dist/src/integration-tests/tools-governance.integration.test.js +98 -0
- package/dist/src/integration-tests/tools-governance.integration.test.js.map +1 -0
- package/dist/src/nonInteractiveCli.js +36 -11
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/providers/logging/git-stats.test.js +11 -1
- package/dist/src/providers/logging/git-stats.test.js.map +1 -1
- package/dist/src/providers/logging/multi-provider-logging.integration.test.js +1 -2
- package/dist/src/providers/logging/multi-provider-logging.integration.test.js.map +1 -1
- package/dist/src/providers/logging/performance.test.js +1 -1
- package/dist/src/providers/logging/performance.test.js.map +1 -1
- package/dist/src/providers/oauth-provider-registration.d.ts +2 -2
- package/dist/src/providers/oauth-provider-registration.js +25 -9
- package/dist/src/providers/oauth-provider-registration.js.map +1 -1
- package/dist/src/providers/provider-gemini-switching.test.js +67 -89
- package/dist/src/providers/provider-gemini-switching.test.js.map +1 -1
- package/dist/src/providers/provider-switching.integration.test.js +42 -98
- package/dist/src/providers/provider-switching.integration.test.js.map +1 -1
- package/dist/src/providers/providerConfigUtils.d.ts +12 -7
- package/dist/src/providers/providerConfigUtils.js +31 -99
- package/dist/src/providers/providerConfigUtils.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.d.ts +17 -1
- package/dist/src/providers/providerManagerInstance.js +157 -175
- package/dist/src/providers/providerManagerInstance.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js +19 -15
- package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js.map +1 -1
- package/dist/src/providers/providerManagerInstance.test.js +2 -5
- package/dist/src/providers/providerManagerInstance.test.js.map +1 -1
- package/dist/src/runtime/__tests__/profileApplication.test.d.ts +5 -0
- package/dist/src/runtime/__tests__/profileApplication.test.js +232 -0
- package/dist/src/runtime/__tests__/profileApplication.test.js.map +1 -0
- package/dist/src/runtime/__tests__/runtimeIsolation.test.d.ts +5 -0
- package/dist/src/runtime/__tests__/runtimeIsolation.test.js +376 -0
- package/dist/src/runtime/__tests__/runtimeIsolation.test.js.map +1 -0
- package/dist/src/runtime/agentRuntimeAdapter.d.ts +249 -0
- package/dist/src/runtime/agentRuntimeAdapter.js +506 -0
- package/dist/src/runtime/agentRuntimeAdapter.js.map +1 -0
- package/dist/src/runtime/agentRuntimeAdapter.spec.d.ts +6 -0
- package/dist/src/runtime/agentRuntimeAdapter.spec.js +866 -0
- package/dist/src/runtime/agentRuntimeAdapter.spec.js.map +1 -0
- package/dist/src/runtime/messages.d.ts +28 -0
- package/dist/src/runtime/messages.js +64 -0
- package/dist/src/runtime/messages.js.map +1 -0
- package/dist/src/runtime/profileApplication.d.ts +33 -0
- package/dist/src/runtime/profileApplication.js +191 -0
- package/dist/src/runtime/profileApplication.js.map +1 -0
- package/dist/src/runtime/providerConfigUtils.test.d.ts +1 -0
- package/dist/src/runtime/providerConfigUtils.test.js +68 -0
- package/dist/src/runtime/providerConfigUtils.test.js.map +1 -0
- package/dist/src/runtime/runtimeContextFactory.d.ts +102 -0
- package/dist/src/runtime/runtimeContextFactory.js +190 -0
- package/dist/src/runtime/runtimeContextFactory.js.map +1 -0
- package/dist/src/runtime/runtimeSettings.d.ts +217 -0
- package/dist/src/runtime/runtimeSettings.js +1094 -0
- package/dist/src/runtime/runtimeSettings.js.map +1 -0
- package/dist/src/runtime/runtimeSettings.test.d.ts +1 -0
- package/dist/src/runtime/runtimeSettings.test.js +320 -0
- package/dist/src/runtime/runtimeSettings.test.js.map +1 -0
- package/dist/src/services/BuiltinCommandLoader.d.ts +13 -4
- package/dist/src/services/BuiltinCommandLoader.js +17 -4
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/McpPromptLoader.js +34 -13
- package/dist/src/services/McpPromptLoader.js.map +1 -1
- package/dist/src/test-utils/mockCommandContext.js +5 -2
- package/dist/src/test-utils/mockCommandContext.js.map +1 -1
- package/dist/src/ui/App.js +29 -49
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.js +59 -38
- package/dist/src/ui/commands/aboutCommand.js.map +1 -1
- package/dist/src/ui/commands/authCommand.js +7 -9
- package/dist/src/ui/commands/authCommand.js.map +1 -1
- package/dist/src/ui/commands/baseurlCommand.js +8 -44
- package/dist/src/ui/commands/baseurlCommand.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +28 -12
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/diagnosticsCommand.d.ts +0 -3
- package/dist/src/ui/commands/diagnosticsCommand.js +45 -191
- package/dist/src/ui/commands/diagnosticsCommand.js.map +1 -1
- package/dist/src/ui/commands/keyCommand.js +9 -58
- package/dist/src/ui/commands/keyCommand.js.map +1 -1
- package/dist/src/ui/commands/keyCommand.test.js +48 -102
- package/dist/src/ui/commands/keyCommand.test.js.map +1 -1
- package/dist/src/ui/commands/keyfileCommand.js +42 -93
- package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
- package/dist/src/ui/commands/logoutCommand.js +2 -2
- package/dist/src/ui/commands/logoutCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +29 -7
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/modelCommand.js +8 -59
- package/dist/src/ui/commands/modelCommand.js.map +1 -1
- package/dist/src/ui/commands/profileCommand.js +151 -267
- package/dist/src/ui/commands/profileCommand.js.map +1 -1
- package/dist/src/ui/commands/profileCommand.test.js +88 -344
- package/dist/src/ui/commands/profileCommand.test.js.map +1 -1
- package/dist/src/ui/commands/providerCommand.js +9 -3
- package/dist/src/ui/commands/providerCommand.js.map +1 -1
- package/dist/src/ui/commands/restoreCommand.js +38 -18
- package/dist/src/ui/commands/restoreCommand.js.map +1 -1
- package/dist/src/ui/commands/schema/argumentResolver.test.d.ts +6 -0
- package/dist/src/ui/commands/schema/argumentResolver.test.js +619 -0
- package/dist/src/ui/commands/schema/argumentResolver.test.js.map +1 -0
- package/dist/src/ui/commands/schema/index.d.ts +15 -0
- package/dist/src/ui/commands/schema/index.js +320 -0
- package/dist/src/ui/commands/schema/index.js.map +1 -0
- package/dist/src/ui/commands/schema/types.d.ts +61 -0
- package/dist/src/ui/commands/schema/types.js +12 -0
- package/dist/src/ui/commands/schema/types.js.map +1 -0
- package/dist/src/ui/commands/setCommand.js +641 -325
- package/dist/src/ui/commands/setCommand.js.map +1 -1
- package/dist/src/ui/commands/setCommand.test.js +92 -388
- package/dist/src/ui/commands/setCommand.test.js.map +1 -1
- package/dist/src/ui/commands/statusCommand.js +2 -2
- package/dist/src/ui/commands/statusCommand.js.map +1 -1
- package/dist/src/ui/commands/subagentCommand.d.ts +16 -0
- package/dist/src/ui/commands/subagentCommand.js +674 -0
- package/dist/src/ui/commands/subagentCommand.js.map +1 -0
- package/dist/src/ui/commands/test/setCommand.mutation.test.d.ts +6 -0
- package/dist/src/ui/commands/test/setCommand.mutation.test.js +132 -0
- package/dist/src/ui/commands/test/setCommand.mutation.test.js.map +1 -0
- package/dist/src/ui/commands/test/setCommand.phase09.test.d.ts +6 -0
- package/dist/src/ui/commands/test/setCommand.phase09.test.js +222 -0
- package/dist/src/ui/commands/test/setCommand.phase09.test.js.map +1 -0
- package/dist/src/ui/commands/test/subagentCommand.schema.test.d.ts +6 -0
- package/dist/src/ui/commands/test/subagentCommand.schema.test.js +125 -0
- package/dist/src/ui/commands/test/subagentCommand.schema.test.js.map +1 -0
- package/dist/src/ui/commands/test/subagentCommand.test.d.ts +1 -0
- package/dist/src/ui/commands/test/subagentCommand.test.js +598 -0
- package/dist/src/ui/commands/test/subagentCommand.test.js.map +1 -0
- package/dist/src/ui/commands/toolformatCommand.js +25 -98
- package/dist/src/ui/commands/toolformatCommand.js.map +1 -1
- package/dist/src/ui/commands/toolformatCommand.test.js +56 -102
- package/dist/src/ui/commands/toolformatCommand.test.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.js +187 -31
- package/dist/src/ui/commands/toolsCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +11 -2
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/components/AuthDialog.js +16 -55
- package/dist/src/ui/components/AuthDialog.js.map +1 -1
- package/dist/src/ui/components/Footer.js +4 -5
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +1 -1
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.js +6 -11
- package/dist/src/ui/components/StatsDisplay.js.map +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.d.ts +13 -1
- package/dist/src/ui/components/SuggestionsDisplay.js +22 -3
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +1 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.js +14 -14
- package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +1 -0
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
- package/dist/src/ui/containers/SessionController.js +61 -117
- package/dist/src/ui/containers/SessionController.js.map +1 -1
- package/dist/src/ui/contexts/RuntimeContext.d.ts +61 -0
- package/dist/src/ui/contexts/RuntimeContext.js +118 -0
- package/dist/src/ui/contexts/RuntimeContext.js.map +1 -0
- package/dist/src/ui/contexts/TodoProvider.d.ts +1 -0
- package/dist/src/ui/contexts/TodoProvider.js +10 -8
- package/dist/src/ui/contexts/TodoProvider.js.map +1 -1
- package/dist/src/ui/contexts/ToolCallProvider.d.ts +1 -0
- package/dist/src/ui/contexts/ToolCallProvider.js +10 -9
- package/dist/src/ui/contexts/ToolCallProvider.js.map +1 -1
- package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.d.ts +6 -0
- package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js +39 -0
- package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.js +11 -3
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +3 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js +4 -1
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js +27 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useAuthCommand.js +11 -3
- package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -0
- package/dist/src/ui/hooks/useCommandCompletion.js +2 -0
- package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +37 -11
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.subagent.spec.d.ts +6 -0
- package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js +232 -0
- package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js.map +1 -0
- package/dist/src/ui/hooks/useLoadProfileDialog.d.ts +1 -1
- package/dist/src/ui/hooks/useLoadProfileDialog.js +18 -57
- package/dist/src/ui/hooks/useLoadProfileDialog.js.map +1 -1
- package/dist/src/ui/hooks/useOpenAIProviderInfo.d.ts +1 -1
- package/dist/src/ui/hooks/useOpenAIProviderInfo.js +12 -7
- package/dist/src/ui/hooks/useOpenAIProviderInfo.js.map +1 -1
- package/dist/src/ui/hooks/useProviderDialog.d.ts +1 -1
- package/dist/src/ui/hooks/useProviderDialog.js +17 -90
- package/dist/src/ui/hooks/useProviderDialog.js.map +1 -1
- package/dist/src/ui/hooks/useProviderModelDialog.d.ts +2 -2
- package/dist/src/ui/hooks/useProviderModelDialog.js +11 -12
- package/dist/src/ui/hooks/useProviderModelDialog.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +3 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +144 -34
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.d.ts +32 -0
- package/dist/src/ui/hooks/useSlashCompletion.js +154 -77
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +39 -14
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +108 -79
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/types.d.ts +1 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/utils/sandbox.js +7 -5
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/validateNonInterActiveAuth.js +4 -2
- package/dist/src/validateNonInterActiveAuth.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +30 -30
- package/dist/src/zed-integration/zedIntegration.js +112 -39
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +5 -3
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,1094 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Vybestack LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { DebugLogger, SettingsService, AuthType, ProfileManager, createProviderRuntimeContext, getActiveProviderRuntimeContext, setActiveProviderRuntimeContext, } from '@vybestack/llxprt-code-core';
|
|
7
|
+
import { createIsolatedRuntimeContext as createIsolatedRuntimeContextInternal, registerIsolatedRuntimeBindings, getCurrentRuntimeScope, enterRuntimeScope, } from './runtimeContextFactory.js';
|
|
8
|
+
// @plan:PLAN-20251020-STATELESSPROVIDER3.P07
|
|
9
|
+
import { applyProfileWithGuards } from './profileApplication.js';
|
|
10
|
+
import { formatMissingRuntimeMessage, formatNormalizationFailureMessage, } from './messages.js';
|
|
11
|
+
import { ensureOAuthProviderRegistered } from '../providers/oauth-provider-registration.js';
|
|
12
|
+
// @plan PLAN-20251027-STATELESS5.P06
|
|
13
|
+
// NOTE: Adapter stub exists but not integrated until Phase 08
|
|
14
|
+
// Verified to compile successfully via: import type { AgentRuntimeAdapter } from './agentRuntimeAdapter.js';
|
|
15
|
+
export { createIsolatedRuntimeContextInternal as createIsolatedRuntimeContext };
|
|
16
|
+
/**
|
|
17
|
+
* @plan:PLAN-20250218-STATELESSPROVIDER.P06
|
|
18
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
|
|
19
|
+
* @requirement:REQ-SP-005
|
|
20
|
+
* @requirement:REQ-SP4-004
|
|
21
|
+
* @requirement:REQ-SP4-005
|
|
22
|
+
* @pseudocode:cli-runtime.md lines 5-15
|
|
23
|
+
*
|
|
24
|
+
* Runtime helper bundle that provides a stable API for CLI commands, hooks,
|
|
25
|
+
* and components to interact with the active provider runtime context without
|
|
26
|
+
* touching singletons directly.
|
|
27
|
+
*
|
|
28
|
+
* P08 stateless hardening ensures all runtime helpers supply explicit
|
|
29
|
+
* stateless provider context (settings/config/userMemory) per invocation,
|
|
30
|
+
* eliminating singleton fallbacks and enforcing runtime isolation.
|
|
31
|
+
*/
|
|
32
|
+
const logger = new DebugLogger('llxprt:runtime:settings');
|
|
33
|
+
const STATELESS_METADATA_KEYS = [
|
|
34
|
+
'statelessHardening',
|
|
35
|
+
'statelessProviderMode',
|
|
36
|
+
'statelessGuards',
|
|
37
|
+
'statelessMode',
|
|
38
|
+
];
|
|
39
|
+
let statelessHardeningPreferenceOverride = null;
|
|
40
|
+
function normalizeStatelessPreference(value) {
|
|
41
|
+
if (typeof value === 'boolean') {
|
|
42
|
+
return value ? 'strict' : 'legacy';
|
|
43
|
+
}
|
|
44
|
+
if (typeof value === 'string') {
|
|
45
|
+
const normalized = value.trim().toLowerCase();
|
|
46
|
+
if (normalized === 'strict' ||
|
|
47
|
+
normalized === 'enabled' ||
|
|
48
|
+
normalized === 'true' ||
|
|
49
|
+
normalized === 'on') {
|
|
50
|
+
return 'strict';
|
|
51
|
+
}
|
|
52
|
+
if (normalized === 'legacy' ||
|
|
53
|
+
normalized === 'disabled' ||
|
|
54
|
+
normalized === 'false' ||
|
|
55
|
+
normalized === 'off') {
|
|
56
|
+
return 'legacy';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function readStatelessPreferenceFromMetadata(metadata) {
|
|
62
|
+
if (!metadata) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
for (const key of STATELESS_METADATA_KEYS) {
|
|
66
|
+
if (Object.prototype.hasOwnProperty.call(metadata, key)) {
|
|
67
|
+
const value = metadata[key];
|
|
68
|
+
const preference = normalizeStatelessPreference(value);
|
|
69
|
+
if (preference) {
|
|
70
|
+
return preference;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P07
|
|
78
|
+
* @requirement:REQ-SP4-005
|
|
79
|
+
*/
|
|
80
|
+
function resolveStatelessHardeningPreference() {
|
|
81
|
+
const scope = getCurrentRuntimeScope();
|
|
82
|
+
const scopePreference = readStatelessPreferenceFromMetadata(scope?.metadata);
|
|
83
|
+
if (scopePreference) {
|
|
84
|
+
return scopePreference;
|
|
85
|
+
}
|
|
86
|
+
const { runtimeId } = resolveActiveRuntimeIdentity();
|
|
87
|
+
const entry = runtimeRegistry.get(runtimeId);
|
|
88
|
+
const entryPreference = readStatelessPreferenceFromMetadata(entry?.metadata);
|
|
89
|
+
if (entryPreference) {
|
|
90
|
+
return entryPreference;
|
|
91
|
+
}
|
|
92
|
+
if (statelessHardeningPreferenceOverride) {
|
|
93
|
+
return statelessHardeningPreferenceOverride;
|
|
94
|
+
}
|
|
95
|
+
return 'strict';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P07
|
|
99
|
+
* @requirement:REQ-SP4-005
|
|
100
|
+
* Configure the global CLI stateless guard preference. Tests and CLI bootstrap
|
|
101
|
+
* can call this to opt into strict guards without environment toggles.
|
|
102
|
+
*/
|
|
103
|
+
export function configureCliStatelessHardening(preference) {
|
|
104
|
+
statelessHardeningPreferenceOverride = preference;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P07
|
|
108
|
+
* @requirement:REQ-SP4-005
|
|
109
|
+
*/
|
|
110
|
+
export function getCliStatelessHardeningOverride() {
|
|
111
|
+
return statelessHardeningPreferenceOverride;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P07
|
|
115
|
+
* @requirement:REQ-SP4-005
|
|
116
|
+
* Reports the currently resolved stateless hardening preference.
|
|
117
|
+
*/
|
|
118
|
+
export function getCliStatelessHardeningPreference() {
|
|
119
|
+
return resolveStatelessHardeningPreference();
|
|
120
|
+
}
|
|
121
|
+
function isStatelessProviderIntegrationEnabled() {
|
|
122
|
+
return resolveStatelessHardeningPreference() === 'strict';
|
|
123
|
+
}
|
|
124
|
+
export function isCliStatelessProviderModeEnabled() {
|
|
125
|
+
return isStatelessProviderIntegrationEnabled();
|
|
126
|
+
}
|
|
127
|
+
const runtimeRegistry = new Map();
|
|
128
|
+
const LEGACY_RUNTIME_ID = 'legacy-singleton';
|
|
129
|
+
function resolveActiveRuntimeIdentity() {
|
|
130
|
+
const scope = getCurrentRuntimeScope();
|
|
131
|
+
if (scope) {
|
|
132
|
+
return scope;
|
|
133
|
+
}
|
|
134
|
+
const context = getActiveProviderRuntimeContext();
|
|
135
|
+
const runtimeId = typeof context.runtimeId === 'string' && context.runtimeId.trim() !== ''
|
|
136
|
+
? context.runtimeId
|
|
137
|
+
: LEGACY_RUNTIME_ID;
|
|
138
|
+
const metadata = context.metadata ?? {};
|
|
139
|
+
return { runtimeId, metadata };
|
|
140
|
+
}
|
|
141
|
+
function upsertRuntimeEntry(runtimeId, update) {
|
|
142
|
+
const current = runtimeRegistry.get(runtimeId);
|
|
143
|
+
const next = {
|
|
144
|
+
runtimeId,
|
|
145
|
+
settingsService: Object.prototype.hasOwnProperty.call(update, 'settingsService')
|
|
146
|
+
? (update.settingsService ?? null)
|
|
147
|
+
: (current?.settingsService ?? null),
|
|
148
|
+
config: Object.prototype.hasOwnProperty.call(update, 'config')
|
|
149
|
+
? (update.config ?? null)
|
|
150
|
+
: (current?.config ?? null),
|
|
151
|
+
providerManager: Object.prototype.hasOwnProperty.call(update, 'providerManager')
|
|
152
|
+
? (update.providerManager ?? null)
|
|
153
|
+
: (current?.providerManager ?? null),
|
|
154
|
+
oauthManager: Object.prototype.hasOwnProperty.call(update, 'oauthManager')
|
|
155
|
+
? (update.oauthManager ?? null)
|
|
156
|
+
: (current?.oauthManager ?? null),
|
|
157
|
+
metadata: update.metadata !== undefined
|
|
158
|
+
? { ...(current?.metadata ?? {}), ...update.metadata }
|
|
159
|
+
: (current?.metadata ?? {}),
|
|
160
|
+
};
|
|
161
|
+
runtimeRegistry.set(runtimeId, next);
|
|
162
|
+
return next;
|
|
163
|
+
}
|
|
164
|
+
function requireRuntimeEntry(runtimeId) {
|
|
165
|
+
const entry = runtimeRegistry.get(runtimeId);
|
|
166
|
+
if (entry) {
|
|
167
|
+
return entry;
|
|
168
|
+
}
|
|
169
|
+
const hint = isStatelessProviderIntegrationEnabled()
|
|
170
|
+
? 'Stateless hardening requires explicit runtime registration.'
|
|
171
|
+
: 'Ensure setCliRuntimeContext() was called before consuming CLI helpers.';
|
|
172
|
+
throw new Error(formatMissingRuntimeMessage({
|
|
173
|
+
runtimeId,
|
|
174
|
+
missingFields: ['runtime registration'],
|
|
175
|
+
hint,
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
function disposeCliRuntime(runtimeId, context) {
|
|
179
|
+
if (context?.revokedTokens?.length) {
|
|
180
|
+
logger.debug(() => `[cli-runtime] Revoked ${context.revokedTokens.length} scoped OAuth token(s) for runtime ${runtimeId}.`);
|
|
181
|
+
}
|
|
182
|
+
runtimeRegistry.delete(runtimeId);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
|
|
186
|
+
* @requirement:REQ-SP4-004
|
|
187
|
+
* @requirement:REQ-SP4-005
|
|
188
|
+
*
|
|
189
|
+
* Acquire the active provider runtime context that CLI bootstrap registered.
|
|
190
|
+
* Throws if the runtime has not yet been initialised.
|
|
191
|
+
*
|
|
192
|
+
* When stateless hardening is enabled, this enforces that all required
|
|
193
|
+
* services (settingsService, config) are present in the runtime registry
|
|
194
|
+
* before allowing provider operations.
|
|
195
|
+
*/
|
|
196
|
+
export function getCliRuntimeContext() {
|
|
197
|
+
const identity = resolveActiveRuntimeIdentity();
|
|
198
|
+
const entry = runtimeRegistry.get(identity.runtimeId);
|
|
199
|
+
if (entry && entry.config) {
|
|
200
|
+
// @plan:PLAN-20251023-STATELESS-HARDENING.P08
|
|
201
|
+
// @requirement:REQ-SP4-004 - Remove singleton fallbacks when stateless hardening is enabled
|
|
202
|
+
const settingsService = entry.settingsService;
|
|
203
|
+
if (isStatelessProviderIntegrationEnabled() && !settingsService) {
|
|
204
|
+
throw new Error(formatMissingRuntimeMessage({
|
|
205
|
+
runtimeId: identity.runtimeId,
|
|
206
|
+
missingFields: ['SettingsService'],
|
|
207
|
+
hint: 'Stateless hardening disables SettingsService fallbacks.',
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
// Fallback path for legacy compatibility (disabled under stateless hardening)
|
|
211
|
+
const resolvedSettings = settingsService ??
|
|
212
|
+
entry.config.getSettingsService() ??
|
|
213
|
+
new SettingsService();
|
|
214
|
+
return createProviderRuntimeContext({
|
|
215
|
+
settingsService: resolvedSettings,
|
|
216
|
+
config: entry.config,
|
|
217
|
+
runtimeId: identity.runtimeId,
|
|
218
|
+
metadata: identity.metadata,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
// @plan:PLAN-20251023-STATELESS-HARDENING.P08
|
|
222
|
+
// Legacy fallback to global context (should not be used under stateless hardening)
|
|
223
|
+
const context = getActiveProviderRuntimeContext();
|
|
224
|
+
if (isStatelessProviderIntegrationEnabled()) {
|
|
225
|
+
throw new Error(formatMissingRuntimeMessage({
|
|
226
|
+
runtimeId: identity.runtimeId,
|
|
227
|
+
missingFields: ['runtime registration'],
|
|
228
|
+
hint: 'Register the runtime via activateIsolatedRuntimeContext() and registerCliProviderInfrastructure() before invoking CLI helpers.',
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
if (!context.config) {
|
|
232
|
+
throw new Error('[cli-runtime] Active provider runtime context is missing Config instance. ' +
|
|
233
|
+
'Ensure gemini bootstrap initialised runtime before invoking helpers.');
|
|
234
|
+
}
|
|
235
|
+
return context;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Obtain the services that CLI surfaces through the runtime context.
|
|
239
|
+
*/
|
|
240
|
+
export function getCliRuntimeServices() {
|
|
241
|
+
const { runtimeId } = resolveActiveRuntimeIdentity();
|
|
242
|
+
const entry = requireRuntimeEntry(runtimeId);
|
|
243
|
+
const context = getCliRuntimeContext();
|
|
244
|
+
const config = entry.config ?? context.config;
|
|
245
|
+
if (!config) {
|
|
246
|
+
throw new Error(formatNormalizationFailureMessage({
|
|
247
|
+
runtimeId,
|
|
248
|
+
missingFields: ['Config'],
|
|
249
|
+
hint: 'registerCliProviderInfrastructure() must supply Config before CLI helpers run.',
|
|
250
|
+
}));
|
|
251
|
+
}
|
|
252
|
+
const settingsService = entry.settingsService ?? context.settingsService;
|
|
253
|
+
if (!settingsService) {
|
|
254
|
+
throw new Error(formatMissingRuntimeMessage({
|
|
255
|
+
runtimeId,
|
|
256
|
+
missingFields: ['SettingsService'],
|
|
257
|
+
hint: 'Call activateIsolatedRuntimeContext() or inject a runtime-specific SettingsService for tests.',
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
const providerManager = entry.providerManager;
|
|
261
|
+
if (!providerManager) {
|
|
262
|
+
throw new Error(formatMissingRuntimeMessage({
|
|
263
|
+
runtimeId,
|
|
264
|
+
missingFields: ['ProviderManager'],
|
|
265
|
+
hint: 'Ensure registerCliProviderInfrastructure() runs inside the runtime activation scope.',
|
|
266
|
+
}));
|
|
267
|
+
}
|
|
268
|
+
return { settingsService, config, providerManager };
|
|
269
|
+
}
|
|
270
|
+
export function getCliProviderManager(options = {}) {
|
|
271
|
+
const services = getCliRuntimeServices();
|
|
272
|
+
const { runtimeId } = resolveActiveRuntimeIdentity();
|
|
273
|
+
const entry = requireRuntimeEntry(runtimeId);
|
|
274
|
+
const oauthManager = entry.oauthManager;
|
|
275
|
+
if (options.addItem && oauthManager) {
|
|
276
|
+
const providersMap = oauthManager.providers;
|
|
277
|
+
if (providersMap instanceof Map) {
|
|
278
|
+
for (const provider of providersMap.values()) {
|
|
279
|
+
const p = provider;
|
|
280
|
+
if (p.name && p.setAddItem) {
|
|
281
|
+
p.setAddItem(options.addItem);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return services.providerManager;
|
|
287
|
+
}
|
|
288
|
+
export function isCliRuntimeStatelessReady() {
|
|
289
|
+
if (!isStatelessProviderIntegrationEnabled()) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
const { runtimeId } = resolveActiveRuntimeIdentity();
|
|
293
|
+
const entry = runtimeRegistry.get(runtimeId);
|
|
294
|
+
if (!entry) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
return Boolean(entry.settingsService && entry.config && entry.providerManager);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
|
|
301
|
+
* @requirement:REQ-SP4-004
|
|
302
|
+
* @requirement:REQ-SP4-005
|
|
303
|
+
*
|
|
304
|
+
* Ensure the active provider runtime context is normalized and pushed into
|
|
305
|
+
* ProviderManager before any provider invocation. This function enforces
|
|
306
|
+
* stateless provider guarantees by requiring explicit runtime-scoped services
|
|
307
|
+
* (settings, config, userMemory) before execution.
|
|
308
|
+
*
|
|
309
|
+
* When stateless hardening is enabled (runtime metadata/global preference),
|
|
310
|
+
* this helper normalizes the current runtime context and registers it with
|
|
311
|
+
* ProviderManager so downstream providers always receive call-scoped
|
|
312
|
+
* configuration without relying on singleton fallbacks.
|
|
313
|
+
*/
|
|
314
|
+
export function ensureStatelessProviderReady() {
|
|
315
|
+
if (!isStatelessProviderIntegrationEnabled()) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const { runtimeId, metadata } = resolveActiveRuntimeIdentity();
|
|
319
|
+
const entry = requireRuntimeEntry(runtimeId);
|
|
320
|
+
const settingsService = entry.settingsService;
|
|
321
|
+
const config = entry.config;
|
|
322
|
+
const providerManager = entry.providerManager;
|
|
323
|
+
const missingFields = [];
|
|
324
|
+
if (!settingsService) {
|
|
325
|
+
missingFields.push('SettingsService');
|
|
326
|
+
}
|
|
327
|
+
if (!config) {
|
|
328
|
+
missingFields.push('Config');
|
|
329
|
+
}
|
|
330
|
+
if (!providerManager) {
|
|
331
|
+
missingFields.push('ProviderManager');
|
|
332
|
+
}
|
|
333
|
+
if (missingFields.length > 0) {
|
|
334
|
+
throw new Error(formatNormalizationFailureMessage({
|
|
335
|
+
runtimeId,
|
|
336
|
+
missingFields,
|
|
337
|
+
hint: 'Call registerCliProviderInfrastructure() inside activateIsolatedRuntimeContext() before invoking providers.',
|
|
338
|
+
}));
|
|
339
|
+
}
|
|
340
|
+
const runtimeContext = createProviderRuntimeContext({
|
|
341
|
+
settingsService: settingsService,
|
|
342
|
+
config: config,
|
|
343
|
+
runtimeId,
|
|
344
|
+
metadata,
|
|
345
|
+
});
|
|
346
|
+
providerManager.prepareStatelessProviderInvocation(runtimeContext);
|
|
347
|
+
logger.debug(() => `[cli-runtime] Stateless provider ready for runtime ${runtimeId} (REQ-SP4-004, REQ-SP4-005)`);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* @plan:PLAN-20251018-STATELESSPROVIDER2.P03
|
|
351
|
+
* @requirement:REQ-SP2-002
|
|
352
|
+
* @pseudocode multi-runtime-baseline.md lines 7-7
|
|
353
|
+
* Delegate helper that activates an isolated runtime while merging metadata overrides per Step 6.
|
|
354
|
+
*/
|
|
355
|
+
export async function activateIsolatedRuntimeContext(handle, options = {}) {
|
|
356
|
+
const runtimeId = options.runtimeId ?? handle.runtimeId;
|
|
357
|
+
const mergedMetadata = {
|
|
358
|
+
...(handle.metadata ?? {}),
|
|
359
|
+
...(options.metadata ?? {}),
|
|
360
|
+
};
|
|
361
|
+
const overrides = {
|
|
362
|
+
...options,
|
|
363
|
+
runtimeId,
|
|
364
|
+
metadata: mergedMetadata,
|
|
365
|
+
};
|
|
366
|
+
enterRuntimeScope({ runtimeId, metadata: mergedMetadata });
|
|
367
|
+
upsertRuntimeEntry(runtimeId, { metadata: mergedMetadata });
|
|
368
|
+
await handle.activate(overrides);
|
|
369
|
+
}
|
|
370
|
+
export function registerCliProviderInfrastructure(manager, oauthManager) {
|
|
371
|
+
const { runtimeId, metadata } = resolveActiveRuntimeIdentity();
|
|
372
|
+
const entry = upsertRuntimeEntry(runtimeId, {
|
|
373
|
+
providerManager: manager,
|
|
374
|
+
oauthManager,
|
|
375
|
+
metadata,
|
|
376
|
+
});
|
|
377
|
+
const context = getActiveProviderRuntimeContext();
|
|
378
|
+
const config = entry.config ?? context.config ?? null;
|
|
379
|
+
if (config) {
|
|
380
|
+
config.setProviderManager(manager);
|
|
381
|
+
manager.setConfig(config);
|
|
382
|
+
upsertRuntimeEntry(runtimeId, { config });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
export function resetCliProviderInfrastructure(runtimeId) {
|
|
386
|
+
let targetRuntimeId = runtimeId;
|
|
387
|
+
if (!targetRuntimeId) {
|
|
388
|
+
try {
|
|
389
|
+
targetRuntimeId = resolveActiveRuntimeIdentity().runtimeId;
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
if (error instanceof Error &&
|
|
393
|
+
(error.name === 'MissingProviderRuntimeError' ||
|
|
394
|
+
/No active provider runtime context/i.test(error.message) ||
|
|
395
|
+
/MissingProviderRuntimeError/.test(error.message))) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
throw error;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!runtimeRegistry.has(targetRuntimeId)) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
upsertRuntimeEntry(targetRuntimeId, {
|
|
405
|
+
providerManager: null,
|
|
406
|
+
oauthManager: null,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
export function getCliOAuthManager() {
|
|
410
|
+
const { runtimeId } = resolveActiveRuntimeIdentity();
|
|
411
|
+
return runtimeRegistry.get(runtimeId)?.oauthManager ?? null;
|
|
412
|
+
}
|
|
413
|
+
const RESERVED_PROVIDER_SETTING_KEYS = new Set([
|
|
414
|
+
'model',
|
|
415
|
+
'enabled',
|
|
416
|
+
'apiKey',
|
|
417
|
+
'api-key',
|
|
418
|
+
'apiKeyfile',
|
|
419
|
+
'api-keyfile',
|
|
420
|
+
'baseUrl',
|
|
421
|
+
'base-url',
|
|
422
|
+
'toolFormat',
|
|
423
|
+
'tool-format',
|
|
424
|
+
'toolFormatOverride',
|
|
425
|
+
'tool-format-override',
|
|
426
|
+
'defaultModel',
|
|
427
|
+
]);
|
|
428
|
+
function resolveActiveProviderName(settingsService, config) {
|
|
429
|
+
if (typeof config.getProvider === 'function') {
|
|
430
|
+
const provider = config.getProvider();
|
|
431
|
+
if (provider && provider.trim() !== '') {
|
|
432
|
+
return provider;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const fromSettings = settingsService.get('activeProvider');
|
|
436
|
+
if (typeof fromSettings === 'string' && fromSettings.trim() !== '') {
|
|
437
|
+
return fromSettings;
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
function getProviderSettingsSnapshot(settingsService, providerName) {
|
|
442
|
+
return settingsService.getProviderSettings(providerName);
|
|
443
|
+
}
|
|
444
|
+
function extractModelParams(providerSettings) {
|
|
445
|
+
const params = {};
|
|
446
|
+
for (const [key, value] of Object.entries(providerSettings)) {
|
|
447
|
+
if (value === undefined ||
|
|
448
|
+
value === null ||
|
|
449
|
+
RESERVED_PROVIDER_SETTING_KEYS.has(key)) {
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
params[key] = value;
|
|
453
|
+
}
|
|
454
|
+
return params;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Accessor for the active CLI Config instance registered with the runtime
|
|
458
|
+
* context. Throws if the bootstrap failed to attach the Config.
|
|
459
|
+
*/
|
|
460
|
+
export function getCliRuntimeConfig() {
|
|
461
|
+
const { config } = getCliRuntimeServices();
|
|
462
|
+
return config;
|
|
463
|
+
}
|
|
464
|
+
function getProviderManagerOrThrow() {
|
|
465
|
+
ensureStatelessProviderReady();
|
|
466
|
+
const { providerManager } = getCliRuntimeServices();
|
|
467
|
+
return providerManager;
|
|
468
|
+
}
|
|
469
|
+
function getActiveProviderOrThrow() {
|
|
470
|
+
const manager = getProviderManagerOrThrow();
|
|
471
|
+
try {
|
|
472
|
+
return manager.getActiveProvider();
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
throw new Error(`[cli-runtime] Failed to resolve active provider: ${error instanceof Error ? error.message : String(error)}`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
export function getActiveModelName() {
|
|
479
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
480
|
+
const providerName = resolveActiveProviderName(settingsService, config);
|
|
481
|
+
if (providerName) {
|
|
482
|
+
const providerSettings = getProviderSettingsSnapshot(settingsService, providerName);
|
|
483
|
+
const storedModel = providerSettings.model;
|
|
484
|
+
if (storedModel && storedModel.trim() !== '') {
|
|
485
|
+
return storedModel;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const configModel = config.getModel();
|
|
489
|
+
if (configModel) {
|
|
490
|
+
return configModel;
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
const provider = providerManager.getActiveProvider();
|
|
494
|
+
return provider.getDefaultModel?.() ?? '';
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
return '';
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
export function getActiveProviderStatus() {
|
|
501
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
502
|
+
const resolvedModel = getActiveModelName();
|
|
503
|
+
const modelName = resolvedModel && resolvedModel.trim() !== '' ? resolvedModel : null;
|
|
504
|
+
const authType = config.getContentGeneratorConfig()?.authType;
|
|
505
|
+
try {
|
|
506
|
+
const provider = providerManager.getActiveProvider();
|
|
507
|
+
const displayLabel = modelName
|
|
508
|
+
? `${provider.name}:${modelName}`
|
|
509
|
+
: provider.name;
|
|
510
|
+
// Try to get baseURL from provider if it has the method
|
|
511
|
+
let baseURL;
|
|
512
|
+
try {
|
|
513
|
+
if ('getBaseURL' in provider &&
|
|
514
|
+
typeof provider
|
|
515
|
+
.getBaseURL === 'function') {
|
|
516
|
+
baseURL = provider.getBaseURL();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
catch {
|
|
520
|
+
baseURL = undefined;
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
providerName: provider.name,
|
|
524
|
+
modelName,
|
|
525
|
+
displayLabel,
|
|
526
|
+
isPaidMode: provider.isPaidMode?.(),
|
|
527
|
+
authType,
|
|
528
|
+
baseURL,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
catch {
|
|
532
|
+
const providerName = resolveActiveProviderName(settingsService, config) ?? null;
|
|
533
|
+
const fallbackLabel = providerName
|
|
534
|
+
? modelName
|
|
535
|
+
? `${providerName}:${modelName}`
|
|
536
|
+
: providerName
|
|
537
|
+
: (modelName ?? 'unknown');
|
|
538
|
+
return {
|
|
539
|
+
providerName,
|
|
540
|
+
modelName,
|
|
541
|
+
displayLabel: fallbackLabel,
|
|
542
|
+
authType,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
export async function listAvailableModels(providerName) {
|
|
547
|
+
const manager = getProviderManagerOrThrow();
|
|
548
|
+
return manager.getAvailableModels(providerName);
|
|
549
|
+
}
|
|
550
|
+
export function getActiveProviderMetrics() {
|
|
551
|
+
const manager = getProviderManagerOrThrow();
|
|
552
|
+
return manager.getProviderMetrics();
|
|
553
|
+
}
|
|
554
|
+
export function getSessionTokenUsage() {
|
|
555
|
+
const manager = getProviderManagerOrThrow();
|
|
556
|
+
return manager.getSessionTokenUsage();
|
|
557
|
+
}
|
|
558
|
+
export function getEphemeralSettings() {
|
|
559
|
+
const { config } = getCliRuntimeServices();
|
|
560
|
+
return config.getEphemeralSettings();
|
|
561
|
+
}
|
|
562
|
+
export function getEphemeralSetting(key) {
|
|
563
|
+
const { config } = getCliRuntimeServices();
|
|
564
|
+
return config.getEphemeralSetting(key);
|
|
565
|
+
}
|
|
566
|
+
export function setEphemeralSetting(key, value) {
|
|
567
|
+
const { config } = getCliRuntimeServices();
|
|
568
|
+
config.setEphemeralSetting(key, value);
|
|
569
|
+
}
|
|
570
|
+
export function clearEphemeralSetting(key) {
|
|
571
|
+
const { config } = getCliRuntimeServices();
|
|
572
|
+
config.setEphemeralSetting(key, undefined);
|
|
573
|
+
}
|
|
574
|
+
export function getActiveModelParams() {
|
|
575
|
+
const { config, settingsService } = getCliRuntimeServices();
|
|
576
|
+
const providerName = resolveActiveProviderName(settingsService, config);
|
|
577
|
+
if (!providerName) {
|
|
578
|
+
return {};
|
|
579
|
+
}
|
|
580
|
+
const providerSettings = getProviderSettingsSnapshot(settingsService, providerName);
|
|
581
|
+
return extractModelParams(providerSettings);
|
|
582
|
+
}
|
|
583
|
+
export function setActiveModelParam(name, value) {
|
|
584
|
+
const { config, settingsService } = getCliRuntimeServices();
|
|
585
|
+
const providerName = resolveActiveProviderName(settingsService, config);
|
|
586
|
+
if (!providerName) {
|
|
587
|
+
throw new Error('No active provider available to set model parameters.');
|
|
588
|
+
}
|
|
589
|
+
settingsService.setProviderSetting(providerName, name, value);
|
|
590
|
+
}
|
|
591
|
+
export function clearActiveModelParam(name) {
|
|
592
|
+
const { config, settingsService } = getCliRuntimeServices();
|
|
593
|
+
const providerName = resolveActiveProviderName(settingsService, config);
|
|
594
|
+
if (!providerName) {
|
|
595
|
+
throw new Error('No active provider available to clear model parameters.');
|
|
596
|
+
}
|
|
597
|
+
settingsService.setProviderSetting(providerName, name, undefined);
|
|
598
|
+
}
|
|
599
|
+
const PROFILE_EPHEMERAL_KEYS = [
|
|
600
|
+
'auth-key',
|
|
601
|
+
'auth-keyfile',
|
|
602
|
+
'context-limit',
|
|
603
|
+
'compression-threshold',
|
|
604
|
+
'base-url',
|
|
605
|
+
'tool-format',
|
|
606
|
+
'api-version',
|
|
607
|
+
'custom-headers',
|
|
608
|
+
'disabled-tools',
|
|
609
|
+
'tool-output-max-items',
|
|
610
|
+
'tool-output-max-tokens',
|
|
611
|
+
'tool-output-truncate-mode',
|
|
612
|
+
'tool-output-item-size-limit',
|
|
613
|
+
'max-prompt-tokens',
|
|
614
|
+
'shell-replacement',
|
|
615
|
+
'todo-continuation',
|
|
616
|
+
'socket-timeout',
|
|
617
|
+
'socket-keepalive',
|
|
618
|
+
'socket-nodelay',
|
|
619
|
+
'streaming',
|
|
620
|
+
'dumponerror',
|
|
621
|
+
'retries',
|
|
622
|
+
'retrywait',
|
|
623
|
+
'maxTurnsPerPrompt',
|
|
624
|
+
];
|
|
625
|
+
export function buildRuntimeProfileSnapshot() {
|
|
626
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
627
|
+
const providerName = resolveActiveProviderName(settingsService, config) ??
|
|
628
|
+
providerManager.getActiveProviderName() ??
|
|
629
|
+
config.getProvider() ??
|
|
630
|
+
'openai';
|
|
631
|
+
const providerSettings = getProviderSettingsSnapshot(settingsService, providerName);
|
|
632
|
+
const currentModel = providerSettings.model ??
|
|
633
|
+
config.getModel() ??
|
|
634
|
+
providerManager.getProviderByName(providerName)?.getDefaultModel?.() ??
|
|
635
|
+
'unknown';
|
|
636
|
+
const ephemeralSettings = config.getEphemeralSettings();
|
|
637
|
+
const snapshot = {};
|
|
638
|
+
for (const key of PROFILE_EPHEMERAL_KEYS) {
|
|
639
|
+
const value = ephemeralSettings[key];
|
|
640
|
+
if (value !== undefined) {
|
|
641
|
+
snapshot[key] = value;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (!('auth-keyfile' in snapshot) || snapshot['auth-keyfile'] === undefined) {
|
|
645
|
+
const authKey = ephemeralSettings['auth-key'] ??
|
|
646
|
+
settingsService.get('auth-key');
|
|
647
|
+
if (authKey) {
|
|
648
|
+
snapshot['auth-key'] = authKey;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (snapshot['base-url'] === undefined) {
|
|
652
|
+
const baseUrl = providerSettings.baseUrl;
|
|
653
|
+
if (baseUrl) {
|
|
654
|
+
snapshot['base-url'] = baseUrl;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
const modelParams = extractModelParams(providerSettings);
|
|
658
|
+
return {
|
|
659
|
+
version: 1,
|
|
660
|
+
provider: providerName,
|
|
661
|
+
model: currentModel,
|
|
662
|
+
modelParams,
|
|
663
|
+
ephemeralSettings: snapshot,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
export async function applyProfileSnapshot(profile, options = {}) {
|
|
667
|
+
const { settingsService } = getCliRuntimeServices();
|
|
668
|
+
const applicationResult = await applyProfileWithGuards(profile, options);
|
|
669
|
+
if (typeof settingsService.setCurrentProfileName === 'function') {
|
|
670
|
+
settingsService.setCurrentProfileName(options.profileName ?? null);
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
settingsService.set('currentProfile', options.profileName ?? null);
|
|
674
|
+
}
|
|
675
|
+
return {
|
|
676
|
+
profileName: options.profileName,
|
|
677
|
+
providerName: applicationResult.providerName,
|
|
678
|
+
modelName: applicationResult.modelName,
|
|
679
|
+
infoMessages: applicationResult.infoMessages,
|
|
680
|
+
warnings: applicationResult.warnings,
|
|
681
|
+
providerChanged: applicationResult.providerChanged,
|
|
682
|
+
authType: applicationResult.authType,
|
|
683
|
+
baseUrl: applicationResult.baseUrl,
|
|
684
|
+
didFallback: applicationResult.didFallback,
|
|
685
|
+
requestedProvider: applicationResult.requestedProvider,
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
export async function saveProfileSnapshot(profileName) {
|
|
689
|
+
const manager = new ProfileManager();
|
|
690
|
+
const snapshot = buildRuntimeProfileSnapshot();
|
|
691
|
+
await manager.saveProfile(profileName, snapshot);
|
|
692
|
+
return snapshot;
|
|
693
|
+
}
|
|
694
|
+
export async function loadProfileByName(profileName) {
|
|
695
|
+
const manager = new ProfileManager();
|
|
696
|
+
const profile = await manager.loadProfile(profileName);
|
|
697
|
+
return applyProfileSnapshot(profile, { profileName });
|
|
698
|
+
}
|
|
699
|
+
export async function deleteProfileByName(profileName) {
|
|
700
|
+
const manager = new ProfileManager();
|
|
701
|
+
await manager.deleteProfile(profileName);
|
|
702
|
+
const { settingsService } = getCliRuntimeServices();
|
|
703
|
+
const currentProfile = typeof settingsService.getCurrentProfileName === 'function'
|
|
704
|
+
? settingsService.getCurrentProfileName()
|
|
705
|
+
: settingsService.get('currentProfile');
|
|
706
|
+
if (currentProfile === profileName) {
|
|
707
|
+
if (typeof settingsService.setCurrentProfileName === 'function') {
|
|
708
|
+
settingsService.setCurrentProfileName(null);
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
settingsService.set('currentProfile', null);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
export async function listSavedProfiles() {
|
|
716
|
+
const manager = new ProfileManager();
|
|
717
|
+
return manager.listProfiles();
|
|
718
|
+
}
|
|
719
|
+
export function getActiveProfileName() {
|
|
720
|
+
const { settingsService } = getCliRuntimeServices();
|
|
721
|
+
if (typeof settingsService.getCurrentProfileName === 'function') {
|
|
722
|
+
return settingsService.getCurrentProfileName();
|
|
723
|
+
}
|
|
724
|
+
return settingsService.get('currentProfile') ?? null;
|
|
725
|
+
}
|
|
726
|
+
export function setDefaultProfileName(profileName) {
|
|
727
|
+
const { settingsService } = getCliRuntimeServices();
|
|
728
|
+
settingsService.set('defaultProfile', profileName ?? undefined);
|
|
729
|
+
}
|
|
730
|
+
export function getRuntimeDiagnosticsSnapshot() {
|
|
731
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
732
|
+
const providerName = resolveActiveProviderName(settingsService, config) ??
|
|
733
|
+
providerManager.getActiveProviderName() ??
|
|
734
|
+
null;
|
|
735
|
+
const modelValue = getActiveModelName();
|
|
736
|
+
const modelName = modelValue && modelValue.trim() !== ''
|
|
737
|
+
? modelValue
|
|
738
|
+
: (config.getModel() ?? null);
|
|
739
|
+
const profileName = getActiveProfileName();
|
|
740
|
+
const modelParams = getActiveModelParams();
|
|
741
|
+
const ephemeralSettings = config.getEphemeralSettings();
|
|
742
|
+
return {
|
|
743
|
+
providerName,
|
|
744
|
+
modelName,
|
|
745
|
+
profileName,
|
|
746
|
+
modelParams,
|
|
747
|
+
ephemeralSettings,
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
export function listProviders() {
|
|
751
|
+
return getCliRuntimeServices().providerManager.listProviders();
|
|
752
|
+
}
|
|
753
|
+
export function getActiveProviderName() {
|
|
754
|
+
const { providerManager } = getCliRuntimeServices();
|
|
755
|
+
return providerManager.getActiveProviderName();
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Register or update the active CLI runtime context.
|
|
759
|
+
*/
|
|
760
|
+
export function setCliRuntimeContext(settingsService, config, options = {}) {
|
|
761
|
+
const runtimeId = options.runtimeId ?? `cli-runtime-${process.pid.toString(16)}`;
|
|
762
|
+
const metadata = { source: 'cli-runtime', ...(options.metadata ?? {}) };
|
|
763
|
+
const nextContext = createProviderRuntimeContext({
|
|
764
|
+
settingsService,
|
|
765
|
+
config,
|
|
766
|
+
runtimeId,
|
|
767
|
+
metadata,
|
|
768
|
+
});
|
|
769
|
+
logger.debug(() => {
|
|
770
|
+
const providerLabel = config && typeof config.getProvider === 'function'
|
|
771
|
+
? ` (provider=${config.getProvider() ?? 'unset'})`
|
|
772
|
+
: '';
|
|
773
|
+
return `[cli-runtime] Registering runtime context ${runtimeId}${providerLabel}`;
|
|
774
|
+
});
|
|
775
|
+
setActiveProviderRuntimeContext(nextContext);
|
|
776
|
+
upsertRuntimeEntry(runtimeId, {
|
|
777
|
+
settingsService,
|
|
778
|
+
config: config ?? null,
|
|
779
|
+
metadata,
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
registerIsolatedRuntimeBindings({
|
|
783
|
+
resetInfrastructure: resetCliProviderInfrastructure,
|
|
784
|
+
setRuntimeContext: setCliRuntimeContext,
|
|
785
|
+
registerInfrastructure: registerCliProviderInfrastructure,
|
|
786
|
+
linkProviderManager: (config, manager) => {
|
|
787
|
+
config.setProviderManager(manager);
|
|
788
|
+
},
|
|
789
|
+
disposeRuntime: disposeCliRuntime,
|
|
790
|
+
}); // Step 5 (multi-runtime-baseline.md line 6) wires CLI activation hooks for isolated runtimes.
|
|
791
|
+
const PROVIDER_SWITCH_EPHEMERAL_KEYS = [
|
|
792
|
+
'auth-key',
|
|
793
|
+
'auth-keyfile',
|
|
794
|
+
'base-url',
|
|
795
|
+
'context-limit',
|
|
796
|
+
'compression-threshold',
|
|
797
|
+
'tool-format',
|
|
798
|
+
'api-version',
|
|
799
|
+
'custom-headers',
|
|
800
|
+
'model',
|
|
801
|
+
'stream-options',
|
|
802
|
+
];
|
|
803
|
+
/**
|
|
804
|
+
* Switch the active provider using the runtime context, updating Config and
|
|
805
|
+
* SettingsService consistently.
|
|
806
|
+
*
|
|
807
|
+
* @plan:PLAN-20250218-STATELESSPROVIDER.P06
|
|
808
|
+
* @requirement:REQ-SP-005
|
|
809
|
+
* @pseudocode:cli-runtime.md lines 9-10
|
|
810
|
+
*/
|
|
811
|
+
export async function switchActiveProvider(providerName, options = {}) {
|
|
812
|
+
const autoOAuth = options.autoOAuth ?? false;
|
|
813
|
+
const name = providerName.trim();
|
|
814
|
+
if (!name) {
|
|
815
|
+
throw new Error('Provider name is required.');
|
|
816
|
+
}
|
|
817
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
818
|
+
const currentProvider = providerManager.getActiveProviderName() || null;
|
|
819
|
+
if (currentProvider === name) {
|
|
820
|
+
return {
|
|
821
|
+
changed: false,
|
|
822
|
+
previousProvider: currentProvider,
|
|
823
|
+
nextProvider: name,
|
|
824
|
+
authType: config.getContentGeneratorConfig()?.authType ?? AuthType.USE_PROVIDER,
|
|
825
|
+
infoMessages: [],
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
logger.debug(() => `[cli-runtime] Switching provider from ${currentProvider ?? 'none'} to ${name}`);
|
|
829
|
+
for (const key of PROVIDER_SWITCH_EPHEMERAL_KEYS) {
|
|
830
|
+
config.setEphemeralSetting(key, undefined);
|
|
831
|
+
}
|
|
832
|
+
await providerManager.setActiveProvider(name);
|
|
833
|
+
config.setProviderManager(providerManager);
|
|
834
|
+
config.setProvider(name);
|
|
835
|
+
logger.debug(() => `[cli-runtime] set config provider=${name}`);
|
|
836
|
+
config.setEphemeralSetting('activeProvider', name);
|
|
837
|
+
logger.debug(() => `[cli-runtime] config ephemeral activeProvider=${config.getEphemeralSetting('activeProvider')}`);
|
|
838
|
+
const activeProvider = providerManager.getActiveProvider();
|
|
839
|
+
const providerSettings = getProviderSettingsSnapshot(settingsService, name);
|
|
840
|
+
// Clear any cached model parameters for the new provider
|
|
841
|
+
const existingParams = extractModelParams(providerSettings);
|
|
842
|
+
for (const key of Object.keys(existingParams)) {
|
|
843
|
+
settingsService.setProviderSetting(name, key, undefined);
|
|
844
|
+
}
|
|
845
|
+
let resolvedDefaultModel = providerSettings.model ??
|
|
846
|
+
activeProvider.getDefaultModel?.() ??
|
|
847
|
+
'';
|
|
848
|
+
if (resolvedDefaultModel) {
|
|
849
|
+
settingsService.setProviderSetting(name, 'model', resolvedDefaultModel);
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
resolvedDefaultModel = '';
|
|
853
|
+
settingsService.setProviderSetting(name, 'model', undefined);
|
|
854
|
+
}
|
|
855
|
+
await settingsService.switchProvider(name);
|
|
856
|
+
logger.debug(() => `[cli-runtime] settingsService activeProvider now=${settingsService.get('activeProvider')}`);
|
|
857
|
+
config.setModel(resolvedDefaultModel);
|
|
858
|
+
const unwrapProvider = (provider) => {
|
|
859
|
+
const visited = new Set();
|
|
860
|
+
let current = provider;
|
|
861
|
+
while (current &&
|
|
862
|
+
typeof current === 'object' &&
|
|
863
|
+
'wrappedProvider' in current &&
|
|
864
|
+
current.wrappedProvider) {
|
|
865
|
+
if (visited.has(current)) {
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
visited.add(current);
|
|
869
|
+
current = current.wrappedProvider;
|
|
870
|
+
}
|
|
871
|
+
return current;
|
|
872
|
+
};
|
|
873
|
+
const baseProvider = unwrapProvider(activeProvider);
|
|
874
|
+
let providerBaseUrl;
|
|
875
|
+
if (name === 'qwen') {
|
|
876
|
+
providerBaseUrl = 'https://portal.qwen.ai/v1';
|
|
877
|
+
}
|
|
878
|
+
if (providerBaseUrl) {
|
|
879
|
+
config.setEphemeralSetting('base-url', providerBaseUrl);
|
|
880
|
+
settingsService.setProviderSetting(name, 'baseUrl', providerBaseUrl);
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
settingsService.setProviderSetting(name, 'baseUrl', undefined);
|
|
884
|
+
}
|
|
885
|
+
let authType;
|
|
886
|
+
if (name === 'gemini') {
|
|
887
|
+
const currentAuthType = config.getContentGeneratorConfig()?.authType;
|
|
888
|
+
if (currentAuthType === AuthType.USE_PROVIDER ||
|
|
889
|
+
currentAuthType === undefined) {
|
|
890
|
+
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
891
|
+
authType = AuthType.USE_VERTEX_AI;
|
|
892
|
+
}
|
|
893
|
+
else if (process.env.GEMINI_API_KEY) {
|
|
894
|
+
authType = AuthType.USE_GEMINI;
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
authType = AuthType.LOGIN_WITH_GOOGLE;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
authType = currentAuthType;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
else {
|
|
905
|
+
authType = AuthType.USE_PROVIDER;
|
|
906
|
+
}
|
|
907
|
+
await config.refreshAuth(authType);
|
|
908
|
+
const infoMessages = [];
|
|
909
|
+
if (name === 'anthropic') {
|
|
910
|
+
const oauthManager = getCliOAuthManager();
|
|
911
|
+
if (oauthManager) {
|
|
912
|
+
ensureOAuthProviderRegistered('anthropic', oauthManager);
|
|
913
|
+
if (autoOAuth) {
|
|
914
|
+
try {
|
|
915
|
+
const hasNonOAuth = typeof baseProvider.hasNonOAuthAuthentication === 'function'
|
|
916
|
+
? await baseProvider.hasNonOAuthAuthentication()
|
|
917
|
+
: true;
|
|
918
|
+
if (!hasNonOAuth) {
|
|
919
|
+
logger.debug(() => `[cli-runtime] Anthropic OAuth check: hasNonOAuth=${hasNonOAuth} manager=${Boolean(oauthManager)}`);
|
|
920
|
+
if (!oauthManager.isOAuthEnabled('anthropic')) {
|
|
921
|
+
await oauthManager.toggleOAuthEnabled('anthropic');
|
|
922
|
+
}
|
|
923
|
+
logger.debug(() => '[cli-runtime] Initiating Anthropic OAuth flow');
|
|
924
|
+
await oauthManager.authenticate('anthropic');
|
|
925
|
+
await config.refreshAuth(authType);
|
|
926
|
+
infoMessages.push('Anthropic OAuth authentication completed. Use /auth anthropic to view status.');
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
catch (error) {
|
|
930
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
931
|
+
infoMessages.push(`Anthropic OAuth authentication failed: ${message}`);
|
|
932
|
+
logger.warn(() => `[cli-runtime] Anthropic OAuth authentication failed: ${message}`);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
if (name !== 'gemini') {
|
|
938
|
+
infoMessages.push('Use /key to set API key if needed.');
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
changed: true,
|
|
942
|
+
previousProvider: currentProvider,
|
|
943
|
+
nextProvider: name,
|
|
944
|
+
defaultModel: resolvedDefaultModel || undefined,
|
|
945
|
+
authType,
|
|
946
|
+
infoMessages,
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
export async function updateActiveProviderApiKey(apiKey) {
|
|
950
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
951
|
+
const provider = providerManager.getActiveProvider();
|
|
952
|
+
const providerName = provider.name;
|
|
953
|
+
const trimmed = apiKey?.trim();
|
|
954
|
+
logger.debug(() => {
|
|
955
|
+
const masked = trimmed ? `***redacted*** (len=${trimmed.length})` : 'null';
|
|
956
|
+
return `[runtime] updateActiveProviderApiKey provider='${providerName}' value=${masked}`;
|
|
957
|
+
});
|
|
958
|
+
let authType;
|
|
959
|
+
if (!trimmed) {
|
|
960
|
+
settingsService.setProviderSetting(providerName, 'apiKey', undefined);
|
|
961
|
+
config.setEphemeralSetting('auth-key', undefined);
|
|
962
|
+
config.setEphemeralSetting('auth-keyfile', undefined);
|
|
963
|
+
if (providerName === 'gemini') {
|
|
964
|
+
authType = AuthType.LOGIN_WITH_GOOGLE;
|
|
965
|
+
await config.refreshAuth(authType);
|
|
966
|
+
}
|
|
967
|
+
const isPaidMode = provider.isPaidMode?.();
|
|
968
|
+
logger.debug(() => `[runtime] api key removed for '${providerName}', paidMode=${String(isPaidMode)}`);
|
|
969
|
+
return {
|
|
970
|
+
changed: true,
|
|
971
|
+
providerName,
|
|
972
|
+
message: `API key removed for provider '${providerName}'` +
|
|
973
|
+
(providerName === 'gemini' && isPaidMode === false
|
|
974
|
+
? '\n✅ You are now using OAuth (no paid usage).'
|
|
975
|
+
: ''),
|
|
976
|
+
isPaidMode,
|
|
977
|
+
authType,
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
settingsService.setProviderSetting(providerName, 'apiKey', trimmed);
|
|
981
|
+
config.setEphemeralSetting('auth-key', trimmed);
|
|
982
|
+
config.setEphemeralSetting('auth-keyfile', undefined);
|
|
983
|
+
if (providerName === 'gemini') {
|
|
984
|
+
authType = AuthType.USE_GEMINI;
|
|
985
|
+
await config.refreshAuth(authType);
|
|
986
|
+
}
|
|
987
|
+
const isPaidMode = provider.isPaidMode?.();
|
|
988
|
+
logger.debug(() => `[runtime] api key updated for '${providerName}', paidMode=${String(isPaidMode)}`);
|
|
989
|
+
return {
|
|
990
|
+
changed: true,
|
|
991
|
+
providerName,
|
|
992
|
+
message: `API key updated for provider '${providerName}'` +
|
|
993
|
+
(providerName === 'gemini' && isPaidMode !== false
|
|
994
|
+
? '\nWARNING: Gemini now runs in paid mode.'
|
|
995
|
+
: ''),
|
|
996
|
+
isPaidMode,
|
|
997
|
+
authType,
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
export async function updateActiveProviderBaseUrl(baseUrl) {
|
|
1001
|
+
const { config, settingsService } = getCliRuntimeServices();
|
|
1002
|
+
const provider = getActiveProviderOrThrow();
|
|
1003
|
+
const providerName = provider.name;
|
|
1004
|
+
const trimmed = baseUrl?.trim();
|
|
1005
|
+
if (!trimmed || trimmed === '' || trimmed === 'none') {
|
|
1006
|
+
settingsService.setProviderSetting(providerName, 'baseUrl', undefined);
|
|
1007
|
+
config.setEphemeralSetting('base-url', trimmed ?? undefined);
|
|
1008
|
+
return {
|
|
1009
|
+
changed: true,
|
|
1010
|
+
providerName,
|
|
1011
|
+
message: `Base URL cleared; provider '${providerName}' now uses the default endpoint.`,
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
settingsService.setProviderSetting(providerName, 'baseUrl', trimmed);
|
|
1015
|
+
config.setEphemeralSetting('base-url', trimmed);
|
|
1016
|
+
return {
|
|
1017
|
+
changed: true,
|
|
1018
|
+
providerName,
|
|
1019
|
+
message: `Base URL updated to '${trimmed}' for provider '${providerName}'.`,
|
|
1020
|
+
baseUrl: trimmed,
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
export async function getActiveToolFormatState() {
|
|
1024
|
+
const { settingsService } = getCliRuntimeServices();
|
|
1025
|
+
const provider = getActiveProviderOrThrow();
|
|
1026
|
+
const providerSettings = getProviderSettingsSnapshot(settingsService, provider.name);
|
|
1027
|
+
const override = providerSettings.toolFormat ?? 'auto';
|
|
1028
|
+
const isAutoDetected = !override || override === 'auto';
|
|
1029
|
+
return {
|
|
1030
|
+
providerName: provider.name,
|
|
1031
|
+
currentFormat: isAutoDetected ? null : override,
|
|
1032
|
+
override: isAutoDetected ? null : override,
|
|
1033
|
+
isAutoDetected,
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
export async function setActiveToolFormatOverride(formatName) {
|
|
1037
|
+
const { settingsService } = getCliRuntimeServices();
|
|
1038
|
+
const provider = getActiveProviderOrThrow();
|
|
1039
|
+
if (!formatName || formatName === 'auto') {
|
|
1040
|
+
await settingsService.updateSettings(provider.name, { toolFormat: 'auto' });
|
|
1041
|
+
return getActiveToolFormatState();
|
|
1042
|
+
}
|
|
1043
|
+
await settingsService.updateSettings(provider.name, {
|
|
1044
|
+
toolFormat: formatName,
|
|
1045
|
+
});
|
|
1046
|
+
return getActiveToolFormatState();
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Update the active model for the current provider while keeping Config and
|
|
1050
|
+
* SettingsService in sync.
|
|
1051
|
+
*
|
|
1052
|
+
* @plan:PLAN-20250218-STATELESSPROVIDER.P06
|
|
1053
|
+
* @requirement:REQ-SP-005
|
|
1054
|
+
* @pseudocode:cli-runtime.md line 10
|
|
1055
|
+
*/
|
|
1056
|
+
export async function setActiveModel(modelName) {
|
|
1057
|
+
const { config, settingsService, providerManager } = getCliRuntimeServices();
|
|
1058
|
+
const activeProvider = providerManager.getActiveProvider();
|
|
1059
|
+
if (!activeProvider) {
|
|
1060
|
+
throw new Error('No active provider is available.');
|
|
1061
|
+
}
|
|
1062
|
+
const providerSettings = getProviderSettingsSnapshot(settingsService, activeProvider.name);
|
|
1063
|
+
const previousModel = providerSettings.model || config.getModel();
|
|
1064
|
+
let authRefreshed = false;
|
|
1065
|
+
try {
|
|
1066
|
+
settingsService.set('activeProvider', activeProvider.name);
|
|
1067
|
+
await settingsService.updateSettings(activeProvider.name, {
|
|
1068
|
+
model: modelName,
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
catch (error) {
|
|
1072
|
+
logger.warn(() => `[cli-runtime] Failed to persist model change via SettingsService: ${error}`);
|
|
1073
|
+
}
|
|
1074
|
+
config.setModel(modelName);
|
|
1075
|
+
if (activeProvider.name === 'anthropic') {
|
|
1076
|
+
const providerWithAuth = activeProvider;
|
|
1077
|
+
if (typeof providerWithAuth.isAuthenticated === 'function') {
|
|
1078
|
+
const hasAuth = await providerWithAuth.isAuthenticated();
|
|
1079
|
+
if (!hasAuth) {
|
|
1080
|
+
const currentAuthType = config.getContentGeneratorConfig()?.authType ||
|
|
1081
|
+
AuthType.LOGIN_WITH_GOOGLE;
|
|
1082
|
+
await config.refreshAuth(currentAuthType);
|
|
1083
|
+
authRefreshed = true;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return {
|
|
1088
|
+
providerName: activeProvider.name,
|
|
1089
|
+
previousModel,
|
|
1090
|
+
nextModel: modelName,
|
|
1091
|
+
authRefreshed,
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
//# sourceMappingURL=runtimeSettings.js.map
|