@vybestack/llxprt-code-core 0.4.7 → 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/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 +18 -1
- package/dist/src/config/config.js +123 -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 +235 -56
- 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 +413 -207
- 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.d.ts +17 -1
- package/dist/src/parsers/TextToolCallParser.js +542 -148
- 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 +392 -457
- 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 +65 -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/history/ContentConverters.js +3 -5
- package/dist/src/services/history/ContentConverters.js.map +1 -1
- package/dist/src/services/shellExecutionService.js +2 -2
- package/dist/src/services/shellExecutionService.js.map +1 -1
- 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 +65 -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/editor.js +10 -8
- package/dist/src/utils/editor.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.js +15 -3
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/memoryImportProcessor.js +22 -3
- package/dist/src/utils/memoryImportProcessor.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
|
@@ -1,19 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
3
|
+
* @requirement REQ-SP2-001
|
|
4
|
+
* @project-plans/debuglogging/requirements.md
|
|
5
|
+
*/
|
|
1
6
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
7
|
import { DebugLogger } from '../../debug/index.js';
|
|
3
8
|
import { ToolFormatter } from '../../tools/ToolFormatter.js';
|
|
4
|
-
import { BaseProvider } from '../BaseProvider.js';
|
|
5
|
-
import { getSettingsService } from '../../settings/settingsServiceInstance.js';
|
|
9
|
+
import { BaseProvider, } from '../BaseProvider.js';
|
|
6
10
|
import { processToolParameters, logDoubleEscapingInChunk, } from '../../tools/doubleEscapeUtils.js';
|
|
7
11
|
import { getCoreSystemPromptAsync } from '../../core/prompts.js';
|
|
12
|
+
import { resolveUserMemory } from '../utils/userMemory.js';
|
|
8
13
|
import { retryWithBackoff, getErrorStatus, isNetworkTransientError, } from '../../utils/retry.js';
|
|
14
|
+
import { getSettingsService } from '../../settings/settingsServiceInstance.js';
|
|
9
15
|
export class AnthropicProvider extends BaseProvider {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
modelTokenPatterns = [
|
|
16
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
17
|
+
// All properties are stateless - no runtime/client caches or constructor-captured config
|
|
18
|
+
// @requirement REQ-SP4-002: Eliminate provider-level caching and memoization
|
|
19
|
+
// @requirement REQ-SP4-003: Auth tokens resolved per call via NormalizedGenerateChatOptions
|
|
20
|
+
// Model patterns for max output tokens - static configuration only
|
|
21
|
+
static modelTokenPatterns = [
|
|
17
22
|
{ pattern: /claude-.*opus-4/i, tokens: 32000 },
|
|
18
23
|
{ pattern: /claude-.*sonnet-4/i, tokens: 64000 },
|
|
19
24
|
{ pattern: /claude-.*haiku-4/i, tokens: 200000 }, // Future-proofing for Haiku 4
|
|
@@ -35,14 +40,9 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
35
40
|
oauthManager,
|
|
36
41
|
};
|
|
37
42
|
super(baseConfig, config);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
apiKey: initialApiKey,
|
|
42
|
-
baseURL: config?.baseUrl || baseURL,
|
|
43
|
-
dangerouslyAllowBrowser: true,
|
|
44
|
-
});
|
|
45
|
-
this.toolFormatter = new ToolFormatter();
|
|
43
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
44
|
+
// No logger instances stored as instance variables - create on demand
|
|
45
|
+
// @requirement REQ-SP4-002: Eliminate constructor-captured config and user-memory
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
48
|
* Implementation of BaseProvider abstract method
|
|
@@ -52,60 +52,116 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
52
52
|
// Anthropic supports OAuth authentication
|
|
53
53
|
return true;
|
|
54
54
|
}
|
|
55
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
56
|
+
// Create loggers on-demand to avoid instance state
|
|
57
|
+
// @requirement REQ-SP4-002: Eliminate provider-level caching
|
|
58
|
+
getLogger() {
|
|
59
|
+
return new DebugLogger('llxprt:anthropic:provider');
|
|
60
|
+
}
|
|
61
|
+
getStreamingLogger() {
|
|
62
|
+
return new DebugLogger('llxprt:anthropic:streaming');
|
|
63
|
+
}
|
|
64
|
+
getToolsLogger() {
|
|
65
|
+
return new DebugLogger('llxprt:anthropic:tools');
|
|
66
|
+
}
|
|
67
|
+
getAuthLogger() {
|
|
68
|
+
return new DebugLogger('llxprt:anthropic:auth');
|
|
69
|
+
}
|
|
70
|
+
getErrorsLogger() {
|
|
71
|
+
return new DebugLogger('llxprt:anthropic:errors');
|
|
72
|
+
}
|
|
73
|
+
instantiateClient(authToken, baseURL) {
|
|
74
|
+
const isOAuthToken = authToken.startsWith('sk-ant-oat');
|
|
75
|
+
const clientConfig = {
|
|
76
|
+
dangerouslyAllowBrowser: true,
|
|
77
|
+
};
|
|
78
|
+
if (baseURL && baseURL.trim() !== '') {
|
|
79
|
+
clientConfig.baseURL = baseURL;
|
|
80
|
+
}
|
|
81
|
+
if (isOAuthToken) {
|
|
82
|
+
clientConfig.authToken = authToken;
|
|
83
|
+
clientConfig.defaultHeaders = {
|
|
84
|
+
'anthropic-beta': 'oauth-2025-04-20',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
clientConfig.apiKey = authToken || '';
|
|
89
|
+
}
|
|
90
|
+
return new Anthropic(clientConfig);
|
|
91
|
+
}
|
|
55
92
|
/**
|
|
56
|
-
* @plan
|
|
57
|
-
* @requirement
|
|
58
|
-
*
|
|
93
|
+
* @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
94
|
+
* @requirement REQ-SP4-002
|
|
95
|
+
* @project-plans/20251023stateless4/analysis/pseudocode/provider-cache-elimination.md line 11
|
|
96
|
+
* Build provider client per call with fresh SDK instance
|
|
59
97
|
*/
|
|
60
|
-
async
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
defaultHeaders: {
|
|
80
|
-
'anthropic-beta': 'oauth-2025-04-20', // Still need the beta header
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
this.anthropic = new Anthropic(oauthConfig);
|
|
98
|
+
async buildProviderClient(options, telemetry) {
|
|
99
|
+
const authLogger = this.getAuthLogger();
|
|
100
|
+
const runtimeAuthToken = options.resolved.authToken;
|
|
101
|
+
let authToken;
|
|
102
|
+
if (typeof runtimeAuthToken === 'string' &&
|
|
103
|
+
runtimeAuthToken.trim() !== '') {
|
|
104
|
+
authToken = runtimeAuthToken;
|
|
105
|
+
}
|
|
106
|
+
else if (runtimeAuthToken &&
|
|
107
|
+
typeof runtimeAuthToken === 'object' &&
|
|
108
|
+
'provide' in runtimeAuthToken &&
|
|
109
|
+
typeof runtimeAuthToken.provide === 'function') {
|
|
110
|
+
try {
|
|
111
|
+
const freshToken = await runtimeAuthToken.provide();
|
|
112
|
+
if (!freshToken) {
|
|
113
|
+
throw new Error(`ProviderCacheError("Auth token unavailable for runtimeId=${options.runtime?.runtimeId} (REQ-SP4-003).")`);
|
|
114
|
+
}
|
|
115
|
+
authToken = freshToken;
|
|
116
|
+
authLogger.debug(() => 'Refreshed OAuth token for call');
|
|
84
117
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
this.anthropic = new Anthropic({
|
|
88
|
-
apiKey: resolvedToken,
|
|
89
|
-
baseURL,
|
|
90
|
-
dangerouslyAllowBrowser: true,
|
|
91
|
-
});
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw new Error(`ProviderCacheError("Auth token unavailable for runtimeId=${options.runtime?.runtimeId} (REQ-SP4-003)."): ${error}`);
|
|
92
120
|
}
|
|
93
|
-
// Track the key to avoid unnecessary client recreation
|
|
94
|
-
this._cachedAuthKey = resolvedToken;
|
|
95
121
|
}
|
|
122
|
+
if (!authToken) {
|
|
123
|
+
authToken = await this.getAuthToken();
|
|
124
|
+
}
|
|
125
|
+
if (!authToken) {
|
|
126
|
+
authLogger.debug(() => 'No authentication available for Anthropic API calls');
|
|
127
|
+
throw new Error('No authentication available for Anthropic API calls. Use /auth anthropic to re-authenticate or /auth anthropic logout to clear any expired session.');
|
|
128
|
+
}
|
|
129
|
+
authLogger.debug(() => 'Creating fresh client instance (stateless)');
|
|
130
|
+
const baseURL = options.resolved.baseURL;
|
|
131
|
+
const client = this.instantiateClient(authToken, baseURL);
|
|
132
|
+
telemetry?.record?.('stateless-provider.call', {
|
|
133
|
+
providerName: 'anthropic',
|
|
134
|
+
cacheEliminated: true,
|
|
135
|
+
});
|
|
136
|
+
return { client, authToken };
|
|
137
|
+
}
|
|
138
|
+
createToolFormatter() {
|
|
139
|
+
return new ToolFormatter();
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
143
|
+
* @requirement REQ-SP4-002
|
|
144
|
+
* @project-plans/20251023stateless4/analysis/pseudocode/provider-cache-elimination.md line 15
|
|
145
|
+
* No operation - stateless provider has no cache to clear
|
|
146
|
+
*/
|
|
147
|
+
clearClientCache(_runtimeKey) {
|
|
148
|
+
this.getLogger().debug(() => 'Cache clear called on stateless provider - no operation');
|
|
149
|
+
}
|
|
150
|
+
clearAuthCache() {
|
|
151
|
+
this.getAuthLogger().debug(() => 'Clearing auth cache');
|
|
152
|
+
super.clearAuthCache();
|
|
96
153
|
}
|
|
97
154
|
async getModels() {
|
|
98
155
|
const authToken = await this.getAuthToken();
|
|
99
156
|
if (!authToken) {
|
|
157
|
+
this.getAuthLogger().debug(() => 'No authentication available for model listing');
|
|
100
158
|
throw new Error('No authentication available for Anthropic API calls. Use /auth anthropic to re-authenticate or /auth anthropic logout to clear any expired session.');
|
|
101
159
|
}
|
|
102
|
-
// Update client with resolved auth (handles OAuth vs API key)
|
|
103
|
-
await this.updateClientWithResolvedAuth();
|
|
104
160
|
// Check if using OAuth - the models.list endpoint doesn't work with OAuth tokens
|
|
105
161
|
const isOAuthToken = authToken.startsWith('sk-ant-oat');
|
|
106
162
|
if (isOAuthToken) {
|
|
107
163
|
// For OAuth, return only the working models
|
|
108
|
-
this.
|
|
164
|
+
this.getAuthLogger().debug(() => 'Using hardcoded model list for OAuth authentication');
|
|
109
165
|
return [
|
|
110
166
|
{
|
|
111
167
|
id: 'claude-opus-4-1-20250805',
|
|
@@ -160,24 +216,28 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
160
216
|
name: 'Claude Haiku 4.5',
|
|
161
217
|
provider: 'anthropic',
|
|
162
218
|
supportedToolFormats: ['anthropic'],
|
|
163
|
-
contextWindow:
|
|
164
|
-
maxOutputTokens:
|
|
219
|
+
contextWindow: 500000,
|
|
220
|
+
maxOutputTokens: 16000,
|
|
165
221
|
},
|
|
166
222
|
{
|
|
167
223
|
id: 'claude-haiku-4-5',
|
|
168
224
|
name: 'Claude Haiku 4.5',
|
|
169
225
|
provider: 'anthropic',
|
|
170
226
|
supportedToolFormats: ['anthropic'],
|
|
171
|
-
contextWindow:
|
|
172
|
-
maxOutputTokens:
|
|
227
|
+
contextWindow: 500000,
|
|
228
|
+
maxOutputTokens: 16000,
|
|
173
229
|
},
|
|
174
230
|
];
|
|
175
231
|
}
|
|
176
232
|
try {
|
|
233
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08: Create fresh client for each operation
|
|
177
234
|
// Fetch models from Anthropic API (beta endpoint) - only for API keys
|
|
178
235
|
const models = [];
|
|
236
|
+
const baseURL = this.getBaseURL();
|
|
237
|
+
const client = this.instantiateClient(authToken, baseURL);
|
|
238
|
+
this.getLogger().debug(() => 'Fetching models from Anthropic API');
|
|
179
239
|
// Handle pagination
|
|
180
|
-
for await (const model of
|
|
240
|
+
for await (const model of client.beta.models.list()) {
|
|
181
241
|
models.push({
|
|
182
242
|
id: model.id,
|
|
183
243
|
name: model.display_name || model.id,
|
|
@@ -203,61 +263,20 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
203
263
|
};
|
|
204
264
|
addLatestAlias('opus');
|
|
205
265
|
addLatestAlias('sonnet');
|
|
266
|
+
this.getLogger().debug(() => `Fetched ${models.length} models from Anthropic API`);
|
|
206
267
|
return models;
|
|
207
268
|
}
|
|
208
269
|
catch (error) {
|
|
209
|
-
this.
|
|
270
|
+
this.getErrorsLogger().debug(() => `Failed to fetch Anthropic models: ${error}`);
|
|
210
271
|
return []; // Return empty array on error
|
|
211
272
|
}
|
|
212
273
|
}
|
|
213
|
-
setApiKey(apiKey) {
|
|
214
|
-
// Call base provider implementation
|
|
215
|
-
super.setApiKey(apiKey);
|
|
216
|
-
// Create a new Anthropic client with the updated API key
|
|
217
|
-
const resolvedBaseURL = this.providerConfig?.baseUrl || this.baseProviderConfig.baseURL;
|
|
218
|
-
this.anthropic = new Anthropic({
|
|
219
|
-
apiKey,
|
|
220
|
-
baseURL: resolvedBaseURL,
|
|
221
|
-
dangerouslyAllowBrowser: true,
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
setBaseUrl(baseUrl) {
|
|
225
|
-
// Call base provider implementation which stores in ephemeral settings
|
|
226
|
-
super.setBaseUrl?.(baseUrl);
|
|
227
|
-
// Create a new Anthropic client with the updated (or cleared) base URL
|
|
228
|
-
// Will be updated with actual token in updateClientWithResolvedAuth
|
|
229
|
-
const resolvedBaseURL = this.getBaseURL();
|
|
230
|
-
this.anthropic = new Anthropic({
|
|
231
|
-
apiKey: null, // Ensure env variables don't leak into OAuth-only flows
|
|
232
|
-
baseURL: resolvedBaseURL,
|
|
233
|
-
dangerouslyAllowBrowser: true,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
setModel(modelId) {
|
|
237
|
-
// Update SettingsService as the source of truth
|
|
238
|
-
try {
|
|
239
|
-
const settingsService = getSettingsService();
|
|
240
|
-
settingsService.setProviderSetting(this.name, 'model', modelId);
|
|
241
|
-
}
|
|
242
|
-
catch (error) {
|
|
243
|
-
this.logger.debug(() => `Failed to persist model to SettingsService: ${error}`);
|
|
244
|
-
}
|
|
245
|
-
// No local caching - always look up from SettingsService
|
|
246
|
-
}
|
|
247
274
|
getCurrentModel() {
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return providerSettings.model;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
catch (error) {
|
|
257
|
-
this.logger.debug(() => `Failed to get model from SettingsService: ${error}`);
|
|
258
|
-
}
|
|
259
|
-
// Always return from getDefaultModel, no caching
|
|
260
|
-
return this.getDefaultModel();
|
|
275
|
+
// Always return from getDefaultModel - providers must not cache model state
|
|
276
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08 @requirement REQ-SP4-002
|
|
277
|
+
const defaultModel = this.getDefaultModel();
|
|
278
|
+
this.getLogger().debug(() => `Using default model: ${defaultModel}`);
|
|
279
|
+
return defaultModel;
|
|
261
280
|
}
|
|
262
281
|
getDefaultModel() {
|
|
263
282
|
// Return hardcoded default - do NOT call getModel() to avoid circular dependency
|
|
@@ -293,7 +312,8 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
293
312
|
return 64000;
|
|
294
313
|
}
|
|
295
314
|
// Try to match model patterns
|
|
296
|
-
|
|
315
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08: Use static instead of instance property
|
|
316
|
+
for (const { pattern, tokens } of AnthropicProvider.modelTokenPatterns) {
|
|
297
317
|
if (pattern.test(modelId)) {
|
|
298
318
|
return tokens;
|
|
299
319
|
}
|
|
@@ -335,67 +355,46 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
335
355
|
throw new Error('Server tools not supported by Anthropic provider');
|
|
336
356
|
}
|
|
337
357
|
/**
|
|
338
|
-
*
|
|
339
|
-
* @param params Parameters to merge with existing, or undefined to clear all
|
|
340
|
-
*/
|
|
341
|
-
setModelParams(params) {
|
|
342
|
-
const settingsService = getSettingsService();
|
|
343
|
-
if (params === undefined) {
|
|
344
|
-
// Clear all model params
|
|
345
|
-
settingsService.setProviderSetting(this.name, 'temperature', undefined);
|
|
346
|
-
settingsService.setProviderSetting(this.name, 'max_tokens', undefined);
|
|
347
|
-
settingsService.setProviderSetting(this.name, 'top_p', undefined);
|
|
348
|
-
settingsService.setProviderSetting(this.name, 'top_k', undefined);
|
|
349
|
-
}
|
|
350
|
-
else {
|
|
351
|
-
// Set each param individually
|
|
352
|
-
if ('temperature' in params) {
|
|
353
|
-
settingsService.setProviderSetting(this.name, 'temperature', params.temperature);
|
|
354
|
-
}
|
|
355
|
-
if ('max_tokens' in params) {
|
|
356
|
-
settingsService.setProviderSetting(this.name, 'max_tokens', params.max_tokens);
|
|
357
|
-
}
|
|
358
|
-
if ('top_p' in params) {
|
|
359
|
-
settingsService.setProviderSetting(this.name, 'top_p', params.top_p);
|
|
360
|
-
}
|
|
361
|
-
if ('top_k' in params) {
|
|
362
|
-
settingsService.setProviderSetting(this.name, 'top_k', params.top_k);
|
|
363
|
-
}
|
|
364
|
-
if ('stop_sequences' in params) {
|
|
365
|
-
settingsService.setProviderSetting(this.name, 'stop_sequences', params.stop_sequences);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Get current model parameters
|
|
358
|
+
* Get current model parameters from SettingsService per call
|
|
371
359
|
* @returns Current parameters or undefined if not set
|
|
360
|
+
* @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
361
|
+
* @requirement REQ-SP4-003
|
|
362
|
+
* Gets model parameters from SettingsService per call (stateless)
|
|
372
363
|
*/
|
|
373
364
|
getModelParams() {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
365
|
+
try {
|
|
366
|
+
const settingsService = this.resolveSettingsService();
|
|
367
|
+
const providerSettings = settingsService.getProviderSettings(this.name);
|
|
368
|
+
const reservedKeys = new Set([
|
|
369
|
+
'enabled',
|
|
370
|
+
'apiKey',
|
|
371
|
+
'api-key',
|
|
372
|
+
'apiKeyfile',
|
|
373
|
+
'api-keyfile',
|
|
374
|
+
'baseUrl',
|
|
375
|
+
'base-url',
|
|
376
|
+
'model',
|
|
377
|
+
'toolFormat',
|
|
378
|
+
'tool-format',
|
|
379
|
+
'toolFormatOverride',
|
|
380
|
+
'tool-format-override',
|
|
381
|
+
'defaultModel',
|
|
382
|
+
]);
|
|
383
|
+
const params = {};
|
|
384
|
+
if (providerSettings) {
|
|
385
|
+
for (const [key, value] of Object.entries(providerSettings)) {
|
|
386
|
+
if (reservedKeys.has(key) || value === undefined || value === null) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
params[key] = value;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return Object.keys(params).length > 0 ? params : undefined;
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
this.getLogger().debug(() => `Failed to get Anthropic provider settings from SettingsService: ${error}`);
|
|
378
396
|
return undefined;
|
|
379
397
|
}
|
|
380
|
-
const params = {};
|
|
381
|
-
if (providerSettings.temperature !== undefined)
|
|
382
|
-
params.temperature = providerSettings.temperature;
|
|
383
|
-
if (providerSettings.max_tokens !== undefined)
|
|
384
|
-
params.max_tokens = providerSettings.max_tokens;
|
|
385
|
-
if (providerSettings.top_p !== undefined)
|
|
386
|
-
params.top_p = providerSettings.top_p;
|
|
387
|
-
if (providerSettings.top_k !== undefined)
|
|
388
|
-
params.top_k = providerSettings.top_k;
|
|
389
|
-
if (providerSettings.stop_sequences !== undefined)
|
|
390
|
-
params.stop_sequences = providerSettings.stop_sequences;
|
|
391
|
-
return Object.keys(params).length > 0 ? params : undefined;
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Override clearAuthCache to also clear cached auth key
|
|
395
|
-
*/
|
|
396
|
-
clearAuthCache() {
|
|
397
|
-
super.clearAuthCache();
|
|
398
|
-
this._cachedAuthKey = undefined;
|
|
399
398
|
}
|
|
400
399
|
/**
|
|
401
400
|
* Check if the provider is authenticated using any available method
|
|
@@ -409,6 +408,8 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
409
408
|
* @returns The detected tool format
|
|
410
409
|
*/
|
|
411
410
|
detectToolFormat() {
|
|
411
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08: Don't reference deprecated instance fields
|
|
412
|
+
// Tools format should be derived from runtime context only
|
|
412
413
|
try {
|
|
413
414
|
const settingsService = getSettingsService();
|
|
414
415
|
// First check SettingsService for toolFormat override in provider settings
|
|
@@ -434,7 +435,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
434
435
|
return 'anthropic';
|
|
435
436
|
}
|
|
436
437
|
catch (error) {
|
|
437
|
-
this.
|
|
438
|
+
this.getLogger().debug(() => `Failed to detect tool format from SettingsService: ${error}`);
|
|
438
439
|
// Fallback detection without SettingsService
|
|
439
440
|
const modelName = this.getCurrentModel().toLowerCase();
|
|
440
441
|
if (modelName.includes('glm-')) {
|
|
@@ -450,23 +451,6 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
450
451
|
// Use the same detection logic as detectToolFormat()
|
|
451
452
|
return this.detectToolFormat();
|
|
452
453
|
}
|
|
453
|
-
/**
|
|
454
|
-
* Set tool format override for this provider
|
|
455
|
-
* @param format The format to use, or null to clear override
|
|
456
|
-
*/
|
|
457
|
-
setToolFormatOverride(format) {
|
|
458
|
-
const settingsService = getSettingsService();
|
|
459
|
-
if (format === null) {
|
|
460
|
-
settingsService.setProviderSetting(this.name, 'toolFormat', 'auto');
|
|
461
|
-
this.logger.debug(() => `Tool format override cleared for ${this.name}`);
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
settingsService.setProviderSetting(this.name, 'toolFormat', format);
|
|
465
|
-
this.logger.debug(() => `Tool format override set to '${format}' for ${this.name}`);
|
|
466
|
-
}
|
|
467
|
-
// Clear cached auth key to ensure new format takes effect
|
|
468
|
-
this._cachedAuthKey = undefined;
|
|
469
|
-
}
|
|
470
454
|
/**
|
|
471
455
|
* Normalize tool IDs from various formats to Anthropic format
|
|
472
456
|
* Handles IDs from OpenAI (call_xxx), Anthropic (toolu_xxx), and history (hist_tool_xxx)
|
|
@@ -511,22 +495,26 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
511
495
|
return 'hist_tool_' + id;
|
|
512
496
|
}
|
|
513
497
|
/**
|
|
514
|
-
*
|
|
515
|
-
*
|
|
498
|
+
* @plan PLAN-20251023-STATELESS-HARDENING.P08
|
|
499
|
+
* @requirement REQ-SP4-002, REQ-SP4-003
|
|
500
|
+
* @project-plans/20251023stateless4/analysis/pseudocode/provider-cache-elimination.md line 11
|
|
516
501
|
*/
|
|
517
|
-
async *
|
|
502
|
+
async *generateChatCompletionWithOptions(options) {
|
|
503
|
+
const { client, authToken } = await this.buildProviderClient(options, options.resolved.telemetry);
|
|
504
|
+
const callFormatter = this.createToolFormatter();
|
|
505
|
+
const { contents: content, tools } = options;
|
|
518
506
|
// Convert IContent directly to Anthropic API format (no IMessage!)
|
|
519
507
|
const anthropicMessages = [];
|
|
520
508
|
// Extract system message if present
|
|
521
509
|
// let systemMessage: string | undefined;
|
|
522
510
|
// Filter out orphaned tool responses at the beginning of the conversation
|
|
523
|
-
//
|
|
524
|
-
//
|
|
525
|
-
//
|
|
511
|
+
// NOTE: These shouldn't be truly orphaned since the same history works with
|
|
512
|
+
// OpenAI/Cerebras. Likely Anthropic has stricter formatting requirements
|
|
513
|
+
// for tool responses that we're not fully meeting yet.
|
|
526
514
|
let startIndex = 0;
|
|
527
515
|
while (startIndex < content.length &&
|
|
528
516
|
content[startIndex].speaker === 'tool') {
|
|
529
|
-
this.
|
|
517
|
+
this.getToolsLogger().debug(() => `Skipping orphaned tool response at beginning of conversation`);
|
|
530
518
|
startIndex++;
|
|
531
519
|
}
|
|
532
520
|
const filteredContent = content.slice(startIndex);
|
|
@@ -552,7 +540,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
552
540
|
return JSON.stringify(result);
|
|
553
541
|
}
|
|
554
542
|
catch (error) {
|
|
555
|
-
this.
|
|
543
|
+
this.getToolsLogger().debug(() => `Failed to stringify tool result, falling back to string conversion: ${error}`);
|
|
556
544
|
return String(result);
|
|
557
545
|
}
|
|
558
546
|
};
|
|
@@ -631,7 +619,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
631
619
|
parametersObj = JSON.parse(parametersObj);
|
|
632
620
|
}
|
|
633
621
|
catch (e) {
|
|
634
|
-
this.
|
|
622
|
+
this.getToolsLogger().debug(() => `Failed to parse tool parameters as JSON: ${e}`);
|
|
635
623
|
parametersObj = {};
|
|
636
624
|
}
|
|
637
625
|
}
|
|
@@ -694,7 +682,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
694
682
|
// Remove orphaned tool results (results without corresponding tool uses)
|
|
695
683
|
const orphanedResults = Array.from(toolResultIds).filter((id) => !toolUseIds.has(id));
|
|
696
684
|
if (orphanedResults.length > 0) {
|
|
697
|
-
this.
|
|
685
|
+
this.getToolsLogger().debug(() => `Found ${orphanedResults.length} orphaned tool results, removing them`);
|
|
698
686
|
// Filter out messages that only contain orphaned tool results
|
|
699
687
|
const filteredMessages = anthropicMessages.filter((msg) => {
|
|
700
688
|
if (msg.role === 'user' && Array.isArray(msg.content)) {
|
|
@@ -716,7 +704,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
716
704
|
// Anthropic requires the first message to be from the user
|
|
717
705
|
if (anthropicMessages.length > 0 && anthropicMessages[0].role !== 'user') {
|
|
718
706
|
// If the first message is not from the user, add a minimal user message
|
|
719
|
-
this.
|
|
707
|
+
this.getLogger().debug(() => `First message is not from user, adding placeholder user message`);
|
|
720
708
|
anthropicMessages.unshift({
|
|
721
709
|
role: 'user',
|
|
722
710
|
content: 'Continue the conversation',
|
|
@@ -734,28 +722,26 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
734
722
|
const detectedFormat = this.detectToolFormat();
|
|
735
723
|
const needsQwenParameterProcessing = detectedFormat === 'qwen';
|
|
736
724
|
// Convert Gemini format tools to anthropic format (always for Anthropic API)
|
|
737
|
-
const anthropicTools =
|
|
738
|
-
const
|
|
739
|
-
|
|
740
|
-
.
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
// Check OAuth mode
|
|
745
|
-
const authToken = await this.getAuthToken();
|
|
746
|
-
const isOAuth = authToken && authToken.startsWith('sk-ant-oat');
|
|
725
|
+
const anthropicTools = callFormatter.convertGeminiToFormat(tools, 'anthropic');
|
|
726
|
+
const toolNamesForPrompt = tools === undefined
|
|
727
|
+
? undefined
|
|
728
|
+
: Array.from(new Set(tools.flatMap((group) => group.functionDeclarations
|
|
729
|
+
.map((decl) => decl.name)
|
|
730
|
+
.filter((name) => Boolean(name)))));
|
|
731
|
+
const isOAuth = authToken.startsWith('sk-ant-oat');
|
|
747
732
|
// Get streaming setting from ephemeral settings (default: enabled)
|
|
748
733
|
const streamingSetting = this.providerConfig?.getEphemeralSettings?.()?.['streaming'];
|
|
749
734
|
const streamingEnabled = streamingSetting !== 'disabled';
|
|
750
735
|
// Build request with proper typing
|
|
751
|
-
const currentModel =
|
|
752
|
-
// Get
|
|
753
|
-
const userMemory =
|
|
754
|
-
|
|
755
|
-
|
|
736
|
+
const currentModel = options.resolved.model;
|
|
737
|
+
// @plan PLAN-20251023-STATELESS-HARDENING.P08: Get userMemory from normalized runtime context
|
|
738
|
+
const userMemory = await resolveUserMemory(options.userMemory, () => options.invocation?.userMemory);
|
|
739
|
+
// Derive model parameters on demand from ephemeral settings
|
|
740
|
+
const configEphemeralSettings = options.invocation?.ephemerals ?? {};
|
|
741
|
+
const requestOverrides = configEphemeralSettings['anthropic'] || {};
|
|
756
742
|
// For OAuth mode, inject core system prompt as the first human message
|
|
757
743
|
if (isOAuth) {
|
|
758
|
-
const corePrompt = await getCoreSystemPromptAsync(userMemory, currentModel,
|
|
744
|
+
const corePrompt = await getCoreSystemPromptAsync(userMemory, currentModel, toolNamesForPrompt);
|
|
759
745
|
if (corePrompt) {
|
|
760
746
|
anthropicMessages.unshift({
|
|
761
747
|
role: 'user',
|
|
@@ -764,14 +750,14 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
764
750
|
}
|
|
765
751
|
}
|
|
766
752
|
const systemPrompt = !isOAuth
|
|
767
|
-
? await getCoreSystemPromptAsync(userMemory, currentModel,
|
|
753
|
+
? await getCoreSystemPromptAsync(userMemory, currentModel, toolNamesForPrompt)
|
|
768
754
|
: undefined;
|
|
769
755
|
const requestBody = {
|
|
770
756
|
model: currentModel,
|
|
771
757
|
messages: anthropicMessages,
|
|
772
758
|
max_tokens: this.getMaxTokensForModel(currentModel),
|
|
773
759
|
stream: streamingEnabled,
|
|
774
|
-
...
|
|
760
|
+
...requestOverrides, // Use derived ephemeral overrides instead of memoized instance state
|
|
775
761
|
...(isOAuth
|
|
776
762
|
? {
|
|
777
763
|
system: "You are Claude Code, Anthropic's official CLI for Claude.",
|
|
@@ -785,18 +771,18 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
785
771
|
};
|
|
786
772
|
// Debug log the tools being sent to Anthropic
|
|
787
773
|
if (anthropicTools && anthropicTools.length > 0) {
|
|
788
|
-
this.
|
|
774
|
+
this.getToolsLogger().debug(() => `[AnthropicProvider] Sending tools to API:`, {
|
|
789
775
|
toolCount: anthropicTools.length,
|
|
790
776
|
toolNames: anthropicTools.map((t) => t.name),
|
|
791
777
|
firstTool: anthropicTools[0],
|
|
792
778
|
requestHasTools: 'tools' in requestBody,
|
|
793
779
|
});
|
|
794
780
|
}
|
|
795
|
-
// Make the API call
|
|
781
|
+
// Make the API call with retry logic
|
|
796
782
|
const customHeaders = this.getCustomHeaders();
|
|
797
783
|
const apiCall = () => customHeaders
|
|
798
|
-
?
|
|
799
|
-
:
|
|
784
|
+
? client.messages.create(requestBody, { headers: customHeaders })
|
|
785
|
+
: client.messages.create(requestBody);
|
|
800
786
|
const { maxAttempts, initialDelayMs } = this.getRetryConfig();
|
|
801
787
|
const response = await retryWithBackoff(apiCall, {
|
|
802
788
|
maxAttempts,
|
|
@@ -808,42 +794,50 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
808
794
|
// Handle streaming response - response is already a Stream when streaming is enabled
|
|
809
795
|
const stream = response;
|
|
810
796
|
let currentToolCall;
|
|
797
|
+
this.getStreamingLogger().debug(() => 'Processing streaming response');
|
|
811
798
|
for await (const chunk of stream) {
|
|
812
799
|
if (chunk.type === 'content_block_start') {
|
|
813
800
|
if (chunk.content_block.type === 'tool_use') {
|
|
801
|
+
const toolBlock = chunk.content_block;
|
|
802
|
+
this.getStreamingLogger().debug(() => `Starting tool use: ${toolBlock.name}`);
|
|
814
803
|
currentToolCall = {
|
|
815
|
-
id:
|
|
816
|
-
name:
|
|
804
|
+
id: toolBlock.id,
|
|
805
|
+
name: toolBlock.name,
|
|
817
806
|
input: '',
|
|
818
807
|
};
|
|
819
808
|
}
|
|
820
809
|
}
|
|
821
810
|
else if (chunk.type === 'content_block_delta') {
|
|
822
811
|
if (chunk.delta.type === 'text_delta') {
|
|
812
|
+
const textDelta = chunk.delta;
|
|
813
|
+
this.getStreamingLogger().debug(() => `Received text delta: ${textDelta.text.length} chars`);
|
|
823
814
|
// Emit text immediately as IContent
|
|
824
815
|
yield {
|
|
825
816
|
speaker: 'ai',
|
|
826
|
-
blocks: [{ type: 'text', text:
|
|
817
|
+
blocks: [{ type: 'text', text: textDelta.text }],
|
|
827
818
|
};
|
|
828
819
|
}
|
|
829
820
|
else if (chunk.delta.type === 'input_json_delta' &&
|
|
830
821
|
currentToolCall) {
|
|
831
|
-
|
|
822
|
+
const jsonDelta = chunk.delta;
|
|
823
|
+
currentToolCall.input += jsonDelta.partial_json;
|
|
832
824
|
// Check for double-escaping patterns
|
|
833
|
-
logDoubleEscapingInChunk(
|
|
825
|
+
logDoubleEscapingInChunk(jsonDelta.partial_json, currentToolCall.name, needsQwenParameterProcessing ? 'qwen' : 'anthropic');
|
|
834
826
|
}
|
|
835
827
|
}
|
|
836
828
|
else if (chunk.type === 'content_block_stop') {
|
|
837
829
|
if (currentToolCall) {
|
|
830
|
+
const activeToolCall = currentToolCall;
|
|
831
|
+
this.getStreamingLogger().debug(() => `Completed tool use: ${activeToolCall.name}`);
|
|
838
832
|
// Process tool parameters with double-escape handling
|
|
839
|
-
const processedParameters = processToolParameters(
|
|
833
|
+
const processedParameters = processToolParameters(activeToolCall.input, activeToolCall.name, needsQwenParameterProcessing ? 'qwen' : 'anthropic');
|
|
840
834
|
yield {
|
|
841
835
|
speaker: 'ai',
|
|
842
836
|
blocks: [
|
|
843
837
|
{
|
|
844
838
|
type: 'tool_call',
|
|
845
|
-
id: this.normalizeToHistoryToolId(
|
|
846
|
-
name:
|
|
839
|
+
id: this.normalizeToHistoryToolId(activeToolCall.id),
|
|
840
|
+
name: activeToolCall.name,
|
|
847
841
|
parameters: processedParameters,
|
|
848
842
|
},
|
|
849
843
|
],
|
|
@@ -853,6 +847,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
853
847
|
}
|
|
854
848
|
else if (chunk.type === 'message_delta' && chunk.usage) {
|
|
855
849
|
// Emit usage metadata
|
|
850
|
+
this.getStreamingLogger().debug(() => `Received usage metadata`);
|
|
856
851
|
yield {
|
|
857
852
|
speaker: 'ai',
|
|
858
853
|
blocks: [],
|
|
@@ -915,11 +910,11 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
915
910
|
shouldRetryAnthropicResponse(error) {
|
|
916
911
|
const status = getErrorStatus(error);
|
|
917
912
|
if (status === 429 || (status && status >= 500 && status < 600)) {
|
|
918
|
-
this.
|
|
913
|
+
this.getLogger().debug(() => `Will retry Anthropic request due to status ${status}`);
|
|
919
914
|
return true;
|
|
920
915
|
}
|
|
921
916
|
if (isNetworkTransientError(error)) {
|
|
922
|
-
this.
|
|
917
|
+
this.getLogger().debug(() => 'Will retry Anthropic request due to transient network error signature.');
|
|
923
918
|
return true;
|
|
924
919
|
}
|
|
925
920
|
return false;
|