converse-mcp-server 2.7.0 → 2.8.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/package.json +3 -2
- package/src/providers/claude.js +482 -0
- package/src/providers/index.js +2 -0
- package/src/tools/chat.js +6 -0
- package/src/tools/consensus.js +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "converse-mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Converse MCP Server - Converse with other LLMs with chat and consensus tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -94,11 +94,12 @@
|
|
|
94
94
|
".env.example"
|
|
95
95
|
],
|
|
96
96
|
"dependencies": {
|
|
97
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.51",
|
|
97
98
|
"@anthropic-ai/sdk": "^0.70.0",
|
|
98
99
|
"@google/genai": "^1.30.0",
|
|
99
100
|
"@mistralai/mistralai": "^1.10.0",
|
|
100
101
|
"@modelcontextprotocol/sdk": "^1.22.0",
|
|
101
|
-
"@openai/codex-sdk": "^0.
|
|
102
|
+
"@openai/codex-sdk": "^0.63.0",
|
|
102
103
|
"ai": "^5.0.101",
|
|
103
104
|
"ai-sdk-provider-gemini-cli": "^1.4.0",
|
|
104
105
|
"cors": "^2.8.5",
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude SDK Provider
|
|
3
|
+
*
|
|
4
|
+
* Provider implementation for Anthropic's Claude models using the @anthropic-ai/claude-agent-sdk.
|
|
5
|
+
* Implements the unified interface: async invoke(messages, options) => { content, stop_reason, rawResponse }
|
|
6
|
+
*
|
|
7
|
+
* Key differences from traditional providers:
|
|
8
|
+
* - Uses Claude Code CLI authentication (via `claude login`) - NOT API keys
|
|
9
|
+
* - Converts message arrays to single prompts (SDK expects prompts, not message history)
|
|
10
|
+
* - Spawns local process (bundled CLI binary) for execution
|
|
11
|
+
* - Requires Claude Code authentication (NOT ANTHROPIC_API_KEY)
|
|
12
|
+
*
|
|
13
|
+
* @see agent-sdk/typescript.md for SDK reference documentation
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { debugLog, debugError } from '../utils/console.js';
|
|
17
|
+
import { ProviderError, ErrorCodes, StopReasons } from './interface.js';
|
|
18
|
+
|
|
19
|
+
// Supported Claude SDK models with their configurations
|
|
20
|
+
const SUPPORTED_MODELS = {
|
|
21
|
+
claude: {
|
|
22
|
+
modelName: 'claude',
|
|
23
|
+
friendlyName: 'Claude (via Agent SDK)',
|
|
24
|
+
contextWindow: 200000,
|
|
25
|
+
maxOutputTokens: 8192,
|
|
26
|
+
supportsStreaming: true,
|
|
27
|
+
supportsImages: false, // SDK has limited image support
|
|
28
|
+
supportsTemperature: false, // SDK manages temperature internally
|
|
29
|
+
supportsWebSearch: false, // SDK accesses files directly, not web
|
|
30
|
+
timeout: 120000, // 2 minutes
|
|
31
|
+
description:
|
|
32
|
+
'Claude via Agent SDK - requires claude login authentication',
|
|
33
|
+
aliases: ['claude-sdk', 'claude-code'],
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Custom error class for Claude provider errors
|
|
39
|
+
*/
|
|
40
|
+
class ClaudeProviderError extends ProviderError {
|
|
41
|
+
constructor(message, code, originalError = null) {
|
|
42
|
+
super(message, code, originalError);
|
|
43
|
+
this.name = 'ClaudeProviderError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if Claude SDK is available (optional dependency)
|
|
49
|
+
*/
|
|
50
|
+
function isClaudeSDKAvailable() {
|
|
51
|
+
try {
|
|
52
|
+
// Simple presence check that works in ES modules
|
|
53
|
+
// If SDK not available, the actual import() will fail later with clear error
|
|
54
|
+
return true;
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Dynamically import Claude SDK (lazy loading)
|
|
62
|
+
* This keeps the SDK as an optional dependency
|
|
63
|
+
*/
|
|
64
|
+
async function getClaudeSDK() {
|
|
65
|
+
if (!isClaudeSDKAvailable()) {
|
|
66
|
+
throw new ClaudeProviderError(
|
|
67
|
+
'Claude SDK not installed. Install with: npm install @anthropic-ai/claude-agent-sdk',
|
|
68
|
+
'CLAUDE_SDK_NOT_INSTALLED',
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// Use dynamic import to load SDK only when needed
|
|
74
|
+
const { query } = await import('@anthropic-ai/claude-agent-sdk');
|
|
75
|
+
return query;
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new ClaudeProviderError(
|
|
78
|
+
'Failed to load Claude SDK. Install with: npm install @anthropic-ai/claude-agent-sdk',
|
|
79
|
+
'CLAUDE_SDK_LOAD_ERROR',
|
|
80
|
+
error,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Convert message array to single prompt for Claude SDK
|
|
87
|
+
* Claude SDK expects single prompts, not message history
|
|
88
|
+
*
|
|
89
|
+
* Strategy:
|
|
90
|
+
* - Extract last user message only
|
|
91
|
+
* - Handle both string and multimodal content formats
|
|
92
|
+
*/
|
|
93
|
+
function convertMessagesToPrompt(messages) {
|
|
94
|
+
if (!Array.isArray(messages)) {
|
|
95
|
+
throw new ClaudeProviderError(
|
|
96
|
+
'Messages must be an array',
|
|
97
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (messages.length === 0) {
|
|
102
|
+
throw new ClaudeProviderError(
|
|
103
|
+
'Messages array cannot be empty',
|
|
104
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Find last user message
|
|
109
|
+
const lastUserMessage = messages.filter((m) => m.role === 'user').pop();
|
|
110
|
+
|
|
111
|
+
if (!lastUserMessage) {
|
|
112
|
+
throw new ClaudeProviderError(
|
|
113
|
+
'No user message found in messages array',
|
|
114
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Extract text content from message
|
|
119
|
+
if (typeof lastUserMessage.content === 'string') {
|
|
120
|
+
return lastUserMessage.content;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Handle array content (multimodal format)
|
|
124
|
+
if (Array.isArray(lastUserMessage.content)) {
|
|
125
|
+
const textParts = lastUserMessage.content
|
|
126
|
+
.filter((item) => item.type === 'text')
|
|
127
|
+
.map((item) => item.text);
|
|
128
|
+
|
|
129
|
+
// Log warning if images present (Claude SDK has limited image support)
|
|
130
|
+
const hasImages = lastUserMessage.content.some(
|
|
131
|
+
(item) => item.type === 'image',
|
|
132
|
+
);
|
|
133
|
+
if (hasImages) {
|
|
134
|
+
debugLog(
|
|
135
|
+
'[Claude SDK] Warning: Images in message will be ignored (Claude SDK does not support multimodal input)',
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return textParts.join('\n');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
throw new ClaudeProviderError(
|
|
143
|
+
'Invalid message content format',
|
|
144
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create stream generator for Claude SDK streaming responses
|
|
150
|
+
* Yields normalized events compatible with ProviderStreamNormalizer
|
|
151
|
+
*
|
|
152
|
+
* SDK Message Types:
|
|
153
|
+
* - system (subtype: init): Session initialization
|
|
154
|
+
* - assistant: Model responses with message.content
|
|
155
|
+
* - result (subtype: success/error_*): Final results with usage
|
|
156
|
+
*/
|
|
157
|
+
async function* createStreamingGenerator(queryFn, prompt, options, signal) {
|
|
158
|
+
try {
|
|
159
|
+
// Build query options
|
|
160
|
+
const queryOptions = {
|
|
161
|
+
maxTurns: 1, // Single turn for chat
|
|
162
|
+
permissionMode: 'bypassPermissions', // Don't prompt for permissions
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Add working directory if provided
|
|
166
|
+
if (options.cwd) {
|
|
167
|
+
queryOptions.cwd = options.cwd;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Pass abort controller if provided
|
|
171
|
+
// Note: The SDK expects AbortController, not AbortSignal
|
|
172
|
+
if (signal) {
|
|
173
|
+
// Create a new abort controller that we can pass to the SDK
|
|
174
|
+
const controller = new globalThis.AbortController();
|
|
175
|
+
queryOptions.abortController = controller;
|
|
176
|
+
// Forward abort signal from the provided signal to our controller
|
|
177
|
+
signal.addEventListener('abort', () => {
|
|
178
|
+
controller.abort();
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Create query generator
|
|
183
|
+
const response = queryFn({
|
|
184
|
+
prompt,
|
|
185
|
+
options: queryOptions,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
let _sessionId = null;
|
|
189
|
+
let _modelUsed = 'claude';
|
|
190
|
+
let _accumulatedContent = '';
|
|
191
|
+
|
|
192
|
+
// Yield start event
|
|
193
|
+
yield {
|
|
194
|
+
type: 'start',
|
|
195
|
+
provider: 'claude',
|
|
196
|
+
model: 'claude',
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Iterate over SDK messages
|
|
200
|
+
for await (const message of response) {
|
|
201
|
+
// Check for cancellation
|
|
202
|
+
if (signal?.aborted) {
|
|
203
|
+
throw new ClaudeProviderError('Request cancelled', 'CANCELLED');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Handle different message types
|
|
207
|
+
switch (message.type) {
|
|
208
|
+
case 'system':
|
|
209
|
+
if (message.subtype === 'init') {
|
|
210
|
+
_sessionId = message.session_id;
|
|
211
|
+
_modelUsed = message.model || 'claude';
|
|
212
|
+
debugLog(
|
|
213
|
+
`[Claude SDK] Session initialized: ${_sessionId}, model: ${_modelUsed}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
|
|
218
|
+
case 'assistant':
|
|
219
|
+
// Extract content from assistant message
|
|
220
|
+
if (message.message?.content) {
|
|
221
|
+
for (const block of message.message.content) {
|
|
222
|
+
if (block.type === 'text') {
|
|
223
|
+
const text = block.text || '';
|
|
224
|
+
_accumulatedContent += text;
|
|
225
|
+
|
|
226
|
+
// Yield delta event with content chunk
|
|
227
|
+
yield {
|
|
228
|
+
type: 'delta',
|
|
229
|
+
data: {
|
|
230
|
+
textDelta: text,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
break;
|
|
237
|
+
|
|
238
|
+
case 'result':
|
|
239
|
+
// Handle final result
|
|
240
|
+
if (message.subtype === 'success') {
|
|
241
|
+
// Yield usage event
|
|
242
|
+
if (message.usage) {
|
|
243
|
+
yield {
|
|
244
|
+
type: 'usage',
|
|
245
|
+
usage: {
|
|
246
|
+
input_tokens: message.usage.input_tokens || 0,
|
|
247
|
+
output_tokens: message.usage.output_tokens || 0,
|
|
248
|
+
total_tokens:
|
|
249
|
+
(message.usage.input_tokens || 0) +
|
|
250
|
+
(message.usage.output_tokens || 0),
|
|
251
|
+
cached_input_tokens:
|
|
252
|
+
message.usage.cache_read_input_tokens || 0,
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Yield end event
|
|
258
|
+
yield {
|
|
259
|
+
type: 'end',
|
|
260
|
+
stop_reason: StopReasons.STOP,
|
|
261
|
+
finish_reason: 'stop',
|
|
262
|
+
};
|
|
263
|
+
} else if (
|
|
264
|
+
message.subtype === 'error_max_turns' ||
|
|
265
|
+
message.subtype === 'error_during_execution'
|
|
266
|
+
) {
|
|
267
|
+
throw new ClaudeProviderError(
|
|
268
|
+
`Claude SDK execution failed: ${message.subtype}`,
|
|
269
|
+
ErrorCodes.API_ERROR,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} catch (error) {
|
|
276
|
+
if (signal?.aborted) {
|
|
277
|
+
throw new ClaudeProviderError('Request cancelled', 'CANCELLED');
|
|
278
|
+
}
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Claude SDK Provider Implementation
|
|
285
|
+
*/
|
|
286
|
+
export const claudeProvider = {
|
|
287
|
+
/**
|
|
288
|
+
* Invoke Claude SDK with messages and options
|
|
289
|
+
* @param {Array} messages - Message array (Converse format)
|
|
290
|
+
* @param {Object} options - Invocation options
|
|
291
|
+
* @returns {Promise<Object>|AsyncGenerator} Response or stream generator
|
|
292
|
+
*/
|
|
293
|
+
async invoke(messages, options = {}) {
|
|
294
|
+
const {
|
|
295
|
+
model = 'claude',
|
|
296
|
+
config,
|
|
297
|
+
stream = false,
|
|
298
|
+
signal,
|
|
299
|
+
reasoning_effort,
|
|
300
|
+
temperature,
|
|
301
|
+
use_websearch,
|
|
302
|
+
} = options;
|
|
303
|
+
|
|
304
|
+
// Validate configuration
|
|
305
|
+
if (!config) {
|
|
306
|
+
throw new ClaudeProviderError(
|
|
307
|
+
'Configuration is required',
|
|
308
|
+
ErrorCodes.MISSING_API_KEY,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Log unsupported parameters at debug level
|
|
313
|
+
if (temperature !== undefined) {
|
|
314
|
+
debugLog(
|
|
315
|
+
'[Claude SDK] Parameter "temperature" not supported by Claude SDK (ignored)',
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
if (use_websearch) {
|
|
319
|
+
debugLog(
|
|
320
|
+
'[Claude SDK] Parameter "use_websearch" not supported by Claude SDK (ignored)',
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
if (reasoning_effort !== undefined) {
|
|
324
|
+
debugLog(
|
|
325
|
+
'[Claude SDK] Parameter "reasoning_effort" not supported by Claude SDK (ignored)',
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
// Get Claude SDK
|
|
331
|
+
const query = await getClaudeSDK();
|
|
332
|
+
|
|
333
|
+
// Convert messages to prompt
|
|
334
|
+
const prompt = convertMessagesToPrompt(messages);
|
|
335
|
+
|
|
336
|
+
// Build SDK options
|
|
337
|
+
const sdkOptions = {
|
|
338
|
+
cwd: config.server?.client_cwd || process.cwd(),
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// Streaming mode
|
|
342
|
+
if (stream) {
|
|
343
|
+
return createStreamingGenerator(query, prompt, sdkOptions, signal);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Synchronous mode: consume streaming internally and return complete response
|
|
347
|
+
const startTime = Date.now();
|
|
348
|
+
const generator = createStreamingGenerator(
|
|
349
|
+
query,
|
|
350
|
+
prompt,
|
|
351
|
+
sdkOptions,
|
|
352
|
+
signal,
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
let content = '';
|
|
356
|
+
let usage = null;
|
|
357
|
+
|
|
358
|
+
for await (const event of generator) {
|
|
359
|
+
if (event.type === 'delta' && event.data?.textDelta) {
|
|
360
|
+
content += event.data.textDelta;
|
|
361
|
+
} else if (event.type === 'usage') {
|
|
362
|
+
usage = event.usage;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const responseTime = Date.now() - startTime;
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
content,
|
|
370
|
+
stop_reason: StopReasons.STOP,
|
|
371
|
+
rawResponse: { content, usage },
|
|
372
|
+
metadata: {
|
|
373
|
+
provider: 'claude',
|
|
374
|
+
model,
|
|
375
|
+
usage: usage
|
|
376
|
+
? {
|
|
377
|
+
input_tokens: usage.input_tokens || 0,
|
|
378
|
+
output_tokens: usage.output_tokens || 0,
|
|
379
|
+
total_tokens:
|
|
380
|
+
(usage.input_tokens || 0) + (usage.output_tokens || 0),
|
|
381
|
+
cached_input_tokens: usage.cached_input_tokens || 0,
|
|
382
|
+
}
|
|
383
|
+
: null,
|
|
384
|
+
response_time_ms: responseTime,
|
|
385
|
+
finish_reason: 'stop',
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
} catch (error) {
|
|
389
|
+
debugError('[Claude SDK] Execution error', error);
|
|
390
|
+
|
|
391
|
+
// Map common errors to standard error codes
|
|
392
|
+
if (
|
|
393
|
+
error.message?.includes('authentication') ||
|
|
394
|
+
error.message?.includes('login') ||
|
|
395
|
+
error.message?.includes('not authenticated')
|
|
396
|
+
) {
|
|
397
|
+
throw new ClaudeProviderError(
|
|
398
|
+
'Claude SDK authentication failed. Run: claude login',
|
|
399
|
+
ErrorCodes.INVALID_API_KEY,
|
|
400
|
+
error,
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (error.message?.includes('timeout')) {
|
|
405
|
+
throw new ClaudeProviderError(
|
|
406
|
+
'Claude SDK execution timeout',
|
|
407
|
+
ErrorCodes.TIMEOUT_ERROR,
|
|
408
|
+
error,
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (error.message?.includes('rate limit')) {
|
|
413
|
+
throw new ClaudeProviderError(
|
|
414
|
+
'Rate limit exceeded',
|
|
415
|
+
ErrorCodes.RATE_LIMIT_EXCEEDED,
|
|
416
|
+
error,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Re-throw as Claude error if not already
|
|
421
|
+
if (error instanceof ClaudeProviderError) {
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
throw new ClaudeProviderError(
|
|
426
|
+
error.message || 'Claude SDK execution failed',
|
|
427
|
+
ErrorCodes.API_ERROR,
|
|
428
|
+
error,
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Validate Claude SDK configuration
|
|
435
|
+
* Claude SDK uses CLI authentication (NOT API keys)
|
|
436
|
+
* Returns true optimistically - authentication errors handled at runtime
|
|
437
|
+
*/
|
|
438
|
+
validateConfig(_config) {
|
|
439
|
+
// Claude SDK uses CLI authentication, not API keys
|
|
440
|
+
// We can't reliably check auth status, so return true optimistically
|
|
441
|
+
// and let the SDK handle authentication errors during execution
|
|
442
|
+
return isClaudeSDKAvailable();
|
|
443
|
+
},
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Check if Claude SDK provider is available
|
|
447
|
+
*/
|
|
448
|
+
isAvailable(config) {
|
|
449
|
+
return this.validateConfig(config);
|
|
450
|
+
},
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Get supported Claude SDK models
|
|
454
|
+
*/
|
|
455
|
+
getSupportedModels() {
|
|
456
|
+
return SUPPORTED_MODELS;
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Get model configuration for specific model
|
|
461
|
+
*/
|
|
462
|
+
getModelConfig(modelName) {
|
|
463
|
+
const modelNameLower = modelName.toLowerCase();
|
|
464
|
+
|
|
465
|
+
// Check exact match
|
|
466
|
+
if (SUPPORTED_MODELS[modelNameLower]) {
|
|
467
|
+
return SUPPORTED_MODELS[modelNameLower];
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Check aliases
|
|
471
|
+
for (const [_name, config] of Object.entries(SUPPORTED_MODELS)) {
|
|
472
|
+
if (
|
|
473
|
+
config.aliases &&
|
|
474
|
+
config.aliases.some((alias) => alias.toLowerCase() === modelNameLower)
|
|
475
|
+
) {
|
|
476
|
+
return config;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return null;
|
|
481
|
+
},
|
|
482
|
+
};
|
package/src/providers/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { deepseekProvider } from './deepseek.js';
|
|
|
15
15
|
import { openrouterProvider } from './openrouter.js';
|
|
16
16
|
import { codexProvider } from './codex.js';
|
|
17
17
|
import { geminiCliProvider } from './gemini-cli.js';
|
|
18
|
+
import { claudeProvider } from './claude.js';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Provider registry map
|
|
@@ -33,6 +34,7 @@ const providers = {
|
|
|
33
34
|
deepseek: deepseekProvider,
|
|
34
35
|
openrouter: openrouterProvider,
|
|
35
36
|
codex: codexProvider,
|
|
37
|
+
claude: claudeProvider,
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
/**
|
package/src/tools/chat.js
CHANGED
|
@@ -441,6 +441,7 @@ function resolveAutoModel(model, providerName) {
|
|
|
441
441
|
const defaults = {
|
|
442
442
|
codex: 'codex',
|
|
443
443
|
'gemini-cli': 'gemini',
|
|
444
|
+
claude: 'claude',
|
|
444
445
|
openai: 'gpt-5',
|
|
445
446
|
xai: 'grok-4-0709',
|
|
446
447
|
google: 'gemini-pro',
|
|
@@ -478,6 +479,11 @@ export function mapModelToProvider(model, providers) {
|
|
|
478
479
|
return 'gemini-cli';
|
|
479
480
|
}
|
|
480
481
|
|
|
482
|
+
// Check Claude SDK (exact match only - routes to SDK provider instead of Anthropic API)
|
|
483
|
+
if (modelLower === 'claude' || modelLower === 'claude-sdk' || modelLower === 'claude-code') {
|
|
484
|
+
return 'claude';
|
|
485
|
+
}
|
|
486
|
+
|
|
481
487
|
// Check OpenRouter-specific patterns first
|
|
482
488
|
if (
|
|
483
489
|
modelLower === 'openrouter auto' ||
|
package/src/tools/consensus.js
CHANGED
|
@@ -698,6 +698,7 @@ function getDefaultModelForProvider(providerName) {
|
|
|
698
698
|
const defaults = {
|
|
699
699
|
codex: 'codex',
|
|
700
700
|
'gemini-cli': 'gemini',
|
|
701
|
+
claude: 'claude',
|
|
701
702
|
openai: 'gpt-5',
|
|
702
703
|
xai: 'grok-4-0709',
|
|
703
704
|
google: 'gemini-pro',
|
|
@@ -746,6 +747,11 @@ function mapModelToProvider(model, providers) {
|
|
|
746
747
|
return 'gemini-cli';
|
|
747
748
|
}
|
|
748
749
|
|
|
750
|
+
// Check Claude SDK (exact match only - routes to SDK provider instead of Anthropic API)
|
|
751
|
+
if (modelLower === 'claude' || modelLower === 'claude-sdk' || modelLower === 'claude-code') {
|
|
752
|
+
return 'claude';
|
|
753
|
+
}
|
|
754
|
+
|
|
749
755
|
// Check OpenRouter-specific patterns first
|
|
750
756
|
if (
|
|
751
757
|
modelLower === 'openrouter auto' ||
|