converse-mcp-server 2.3.1 → 2.4.1
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/README.md +771 -738
- package/docs/API.md +10 -1
- package/docs/PROVIDERS.md +8 -4
- package/package.json +12 -12
- package/src/async/asyncJobStore.js +82 -52
- package/src/async/eventBus.js +25 -20
- package/src/async/fileCache.js +121 -40
- package/src/async/jobRunner.js +65 -39
- package/src/async/providerStreamNormalizer.js +203 -117
- package/src/config.js +374 -102
- package/src/continuationStore.js +32 -24
- package/src/index.js +45 -25
- package/src/prompts/helpPrompt.js +328 -305
- package/src/providers/anthropic.js +303 -119
- package/src/providers/codex.js +103 -45
- package/src/providers/deepseek.js +24 -8
- package/src/providers/google.js +337 -93
- package/src/providers/index.js +1 -1
- package/src/providers/interface.js +16 -11
- package/src/providers/mistral.js +179 -69
- package/src/providers/openai-compatible.js +231 -94
- package/src/providers/openai.js +1094 -914
- package/src/providers/openrouter-endpoints-client.js +220 -216
- package/src/providers/openrouter.js +426 -381
- package/src/providers/xai.js +153 -56
- package/src/resources/helpResource.js +70 -67
- package/src/router.js +95 -67
- package/src/services/summarizationService.js +51 -24
- package/src/systemPrompts.js +89 -89
- package/src/tools/cancelJob.js +31 -19
- package/src/tools/chat.js +997 -883
- package/src/tools/checkStatus.js +86 -65
- package/src/tools/consensus.js +400 -234
- package/src/tools/index.js +39 -16
- package/src/transport/httpTransport.js +82 -55
- package/src/utils/contextProcessor.js +54 -37
- package/src/utils/errorHandler.js +95 -45
- package/src/utils/fileValidator.js +107 -98
- package/src/utils/formatStatus.js +122 -64
- package/src/utils/logger.js +459 -449
- package/src/utils/pathUtils.js +2 -2
- package/src/utils/tokenLimiter.js +216 -216
|
@@ -26,8 +26,23 @@ const SUPPORTED_MODELS = {
|
|
|
26
26
|
minThinkingTokens: 1024,
|
|
27
27
|
maxThinkingTokens: 32000,
|
|
28
28
|
timeout: 300000,
|
|
29
|
-
description:
|
|
30
|
-
|
|
29
|
+
description:
|
|
30
|
+
'Claude Opus 4.1 - Highest level of intelligence and capability with extended thinking',
|
|
31
|
+
aliases: [
|
|
32
|
+
'claude-opus-4-1',
|
|
33
|
+
'claude-4.1-opus',
|
|
34
|
+
'claude-4-1-opus',
|
|
35
|
+
'opus-4.1',
|
|
36
|
+
'opus-4-1',
|
|
37
|
+
'claude-4-opus',
|
|
38
|
+
'opus-4',
|
|
39
|
+
'opus',
|
|
40
|
+
'claude-opus',
|
|
41
|
+
'claude-opus-4',
|
|
42
|
+
'opus4',
|
|
43
|
+
'opus4.1',
|
|
44
|
+
'claude-opus-4.1',
|
|
45
|
+
],
|
|
31
46
|
},
|
|
32
47
|
'claude-sonnet-4-5-20250929': {
|
|
33
48
|
modelName: 'claude-sonnet-4-5-20250929',
|
|
@@ -43,8 +58,17 @@ const SUPPORTED_MODELS = {
|
|
|
43
58
|
maxThinkingTokens: 64000,
|
|
44
59
|
timeout: 300000,
|
|
45
60
|
supports1MContext: true, // Beta 1M context support
|
|
46
|
-
description:
|
|
47
|
-
|
|
61
|
+
description:
|
|
62
|
+
'Claude Sonnet 4.5 - Latest Sonnet with enhanced intelligence and optional 1M context',
|
|
63
|
+
aliases: [
|
|
64
|
+
'claude-4.5-sonnet',
|
|
65
|
+
'sonnet-4.5',
|
|
66
|
+
'claude-sonnet-4.5',
|
|
67
|
+
'sonnet4.5',
|
|
68
|
+
'claude-sonnet-4-5',
|
|
69
|
+
'sonnet',
|
|
70
|
+
'claude-sonnet',
|
|
71
|
+
],
|
|
48
72
|
},
|
|
49
73
|
'claude-sonnet-4-20250514': {
|
|
50
74
|
modelName: 'claude-sonnet-4-20250514',
|
|
@@ -60,8 +84,9 @@ const SUPPORTED_MODELS = {
|
|
|
60
84
|
maxThinkingTokens: 64000,
|
|
61
85
|
timeout: 300000,
|
|
62
86
|
supports1MContext: true, // Beta 1M context support
|
|
63
|
-
description:
|
|
64
|
-
|
|
87
|
+
description:
|
|
88
|
+
'Claude Sonnet 4 - High intelligence and balanced performance with extended thinking',
|
|
89
|
+
aliases: ['claude-4-sonnet', 'sonnet-4', 'claude-sonnet-4', 'sonnet4'],
|
|
65
90
|
},
|
|
66
91
|
'claude-3-7-sonnet-20250219': {
|
|
67
92
|
modelName: 'claude-3-7-sonnet-20250219',
|
|
@@ -77,7 +102,13 @@ const SUPPORTED_MODELS = {
|
|
|
77
102
|
maxThinkingTokens: 64000,
|
|
78
103
|
timeout: 300000,
|
|
79
104
|
description: 'Claude 3.7 Sonnet - Enhanced 3.x generation with thinking',
|
|
80
|
-
aliases: [
|
|
105
|
+
aliases: [
|
|
106
|
+
'claude-3.7-sonnet',
|
|
107
|
+
'sonnet-3.7',
|
|
108
|
+
'claude-3-7-sonnet',
|
|
109
|
+
'claude 3.7 sonnet',
|
|
110
|
+
'sonnet 3.7',
|
|
111
|
+
],
|
|
81
112
|
},
|
|
82
113
|
'claude-haiku-4-5-20251001': {
|
|
83
114
|
modelName: 'claude-haiku-4-5-20251001',
|
|
@@ -92,8 +123,20 @@ const SUPPORTED_MODELS = {
|
|
|
92
123
|
minThinkingTokens: 1024,
|
|
93
124
|
maxThinkingTokens: 64000,
|
|
94
125
|
timeout: 300000,
|
|
95
|
-
description:
|
|
96
|
-
|
|
126
|
+
description:
|
|
127
|
+
'Claude Haiku 4.5 - Fast and intelligent model with extended thinking',
|
|
128
|
+
aliases: [
|
|
129
|
+
'claude-haiku-4-5',
|
|
130
|
+
'claude-4.5-haiku',
|
|
131
|
+
'claude-4-5-haiku',
|
|
132
|
+
'haiku-4.5',
|
|
133
|
+
'haiku-4-5',
|
|
134
|
+
'claude-haiku-4.5',
|
|
135
|
+
'haiku4.5',
|
|
136
|
+
'claude-haiku-4',
|
|
137
|
+
'haiku',
|
|
138
|
+
'claude-haiku',
|
|
139
|
+
],
|
|
97
140
|
},
|
|
98
141
|
'claude-3-5-sonnet-20241022': {
|
|
99
142
|
modelName: 'claude-3-5-sonnet-20241022',
|
|
@@ -107,7 +150,14 @@ const SUPPORTED_MODELS = {
|
|
|
107
150
|
supportsThinking: false,
|
|
108
151
|
timeout: 300000,
|
|
109
152
|
description: 'Claude 3.5 Sonnet - Fast and intelligent model',
|
|
110
|
-
aliases: [
|
|
153
|
+
aliases: [
|
|
154
|
+
'claude-3.5-sonnet',
|
|
155
|
+
'claude-3-5-sonnet-latest',
|
|
156
|
+
'claude-sonnet-3.5',
|
|
157
|
+
'sonnet-3.5',
|
|
158
|
+
'claude 3.5 sonnet',
|
|
159
|
+
'sonnet 3.5',
|
|
160
|
+
],
|
|
111
161
|
},
|
|
112
162
|
'claude-3-5-haiku-20241022': {
|
|
113
163
|
modelName: 'claude-3-5-haiku-20241022',
|
|
@@ -121,29 +171,35 @@ const SUPPORTED_MODELS = {
|
|
|
121
171
|
supportsThinking: false,
|
|
122
172
|
timeout: 180000,
|
|
123
173
|
description: 'Claude 3.5 Haiku - Fastest model, best for simple queries',
|
|
124
|
-
aliases: [
|
|
125
|
-
|
|
174
|
+
aliases: [
|
|
175
|
+
'claude-3.5-haiku',
|
|
176
|
+
'claude-3-5-haiku-latest',
|
|
177
|
+
'haiku-3.5',
|
|
178
|
+
'claude 3.5 haiku',
|
|
179
|
+
'haiku 3.5',
|
|
180
|
+
],
|
|
181
|
+
},
|
|
126
182
|
};
|
|
127
183
|
|
|
128
184
|
/**
|
|
129
185
|
* Map Anthropic stop reasons to unified format
|
|
130
186
|
*/
|
|
131
187
|
const STOP_REASON_MAP = {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
188
|
+
end_turn: StopReasons.STOP,
|
|
189
|
+
max_tokens: StopReasons.LENGTH,
|
|
190
|
+
stop_sequence: StopReasons.STOP,
|
|
191
|
+
tool_use: StopReasons.TOOL_USE,
|
|
136
192
|
};
|
|
137
193
|
|
|
138
194
|
/**
|
|
139
195
|
* Thinking budget percentages mapped to reasoning_effort
|
|
140
196
|
*/
|
|
141
197
|
const THINKING_BUDGETS = {
|
|
142
|
-
minimal: 0.05,
|
|
143
|
-
low: 0.15,
|
|
144
|
-
medium: 0.33,
|
|
145
|
-
high: 0.67,
|
|
146
|
-
max: 1.0
|
|
198
|
+
minimal: 0.05, // 5% of max thinking tokens
|
|
199
|
+
low: 0.15, // 15% of max thinking tokens
|
|
200
|
+
medium: 0.33, // 33% of max thinking tokens (default)
|
|
201
|
+
high: 0.67, // 67% of max thinking tokens
|
|
202
|
+
max: 1.0, // 100% of max thinking tokens
|
|
147
203
|
};
|
|
148
204
|
|
|
149
205
|
/**
|
|
@@ -206,13 +262,16 @@ function validateApiKey(apiKey) {
|
|
|
206
262
|
*/
|
|
207
263
|
function convertMessagesToAnthropic(messages, options = {}) {
|
|
208
264
|
if (!Array.isArray(messages)) {
|
|
209
|
-
throw new AnthropicProviderError(
|
|
265
|
+
throw new AnthropicProviderError(
|
|
266
|
+
'Messages must be an array',
|
|
267
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
268
|
+
);
|
|
210
269
|
}
|
|
211
270
|
|
|
212
271
|
const {
|
|
213
272
|
enableSystemCache = true, // Always cache system messages by default
|
|
214
273
|
cacheUserMessages = false,
|
|
215
|
-
cacheMessageThreshold = 5 // Cache messages after this many turns
|
|
274
|
+
cacheMessageThreshold = 5, // Cache messages after this many turns
|
|
216
275
|
} = options;
|
|
217
276
|
const systemContent = [];
|
|
218
277
|
let systemText = '';
|
|
@@ -220,17 +279,26 @@ function convertMessagesToAnthropic(messages, options = {}) {
|
|
|
220
279
|
|
|
221
280
|
for (const [index, msg] of messages.entries()) {
|
|
222
281
|
if (!msg || typeof msg !== 'object') {
|
|
223
|
-
throw new AnthropicProviderError(
|
|
282
|
+
throw new AnthropicProviderError(
|
|
283
|
+
`Message at index ${index} must be an object`,
|
|
284
|
+
ErrorCodes.INVALID_MESSAGE,
|
|
285
|
+
);
|
|
224
286
|
}
|
|
225
287
|
|
|
226
288
|
const { role, content } = msg;
|
|
227
289
|
|
|
228
290
|
if (!role || !['system', 'user', 'assistant'].includes(role)) {
|
|
229
|
-
throw new AnthropicProviderError(
|
|
291
|
+
throw new AnthropicProviderError(
|
|
292
|
+
`Invalid role "${role}" at message index ${index}`,
|
|
293
|
+
ErrorCodes.INVALID_ROLE,
|
|
294
|
+
);
|
|
230
295
|
}
|
|
231
296
|
|
|
232
297
|
if (!content) {
|
|
233
|
-
throw new AnthropicProviderError(
|
|
298
|
+
throw new AnthropicProviderError(
|
|
299
|
+
`Message content is required at index ${index}`,
|
|
300
|
+
ErrorCodes.MISSING_CONTENT,
|
|
301
|
+
);
|
|
234
302
|
}
|
|
235
303
|
|
|
236
304
|
if (role === 'system') {
|
|
@@ -245,7 +313,7 @@ function convertMessagesToAnthropic(messages, options = {}) {
|
|
|
245
313
|
if (item.type === 'text') {
|
|
246
314
|
anthropicContent.push({
|
|
247
315
|
type: 'text',
|
|
248
|
-
text: item.text
|
|
316
|
+
text: item.text,
|
|
249
317
|
});
|
|
250
318
|
} else if (item.type === 'image' && item.source) {
|
|
251
319
|
// Content is already in Anthropic format
|
|
@@ -254,22 +322,24 @@ function convertMessagesToAnthropic(messages, options = {}) {
|
|
|
254
322
|
source: {
|
|
255
323
|
type: 'base64',
|
|
256
324
|
media_type: item.source.media_type,
|
|
257
|
-
data: item.source.data
|
|
258
|
-
}
|
|
325
|
+
data: item.source.data,
|
|
326
|
+
},
|
|
259
327
|
});
|
|
260
|
-
debugLog(
|
|
328
|
+
debugLog(
|
|
329
|
+
`[Anthropic] Processing image: ${item.source.media_type}, data length: ${item.source.data.length}`,
|
|
330
|
+
);
|
|
261
331
|
}
|
|
262
332
|
}
|
|
263
333
|
|
|
264
334
|
anthropicMessages.push({
|
|
265
335
|
role,
|
|
266
|
-
content: anthropicContent
|
|
336
|
+
content: anthropicContent,
|
|
267
337
|
});
|
|
268
338
|
} else {
|
|
269
339
|
// Simple string content
|
|
270
340
|
anthropicMessages.push({
|
|
271
341
|
role,
|
|
272
|
-
content
|
|
342
|
+
content,
|
|
273
343
|
});
|
|
274
344
|
}
|
|
275
345
|
}
|
|
@@ -277,7 +347,10 @@ function convertMessagesToAnthropic(messages, options = {}) {
|
|
|
277
347
|
|
|
278
348
|
// Ensure first message is from user
|
|
279
349
|
if (anthropicMessages.length > 0 && anthropicMessages[0].role !== 'user') {
|
|
280
|
-
throw new AnthropicProviderError(
|
|
350
|
+
throw new AnthropicProviderError(
|
|
351
|
+
'First message must be from user role',
|
|
352
|
+
ErrorCodes.INVALID_MESSAGE,
|
|
353
|
+
);
|
|
281
354
|
}
|
|
282
355
|
|
|
283
356
|
// Ensure messages alternate between user and assistant
|
|
@@ -288,7 +361,7 @@ function convertMessagesToAnthropic(messages, options = {}) {
|
|
|
288
361
|
if (prevRole === currRole) {
|
|
289
362
|
throw new AnthropicProviderError(
|
|
290
363
|
`Messages must alternate between user and assistant. Found consecutive ${currRole} messages at index ${i}`,
|
|
291
|
-
ErrorCodes.INVALID_MESSAGE
|
|
364
|
+
ErrorCodes.INVALID_MESSAGE,
|
|
292
365
|
);
|
|
293
366
|
}
|
|
294
367
|
}
|
|
@@ -298,15 +371,19 @@ function convertMessagesToAnthropic(messages, options = {}) {
|
|
|
298
371
|
if (systemText) {
|
|
299
372
|
if (enableSystemCache) {
|
|
300
373
|
// Use array format with cache control for system prompt
|
|
301
|
-
systemResult = [
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
374
|
+
systemResult = [
|
|
375
|
+
{
|
|
376
|
+
type: 'text',
|
|
377
|
+
text: systemText,
|
|
378
|
+
cache_control: {
|
|
379
|
+
type: 'ephemeral',
|
|
380
|
+
ttl: '1h', // 1 hour cache duration
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
];
|
|
384
|
+
debugLog(
|
|
385
|
+
`[Anthropic] System prompt caching enabled (ephemeral with ttl-extender for 1 hour) - ${systemText.length} chars`,
|
|
386
|
+
);
|
|
310
387
|
} else {
|
|
311
388
|
// Use simple string format without caching
|
|
312
389
|
systemResult = systemText;
|
|
@@ -343,7 +420,7 @@ async function getAnthropicSDK() {
|
|
|
343
420
|
throw new AnthropicProviderError(
|
|
344
421
|
'Failed to load Anthropic SDK. Please install @anthropic-ai/sdk',
|
|
345
422
|
ErrorCodes.API_ERROR,
|
|
346
|
-
error
|
|
423
|
+
error,
|
|
347
424
|
);
|
|
348
425
|
}
|
|
349
426
|
}
|
|
@@ -377,11 +454,17 @@ export const anthropicProvider = {
|
|
|
377
454
|
|
|
378
455
|
// Validate API key
|
|
379
456
|
if (!config?.apiKeys?.anthropic) {
|
|
380
|
-
throw new AnthropicProviderError(
|
|
457
|
+
throw new AnthropicProviderError(
|
|
458
|
+
'Anthropic API key not configured',
|
|
459
|
+
ErrorCodes.MISSING_API_KEY,
|
|
460
|
+
);
|
|
381
461
|
}
|
|
382
462
|
|
|
383
463
|
if (!validateApiKey(config.apiKeys.anthropic)) {
|
|
384
|
-
throw new AnthropicProviderError(
|
|
464
|
+
throw new AnthropicProviderError(
|
|
465
|
+
'Invalid Anthropic API key format',
|
|
466
|
+
ErrorCodes.INVALID_API_KEY,
|
|
467
|
+
);
|
|
385
468
|
}
|
|
386
469
|
|
|
387
470
|
// Get Anthropic SDK
|
|
@@ -395,21 +478,27 @@ export const anthropicProvider = {
|
|
|
395
478
|
const anthropic = new Anthropic({
|
|
396
479
|
apiKey: config.apiKeys.anthropic,
|
|
397
480
|
// Increase timeout to 20 minutes for thinking models that may take longer
|
|
398
|
-
timeout: 20 * 60 * 1000
|
|
481
|
+
timeout: 20 * 60 * 1000,
|
|
399
482
|
});
|
|
400
483
|
|
|
401
484
|
// Build beta features array for the request
|
|
402
485
|
// Use both prompt caching and extended cache duration for 1-hour caching
|
|
403
|
-
const betas = [
|
|
486
|
+
const betas = [
|
|
487
|
+
'prompt-caching-2024-07-31',
|
|
488
|
+
'extended-cache-ttl-2025-04-11',
|
|
489
|
+
];
|
|
404
490
|
|
|
405
491
|
// Add 1M context beta feature if model supports it
|
|
406
492
|
if (modelConfig.supports1MContext) {
|
|
407
493
|
betas.push('context-1m-2025-08-07');
|
|
408
|
-
debugLog(
|
|
494
|
+
debugLog(
|
|
495
|
+
`[Anthropic] Model ${resolvedModel} supports 1M context window with beta feature`,
|
|
496
|
+
);
|
|
409
497
|
}
|
|
410
498
|
|
|
411
499
|
// Convert messages to Anthropic format (system messages are always cached)
|
|
412
|
-
const { systemPrompt, messages: anthropicMessages } =
|
|
500
|
+
const { systemPrompt, messages: anthropicMessages } =
|
|
501
|
+
convertMessagesToAnthropic(messages);
|
|
413
502
|
|
|
414
503
|
// Build request payload
|
|
415
504
|
const requestPayload = {
|
|
@@ -417,7 +506,7 @@ export const anthropicProvider = {
|
|
|
417
506
|
messages: anthropicMessages,
|
|
418
507
|
stream,
|
|
419
508
|
betas, // Include beta features
|
|
420
|
-
...otherOptions
|
|
509
|
+
...otherOptions,
|
|
421
510
|
};
|
|
422
511
|
|
|
423
512
|
// Add system prompt if present
|
|
@@ -427,7 +516,10 @@ export const anthropicProvider = {
|
|
|
427
516
|
|
|
428
517
|
// Set max tokens - API requires this field
|
|
429
518
|
if (maxTokens) {
|
|
430
|
-
requestPayload.max_tokens = Math.min(
|
|
519
|
+
requestPayload.max_tokens = Math.min(
|
|
520
|
+
maxTokens,
|
|
521
|
+
modelConfig.maxOutputTokens || 8192,
|
|
522
|
+
);
|
|
431
523
|
} else {
|
|
432
524
|
// Use model's default max output tokens
|
|
433
525
|
requestPayload.max_tokens = modelConfig.maxOutputTokens || 8192;
|
|
@@ -435,26 +527,39 @@ export const anthropicProvider = {
|
|
|
435
527
|
|
|
436
528
|
// Add thinking configuration for models that support it
|
|
437
529
|
if (modelConfig.supportsThinking && reasoning_effort) {
|
|
438
|
-
const thinkingBudget = calculateThinkingBudget(
|
|
439
|
-
|
|
530
|
+
const thinkingBudget = calculateThinkingBudget(
|
|
531
|
+
modelConfig,
|
|
532
|
+
reasoning_effort,
|
|
533
|
+
);
|
|
534
|
+
debugLog(
|
|
535
|
+
`[Anthropic] Model ${resolvedModel}: maxOutputTokens=${modelConfig.maxOutputTokens}, maxThinkingTokens=${modelConfig.maxThinkingTokens}, thinkingBudget=${thinkingBudget}`,
|
|
536
|
+
);
|
|
440
537
|
|
|
441
538
|
// For 4 series models, we trust the SDK defaults work with thinking
|
|
442
539
|
// For other models, check against max_tokens if set
|
|
443
|
-
const maxTokensLimit =
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
540
|
+
const maxTokensLimit =
|
|
541
|
+
requestPayload.max_tokens ||
|
|
542
|
+
(resolvedModel.includes('claude-opus-4')
|
|
543
|
+
? 32000
|
|
544
|
+
: resolvedModel.includes('claude-sonnet-4-5') ||
|
|
545
|
+
resolvedModel.includes('claude-sonnet-4')
|
|
546
|
+
? 64000
|
|
547
|
+
: modelConfig.maxOutputTokens);
|
|
447
548
|
|
|
448
549
|
if (thinkingBudget > 0 && thinkingBudget < maxTokensLimit) {
|
|
449
550
|
// According to Anthropic docs: thinking tokens count towards max_tokens limit
|
|
450
551
|
// thinking.budget_tokens must be >= 1024 and < max_tokens
|
|
451
552
|
requestPayload.thinking = {
|
|
452
553
|
type: 'enabled',
|
|
453
|
-
budget_tokens: thinkingBudget
|
|
554
|
+
budget_tokens: thinkingBudget,
|
|
454
555
|
};
|
|
455
|
-
debugLog(
|
|
556
|
+
debugLog(
|
|
557
|
+
`[Anthropic] Thinking enabled with budget: ${thinkingBudget} tokens (${reasoning_effort} effort)`,
|
|
558
|
+
);
|
|
456
559
|
} else {
|
|
457
|
-
debugLog(
|
|
560
|
+
debugLog(
|
|
561
|
+
`[Anthropic] Thinking not enabled: budget ${thinkingBudget} must be < max_tokens limit ${maxTokensLimit}`,
|
|
562
|
+
);
|
|
458
563
|
}
|
|
459
564
|
}
|
|
460
565
|
|
|
@@ -471,28 +576,49 @@ export const anthropicProvider = {
|
|
|
471
576
|
|
|
472
577
|
// If streaming is requested and model doesn't support it, fall back to non-streaming
|
|
473
578
|
if (stream && modelConfig.supportsStreaming === false) {
|
|
474
|
-
debugLog(
|
|
579
|
+
debugLog(
|
|
580
|
+
`[Anthropic] Model ${resolvedModel} doesn't support streaming, falling back to non-streaming mode`,
|
|
581
|
+
);
|
|
475
582
|
requestPayload.stream = false;
|
|
476
583
|
}
|
|
477
584
|
|
|
478
585
|
// Handle streaming requests
|
|
479
586
|
if (stream && requestPayload.stream !== false) {
|
|
480
|
-
return this._createStreamingGenerator(
|
|
587
|
+
return this._createStreamingGenerator(
|
|
588
|
+
anthropic,
|
|
589
|
+
requestPayload,
|
|
590
|
+
resolvedModel,
|
|
591
|
+
modelConfig,
|
|
592
|
+
reasoning_effort,
|
|
593
|
+
);
|
|
481
594
|
}
|
|
482
595
|
|
|
483
596
|
try {
|
|
484
|
-
debugLog(
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
597
|
+
debugLog(
|
|
598
|
+
`[Anthropic] Calling ${resolvedModel} with ${anthropicMessages.length} messages`,
|
|
599
|
+
);
|
|
600
|
+
debugLog(
|
|
601
|
+
'[Anthropic] Request payload:',
|
|
602
|
+
JSON.stringify(
|
|
603
|
+
{
|
|
604
|
+
model: requestPayload.model,
|
|
605
|
+
max_tokens: requestPayload.max_tokens,
|
|
606
|
+
thinking: requestPayload.thinking,
|
|
607
|
+
temperature: requestPayload.temperature,
|
|
608
|
+
betas: requestPayload.betas,
|
|
609
|
+
message_count: requestPayload.messages?.length,
|
|
610
|
+
system_length: Array.isArray(requestPayload.system)
|
|
611
|
+
? requestPayload.system[0]?.text?.length
|
|
612
|
+
: requestPayload.system?.length,
|
|
613
|
+
},
|
|
614
|
+
null,
|
|
615
|
+
2,
|
|
616
|
+
),
|
|
617
|
+
);
|
|
494
618
|
if (systemPrompt) {
|
|
495
|
-
debugLog(
|
|
619
|
+
debugLog(
|
|
620
|
+
`[Anthropic] System prompt length: ${systemPrompt.length} characters`,
|
|
621
|
+
);
|
|
496
622
|
}
|
|
497
623
|
|
|
498
624
|
const startTime = Date.now();
|
|
@@ -519,11 +645,15 @@ export const anthropicProvider = {
|
|
|
519
645
|
}
|
|
520
646
|
|
|
521
647
|
if (!content) {
|
|
522
|
-
throw new AnthropicProviderError(
|
|
648
|
+
throw new AnthropicProviderError(
|
|
649
|
+
'No content in response from Anthropic',
|
|
650
|
+
ErrorCodes.NO_RESPONSE_CONTENT,
|
|
651
|
+
);
|
|
523
652
|
}
|
|
524
653
|
|
|
525
654
|
// Map stop reason
|
|
526
|
-
const stopReason =
|
|
655
|
+
const stopReason =
|
|
656
|
+
STOP_REASON_MAP[response.stop_reason] || StopReasons.OTHER;
|
|
527
657
|
|
|
528
658
|
// Extract usage information
|
|
529
659
|
const usage = response.usage || {};
|
|
@@ -538,18 +668,20 @@ export const anthropicProvider = {
|
|
|
538
668
|
usage: {
|
|
539
669
|
input_tokens: usage.input_tokens || 0,
|
|
540
670
|
output_tokens: usage.output_tokens || 0,
|
|
541
|
-
total_tokens:
|
|
671
|
+
total_tokens:
|
|
672
|
+
(usage.input_tokens || 0) + (usage.output_tokens || 0),
|
|
542
673
|
thinking_tokens: usage.thinking_input_tokens || 0,
|
|
543
674
|
cache_creation_input_tokens: usage.cache_creation_input_tokens || 0,
|
|
544
|
-
cache_read_input_tokens: usage.cache_read_input_tokens || 0
|
|
675
|
+
cache_read_input_tokens: usage.cache_read_input_tokens || 0,
|
|
545
676
|
},
|
|
546
677
|
response_time_ms: responseTime,
|
|
547
678
|
finish_reason: response.stop_reason,
|
|
548
679
|
provider: 'anthropic',
|
|
549
|
-
reasoning_effort: modelConfig.supportsThinking
|
|
550
|
-
|
|
680
|
+
reasoning_effort: modelConfig.supportsThinking
|
|
681
|
+
? reasoning_effort
|
|
682
|
+
: null,
|
|
683
|
+
},
|
|
551
684
|
};
|
|
552
|
-
|
|
553
685
|
} catch (error) {
|
|
554
686
|
debugError('[Anthropic] Error during API call:', error);
|
|
555
687
|
|
|
@@ -560,28 +692,55 @@ export const anthropicProvider = {
|
|
|
560
692
|
|
|
561
693
|
// Handle specific Anthropic errors
|
|
562
694
|
if (error.status === 401) {
|
|
563
|
-
throw new AnthropicProviderError(
|
|
695
|
+
throw new AnthropicProviderError(
|
|
696
|
+
'Invalid Anthropic API key',
|
|
697
|
+
ErrorCodes.INVALID_API_KEY,
|
|
698
|
+
error,
|
|
699
|
+
);
|
|
564
700
|
} else if (error.status === 429) {
|
|
565
|
-
throw new AnthropicProviderError(
|
|
701
|
+
throw new AnthropicProviderError(
|
|
702
|
+
'Anthropic rate limit exceeded',
|
|
703
|
+
ErrorCodes.RATE_LIMIT_EXCEEDED,
|
|
704
|
+
error,
|
|
705
|
+
);
|
|
566
706
|
} else if (error.status === 403) {
|
|
567
|
-
throw new AnthropicProviderError(
|
|
707
|
+
throw new AnthropicProviderError(
|
|
708
|
+
'Anthropic API quota exceeded or forbidden',
|
|
709
|
+
ErrorCodes.QUOTA_EXCEEDED,
|
|
710
|
+
error,
|
|
711
|
+
);
|
|
568
712
|
} else if (error.error?.type === 'invalid_request_error') {
|
|
569
|
-
throw new AnthropicProviderError(
|
|
713
|
+
throw new AnthropicProviderError(
|
|
714
|
+
`Invalid request: ${error.error.message}`,
|
|
715
|
+
ErrorCodes.INVALID_REQUEST,
|
|
716
|
+
error,
|
|
717
|
+
);
|
|
570
718
|
} else if (error.error?.type === 'not_found_error') {
|
|
571
|
-
throw new AnthropicProviderError(
|
|
572
|
-
|
|
573
|
-
|
|
719
|
+
throw new AnthropicProviderError(
|
|
720
|
+
`Model ${resolvedModel} not found`,
|
|
721
|
+
ErrorCodes.MODEL_NOT_FOUND,
|
|
722
|
+
error,
|
|
723
|
+
);
|
|
724
|
+
} else if (
|
|
725
|
+
error.message?.includes('context length') ||
|
|
726
|
+
error.message?.includes('context_length') ||
|
|
727
|
+
(error.message?.includes('token') && error.message?.includes('limit'))
|
|
728
|
+
) {
|
|
574
729
|
debugError('[Anthropic] Context length error - Full error:', error);
|
|
575
730
|
debugError('[Anthropic] Error message:', error.message);
|
|
576
731
|
debugError('[Anthropic] Error response:', error.response);
|
|
577
|
-
throw new AnthropicProviderError(
|
|
732
|
+
throw new AnthropicProviderError(
|
|
733
|
+
`Context length exceeded for model: ${error.message}`,
|
|
734
|
+
ErrorCodes.CONTEXT_LENGTH_EXCEEDED,
|
|
735
|
+
error,
|
|
736
|
+
);
|
|
578
737
|
}
|
|
579
738
|
|
|
580
739
|
// Generic error handling
|
|
581
740
|
throw new AnthropicProviderError(
|
|
582
741
|
`Anthropic API error: ${error.message || 'Unknown error'}`,
|
|
583
742
|
ErrorCodes.API_ERROR,
|
|
584
|
-
error
|
|
743
|
+
error,
|
|
585
744
|
);
|
|
586
745
|
}
|
|
587
746
|
},
|
|
@@ -596,8 +755,16 @@ export const anthropicProvider = {
|
|
|
596
755
|
* @param {string} reasoning_effort - Reasoning effort level
|
|
597
756
|
* @returns {AsyncGenerator} - Async generator yielding streaming events
|
|
598
757
|
*/
|
|
599
|
-
async *_createStreamingGenerator(
|
|
600
|
-
|
|
758
|
+
async *_createStreamingGenerator(
|
|
759
|
+
anthropic,
|
|
760
|
+
requestPayload,
|
|
761
|
+
resolvedModel,
|
|
762
|
+
modelConfig,
|
|
763
|
+
reasoning_effort,
|
|
764
|
+
) {
|
|
765
|
+
debugLog(
|
|
766
|
+
`[Anthropic] Starting streaming for ${resolvedModel} with ${requestPayload.messages?.length} messages`,
|
|
767
|
+
);
|
|
601
768
|
|
|
602
769
|
const startTime = Date.now();
|
|
603
770
|
let totalContent = '';
|
|
@@ -612,7 +779,7 @@ export const anthropicProvider = {
|
|
|
612
779
|
timestamp: new Date().toISOString(),
|
|
613
780
|
model: resolvedModel,
|
|
614
781
|
provider: 'anthropic',
|
|
615
|
-
thinking_mode: modelConfig.supportsThinking && !!reasoning_effort
|
|
782
|
+
thinking_mode: modelConfig.supportsThinking && !!reasoning_effort,
|
|
616
783
|
};
|
|
617
784
|
|
|
618
785
|
// Enable streaming in request payload
|
|
@@ -634,7 +801,9 @@ export const anthropicProvider = {
|
|
|
634
801
|
|
|
635
802
|
case 'content_block_start':
|
|
636
803
|
// Content block started (text, thinking, etc.)
|
|
637
|
-
debugLog(
|
|
804
|
+
debugLog(
|
|
805
|
+
`[Anthropic] Content block started: ${event.content_block?.type}`,
|
|
806
|
+
);
|
|
638
807
|
break;
|
|
639
808
|
|
|
640
809
|
case 'content_block_delta':
|
|
@@ -646,7 +815,7 @@ export const anthropicProvider = {
|
|
|
646
815
|
yield {
|
|
647
816
|
type: 'delta',
|
|
648
817
|
content,
|
|
649
|
-
timestamp: new Date().toISOString()
|
|
818
|
+
timestamp: new Date().toISOString(),
|
|
650
819
|
};
|
|
651
820
|
}
|
|
652
821
|
} else if (event.delta?.type === 'thinking_delta') {
|
|
@@ -655,14 +824,18 @@ export const anthropicProvider = {
|
|
|
655
824
|
if (thinking) {
|
|
656
825
|
thinkingContent += thinking;
|
|
657
826
|
// Optionally yield thinking deltas for debugging
|
|
658
|
-
debugLog(
|
|
827
|
+
debugLog(
|
|
828
|
+
`[Anthropic] Thinking delta: ${thinking.substring(0, 100)}...`,
|
|
829
|
+
);
|
|
659
830
|
}
|
|
660
831
|
}
|
|
661
832
|
break;
|
|
662
833
|
|
|
663
834
|
case 'content_block_stop':
|
|
664
835
|
// Content block completed
|
|
665
|
-
debugLog(
|
|
836
|
+
debugLog(
|
|
837
|
+
`[Anthropic] Content block stopped at index ${event.index}`,
|
|
838
|
+
);
|
|
666
839
|
break;
|
|
667
840
|
|
|
668
841
|
case 'message_delta':
|
|
@@ -689,11 +862,13 @@ export const anthropicProvider = {
|
|
|
689
862
|
throw new AnthropicProviderError(
|
|
690
863
|
`Streaming error: ${event.error?.message || 'Unknown streaming error'}`,
|
|
691
864
|
ErrorCodes.API_ERROR,
|
|
692
|
-
event.error
|
|
865
|
+
event.error,
|
|
693
866
|
);
|
|
694
867
|
|
|
695
868
|
default:
|
|
696
|
-
debugLog(
|
|
869
|
+
debugLog(
|
|
870
|
+
`[Anthropic] Unknown streaming event type: ${event.type}`,
|
|
871
|
+
);
|
|
697
872
|
break;
|
|
698
873
|
}
|
|
699
874
|
} catch (eventError) {
|
|
@@ -703,9 +878,9 @@ export const anthropicProvider = {
|
|
|
703
878
|
error: {
|
|
704
879
|
message: `Event processing error: ${eventError.message}`,
|
|
705
880
|
code: 'EVENT_PROCESSING_ERROR',
|
|
706
|
-
recoverable: true
|
|
881
|
+
recoverable: true,
|
|
707
882
|
},
|
|
708
|
-
timestamp: new Date().toISOString()
|
|
883
|
+
timestamp: new Date().toISOString(),
|
|
709
884
|
};
|
|
710
885
|
}
|
|
711
886
|
}
|
|
@@ -720,12 +895,14 @@ export const anthropicProvider = {
|
|
|
720
895
|
usage: {
|
|
721
896
|
input_tokens: lastUsage.input_tokens || 0,
|
|
722
897
|
output_tokens: lastUsage.output_tokens || 0,
|
|
723
|
-
total_tokens:
|
|
898
|
+
total_tokens:
|
|
899
|
+
(lastUsage.input_tokens || 0) + (lastUsage.output_tokens || 0),
|
|
724
900
|
thinking_tokens: lastUsage.thinking_input_tokens || 0,
|
|
725
|
-
cache_creation_input_tokens:
|
|
726
|
-
|
|
901
|
+
cache_creation_input_tokens:
|
|
902
|
+
lastUsage.cache_creation_input_tokens || 0,
|
|
903
|
+
cache_read_input_tokens: lastUsage.cache_read_input_tokens || 0,
|
|
727
904
|
},
|
|
728
|
-
timestamp: new Date().toISOString()
|
|
905
|
+
timestamp: new Date().toISOString(),
|
|
729
906
|
};
|
|
730
907
|
}
|
|
731
908
|
|
|
@@ -739,20 +916,23 @@ export const anthropicProvider = {
|
|
|
739
916
|
usage: {
|
|
740
917
|
input_tokens: lastUsage?.input_tokens || 0,
|
|
741
918
|
output_tokens: lastUsage?.output_tokens || 0,
|
|
742
|
-
total_tokens:
|
|
919
|
+
total_tokens:
|
|
920
|
+
(lastUsage?.input_tokens || 0) + (lastUsage?.output_tokens || 0),
|
|
743
921
|
thinking_tokens: lastUsage?.thinking_input_tokens || 0,
|
|
744
|
-
cache_creation_input_tokens:
|
|
745
|
-
|
|
922
|
+
cache_creation_input_tokens:
|
|
923
|
+
lastUsage?.cache_creation_input_tokens || 0,
|
|
924
|
+
cache_read_input_tokens: lastUsage?.cache_read_input_tokens || 0,
|
|
746
925
|
},
|
|
747
926
|
response_time_ms: responseTime,
|
|
748
927
|
finish_reason: finishReason,
|
|
749
928
|
provider: 'anthropic',
|
|
750
|
-
reasoning_effort: modelConfig.supportsThinking
|
|
751
|
-
|
|
929
|
+
reasoning_effort: modelConfig.supportsThinking
|
|
930
|
+
? reasoning_effort
|
|
931
|
+
: null,
|
|
932
|
+
thinking_content: thinkingContent || null,
|
|
752
933
|
},
|
|
753
|
-
timestamp: new Date().toISOString()
|
|
934
|
+
timestamp: new Date().toISOString(),
|
|
754
935
|
};
|
|
755
|
-
|
|
756
936
|
} catch (error) {
|
|
757
937
|
debugError('[Anthropic] Streaming error:', error);
|
|
758
938
|
|
|
@@ -781,8 +961,11 @@ export const anthropicProvider = {
|
|
|
781
961
|
} else if (error.error?.type === 'not_found_error') {
|
|
782
962
|
errorCode = 'MODEL_NOT_FOUND';
|
|
783
963
|
errorMessage = `Model ${resolvedModel} not found`;
|
|
784
|
-
} else if (
|
|
785
|
-
|
|
964
|
+
} else if (
|
|
965
|
+
error.message?.includes('context length') ||
|
|
966
|
+
error.message?.includes('context_length') ||
|
|
967
|
+
(error.message?.includes('token') && error.message?.includes('limit'))
|
|
968
|
+
) {
|
|
786
969
|
errorCode = 'CONTEXT_LENGTH_EXCEEDED';
|
|
787
970
|
errorMessage = `Context length exceeded for model: ${error.message}`;
|
|
788
971
|
}
|
|
@@ -793,9 +976,9 @@ export const anthropicProvider = {
|
|
|
793
976
|
message: errorMessage,
|
|
794
977
|
code: errorCode,
|
|
795
978
|
recoverable,
|
|
796
|
-
originalError: error
|
|
979
|
+
originalError: error,
|
|
797
980
|
},
|
|
798
|
-
timestamp: new Date().toISOString()
|
|
981
|
+
timestamp: new Date().toISOString(),
|
|
799
982
|
};
|
|
800
983
|
|
|
801
984
|
// Re-throw the error to maintain existing error handling behavior
|
|
@@ -809,7 +992,9 @@ export const anthropicProvider = {
|
|
|
809
992
|
* @returns {boolean} - True if configuration is valid
|
|
810
993
|
*/
|
|
811
994
|
validateConfig(config) {
|
|
812
|
-
return !!(
|
|
995
|
+
return !!(
|
|
996
|
+
config?.apiKeys?.anthropic && validateApiKey(config.apiKeys.anthropic)
|
|
997
|
+
);
|
|
813
998
|
},
|
|
814
999
|
|
|
815
1000
|
/**
|
|
@@ -837,6 +1022,5 @@ export const anthropicProvider = {
|
|
|
837
1022
|
getModelConfig(modelName) {
|
|
838
1023
|
const resolved = resolveModelName(modelName);
|
|
839
1024
|
return SUPPORTED_MODELS[resolved] || null;
|
|
840
|
-
}
|
|
1025
|
+
},
|
|
841
1026
|
};
|
|
842
|
-
|