converse-mcp-server 2.16.0 → 2.17.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 +4 -4
- package/src/providers/copilot.js +303 -17
- 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.17.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,14 +94,14 @@
|
|
|
94
94
|
".env.example"
|
|
95
95
|
],
|
|
96
96
|
"dependencies": {
|
|
97
|
-
"@anthropic-ai/claude-agent-sdk": "^0.2.
|
|
97
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.50",
|
|
98
98
|
"@anthropic-ai/sdk": "^0.74.0",
|
|
99
99
|
"@github/copilot-sdk": "^0.1.25",
|
|
100
100
|
"@google/genai": "^1.42.0",
|
|
101
101
|
"@mistralai/mistralai": "^1.14.0",
|
|
102
102
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
103
103
|
"@openai/codex-sdk": "^0.101.0",
|
|
104
|
-
"ai": "^6.0.
|
|
104
|
+
"ai": "^6.0.97",
|
|
105
105
|
"ai-sdk-provider-gemini-cli": "^2.0.1",
|
|
106
106
|
"cors": "^2.8.6",
|
|
107
107
|
"dotenv": "^17.3.1",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"devDependencies": {
|
|
116
116
|
"@vitest/coverage-v8": "^4.0.18",
|
|
117
117
|
"cross-env": "^10.1.0",
|
|
118
|
-
"eslint": "^10.0.
|
|
118
|
+
"eslint": "^10.0.1",
|
|
119
119
|
"prettier": "^3.8.1",
|
|
120
120
|
"rimraf": "^6.1.3",
|
|
121
121
|
"vitest": "^4.0.18"
|
package/src/providers/copilot.js
CHANGED
|
@@ -27,9 +27,236 @@ const SUPPORTED_MODELS = {
|
|
|
27
27
|
supportsWebSearch: false,
|
|
28
28
|
timeout: 120000,
|
|
29
29
|
description:
|
|
30
|
-
|
|
30
|
+
'GitHub Copilot via CLI SDK - uses default or env-configured model',
|
|
31
31
|
aliases: ['copilot-sdk', 'github-copilot'],
|
|
32
32
|
},
|
|
33
|
+
|
|
34
|
+
// OpenAI models
|
|
35
|
+
'gpt-4.1': {
|
|
36
|
+
modelName: 'gpt-4.1',
|
|
37
|
+
friendlyName: 'GPT-4.1 (via Copilot)',
|
|
38
|
+
contextWindow: 1047576,
|
|
39
|
+
maxOutputTokens: 32768,
|
|
40
|
+
supportsStreaming: true,
|
|
41
|
+
supportsImages: false,
|
|
42
|
+
supportsTemperature: false,
|
|
43
|
+
supportsWebSearch: false,
|
|
44
|
+
timeout: 120000,
|
|
45
|
+
description: 'OpenAI GPT-4.1 via Copilot subscription',
|
|
46
|
+
aliases: [],
|
|
47
|
+
},
|
|
48
|
+
'gpt-5-mini': {
|
|
49
|
+
modelName: 'gpt-5-mini',
|
|
50
|
+
friendlyName: 'GPT-5 Mini (via Copilot)',
|
|
51
|
+
contextWindow: 1047576,
|
|
52
|
+
maxOutputTokens: 16384,
|
|
53
|
+
supportsStreaming: true,
|
|
54
|
+
supportsImages: false,
|
|
55
|
+
supportsTemperature: false,
|
|
56
|
+
supportsWebSearch: false,
|
|
57
|
+
timeout: 120000,
|
|
58
|
+
description: 'OpenAI GPT-5 Mini via Copilot subscription',
|
|
59
|
+
aliases: [],
|
|
60
|
+
},
|
|
61
|
+
'gpt-5.1': {
|
|
62
|
+
modelName: 'gpt-5.1',
|
|
63
|
+
friendlyName: 'GPT-5.1 (via Copilot)',
|
|
64
|
+
contextWindow: 1047576,
|
|
65
|
+
maxOutputTokens: 32768,
|
|
66
|
+
supportsStreaming: true,
|
|
67
|
+
supportsImages: false,
|
|
68
|
+
supportsTemperature: false,
|
|
69
|
+
supportsWebSearch: false,
|
|
70
|
+
timeout: 120000,
|
|
71
|
+
description: 'OpenAI GPT-5.1 via Copilot subscription',
|
|
72
|
+
aliases: [],
|
|
73
|
+
},
|
|
74
|
+
'gpt-5.1-codex': {
|
|
75
|
+
modelName: 'gpt-5.1-codex',
|
|
76
|
+
friendlyName: 'GPT-5.1 Codex (via Copilot)',
|
|
77
|
+
contextWindow: 192000,
|
|
78
|
+
maxOutputTokens: 16384,
|
|
79
|
+
supportsStreaming: true,
|
|
80
|
+
supportsImages: false,
|
|
81
|
+
supportsTemperature: false,
|
|
82
|
+
supportsWebSearch: false,
|
|
83
|
+
timeout: 300000,
|
|
84
|
+
description: 'OpenAI GPT-5.1 Codex via Copilot subscription',
|
|
85
|
+
aliases: [],
|
|
86
|
+
},
|
|
87
|
+
'gpt-5.1-codex-mini': {
|
|
88
|
+
modelName: 'gpt-5.1-codex-mini',
|
|
89
|
+
friendlyName: 'GPT-5.1 Codex Mini (via Copilot)',
|
|
90
|
+
contextWindow: 192000,
|
|
91
|
+
maxOutputTokens: 16384,
|
|
92
|
+
supportsStreaming: true,
|
|
93
|
+
supportsImages: false,
|
|
94
|
+
supportsTemperature: false,
|
|
95
|
+
supportsWebSearch: false,
|
|
96
|
+
timeout: 300000,
|
|
97
|
+
description: 'OpenAI GPT-5.1 Codex Mini via Copilot subscription',
|
|
98
|
+
aliases: [],
|
|
99
|
+
},
|
|
100
|
+
'gpt-5.1-codex-max': {
|
|
101
|
+
modelName: 'gpt-5.1-codex-max',
|
|
102
|
+
friendlyName: 'GPT-5.1 Codex Max (via Copilot)',
|
|
103
|
+
contextWindow: 192000,
|
|
104
|
+
maxOutputTokens: 16384,
|
|
105
|
+
supportsStreaming: true,
|
|
106
|
+
supportsImages: false,
|
|
107
|
+
supportsTemperature: false,
|
|
108
|
+
supportsWebSearch: false,
|
|
109
|
+
timeout: 600000,
|
|
110
|
+
description: 'OpenAI GPT-5.1 Codex Max via Copilot subscription',
|
|
111
|
+
aliases: [],
|
|
112
|
+
},
|
|
113
|
+
'gpt-5.2': {
|
|
114
|
+
modelName: 'gpt-5.2',
|
|
115
|
+
friendlyName: 'GPT-5.2 (via Copilot)',
|
|
116
|
+
contextWindow: 1047576,
|
|
117
|
+
maxOutputTokens: 32768,
|
|
118
|
+
supportsStreaming: true,
|
|
119
|
+
supportsImages: false,
|
|
120
|
+
supportsTemperature: false,
|
|
121
|
+
supportsWebSearch: false,
|
|
122
|
+
timeout: 120000,
|
|
123
|
+
description: 'OpenAI GPT-5.2 via Copilot subscription',
|
|
124
|
+
aliases: ['gpt-5'],
|
|
125
|
+
},
|
|
126
|
+
'gpt-5.2-codex': {
|
|
127
|
+
modelName: 'gpt-5.2-codex',
|
|
128
|
+
friendlyName: 'GPT-5.2 Codex (via Copilot)',
|
|
129
|
+
contextWindow: 192000,
|
|
130
|
+
maxOutputTokens: 16384,
|
|
131
|
+
supportsStreaming: true,
|
|
132
|
+
supportsImages: false,
|
|
133
|
+
supportsTemperature: false,
|
|
134
|
+
supportsWebSearch: false,
|
|
135
|
+
timeout: 300000,
|
|
136
|
+
description: 'OpenAI GPT-5.2 Codex via Copilot subscription',
|
|
137
|
+
aliases: [],
|
|
138
|
+
},
|
|
139
|
+
'gpt-5.3-codex': {
|
|
140
|
+
modelName: 'gpt-5.3-codex',
|
|
141
|
+
friendlyName: 'GPT-5.3 Codex (via Copilot)',
|
|
142
|
+
contextWindow: 192000,
|
|
143
|
+
maxOutputTokens: 16384,
|
|
144
|
+
supportsStreaming: true,
|
|
145
|
+
supportsImages: false,
|
|
146
|
+
supportsTemperature: false,
|
|
147
|
+
supportsWebSearch: false,
|
|
148
|
+
timeout: 300000,
|
|
149
|
+
description: 'OpenAI GPT-5.3 Codex via Copilot subscription',
|
|
150
|
+
aliases: ['codex'],
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// Anthropic models
|
|
154
|
+
'claude-haiku-4.5': {
|
|
155
|
+
modelName: 'claude-haiku-4.5',
|
|
156
|
+
friendlyName: 'Claude Haiku 4.5 (via Copilot)',
|
|
157
|
+
contextWindow: 200000,
|
|
158
|
+
maxOutputTokens: 8192,
|
|
159
|
+
supportsStreaming: true,
|
|
160
|
+
supportsImages: false,
|
|
161
|
+
supportsTemperature: false,
|
|
162
|
+
supportsWebSearch: false,
|
|
163
|
+
timeout: 120000,
|
|
164
|
+
description: 'Anthropic Claude Haiku 4.5 via Copilot subscription',
|
|
165
|
+
aliases: ['haiku'],
|
|
166
|
+
},
|
|
167
|
+
'claude-sonnet-4': {
|
|
168
|
+
modelName: 'claude-sonnet-4',
|
|
169
|
+
friendlyName: 'Claude Sonnet 4 (via Copilot)',
|
|
170
|
+
contextWindow: 200000,
|
|
171
|
+
maxOutputTokens: 16384,
|
|
172
|
+
supportsStreaming: true,
|
|
173
|
+
supportsImages: false,
|
|
174
|
+
supportsTemperature: false,
|
|
175
|
+
supportsWebSearch: false,
|
|
176
|
+
timeout: 120000,
|
|
177
|
+
description: 'Anthropic Claude Sonnet 4 via Copilot subscription',
|
|
178
|
+
aliases: [],
|
|
179
|
+
},
|
|
180
|
+
'claude-sonnet-4.5': {
|
|
181
|
+
modelName: 'claude-sonnet-4.5',
|
|
182
|
+
friendlyName: 'Claude Sonnet 4.5 (via Copilot)',
|
|
183
|
+
contextWindow: 200000,
|
|
184
|
+
maxOutputTokens: 16384,
|
|
185
|
+
supportsStreaming: true,
|
|
186
|
+
supportsImages: false,
|
|
187
|
+
supportsTemperature: false,
|
|
188
|
+
supportsWebSearch: false,
|
|
189
|
+
timeout: 120000,
|
|
190
|
+
description: 'Anthropic Claude Sonnet 4.5 via Copilot subscription',
|
|
191
|
+
aliases: [],
|
|
192
|
+
},
|
|
193
|
+
'claude-sonnet-4.6': {
|
|
194
|
+
modelName: 'claude-sonnet-4.6',
|
|
195
|
+
friendlyName: 'Claude Sonnet 4.6 (via Copilot)',
|
|
196
|
+
contextWindow: 200000,
|
|
197
|
+
maxOutputTokens: 16384,
|
|
198
|
+
supportsStreaming: true,
|
|
199
|
+
supportsImages: false,
|
|
200
|
+
supportsTemperature: false,
|
|
201
|
+
supportsWebSearch: false,
|
|
202
|
+
timeout: 120000,
|
|
203
|
+
description: 'Anthropic Claude Sonnet 4.6 via Copilot subscription',
|
|
204
|
+
aliases: ['sonnet'],
|
|
205
|
+
},
|
|
206
|
+
'claude-opus-4.5': {
|
|
207
|
+
modelName: 'claude-opus-4.5',
|
|
208
|
+
friendlyName: 'Claude Opus 4.5 (via Copilot)',
|
|
209
|
+
contextWindow: 200000,
|
|
210
|
+
maxOutputTokens: 32768,
|
|
211
|
+
supportsStreaming: true,
|
|
212
|
+
supportsImages: false,
|
|
213
|
+
supportsTemperature: false,
|
|
214
|
+
supportsWebSearch: false,
|
|
215
|
+
timeout: 300000,
|
|
216
|
+
description: 'Anthropic Claude Opus 4.5 via Copilot subscription',
|
|
217
|
+
aliases: [],
|
|
218
|
+
},
|
|
219
|
+
'claude-opus-4.6': {
|
|
220
|
+
modelName: 'claude-opus-4.6',
|
|
221
|
+
friendlyName: 'Claude Opus 4.6 (via Copilot)',
|
|
222
|
+
contextWindow: 200000,
|
|
223
|
+
maxOutputTokens: 32768,
|
|
224
|
+
supportsStreaming: true,
|
|
225
|
+
supportsImages: false,
|
|
226
|
+
supportsTemperature: false,
|
|
227
|
+
supportsWebSearch: false,
|
|
228
|
+
timeout: 300000,
|
|
229
|
+
description: 'Anthropic Claude Opus 4.6 via Copilot subscription',
|
|
230
|
+
aliases: ['opus'],
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
// Google models
|
|
234
|
+
'gemini-3-pro-preview': {
|
|
235
|
+
modelName: 'gemini-3-pro-preview',
|
|
236
|
+
friendlyName: 'Gemini 3 Pro Preview (via Copilot)',
|
|
237
|
+
contextWindow: 1048576,
|
|
238
|
+
maxOutputTokens: 65536,
|
|
239
|
+
supportsStreaming: true,
|
|
240
|
+
supportsImages: false,
|
|
241
|
+
supportsTemperature: false,
|
|
242
|
+
supportsWebSearch: false,
|
|
243
|
+
timeout: 300000,
|
|
244
|
+
description: 'Google Gemini 3 Pro Preview via Copilot subscription',
|
|
245
|
+
aliases: ['gemini-3-pro'],
|
|
246
|
+
},
|
|
247
|
+
'gemini-3.1-pro-preview': {
|
|
248
|
+
modelName: 'gemini-3.1-pro-preview',
|
|
249
|
+
friendlyName: 'Gemini 3.1 Pro Preview (via Copilot)',
|
|
250
|
+
contextWindow: 1048576,
|
|
251
|
+
maxOutputTokens: 65536,
|
|
252
|
+
supportsStreaming: true,
|
|
253
|
+
supportsImages: false,
|
|
254
|
+
supportsTemperature: false,
|
|
255
|
+
supportsWebSearch: false,
|
|
256
|
+
timeout: 300000,
|
|
257
|
+
description: 'Google Gemini 3.1 Pro Preview via Copilot subscription',
|
|
258
|
+
aliases: ['gemini', 'gemini-3.1-pro'],
|
|
259
|
+
},
|
|
33
260
|
};
|
|
34
261
|
|
|
35
262
|
class CopilotProviderError extends ProviderError {
|
|
@@ -196,28 +423,76 @@ function createPermissionHandler(accessLevel) {
|
|
|
196
423
|
};
|
|
197
424
|
}
|
|
198
425
|
|
|
426
|
+
/**
|
|
427
|
+
* Resolve a friendly alias to its SDK model identifier (case-insensitive)
|
|
428
|
+
* Returns the resolved model name, or null if no alias matches
|
|
429
|
+
*/
|
|
430
|
+
function resolveModelAlias(name) {
|
|
431
|
+
if (typeof name !== 'string') return null;
|
|
432
|
+
const lower = name.toLowerCase().trim();
|
|
433
|
+
if (!lower) return null;
|
|
434
|
+
|
|
435
|
+
// Direct key match
|
|
436
|
+
if (SUPPORTED_MODELS[lower] && lower !== 'copilot') {
|
|
437
|
+
return SUPPORTED_MODELS[lower].modelName;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Alias match
|
|
441
|
+
for (const config of Object.values(SUPPORTED_MODELS)) {
|
|
442
|
+
if (config.modelName === 'copilot') continue;
|
|
443
|
+
if (
|
|
444
|
+
config.aliases &&
|
|
445
|
+
config.aliases.some((alias) => alias.toLowerCase() === lower)
|
|
446
|
+
) {
|
|
447
|
+
return config.modelName;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
|
|
199
454
|
/**
|
|
200
455
|
* Resolve model to pass to SDK session
|
|
201
456
|
* Precedence: explicit model param > config COPILOT_MODEL > omit (SDK default)
|
|
202
457
|
*
|
|
458
|
+
* Handles copilot: prefix stripping, alias resolution, and env var fallback.
|
|
203
459
|
* Note: "copilot" is a Converse routing alias, not a valid SDK model ID.
|
|
204
|
-
* Only pass through model names that are actual SDK model IDs.
|
|
205
460
|
*/
|
|
206
461
|
function resolveSessionModel(requestModel, config) {
|
|
207
462
|
const converseAliases = ['copilot', 'copilot-sdk', 'github-copilot'];
|
|
208
463
|
|
|
209
|
-
//
|
|
210
|
-
if (requestModel
|
|
211
|
-
|
|
464
|
+
// Guard non-string inputs
|
|
465
|
+
if (typeof requestModel !== 'string') {
|
|
466
|
+
requestModel = '';
|
|
212
467
|
}
|
|
213
468
|
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
|
|
469
|
+
// Strip copilot: prefix (case-insensitive)
|
|
470
|
+
let effectiveModel = requestModel;
|
|
471
|
+
if (effectiveModel.toLowerCase().startsWith('copilot:')) {
|
|
472
|
+
effectiveModel = effectiveModel.slice('copilot:'.length).trim();
|
|
217
473
|
}
|
|
218
474
|
|
|
219
|
-
//
|
|
220
|
-
|
|
475
|
+
// Empty suffix or converse alias → use env/default
|
|
476
|
+
if (
|
|
477
|
+
!effectiveModel ||
|
|
478
|
+
converseAliases.includes(effectiveModel.toLowerCase())
|
|
479
|
+
) {
|
|
480
|
+
const envModel = config?.providers?.copilotmodel;
|
|
481
|
+
if (envModel) {
|
|
482
|
+
let resolved = typeof envModel === 'string' ? envModel : '';
|
|
483
|
+
if (resolved.toLowerCase().startsWith('copilot:')) {
|
|
484
|
+
resolved = resolved.slice('copilot:'.length).trim();
|
|
485
|
+
}
|
|
486
|
+
if (!resolved || converseAliases.includes(resolved.toLowerCase())) {
|
|
487
|
+
return undefined;
|
|
488
|
+
}
|
|
489
|
+
return resolveModelAlias(resolved) || resolved;
|
|
490
|
+
}
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Resolve alias or passthrough unknown models to SDK
|
|
495
|
+
return resolveModelAlias(effectiveModel) || effectiveModel;
|
|
221
496
|
}
|
|
222
497
|
|
|
223
498
|
/**
|
|
@@ -376,6 +651,8 @@ async function* createStreamingGenerator(client, prompt, options, signal, config
|
|
|
376
651
|
}
|
|
377
652
|
}
|
|
378
653
|
|
|
654
|
+
export { resolveModelAlias, resolveSessionModel };
|
|
655
|
+
|
|
379
656
|
/**
|
|
380
657
|
* Copilot SDK Provider Implementation
|
|
381
658
|
*/
|
|
@@ -419,6 +696,7 @@ export const copilotProvider = {
|
|
|
419
696
|
const client = await getCopilotClient(cwd);
|
|
420
697
|
const prompt = convertMessagesToPrompt(messages);
|
|
421
698
|
|
|
699
|
+
const sessionModel = resolveSessionModel(model, config);
|
|
422
700
|
const modelConfig = SUPPORTED_MODELS.copilot;
|
|
423
701
|
const invokeOptions = {
|
|
424
702
|
model,
|
|
@@ -458,13 +736,13 @@ export const copilotProvider = {
|
|
|
458
736
|
rawResponse: { content, usage },
|
|
459
737
|
metadata: {
|
|
460
738
|
provider: 'copilot',
|
|
461
|
-
model,
|
|
739
|
+
model: sessionModel || 'copilot',
|
|
462
740
|
usage: usage
|
|
463
741
|
? {
|
|
464
742
|
input_tokens: usage.input_tokens || 0,
|
|
465
743
|
output_tokens: usage.output_tokens || 0,
|
|
466
744
|
total_tokens:
|
|
467
|
-
|
|
745
|
+
(usage.input_tokens || 0) + (usage.output_tokens || 0),
|
|
468
746
|
cached_input_tokens: usage.cached_input_tokens || 0,
|
|
469
747
|
}
|
|
470
748
|
: null,
|
|
@@ -533,16 +811,24 @@ export const copilotProvider = {
|
|
|
533
811
|
},
|
|
534
812
|
|
|
535
813
|
getModelConfig(modelName) {
|
|
536
|
-
|
|
814
|
+
if (typeof modelName !== 'string') return null;
|
|
815
|
+
|
|
816
|
+
let name = modelName;
|
|
817
|
+
if (name.toLowerCase().startsWith('copilot:')) {
|
|
818
|
+
name = name.slice('copilot:'.length).trim();
|
|
819
|
+
}
|
|
820
|
+
if (!name) return SUPPORTED_MODELS.copilot;
|
|
821
|
+
|
|
822
|
+
const nameLower = name.toLowerCase();
|
|
537
823
|
|
|
538
|
-
if (SUPPORTED_MODELS[
|
|
539
|
-
return SUPPORTED_MODELS[
|
|
824
|
+
if (SUPPORTED_MODELS[nameLower]) {
|
|
825
|
+
return SUPPORTED_MODELS[nameLower];
|
|
540
826
|
}
|
|
541
827
|
|
|
542
|
-
for (const
|
|
828
|
+
for (const config of Object.values(SUPPORTED_MODELS)) {
|
|
543
829
|
if (
|
|
544
830
|
config.aliases &&
|
|
545
|
-
|
|
831
|
+
config.aliases.some((alias) => alias.toLowerCase() === nameLower)
|
|
546
832
|
) {
|
|
547
833
|
return config;
|
|
548
834
|
}
|
package/src/tools/chat.js
CHANGED
|
@@ -584,6 +584,12 @@ export function mapModelToProvider(model, providers) {
|
|
|
584
584
|
return 'copilot';
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
+
// Check copilot: prefix (e.g., copilot:gpt-5.2, copilot:claude-sonnet-4.6)
|
|
588
|
+
// Must be before slash-format and keyword matching to prevent misrouting
|
|
589
|
+
if (modelLower.startsWith('copilot:')) {
|
|
590
|
+
return 'copilot';
|
|
591
|
+
}
|
|
592
|
+
|
|
587
593
|
// Check OpenRouter-specific patterns first
|
|
588
594
|
if (
|
|
589
595
|
modelLower === 'openrouter auto' ||
|
package/src/tools/consensus.js
CHANGED
|
@@ -787,6 +787,12 @@ function mapModelToProvider(model, providers) {
|
|
|
787
787
|
return 'copilot';
|
|
788
788
|
}
|
|
789
789
|
|
|
790
|
+
// Check copilot: prefix (e.g., copilot:gpt-5.2, copilot:claude-sonnet-4.6)
|
|
791
|
+
// Must be before slash-format and keyword matching to prevent misrouting
|
|
792
|
+
if (modelLower.startsWith('copilot:')) {
|
|
793
|
+
return 'copilot';
|
|
794
|
+
}
|
|
795
|
+
|
|
790
796
|
// Check OpenRouter-specific patterns first
|
|
791
797
|
if (
|
|
792
798
|
modelLower === 'openrouter auto' ||
|