@vybestack/llxprt-code-core 0.4.7 → 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.
Files changed (216) hide show
  1. package/dist/prompt-config/defaults/default-prompts.json +4 -17
  2. package/dist/src/auth/precedence.d.ts +69 -9
  3. package/dist/src/auth/precedence.js +467 -69
  4. package/dist/src/auth/precedence.js.map +1 -1
  5. package/dist/src/auth/types.d.ts +2 -2
  6. package/dist/src/config/config.d.ts +18 -1
  7. package/dist/src/config/config.js +123 -6
  8. package/dist/src/config/config.js.map +1 -1
  9. package/dist/src/config/index.d.ts +6 -0
  10. package/dist/src/config/index.js +5 -0
  11. package/dist/src/config/index.js.map +1 -1
  12. package/dist/src/config/profileManager.d.ts +23 -3
  13. package/dist/src/config/profileManager.js +54 -7
  14. package/dist/src/config/profileManager.js.map +1 -1
  15. package/dist/src/config/subagentManager.d.ts +96 -0
  16. package/dist/src/config/subagentManager.js +371 -0
  17. package/dist/src/config/subagentManager.js.map +1 -0
  18. package/dist/src/config/types.d.ts +18 -0
  19. package/dist/src/config/types.js +3 -0
  20. package/dist/src/config/types.js.map +1 -0
  21. package/dist/src/core/client.d.ts +27 -7
  22. package/dist/src/core/client.js +221 -56
  23. package/dist/src/core/client.js.map +1 -1
  24. package/dist/src/core/contentGenerator.d.ts +3 -1
  25. package/dist/src/core/contentGenerator.js +3 -0
  26. package/dist/src/core/contentGenerator.js.map +1 -1
  27. package/dist/src/core/coreToolScheduler.d.ts +1 -5
  28. package/dist/src/core/coreToolScheduler.js +95 -23
  29. package/dist/src/core/coreToolScheduler.js.map +1 -1
  30. package/dist/src/core/geminiChat.d.ts +42 -12
  31. package/dist/src/core/geminiChat.js +413 -207
  32. package/dist/src/core/geminiChat.js.map +1 -1
  33. package/dist/src/core/nonInteractiveToolExecutor.d.ts +3 -2
  34. package/dist/src/core/nonInteractiveToolExecutor.js +94 -10
  35. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  36. package/dist/src/core/subagent.d.ts +86 -7
  37. package/dist/src/core/subagent.js +809 -79
  38. package/dist/src/core/subagent.js.map +1 -1
  39. package/dist/src/core/subagentOrchestrator.d.ts +73 -0
  40. package/dist/src/core/subagentOrchestrator.js +383 -0
  41. package/dist/src/core/subagentOrchestrator.js.map +1 -0
  42. package/dist/src/core/subagentScheduler.d.ts +16 -0
  43. package/dist/src/core/subagentScheduler.js +7 -0
  44. package/dist/src/core/subagentScheduler.js.map +1 -0
  45. package/dist/src/core/turn.d.ts +5 -1
  46. package/dist/src/core/turn.js +5 -1
  47. package/dist/src/core/turn.js.map +1 -1
  48. package/dist/src/hooks/tool-render-suppression-hook.js +6 -1
  49. package/dist/src/hooks/tool-render-suppression-hook.js.map +1 -1
  50. package/dist/src/ide/ideContext.d.ts +32 -32
  51. package/dist/src/index.d.ts +19 -1
  52. package/dist/src/index.js +15 -2
  53. package/dist/src/index.js.map +1 -1
  54. package/dist/src/interfaces/index.d.ts +1 -0
  55. package/dist/src/interfaces/index.js +4 -0
  56. package/dist/src/interfaces/index.js.map +1 -0
  57. package/dist/src/interfaces/nodejs-error.interface.d.ts +4 -0
  58. package/dist/src/interfaces/nodejs-error.interface.js +2 -0
  59. package/dist/src/interfaces/nodejs-error.interface.js.map +1 -0
  60. package/dist/src/parsers/TextToolCallParser.js +41 -1
  61. package/dist/src/parsers/TextToolCallParser.js.map +1 -1
  62. package/dist/src/prompt-config/defaults/core.md +15 -0
  63. package/dist/src/prompt-config/defaults/providers/gemini/core.md +203 -119
  64. package/dist/src/prompt-config/defaults/tool-defaults.js +2 -0
  65. package/dist/src/prompt-config/defaults/tool-defaults.js.map +1 -1
  66. package/dist/src/prompt-config/defaults/tools/list-subagents.md +7 -0
  67. package/dist/src/prompt-config/defaults/tools/task.md +8 -0
  68. package/dist/src/providers/BaseProvider.d.ts +115 -30
  69. package/dist/src/providers/BaseProvider.js +445 -109
  70. package/dist/src/providers/BaseProvider.js.map +1 -1
  71. package/dist/src/providers/IProvider.d.ts +50 -18
  72. package/dist/src/providers/LoggingProviderWrapper.d.ts +60 -16
  73. package/dist/src/providers/LoggingProviderWrapper.js +213 -60
  74. package/dist/src/providers/LoggingProviderWrapper.js.map +1 -1
  75. package/dist/src/providers/ProviderManager.d.ts +73 -2
  76. package/dist/src/providers/ProviderManager.js +492 -40
  77. package/dist/src/providers/ProviderManager.js.map +1 -1
  78. package/dist/src/providers/anthropic/AnthropicProvider.d.ts +35 -38
  79. package/dist/src/providers/anthropic/AnthropicProvider.js +222 -227
  80. package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
  81. package/dist/src/providers/errors.d.ts +86 -0
  82. package/dist/src/providers/errors.js +89 -0
  83. package/dist/src/providers/errors.js.map +1 -1
  84. package/dist/src/providers/gemini/GeminiProvider.d.ts +101 -41
  85. package/dist/src/providers/gemini/GeminiProvider.js +386 -311
  86. package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
  87. package/dist/src/providers/openai/ConversationCache.d.ts +5 -3
  88. package/dist/src/providers/openai/ConversationCache.js +93 -32
  89. package/dist/src/providers/openai/ConversationCache.js.map +1 -1
  90. package/dist/src/providers/openai/OpenAIProvider.d.ts +82 -42
  91. package/dist/src/providers/openai/OpenAIProvider.js +374 -453
  92. package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
  93. package/dist/src/providers/openai/getOpenAIProviderInfo.d.ts +1 -1
  94. package/dist/src/providers/openai/getOpenAIProviderInfo.js +52 -22
  95. package/dist/src/providers/openai/getOpenAIProviderInfo.js.map +1 -1
  96. package/dist/src/providers/openai/openaiRequestParams.d.ts +7 -0
  97. package/dist/src/providers/openai/openaiRequestParams.js +66 -0
  98. package/dist/src/providers/openai/openaiRequestParams.js.map +1 -0
  99. package/dist/src/providers/openai-responses/OpenAIResponsesProvider.d.ts +6 -33
  100. package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js +84 -183
  101. package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js.map +1 -1
  102. package/dist/src/providers/types/providerRuntime.d.ts +17 -0
  103. package/dist/src/providers/types/providerRuntime.js +7 -0
  104. package/dist/src/providers/types/providerRuntime.js.map +1 -0
  105. package/dist/src/providers/utils/authToken.d.ts +12 -0
  106. package/dist/src/providers/utils/authToken.js +17 -0
  107. package/dist/src/providers/utils/authToken.js.map +1 -0
  108. package/dist/src/providers/utils/userMemory.d.ts +8 -0
  109. package/dist/src/providers/utils/userMemory.js +34 -0
  110. package/dist/src/providers/utils/userMemory.js.map +1 -0
  111. package/dist/src/runtime/AgentRuntimeContext.d.ts +213 -0
  112. package/dist/src/runtime/AgentRuntimeContext.js +17 -0
  113. package/dist/src/runtime/AgentRuntimeContext.js.map +1 -0
  114. package/dist/src/runtime/AgentRuntimeLoader.d.ts +47 -0
  115. package/dist/src/runtime/AgentRuntimeLoader.js +122 -0
  116. package/dist/src/runtime/AgentRuntimeLoader.js.map +1 -0
  117. package/dist/src/runtime/AgentRuntimeState.d.ts +232 -0
  118. package/dist/src/runtime/AgentRuntimeState.js +439 -0
  119. package/dist/src/runtime/AgentRuntimeState.js.map +1 -0
  120. package/dist/src/runtime/RuntimeInvocationContext.d.ts +51 -0
  121. package/dist/src/runtime/RuntimeInvocationContext.js +52 -0
  122. package/dist/src/runtime/RuntimeInvocationContext.js.map +1 -0
  123. package/dist/src/runtime/createAgentRuntimeContext.d.ts +7 -0
  124. package/dist/src/runtime/createAgentRuntimeContext.js +58 -0
  125. package/dist/src/runtime/createAgentRuntimeContext.js.map +1 -0
  126. package/dist/src/runtime/index.d.ts +13 -0
  127. package/dist/src/runtime/index.js +14 -0
  128. package/dist/src/runtime/index.js.map +1 -0
  129. package/dist/src/runtime/providerRuntimeContext.d.ts +30 -0
  130. package/dist/src/runtime/providerRuntimeContext.js +70 -0
  131. package/dist/src/runtime/providerRuntimeContext.js.map +1 -0
  132. package/dist/src/runtime/runtimeAdapters.d.ts +22 -0
  133. package/dist/src/runtime/runtimeAdapters.js +81 -0
  134. package/dist/src/runtime/runtimeAdapters.js.map +1 -0
  135. package/dist/src/runtime/runtimeStateFactory.d.ts +21 -0
  136. package/dist/src/runtime/runtimeStateFactory.js +104 -0
  137. package/dist/src/runtime/runtimeStateFactory.js.map +1 -0
  138. package/dist/src/services/history/ContentConverters.js +3 -5
  139. package/dist/src/services/history/ContentConverters.js.map +1 -1
  140. package/dist/src/services/shellExecutionService.js +2 -2
  141. package/dist/src/services/shellExecutionService.js.map +1 -1
  142. package/dist/src/services/todo-context-tracker.d.ts +10 -8
  143. package/dist/src/services/todo-context-tracker.js +26 -10
  144. package/dist/src/services/todo-context-tracker.js.map +1 -1
  145. package/dist/src/services/tool-call-tracker-service.d.ts +11 -7
  146. package/dist/src/services/tool-call-tracker-service.js +89 -29
  147. package/dist/src/services/tool-call-tracker-service.js.map +1 -1
  148. package/dist/src/settings/SettingsService.d.ts +4 -0
  149. package/dist/src/settings/SettingsService.js +58 -2
  150. package/dist/src/settings/SettingsService.js.map +1 -1
  151. package/dist/src/settings/settingsServiceInstance.d.ts +6 -1
  152. package/dist/src/settings/settingsServiceInstance.js +28 -8
  153. package/dist/src/settings/settingsServiceInstance.js.map +1 -1
  154. package/dist/src/telemetry/loggers.d.ts +5 -1
  155. package/dist/src/telemetry/loggers.js.map +1 -1
  156. package/dist/src/telemetry/loggers.test.circular.js +4 -0
  157. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  158. package/dist/src/telemetry/metrics.d.ts +3 -1
  159. package/dist/src/telemetry/metrics.js.map +1 -1
  160. package/dist/src/telemetry/types.d.ts +1 -0
  161. package/dist/src/telemetry/types.js +3 -0
  162. package/dist/src/telemetry/types.js.map +1 -1
  163. package/dist/src/test-utils/index.d.ts +2 -0
  164. package/dist/src/test-utils/index.js +2 -0
  165. package/dist/src/test-utils/index.js.map +1 -1
  166. package/dist/src/test-utils/mockWorkspaceContext.d.ts +0 -3
  167. package/dist/src/test-utils/mockWorkspaceContext.js +3 -4
  168. package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -1
  169. package/dist/src/test-utils/providerCallOptions.d.ts +43 -0
  170. package/dist/src/test-utils/providerCallOptions.js +137 -0
  171. package/dist/src/test-utils/providerCallOptions.js.map +1 -0
  172. package/dist/src/test-utils/runtime.d.ts +92 -0
  173. package/dist/src/test-utils/runtime.js +226 -0
  174. package/dist/src/test-utils/runtime.js.map +1 -0
  175. package/dist/src/test-utils/tools.d.ts +4 -4
  176. package/dist/src/test-utils/tools.js +20 -10
  177. package/dist/src/test-utils/tools.js.map +1 -1
  178. package/dist/src/tools/list-subagents.d.ts +31 -0
  179. package/dist/src/tools/list-subagents.js +109 -0
  180. package/dist/src/tools/list-subagents.js.map +1 -0
  181. package/dist/src/tools/task.d.ts +87 -0
  182. package/dist/src/tools/task.js +427 -0
  183. package/dist/src/tools/task.js.map +1 -0
  184. package/dist/src/tools/todo-read.js +1 -1
  185. package/dist/src/tools/todo-read.js.map +1 -1
  186. package/dist/src/tools/todo-store.js +4 -2
  187. package/dist/src/tools/todo-store.js.map +1 -1
  188. package/dist/src/tools/todo-write.js +4 -2
  189. package/dist/src/tools/todo-write.js.map +1 -1
  190. package/dist/src/tools/tool-error.d.ts +1 -0
  191. package/dist/src/tools/tool-error.js +1 -0
  192. package/dist/src/tools/tool-error.js.map +1 -1
  193. package/dist/src/tools/tool-registry.d.ts +2 -0
  194. package/dist/src/tools/tool-registry.js +46 -21
  195. package/dist/src/tools/tool-registry.js.map +1 -1
  196. package/dist/src/types/modelParams.d.ts +4 -0
  197. package/dist/src/utils/gitIgnoreParser.js +15 -3
  198. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  199. package/dist/src/utils/memoryImportProcessor.js +22 -3
  200. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  201. package/package.json +1 -1
  202. package/dist/src/prompt-config/defaults/providers/anthropic/core.md +0 -97
  203. package/dist/src/prompt-config/defaults/providers/anthropic/tools/glob.md +0 -34
  204. package/dist/src/prompt-config/defaults/providers/anthropic/tools/list-directory.md +0 -11
  205. package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-file.md +0 -14
  206. package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-many-files.md +0 -31
  207. package/dist/src/prompt-config/defaults/providers/anthropic/tools/replace.md +0 -41
  208. package/dist/src/prompt-config/defaults/providers/anthropic/tools/run-shell-command.md +0 -32
  209. package/dist/src/prompt-config/defaults/providers/anthropic/tools/save-memory.md +0 -35
  210. package/dist/src/prompt-config/defaults/providers/anthropic/tools/search-file-content.md +0 -44
  211. package/dist/src/prompt-config/defaults/providers/anthropic/tools/todo-write.md +0 -45
  212. package/dist/src/prompt-config/defaults/providers/anthropic/tools/write-file.md +0 -11
  213. package/dist/src/prompt-config/defaults/providers/openai/core.md +0 -97
  214. package/dist/src/prompt-config/defaults/providers/openai/tools/todo-pause.md +0 -28
  215. package/dist/src/prompt-config/defaults/providers/openai/tools/todo-read.md +0 -5
  216. 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
- logger;
11
- anthropic;
12
- toolFormatter;
13
- toolFormat = 'anthropic';
14
- _cachedAuthKey; // Track cached auth key for client recreation
15
- // Model patterns for max output tokens
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
- this.logger = new DebugLogger('llxprt:anthropic:provider');
39
- const initialApiKey = typeof apiKey === 'string' && apiKey.trim() !== '' ? apiKey : null;
40
- this.anthropic = new Anthropic({
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:PLAN-20250823-AUTHFIXES.P15
57
- * @requirement:REQ-004
58
- * Update the Anthropic client with resolved authentication if needed
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 updateClientWithResolvedAuth() {
61
- const resolvedToken = await this.getAuthToken();
62
- if (!resolvedToken) {
63
- 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.');
64
- }
65
- // Only recreate client if auth changed
66
- if (this._cachedAuthKey !== resolvedToken) {
67
- // Check if this is an OAuth token (starts with sk-ant-oat)
68
- const isOAuthToken = resolvedToken.startsWith('sk-ant-oat');
69
- // Use the unified getBaseURL() method from BaseProvider
70
- const baseURL = this.getBaseURL();
71
- if (isOAuthToken) {
72
- // For OAuth tokens, use authToken field which sends Bearer token
73
- // Don't pass apiKey at all - just authToken
74
- const oauthConfig = {
75
- authToken: resolvedToken, // Use authToken for OAuth Bearer tokens
76
- apiKey: null, // Explicitly disable API key fallback when using OAuth
77
- baseURL,
78
- dangerouslyAllowBrowser: true,
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
- else {
86
- // Regular API key auth
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.logger.debug(() => 'Using hardcoded model list for OAuth authentication');
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: 200000,
164
- maxOutputTokens: 64000,
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: 200000,
172
- maxOutputTokens: 64000,
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 this.anthropic.beta.models.list()) {
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.logger.debug(() => `Failed to fetch Anthropic models: ${error}`);
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
- // Try to get from SettingsService first (source of truth)
249
- try {
250
- const settingsService = getSettingsService();
251
- const providerSettings = settingsService.getProviderSettings(this.name);
252
- if (providerSettings.model) {
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
- for (const { pattern, tokens } of this.modelTokenPatterns) {
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
- * Set model parameters that will be merged into API calls
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
- // Always get from SettingsService
375
- const settingsService = getSettingsService();
376
- const providerSettings = settingsService.getProviderSettings(this.name);
377
- if (!providerSettings) {
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.logger.debug(() => `Failed to detect tool format from SettingsService: ${error}`);
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
- * Generate chat completion with IContent interface
515
- * Convert IContent directly to Anthropic API format
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 *generateChatCompletion(content, tools) {
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
- // TODO: Investigate post-0.2.2 - These shouldn't be truly orphaned since the same
524
- // history works with OpenAI/Cerebras. Likely Anthropic has stricter formatting
525
- // requirements for tool responses that we're not fully meeting yet.
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.logger.debug(() => `Skipping orphaned tool response at beginning of conversation`);
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.logger.debug(() => `Failed to stringify tool result, falling back to string conversion: ${error}`);
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.logger.debug(() => `Failed to parse tool parameters as JSON: ${e}`);
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.logger.debug(() => `Found ${orphanedResults.length} orphaned tool results, removing them`);
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.logger.debug(() => `First message is not from user, adding placeholder user message`);
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 = this.toolFormatter.convertGeminiToFormat(tools, 'anthropic');
738
- const flattenedToolNames = tools?.flatMap((group) => group.functionDeclarations
739
- .map((decl) => decl.name)
740
- .filter((name) => !!name)) ?? [];
741
- const toolNamesArg = tools === undefined ? undefined : Array.from(new Set(flattenedToolNames));
742
- // Ensure authentication
743
- await this.updateClientWithResolvedAuth();
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 = this.getCurrentModel();
752
- // Get the system prompt for non-OAuth mode
753
- const userMemory = this.globalConfig?.getUserMemory
754
- ? this.globalConfig.getUserMemory()
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, toolNamesArg);
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, toolNamesArg)
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
- ...(this.getModelParams() || {}),
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.logger.debug(() => `[AnthropicProvider] Sending tools to API:`, {
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 directly with type assertion
781
+ // Make the API call with retry logic
796
782
  const customHeaders = this.getCustomHeaders();
797
783
  const apiCall = () => customHeaders
798
- ? this.anthropic.messages.create(requestBody, { headers: customHeaders })
799
- : this.anthropic.messages.create(requestBody);
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: chunk.content_block.id,
816
- name: chunk.content_block.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: chunk.delta.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
- currentToolCall.input += chunk.delta.partial_json;
822
+ const jsonDelta = chunk.delta;
823
+ currentToolCall.input += jsonDelta.partial_json;
832
824
  // Check for double-escaping patterns
833
- logDoubleEscapingInChunk(chunk.delta.partial_json, currentToolCall.name, needsQwenParameterProcessing ? 'qwen' : 'anthropic');
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(currentToolCall.input, currentToolCall.name, needsQwenParameterProcessing ? 'qwen' : 'anthropic');
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(currentToolCall.id),
846
- name: currentToolCall.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.logger.debug(() => `Will retry Anthropic request due to status ${status}`);
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.logger.debug(() => 'Will retry Anthropic request due to transient network error signature.');
917
+ this.getLogger().debug(() => 'Will retry Anthropic request due to transient network error signature.');
923
918
  return true;
924
919
  }
925
920
  return false;