@vybestack/llxprt-code-core 0.4.8 → 0.5.0-nightly.251102.f115237d
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/prompt-config/defaults/default-prompts.json +4 -17
- package/dist/src/auth/precedence.d.ts +69 -9
- package/dist/src/auth/precedence.js +467 -69
- package/dist/src/auth/precedence.js.map +1 -1
- package/dist/src/auth/types.d.ts +2 -2
- package/dist/src/config/config.d.ts +15 -1
- package/dist/src/config/config.js +118 -6
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/index.d.ts +6 -0
- package/dist/src/config/index.js +5 -0
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/profileManager.d.ts +23 -3
- package/dist/src/config/profileManager.js +54 -7
- package/dist/src/config/profileManager.js.map +1 -1
- package/dist/src/config/subagentManager.d.ts +96 -0
- package/dist/src/config/subagentManager.js +371 -0
- package/dist/src/config/subagentManager.js.map +1 -0
- package/dist/src/config/types.d.ts +18 -0
- package/dist/src/config/types.js +3 -0
- package/dist/src/config/types.js.map +1 -0
- package/dist/src/core/client.d.ts +27 -7
- package/dist/src/core/client.js +217 -55
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +3 -1
- package/dist/src/core/contentGenerator.js +3 -0
- package/dist/src/core/contentGenerator.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +1 -5
- package/dist/src/core/coreToolScheduler.js +95 -23
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +42 -12
- package/dist/src/core/geminiChat.js +405 -205
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.d.ts +3 -2
- package/dist/src/core/nonInteractiveToolExecutor.js +94 -10
- package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
- package/dist/src/core/subagent.d.ts +86 -7
- package/dist/src/core/subagent.js +809 -79
- package/dist/src/core/subagent.js.map +1 -1
- package/dist/src/core/subagentOrchestrator.d.ts +73 -0
- package/dist/src/core/subagentOrchestrator.js +383 -0
- package/dist/src/core/subagentOrchestrator.js.map +1 -0
- package/dist/src/core/subagentScheduler.d.ts +16 -0
- package/dist/src/core/subagentScheduler.js +7 -0
- package/dist/src/core/subagentScheduler.js.map +1 -0
- package/dist/src/core/turn.d.ts +5 -1
- package/dist/src/core/turn.js +5 -1
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/hooks/tool-render-suppression-hook.js +6 -1
- package/dist/src/hooks/tool-render-suppression-hook.js.map +1 -1
- package/dist/src/ide/ideContext.d.ts +32 -32
- package/dist/src/index.d.ts +19 -1
- package/dist/src/index.js +15 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/index.d.ts +1 -0
- package/dist/src/interfaces/index.js +4 -0
- package/dist/src/interfaces/index.js.map +1 -0
- package/dist/src/interfaces/nodejs-error.interface.d.ts +4 -0
- package/dist/src/interfaces/nodejs-error.interface.js +2 -0
- package/dist/src/interfaces/nodejs-error.interface.js.map +1 -0
- package/dist/src/parsers/TextToolCallParser.js +41 -1
- package/dist/src/parsers/TextToolCallParser.js.map +1 -1
- package/dist/src/prompt-config/defaults/core.md +15 -0
- package/dist/src/prompt-config/defaults/providers/gemini/core.md +203 -119
- package/dist/src/prompt-config/defaults/tool-defaults.js +2 -0
- package/dist/src/prompt-config/defaults/tool-defaults.js.map +1 -1
- package/dist/src/prompt-config/defaults/tools/list-subagents.md +7 -0
- package/dist/src/prompt-config/defaults/tools/task.md +8 -0
- package/dist/src/providers/BaseProvider.d.ts +115 -30
- package/dist/src/providers/BaseProvider.js +445 -109
- package/dist/src/providers/BaseProvider.js.map +1 -1
- package/dist/src/providers/IProvider.d.ts +50 -18
- package/dist/src/providers/LoggingProviderWrapper.d.ts +60 -16
- package/dist/src/providers/LoggingProviderWrapper.js +213 -60
- package/dist/src/providers/LoggingProviderWrapper.js.map +1 -1
- package/dist/src/providers/ProviderManager.d.ts +73 -2
- package/dist/src/providers/ProviderManager.js +492 -40
- package/dist/src/providers/ProviderManager.js.map +1 -1
- package/dist/src/providers/anthropic/AnthropicProvider.d.ts +35 -38
- package/dist/src/providers/anthropic/AnthropicProvider.js +222 -227
- package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
- package/dist/src/providers/errors.d.ts +86 -0
- package/dist/src/providers/errors.js +89 -0
- package/dist/src/providers/errors.js.map +1 -1
- package/dist/src/providers/gemini/GeminiProvider.d.ts +101 -41
- package/dist/src/providers/gemini/GeminiProvider.js +386 -311
- package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
- package/dist/src/providers/openai/ConversationCache.d.ts +5 -3
- package/dist/src/providers/openai/ConversationCache.js +93 -32
- package/dist/src/providers/openai/ConversationCache.js.map +1 -1
- package/dist/src/providers/openai/OpenAIProvider.d.ts +82 -42
- package/dist/src/providers/openai/OpenAIProvider.js +373 -532
- package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
- package/dist/src/providers/openai/getOpenAIProviderInfo.d.ts +1 -1
- package/dist/src/providers/openai/getOpenAIProviderInfo.js +52 -22
- package/dist/src/providers/openai/getOpenAIProviderInfo.js.map +1 -1
- package/dist/src/providers/openai/openaiRequestParams.d.ts +7 -0
- package/dist/src/providers/openai/openaiRequestParams.js +66 -0
- package/dist/src/providers/openai/openaiRequestParams.js.map +1 -0
- package/dist/src/providers/openai-responses/OpenAIResponsesProvider.d.ts +6 -33
- package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js +84 -183
- package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js.map +1 -1
- package/dist/src/providers/types/providerRuntime.d.ts +17 -0
- package/dist/src/providers/types/providerRuntime.js +7 -0
- package/dist/src/providers/types/providerRuntime.js.map +1 -0
- package/dist/src/providers/utils/authToken.d.ts +12 -0
- package/dist/src/providers/utils/authToken.js +17 -0
- package/dist/src/providers/utils/authToken.js.map +1 -0
- package/dist/src/providers/utils/userMemory.d.ts +8 -0
- package/dist/src/providers/utils/userMemory.js +34 -0
- package/dist/src/providers/utils/userMemory.js.map +1 -0
- package/dist/src/runtime/AgentRuntimeContext.d.ts +213 -0
- package/dist/src/runtime/AgentRuntimeContext.js +17 -0
- package/dist/src/runtime/AgentRuntimeContext.js.map +1 -0
- package/dist/src/runtime/AgentRuntimeLoader.d.ts +47 -0
- package/dist/src/runtime/AgentRuntimeLoader.js +122 -0
- package/dist/src/runtime/AgentRuntimeLoader.js.map +1 -0
- package/dist/src/runtime/AgentRuntimeState.d.ts +232 -0
- package/dist/src/runtime/AgentRuntimeState.js +439 -0
- package/dist/src/runtime/AgentRuntimeState.js.map +1 -0
- package/dist/src/runtime/RuntimeInvocationContext.d.ts +51 -0
- package/dist/src/runtime/RuntimeInvocationContext.js +52 -0
- package/dist/src/runtime/RuntimeInvocationContext.js.map +1 -0
- package/dist/src/runtime/createAgentRuntimeContext.d.ts +7 -0
- package/dist/src/runtime/createAgentRuntimeContext.js +58 -0
- package/dist/src/runtime/createAgentRuntimeContext.js.map +1 -0
- package/dist/src/runtime/index.d.ts +13 -0
- package/dist/src/runtime/index.js +14 -0
- package/dist/src/runtime/index.js.map +1 -0
- package/dist/src/runtime/providerRuntimeContext.d.ts +30 -0
- package/dist/src/runtime/providerRuntimeContext.js +70 -0
- package/dist/src/runtime/providerRuntimeContext.js.map +1 -0
- package/dist/src/runtime/runtimeAdapters.d.ts +22 -0
- package/dist/src/runtime/runtimeAdapters.js +81 -0
- package/dist/src/runtime/runtimeAdapters.js.map +1 -0
- package/dist/src/runtime/runtimeStateFactory.d.ts +21 -0
- package/dist/src/runtime/runtimeStateFactory.js +104 -0
- package/dist/src/runtime/runtimeStateFactory.js.map +1 -0
- package/dist/src/services/todo-context-tracker.d.ts +10 -8
- package/dist/src/services/todo-context-tracker.js +26 -10
- package/dist/src/services/todo-context-tracker.js.map +1 -1
- package/dist/src/services/tool-call-tracker-service.d.ts +11 -7
- package/dist/src/services/tool-call-tracker-service.js +89 -29
- package/dist/src/services/tool-call-tracker-service.js.map +1 -1
- package/dist/src/settings/SettingsService.d.ts +4 -0
- package/dist/src/settings/SettingsService.js +58 -2
- package/dist/src/settings/SettingsService.js.map +1 -1
- package/dist/src/settings/settingsServiceInstance.d.ts +6 -1
- package/dist/src/settings/settingsServiceInstance.js +28 -8
- package/dist/src/settings/settingsServiceInstance.js.map +1 -1
- package/dist/src/telemetry/loggers.d.ts +5 -1
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.circular.js +4 -0
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +3 -1
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +1 -0
- package/dist/src/telemetry/types.js +3 -0
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/test-utils/index.d.ts +2 -0
- package/dist/src/test-utils/index.js +2 -0
- package/dist/src/test-utils/index.js.map +1 -1
- package/dist/src/test-utils/mockWorkspaceContext.d.ts +0 -3
- package/dist/src/test-utils/mockWorkspaceContext.js +3 -4
- package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -1
- package/dist/src/test-utils/providerCallOptions.d.ts +43 -0
- package/dist/src/test-utils/providerCallOptions.js +137 -0
- package/dist/src/test-utils/providerCallOptions.js.map +1 -0
- package/dist/src/test-utils/runtime.d.ts +92 -0
- package/dist/src/test-utils/runtime.js +226 -0
- package/dist/src/test-utils/runtime.js.map +1 -0
- package/dist/src/test-utils/tools.d.ts +4 -4
- package/dist/src/test-utils/tools.js +20 -10
- package/dist/src/test-utils/tools.js.map +1 -1
- package/dist/src/tools/list-subagents.d.ts +31 -0
- package/dist/src/tools/list-subagents.js +109 -0
- package/dist/src/tools/list-subagents.js.map +1 -0
- package/dist/src/tools/task.d.ts +87 -0
- package/dist/src/tools/task.js +427 -0
- package/dist/src/tools/task.js.map +1 -0
- package/dist/src/tools/todo-read.js +1 -1
- package/dist/src/tools/todo-read.js.map +1 -1
- package/dist/src/tools/todo-store.js +4 -2
- package/dist/src/tools/todo-store.js.map +1 -1
- package/dist/src/tools/todo-write.js +4 -2
- package/dist/src/tools/todo-write.js.map +1 -1
- package/dist/src/tools/tool-error.d.ts +1 -0
- package/dist/src/tools/tool-error.js +1 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +2 -0
- package/dist/src/tools/tool-registry.js +46 -21
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/types/modelParams.d.ts +4 -0
- package/dist/src/utils/gitIgnoreParser.js +15 -3
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/prompt-config/defaults/providers/anthropic/core.md +0 -97
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/glob.md +0 -34
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/list-directory.md +0 -11
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-file.md +0 -14
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-many-files.md +0 -31
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/replace.md +0 -41
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/run-shell-command.md +0 -32
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/save-memory.md +0 -35
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/search-file-content.md +0 -44
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/todo-write.md +0 -45
- package/dist/src/prompt-config/defaults/providers/anthropic/tools/write-file.md +0 -11
- package/dist/src/prompt-config/defaults/providers/openai/core.md +0 -97
- package/dist/src/prompt-config/defaults/providers/openai/tools/todo-pause.md +0 -28
- package/dist/src/prompt-config/defaults/providers/openai/tools/todo-read.md +0 -5
- package/dist/src/prompt-config/defaults/providers/openai/tools/todo-write.md +0 -45
|
@@ -7,11 +7,42 @@
|
|
|
7
7
|
import { LoggingProviderWrapper } from './LoggingProviderWrapper.js';
|
|
8
8
|
import { logProviderSwitch, logProviderCapability, } from '../telemetry/loggers.js';
|
|
9
9
|
import { ProviderSwitchEvent, ProviderCapabilityEvent, } from '../telemetry/types.js';
|
|
10
|
-
import {
|
|
10
|
+
import { getActiveProviderRuntimeContext, } from '../runtime/providerRuntimeContext.js';
|
|
11
|
+
import { MissingProviderRuntimeError, ProviderRuntimeNormalizationError, } from './errors.js';
|
|
12
|
+
import { createRuntimeInvocationContext } from '../runtime/RuntimeInvocationContext.js';
|
|
13
|
+
const PROVIDER_CAPABILITY_HINTS = {
|
|
14
|
+
gemini: {
|
|
15
|
+
hasModelSelection: true,
|
|
16
|
+
hasApiKeyConfig: true,
|
|
17
|
+
hasBaseUrlConfig: false,
|
|
18
|
+
},
|
|
19
|
+
openai: {
|
|
20
|
+
hasModelSelection: true,
|
|
21
|
+
hasApiKeyConfig: true,
|
|
22
|
+
hasBaseUrlConfig: true,
|
|
23
|
+
},
|
|
24
|
+
'openai-responses': {
|
|
25
|
+
hasModelSelection: false,
|
|
26
|
+
hasApiKeyConfig: true,
|
|
27
|
+
hasBaseUrlConfig: true,
|
|
28
|
+
},
|
|
29
|
+
anthropic: {
|
|
30
|
+
hasModelSelection: true,
|
|
31
|
+
hasApiKeyConfig: true,
|
|
32
|
+
hasBaseUrlConfig: true,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
11
35
|
export class ProviderManager {
|
|
12
36
|
providers;
|
|
13
37
|
serverToolsProvider;
|
|
14
38
|
config;
|
|
39
|
+
/**
|
|
40
|
+
* @plan PLAN-20250218-STATELESSPROVIDER.P05
|
|
41
|
+
* @requirement REQ-SP-001
|
|
42
|
+
* @pseudocode provider-invocation.md lines 8-15
|
|
43
|
+
*/
|
|
44
|
+
settingsService;
|
|
45
|
+
runtime;
|
|
15
46
|
providerCapabilities = new Map();
|
|
16
47
|
sessionTokenUsage = {
|
|
17
48
|
input: 0,
|
|
@@ -21,19 +52,86 @@ export class ProviderManager {
|
|
|
21
52
|
thought: 0,
|
|
22
53
|
total: 0,
|
|
23
54
|
};
|
|
24
|
-
constructor() {
|
|
55
|
+
constructor(init) {
|
|
56
|
+
const resolved = this.resolveInit(init);
|
|
25
57
|
this.providers = new Map();
|
|
26
58
|
this.serverToolsProvider = null;
|
|
59
|
+
this.settingsService = resolved.settingsService;
|
|
60
|
+
this.config = resolved.config ?? this.config;
|
|
61
|
+
this.runtime = resolved.runtime;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* @plan PLAN-20250218-STATELESSPROVIDER.P05
|
|
65
|
+
* @requirement REQ-SP-001
|
|
66
|
+
* @pseudocode provider-invocation.md lines 8-15
|
|
67
|
+
* @plan:PLAN-20251018-STATELESSPROVIDER2.P03
|
|
68
|
+
* @requirement:REQ-SP2-002
|
|
69
|
+
* @pseudocode multi-runtime-baseline.md lines 3-4
|
|
70
|
+
*/
|
|
71
|
+
resolveInit(init) {
|
|
72
|
+
let fallback = null;
|
|
73
|
+
const ensureFallback = () => {
|
|
74
|
+
if (!fallback) {
|
|
75
|
+
fallback = getActiveProviderRuntimeContext();
|
|
76
|
+
}
|
|
77
|
+
return fallback;
|
|
78
|
+
};
|
|
79
|
+
if (!init) {
|
|
80
|
+
const resolved = ensureFallback();
|
|
81
|
+
return {
|
|
82
|
+
settingsService: resolved.settingsService,
|
|
83
|
+
config: resolved.config,
|
|
84
|
+
runtime: resolved,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (typeof init === 'object' &&
|
|
88
|
+
init !== null &&
|
|
89
|
+
'settingsService' in init &&
|
|
90
|
+
('runtimeId' in init || 'metadata' in init)) {
|
|
91
|
+
const context = init;
|
|
92
|
+
return {
|
|
93
|
+
settingsService: context.settingsService,
|
|
94
|
+
config: context.config,
|
|
95
|
+
runtime: context,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const initObj = init;
|
|
99
|
+
const runtime = initObj.runtime;
|
|
100
|
+
let settingsService = initObj.settingsService ?? runtime?.settingsService ?? null;
|
|
101
|
+
let config = initObj.config ?? runtime?.config ?? undefined;
|
|
102
|
+
if (!settingsService || !config) {
|
|
103
|
+
const resolved = ensureFallback();
|
|
104
|
+
settingsService = settingsService ?? resolved.settingsService;
|
|
105
|
+
config = config ?? resolved.config;
|
|
106
|
+
return {
|
|
107
|
+
settingsService,
|
|
108
|
+
config,
|
|
109
|
+
runtime: runtime ?? resolved,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
settingsService,
|
|
114
|
+
config,
|
|
115
|
+
runtime,
|
|
116
|
+
};
|
|
27
117
|
}
|
|
28
118
|
setConfig(config) {
|
|
29
119
|
const oldLoggingEnabled = this.config?.getConversationLoggingEnabled() ?? false;
|
|
30
120
|
const newLoggingEnabled = config.getConversationLoggingEnabled();
|
|
31
121
|
this.config = config;
|
|
122
|
+
this.runtime = this.runtime
|
|
123
|
+
? { ...this.runtime, config }
|
|
124
|
+
: { settingsService: this.settingsService, config };
|
|
32
125
|
// If logging state changed, update provider wrapping
|
|
33
126
|
if (oldLoggingEnabled !== newLoggingEnabled) {
|
|
34
127
|
this.updateProviderWrapping();
|
|
35
128
|
}
|
|
36
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* @plan PLAN-20251018-STATELESSPROVIDER2.P06
|
|
132
|
+
* @requirement REQ-SP2-001
|
|
133
|
+
* @pseudocode base-provider-call-contract.md lines 3-5
|
|
134
|
+
*/
|
|
37
135
|
updateProviderWrapping() {
|
|
38
136
|
// Re-wrap all providers (ALWAYS wrap for token tracking)
|
|
39
137
|
const providers = new Map(this.providers);
|
|
@@ -43,13 +141,13 @@ export class ProviderManager {
|
|
|
43
141
|
if ('wrappedProvider' in provider && provider.wrappedProvider) {
|
|
44
142
|
baseProvider = provider.wrappedProvider;
|
|
45
143
|
}
|
|
144
|
+
this.syncProviderRuntime(baseProvider);
|
|
46
145
|
// ALWAYS wrap with LoggingProviderWrapper for token tracking
|
|
47
146
|
let finalProvider = baseProvider;
|
|
48
147
|
if (this.config) {
|
|
49
|
-
baseProvider.setConfig?.(this.config);
|
|
50
148
|
finalProvider = new LoggingProviderWrapper(baseProvider, this.config);
|
|
51
|
-
finalProvider.setConfig?.(this.config);
|
|
52
149
|
}
|
|
150
|
+
this.syncProviderRuntime(finalProvider);
|
|
53
151
|
this.providers.set(name, finalProvider);
|
|
54
152
|
// Update server tools provider reference if needed
|
|
55
153
|
if (this.serverToolsProvider && this.serverToolsProvider.name === name) {
|
|
@@ -57,17 +155,261 @@ export class ProviderManager {
|
|
|
57
155
|
}
|
|
58
156
|
}
|
|
59
157
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
158
|
+
/**
|
|
159
|
+
* @plan PLAN-20250218-STATELESSPROVIDER.P05
|
|
160
|
+
* @requirement REQ-SP-001
|
|
161
|
+
* @pseudocode provider-invocation.md lines 8-15
|
|
162
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P05
|
|
163
|
+
* @requirement:REQ-SP4-001
|
|
164
|
+
* @pseudocode provider-runtime-handling.md lines 10-15
|
|
165
|
+
*/
|
|
166
|
+
syncProviderRuntime(provider) {
|
|
167
|
+
const runtimeAware = provider;
|
|
168
|
+
runtimeAware.setRuntimeSettingsService?.(this.settingsService);
|
|
169
|
+
if (this.config && runtimeAware.setConfig) {
|
|
170
|
+
runtimeAware.setConfig(this.config);
|
|
171
|
+
}
|
|
172
|
+
if (runtimeAware.setRuntimeContextResolver &&
|
|
173
|
+
typeof runtimeAware.setRuntimeContextResolver === 'function') {
|
|
174
|
+
runtimeAware.setRuntimeContextResolver(() => this.snapshotRuntimeContext('ProviderManager.syncProviderRuntime'));
|
|
175
|
+
}
|
|
176
|
+
if (runtimeAware.setOptionsNormalizer &&
|
|
177
|
+
typeof runtimeAware.setOptionsNormalizer === 'function') {
|
|
178
|
+
runtimeAware.setOptionsNormalizer((options, providerName) => this.normalizeRuntimeInputs(options, providerName));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P05
|
|
183
|
+
* @requirement:REQ-SP4-001
|
|
184
|
+
* @pseudocode provider-runtime-handling.md lines 10-15
|
|
185
|
+
*/
|
|
186
|
+
snapshotRuntimeContext(source) {
|
|
187
|
+
const baseRuntime = this.runtime ?? {
|
|
188
|
+
settingsService: this.settingsService,
|
|
189
|
+
config: this.config,
|
|
190
|
+
runtimeId: 'provider-manager.default-runtime',
|
|
191
|
+
metadata: { source: 'ProviderManager', requirement: 'REQ-SP4-001' },
|
|
192
|
+
};
|
|
193
|
+
if (!this.runtime) {
|
|
194
|
+
this.runtime = baseRuntime;
|
|
195
|
+
}
|
|
196
|
+
else if (!this.runtime.config && baseRuntime.config) {
|
|
197
|
+
this.runtime = { ...this.runtime, config: baseRuntime.config };
|
|
198
|
+
}
|
|
199
|
+
const settingsService = baseRuntime.settingsService;
|
|
200
|
+
if (!settingsService) {
|
|
201
|
+
throw new MissingProviderRuntimeError({
|
|
202
|
+
providerKey: 'ProviderManager',
|
|
203
|
+
missingFields: ['settings'],
|
|
204
|
+
stage: source,
|
|
205
|
+
metadata: {
|
|
206
|
+
requirement: 'REQ-SP4-001',
|
|
207
|
+
hint: 'ProviderManager requires a SettingsService to construct runtime contexts.',
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const config = baseRuntime.config ?? this.config;
|
|
212
|
+
if (!config) {
|
|
213
|
+
throw new MissingProviderRuntimeError({
|
|
214
|
+
providerKey: 'ProviderManager',
|
|
215
|
+
missingFields: ['config'],
|
|
216
|
+
stage: source,
|
|
217
|
+
metadata: {
|
|
218
|
+
requirement: 'REQ-SP4-001',
|
|
219
|
+
hint: 'Call ProviderManager.setConfig before invoking providers.',
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
const baseMetadata = baseRuntime.metadata ?? {};
|
|
224
|
+
const callMetadata = {
|
|
225
|
+
...baseMetadata,
|
|
226
|
+
source,
|
|
227
|
+
requirement: 'REQ-SP4-001',
|
|
228
|
+
generatedAt: new Date().toISOString(),
|
|
229
|
+
};
|
|
230
|
+
const baseId = baseRuntime.runtimeId;
|
|
231
|
+
const callRuntimeId = typeof baseId === 'string' && baseId.trim() !== ''
|
|
232
|
+
? `${baseId}:${Math.random().toString(36).slice(2, 10)}`
|
|
233
|
+
: `provider-manager:${source}:${Date.now().toString(36)}`;
|
|
234
|
+
return {
|
|
235
|
+
settingsService,
|
|
236
|
+
config,
|
|
237
|
+
runtimeId: callRuntimeId,
|
|
238
|
+
metadata: callMetadata,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* @plan:PLAN-20251023-STATELESS-HARDENING.P08
|
|
243
|
+
* @requirement:REQ-SP4-002
|
|
244
|
+
* @requirement:REQ-SP4-003
|
|
245
|
+
* @requirement:REQ-SP4-004
|
|
246
|
+
* @requirement:REQ-SP4-005
|
|
247
|
+
* @pseudocode provider-runtime-handling.md lines 10-16
|
|
248
|
+
*
|
|
249
|
+
* Normalize runtime inputs per call - no stored settings/config fallbacks.
|
|
250
|
+
* This method enforces that all runtime context is provided per-call and that
|
|
251
|
+
* providers cannot rely on stored state.
|
|
252
|
+
*/
|
|
253
|
+
normalizeRuntimeInputs(rawOptions, providerName) {
|
|
254
|
+
const runtimeId = rawOptions.runtime?.runtimeId || 'unknown';
|
|
255
|
+
const targetProvider = providerName || this.getActiveProviderName();
|
|
256
|
+
// REQ-SP4-002: Check for required settings service and config in runtime context
|
|
257
|
+
const settingsService = rawOptions.settings ?? rawOptions.runtime?.settingsService;
|
|
258
|
+
const config = rawOptions.config ?? rawOptions.runtime?.config;
|
|
259
|
+
if (!settingsService) {
|
|
260
|
+
throw new ProviderRuntimeNormalizationError({
|
|
261
|
+
providerKey: 'ProviderManager',
|
|
262
|
+
message: 'ProviderManager requires call-scoped settings; legacy provider state is disabled.',
|
|
263
|
+
requirement: 'REQ-SP4-002',
|
|
264
|
+
runtimeId,
|
|
265
|
+
stage: 'normalizeRuntimeInputs',
|
|
266
|
+
metadata: {
|
|
267
|
+
hint: 'SettingsService must be provided in options.settings or runtime.settingsService',
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (!config) {
|
|
272
|
+
throw new ProviderRuntimeNormalizationError({
|
|
273
|
+
providerKey: 'ProviderManager',
|
|
274
|
+
message: 'ProviderManager requires call-scoped config; legacy provider state is disabled.',
|
|
275
|
+
requirement: 'REQ-SP4-002',
|
|
276
|
+
runtimeId,
|
|
277
|
+
stage: 'normalizeRuntimeInputs',
|
|
278
|
+
metadata: {
|
|
279
|
+
hint: 'Config must be provided in options.config or runtime.config',
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
// REQ-SP4-003: Compose normalized.resolved with runtime helpers
|
|
284
|
+
const providerSettings = settingsService.getProviderSettings(targetProvider);
|
|
285
|
+
const providerInstance = this.providers.get(targetProvider);
|
|
286
|
+
const resolved = {
|
|
287
|
+
model: rawOptions.resolved?.model ??
|
|
288
|
+
config.getModel?.() ??
|
|
289
|
+
providerSettings.model ??
|
|
290
|
+
(providerInstance
|
|
291
|
+
? this.getStoredModelName(providerInstance)
|
|
292
|
+
: undefined),
|
|
293
|
+
baseURL: rawOptions.resolved?.baseURL ??
|
|
294
|
+
providerSettings.baseURL,
|
|
295
|
+
authToken: rawOptions.resolved?.authToken ??
|
|
296
|
+
providerSettings.apiKey,
|
|
297
|
+
telemetry: {
|
|
298
|
+
...rawOptions.resolved?.telemetry,
|
|
299
|
+
runtimeId,
|
|
300
|
+
normalizedAt: new Date().toISOString(),
|
|
301
|
+
provider: targetProvider,
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
// REQ-SP4-003: Validate required fields in resolved options
|
|
305
|
+
const missingFields = [];
|
|
306
|
+
if (!resolved.model)
|
|
307
|
+
missingFields.push('model');
|
|
308
|
+
// Note: Gemini and some providers don't require baseURL/authToken in all configurations
|
|
309
|
+
const baseUrlOptionalProviders = new Set([
|
|
310
|
+
'gemini',
|
|
311
|
+
'openai',
|
|
312
|
+
'openai-responses',
|
|
313
|
+
'anthropic',
|
|
314
|
+
]);
|
|
315
|
+
if (!resolved.baseURL && !baseUrlOptionalProviders.has(targetProvider)) {
|
|
316
|
+
missingFields.push('baseURL');
|
|
317
|
+
}
|
|
318
|
+
if (!resolved.authToken && targetProvider !== 'gemini') {
|
|
319
|
+
// Check if provider can resolve auth lazily (e.g., via OAuth)
|
|
320
|
+
// If the provider has getAuthToken(), it can handle its own auth precedence
|
|
321
|
+
const providerInstance = this.providers.get(targetProvider);
|
|
322
|
+
let actualProvider = providerInstance;
|
|
323
|
+
if (providerInstance && 'wrappedProvider' in providerInstance) {
|
|
324
|
+
actualProvider = providerInstance
|
|
325
|
+
.wrappedProvider;
|
|
326
|
+
}
|
|
327
|
+
const canResolveAuth = actualProvider &&
|
|
328
|
+
'getAuthToken' in actualProvider &&
|
|
329
|
+
typeof actualProvider.getAuthToken === 'function';
|
|
330
|
+
if (!canResolveAuth) {
|
|
331
|
+
// Only fail for providers without lazy auth resolution capability
|
|
332
|
+
missingFields.push('authToken');
|
|
333
|
+
}
|
|
334
|
+
// Otherwise let the provider run its multi-modal precedence chain:
|
|
335
|
+
// 1. Manual key (from /key)
|
|
336
|
+
// 2. Keyfile (from /keyfile)
|
|
337
|
+
// 3. Environment variables
|
|
338
|
+
// 4. OAuth token (if enabled)
|
|
339
|
+
}
|
|
340
|
+
if (missingFields.length > 0) {
|
|
341
|
+
throw new ProviderRuntimeNormalizationError({
|
|
342
|
+
providerKey: 'ProviderManager',
|
|
343
|
+
message: `Incomplete runtime resolution (${missingFields.join(', ')}) for runtimeId=${runtimeId}`,
|
|
344
|
+
requirement: 'REQ-SP4-003',
|
|
345
|
+
runtimeId,
|
|
346
|
+
stage: 'normalizeRuntimeInputs',
|
|
347
|
+
metadata: { missingFields, provider: targetProvider },
|
|
348
|
+
});
|
|
63
349
|
}
|
|
350
|
+
// REQ-SP4-005: Ensure normalized.userMemory and metadata derive from runtime context
|
|
351
|
+
const userMemory = rawOptions.userMemory ?? config.getUserMemory?.();
|
|
352
|
+
const metadata = {
|
|
353
|
+
...rawOptions.metadata,
|
|
354
|
+
...rawOptions.runtime?.metadata,
|
|
355
|
+
_normalized: true,
|
|
356
|
+
_normalizationTime: new Date().toISOString(),
|
|
357
|
+
_runtimeId: runtimeId,
|
|
358
|
+
_provider: targetProvider,
|
|
359
|
+
};
|
|
360
|
+
const normalizedRuntime = {
|
|
361
|
+
...(rawOptions.runtime ?? {}),
|
|
362
|
+
settingsService,
|
|
363
|
+
config,
|
|
364
|
+
runtimeId,
|
|
365
|
+
metadata,
|
|
366
|
+
};
|
|
367
|
+
const userMemorySnapshot = typeof userMemory === 'string' ? userMemory : config.getUserMemory?.();
|
|
368
|
+
const invocation = rawOptions.invocation ??
|
|
369
|
+
createRuntimeInvocationContext({
|
|
370
|
+
runtime: normalizedRuntime,
|
|
371
|
+
settings: settingsService,
|
|
372
|
+
providerName: targetProvider,
|
|
373
|
+
ephemeralsSnapshot: this.buildEphemeralsSnapshot(settingsService, targetProvider),
|
|
374
|
+
telemetry: resolved.telemetry,
|
|
375
|
+
metadata,
|
|
376
|
+
userMemory: userMemorySnapshot ?? undefined,
|
|
377
|
+
fallbackRuntimeId: runtimeId,
|
|
378
|
+
});
|
|
379
|
+
return {
|
|
380
|
+
...rawOptions,
|
|
381
|
+
settings: settingsService,
|
|
382
|
+
config,
|
|
383
|
+
runtime: normalizedRuntime,
|
|
384
|
+
resolved,
|
|
385
|
+
userMemory,
|
|
386
|
+
metadata,
|
|
387
|
+
invocation,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
buildEphemeralsSnapshot(settingsService, providerName) {
|
|
391
|
+
const globalEphemerals = settingsService.getAllGlobalSettings();
|
|
392
|
+
const providerEphemerals = settingsService.getProviderSettings(providerName);
|
|
393
|
+
const snapshot = {
|
|
394
|
+
...globalEphemerals,
|
|
395
|
+
};
|
|
396
|
+
snapshot[providerName] = { ...providerEphemerals };
|
|
397
|
+
return snapshot;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* @plan PLAN-20251018-STATELESSPROVIDER2.P06
|
|
401
|
+
* @requirement REQ-SP2-001
|
|
402
|
+
* @pseudocode base-provider-call-contract.md lines 3-5
|
|
403
|
+
*/
|
|
404
|
+
registerProvider(provider) {
|
|
405
|
+
this.syncProviderRuntime(provider);
|
|
64
406
|
// ALWAYS wrap provider to enable token tracking
|
|
65
407
|
// (LoggingProviderWrapper handles both token tracking AND conversation logging)
|
|
66
408
|
let finalProvider = provider;
|
|
67
409
|
if (this.config) {
|
|
68
410
|
finalProvider = new LoggingProviderWrapper(provider, this.config);
|
|
69
|
-
finalProvider.setConfig?.(this.config);
|
|
70
411
|
}
|
|
412
|
+
this.syncProviderRuntime(finalProvider);
|
|
71
413
|
this.providers.set(provider.name, finalProvider);
|
|
72
414
|
// Capture provider capabilities
|
|
73
415
|
const capabilities = this.captureProviderCapabilities(provider);
|
|
@@ -78,10 +420,9 @@ export class ProviderManager {
|
|
|
78
420
|
logProviderCapability(this.config, new ProviderCapabilityEvent(provider.name, capabilities, context));
|
|
79
421
|
}
|
|
80
422
|
// If this is the default provider and no provider is active, set it as active
|
|
81
|
-
const
|
|
82
|
-
const currentActiveProvider = settingsService.get('activeProvider');
|
|
423
|
+
const currentActiveProvider = this.settingsService.get('activeProvider');
|
|
83
424
|
if (provider.isDefault && !currentActiveProvider) {
|
|
84
|
-
settingsService.set('activeProvider', provider.name);
|
|
425
|
+
this.settingsService.set('activeProvider', provider.name);
|
|
85
426
|
}
|
|
86
427
|
// If registering Gemini and we don't have a serverToolsProvider, use it
|
|
87
428
|
if (provider.name === 'gemini' && !this.serverToolsProvider) {
|
|
@@ -92,22 +433,26 @@ export class ProviderManager {
|
|
|
92
433
|
this.serverToolsProvider = provider;
|
|
93
434
|
}
|
|
94
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* @plan PLAN-20251018-STATELESSPROVIDER2.P06
|
|
438
|
+
* @requirement REQ-SP2-001
|
|
439
|
+
* @pseudocode base-provider-call-contract.md lines 3-5
|
|
440
|
+
*/
|
|
95
441
|
setActiveProvider(name) {
|
|
96
442
|
if (!this.providers.has(name)) {
|
|
97
443
|
throw new Error('Provider not found');
|
|
98
444
|
}
|
|
99
445
|
// Store reference to the current active provider before switching
|
|
100
|
-
const
|
|
101
|
-
const previousProviderName = settingsService.get('activeProvider') || '';
|
|
446
|
+
const previousProviderName = this.settingsService.get('activeProvider') || '';
|
|
102
447
|
// Only clear state from the provider we're switching FROM
|
|
103
448
|
// BUT never clear the serverToolsProvider's state
|
|
104
449
|
if (previousProviderName && previousProviderName !== name) {
|
|
105
450
|
const previousProvider = this.providers.get(previousProviderName);
|
|
106
|
-
if (previousProvider &&
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
451
|
+
if (previousProvider &&
|
|
452
|
+
previousProvider !== this.serverToolsProvider &&
|
|
453
|
+
'clearState' in previousProvider) {
|
|
454
|
+
const candidate = previousProvider;
|
|
455
|
+
candidate.clearState?.();
|
|
111
456
|
}
|
|
112
457
|
}
|
|
113
458
|
// Log provider switch if conversation logging enabled
|
|
@@ -117,7 +462,7 @@ export class ProviderManager {
|
|
|
117
462
|
logProviderSwitch(this.config, new ProviderSwitchEvent(previousProviderName, name, this.generateConversationId(), this.isContextPreserved(previousProviderName, name)));
|
|
118
463
|
}
|
|
119
464
|
// Update SettingsService as the single source of truth
|
|
120
|
-
settingsService.set('activeProvider', name);
|
|
465
|
+
this.settingsService.set('activeProvider', name);
|
|
121
466
|
// If switching to Gemini, use it as both active and serverTools provider
|
|
122
467
|
// BUT only if we don't already have a Gemini serverToolsProvider with auth state
|
|
123
468
|
if (name === 'gemini') {
|
|
@@ -134,16 +479,36 @@ export class ProviderManager {
|
|
|
134
479
|
}
|
|
135
480
|
}
|
|
136
481
|
clearActiveProvider() {
|
|
137
|
-
|
|
138
|
-
settingsService.set('activeProvider', '');
|
|
482
|
+
this.settingsService.set('activeProvider', '');
|
|
139
483
|
}
|
|
140
484
|
getActiveProvider() {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
if (!
|
|
485
|
+
const activeProviderName = this.settingsService.get('activeProvider') || '';
|
|
486
|
+
let resolvedName = activeProviderName;
|
|
487
|
+
if (!resolvedName) {
|
|
488
|
+
const preferredFromConfig = this.config?.getProvider?.();
|
|
489
|
+
if (preferredFromConfig && this.providers.has(preferredFromConfig)) {
|
|
490
|
+
resolvedName = preferredFromConfig;
|
|
491
|
+
}
|
|
492
|
+
else if (this.providers.has('openai')) {
|
|
493
|
+
resolvedName = 'openai';
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
const firstProvider = this.providers.keys().next();
|
|
497
|
+
resolvedName = firstProvider.done ? '' : firstProvider.value;
|
|
498
|
+
}
|
|
499
|
+
if (resolvedName) {
|
|
500
|
+
try {
|
|
501
|
+
this.setActiveProvider(resolvedName);
|
|
502
|
+
}
|
|
503
|
+
catch (error) {
|
|
504
|
+
throw new Error(`Unable to set default provider '${resolvedName}': ${String(error)}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (!resolvedName) {
|
|
144
509
|
throw new Error('No active provider set');
|
|
145
510
|
}
|
|
146
|
-
const provider = this.providers.get(
|
|
511
|
+
const provider = this.providers.get(resolvedName);
|
|
147
512
|
if (!provider) {
|
|
148
513
|
throw new Error('Active provider not found');
|
|
149
514
|
}
|
|
@@ -178,12 +543,10 @@ export class ProviderManager {
|
|
|
178
543
|
return this.providers.get(name);
|
|
179
544
|
}
|
|
180
545
|
getActiveProviderName() {
|
|
181
|
-
|
|
182
|
-
return settingsService.get('activeProvider') || '';
|
|
546
|
+
return this.settingsService.get('activeProvider') || '';
|
|
183
547
|
}
|
|
184
548
|
hasActiveProvider() {
|
|
185
|
-
const
|
|
186
|
-
const activeProviderName = settingsService.get('activeProvider') || '';
|
|
549
|
+
const activeProviderName = this.settingsService.get('activeProvider') || '';
|
|
187
550
|
return activeProviderName !== '' && this.providers.has(activeProviderName);
|
|
188
551
|
}
|
|
189
552
|
getServerToolsProvider() {
|
|
@@ -218,39 +581,55 @@ export class ProviderManager {
|
|
|
218
581
|
// Context is considered preserved if compatibility is high
|
|
219
582
|
return capabilityScore > 0.7;
|
|
220
583
|
}
|
|
584
|
+
getStoredModelName(provider) {
|
|
585
|
+
const providerSettings = this.settingsService.getProviderSettings(provider.name);
|
|
586
|
+
const storedModel = providerSettings.model;
|
|
587
|
+
if (storedModel && typeof storedModel === 'string' && storedModel.trim()) {
|
|
588
|
+
return storedModel;
|
|
589
|
+
}
|
|
590
|
+
if (this.config &&
|
|
591
|
+
typeof this.config.getProvider === 'function' &&
|
|
592
|
+
this.config.getProvider() === provider.name) {
|
|
593
|
+
const configModel = this.config.getModel();
|
|
594
|
+
if (configModel) {
|
|
595
|
+
return configModel;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return provider.getDefaultModel?.() ?? '';
|
|
599
|
+
}
|
|
221
600
|
captureProviderCapabilities(provider) {
|
|
601
|
+
const hints = PROVIDER_CAPABILITY_HINTS[provider.name] ?? {};
|
|
222
602
|
return {
|
|
223
603
|
supportsStreaming: true, // All current providers support streaming
|
|
224
604
|
supportsTools: provider.getServerTools().length > 0,
|
|
225
605
|
supportsVision: this.detectVisionSupport(provider),
|
|
226
606
|
maxTokens: this.getProviderMaxTokens(provider),
|
|
227
607
|
supportedFormats: this.getSupportedToolFormats(provider),
|
|
228
|
-
hasModelSelection:
|
|
229
|
-
hasApiKeyConfig:
|
|
230
|
-
hasBaseUrlConfig:
|
|
608
|
+
hasModelSelection: hints.hasModelSelection ?? true,
|
|
609
|
+
hasApiKeyConfig: hints.hasApiKeyConfig ?? true,
|
|
610
|
+
hasBaseUrlConfig: hints.hasBaseUrlConfig ?? true,
|
|
231
611
|
supportsPaidMode: typeof provider.isPaidMode === 'function',
|
|
232
612
|
};
|
|
233
613
|
}
|
|
234
614
|
detectVisionSupport(provider) {
|
|
235
615
|
// Provider-specific vision detection logic
|
|
616
|
+
const model = this.getStoredModelName(provider).toLowerCase();
|
|
236
617
|
switch (provider.name) {
|
|
237
618
|
case 'gemini': {
|
|
238
619
|
return true;
|
|
239
620
|
}
|
|
240
621
|
case 'openai': {
|
|
241
|
-
const model = provider.getCurrentModel?.() || '';
|
|
242
622
|
return model.includes('vision') || model.includes('gpt-4');
|
|
243
623
|
}
|
|
244
624
|
case 'anthropic': {
|
|
245
|
-
|
|
246
|
-
return claudeModel.includes('claude-3');
|
|
625
|
+
return model.includes('claude-3');
|
|
247
626
|
}
|
|
248
627
|
default:
|
|
249
628
|
return false;
|
|
250
629
|
}
|
|
251
630
|
}
|
|
252
631
|
getProviderMaxTokens(provider) {
|
|
253
|
-
const model = provider.
|
|
632
|
+
const model = this.getStoredModelName(provider).toLowerCase();
|
|
254
633
|
switch (provider.name) {
|
|
255
634
|
case 'gemini':
|
|
256
635
|
if (model.includes('pro'))
|
|
@@ -285,10 +664,12 @@ export class ProviderManager {
|
|
|
285
664
|
}
|
|
286
665
|
}
|
|
287
666
|
createProviderContext(provider, capabilities) {
|
|
667
|
+
const providerSettings = this.settingsService.getProviderSettings(provider.name);
|
|
668
|
+
const toolFormatSetting = providerSettings.toolFormat ?? 'auto';
|
|
288
669
|
return {
|
|
289
670
|
providerName: provider.name,
|
|
290
|
-
currentModel:
|
|
291
|
-
toolFormat:
|
|
671
|
+
currentModel: this.getStoredModelName(provider) || 'unknown',
|
|
672
|
+
toolFormat: toolFormatSetting,
|
|
292
673
|
isPaidMode: provider.isPaidMode?.() || false,
|
|
293
674
|
capabilities,
|
|
294
675
|
sessionStartTime: Date.now(),
|
|
@@ -388,10 +769,81 @@ export class ProviderManager {
|
|
|
388
769
|
// Conversation ID is now managed by the logging system
|
|
389
770
|
}
|
|
390
771
|
getProviderCapabilities(providerName) {
|
|
391
|
-
const
|
|
392
|
-
|
|
772
|
+
const name = providerName ||
|
|
773
|
+
this.settingsService.get('activeProvider') ||
|
|
774
|
+
'';
|
|
393
775
|
return this.providerCapabilities.get(name);
|
|
394
776
|
}
|
|
777
|
+
/* @plan:PLAN-20251023-STATELESS-HARDENING.P06 */
|
|
778
|
+
/* @requirement:REQ-SP4-004 */
|
|
779
|
+
prepareStatelessProviderInvocation(context) {
|
|
780
|
+
const stage = 'ProviderManager.prepareStatelessProviderInvocation';
|
|
781
|
+
const runtimeContext = context ?? this.runtime;
|
|
782
|
+
if (!runtimeContext) {
|
|
783
|
+
throw new MissingProviderRuntimeError({
|
|
784
|
+
providerKey: 'ProviderManager',
|
|
785
|
+
missingFields: ['runtime'],
|
|
786
|
+
requirement: 'REQ-SP4-004',
|
|
787
|
+
stage,
|
|
788
|
+
metadata: {
|
|
789
|
+
hint: 'Register CLI runtime context before invoking providers.',
|
|
790
|
+
},
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
if (!runtimeContext.settingsService) {
|
|
794
|
+
throw new MissingProviderRuntimeError({
|
|
795
|
+
providerKey: 'ProviderManager',
|
|
796
|
+
missingFields: ['settings'],
|
|
797
|
+
requirement: 'REQ-SP4-004',
|
|
798
|
+
stage,
|
|
799
|
+
metadata: {
|
|
800
|
+
runtimeId: runtimeContext.runtimeId,
|
|
801
|
+
hint: 'ProviderManager requires a SettingsService for stateless invocation.',
|
|
802
|
+
},
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
const resolvedConfig = runtimeContext.config ?? this.config;
|
|
806
|
+
if (!resolvedConfig) {
|
|
807
|
+
throw new MissingProviderRuntimeError({
|
|
808
|
+
providerKey: 'ProviderManager',
|
|
809
|
+
missingFields: ['config'],
|
|
810
|
+
requirement: 'REQ-SP4-004',
|
|
811
|
+
stage,
|
|
812
|
+
metadata: {
|
|
813
|
+
runtimeId: runtimeContext.runtimeId,
|
|
814
|
+
hint: 'ProviderManager requires Config before stateless invocation.',
|
|
815
|
+
},
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
const statelessMetadata = {
|
|
819
|
+
...(runtimeContext.metadata ?? {}),
|
|
820
|
+
statelessHardening: 'strict',
|
|
821
|
+
statelessProviderMode: 'strict',
|
|
822
|
+
statelessGuards: true,
|
|
823
|
+
statelessMode: 'strict',
|
|
824
|
+
requirement: 'REQ-SP4-004',
|
|
825
|
+
source: stage,
|
|
826
|
+
preparedAt: new Date().toISOString(),
|
|
827
|
+
};
|
|
828
|
+
this.runtime = {
|
|
829
|
+
...runtimeContext,
|
|
830
|
+
settingsService: runtimeContext.settingsService,
|
|
831
|
+
config: resolvedConfig,
|
|
832
|
+
metadata: statelessMetadata,
|
|
833
|
+
};
|
|
834
|
+
this.settingsService = runtimeContext.settingsService;
|
|
835
|
+
this.config = resolvedConfig;
|
|
836
|
+
for (const provider of this.providers.values()) {
|
|
837
|
+
this.attachStatelessRuntimeMetadata(provider, statelessMetadata);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
attachStatelessRuntimeMetadata(provider, metadata) {
|
|
841
|
+
const statelessAware = provider;
|
|
842
|
+
statelessAware.attachStatelessRuntimeMetadata?.(metadata);
|
|
843
|
+
if (statelessAware.wrappedProvider) {
|
|
844
|
+
this.attachStatelessRuntimeMetadata(statelessAware.wrappedProvider, metadata);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
395
847
|
compareProviders(provider1, provider2) {
|
|
396
848
|
const cap1 = this.providerCapabilities.get(provider1);
|
|
397
849
|
const cap2 = this.providerCapabilities.get(provider2);
|