converse-mcp-server 2.3.1 → 2.4.0
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 +323 -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
package/src/providers/codex.js
CHANGED
|
@@ -19,7 +19,7 @@ import { normalizeExtendedPath } from '../utils/pathUtils.js';
|
|
|
19
19
|
|
|
20
20
|
// Supported Codex models with their configurations
|
|
21
21
|
const SUPPORTED_MODELS = {
|
|
22
|
-
|
|
22
|
+
codex: {
|
|
23
23
|
modelName: 'codex',
|
|
24
24
|
friendlyName: 'OpenAI Codex (GPT-5)',
|
|
25
25
|
contextWindow: 400000,
|
|
@@ -29,9 +29,10 @@ const SUPPORTED_MODELS = {
|
|
|
29
29
|
supportsTemperature: false, // Codex manages temperature internally
|
|
30
30
|
supportsWebSearch: false, // Codex accesses files directly, not web
|
|
31
31
|
timeout: 60000, // 60 seconds (Codex can take 5-20s for responses)
|
|
32
|
-
description:
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
description:
|
|
33
|
+
'OpenAI Codex agentic coding assistant with local file access and tool execution',
|
|
34
|
+
aliases: ['gpt-5-codex', 'gpt5-codex'],
|
|
35
|
+
},
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -66,7 +67,7 @@ async function getCodexSDK() {
|
|
|
66
67
|
if (!isCodexAvailable()) {
|
|
67
68
|
throw new CodexProviderError(
|
|
68
69
|
'Codex SDK not installed. Install with: npm install @openai/codex-sdk',
|
|
69
|
-
'CODEX_NOT_INSTALLED'
|
|
70
|
+
'CODEX_NOT_INSTALLED',
|
|
70
71
|
);
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -78,7 +79,7 @@ async function getCodexSDK() {
|
|
|
78
79
|
throw new CodexProviderError(
|
|
79
80
|
'Failed to load Codex SDK',
|
|
80
81
|
'CODEX_LOAD_ERROR',
|
|
81
|
-
error
|
|
82
|
+
error,
|
|
82
83
|
);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
@@ -93,18 +94,27 @@ async function getCodexSDK() {
|
|
|
93
94
|
*/
|
|
94
95
|
function convertMessagesToPrompt(messages) {
|
|
95
96
|
if (!Array.isArray(messages)) {
|
|
96
|
-
throw new CodexProviderError(
|
|
97
|
+
throw new CodexProviderError(
|
|
98
|
+
'Messages must be an array',
|
|
99
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
100
|
+
);
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
if (messages.length === 0) {
|
|
100
|
-
throw new CodexProviderError(
|
|
104
|
+
throw new CodexProviderError(
|
|
105
|
+
'Messages array cannot be empty',
|
|
106
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
107
|
+
);
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
// Find last user message
|
|
104
|
-
const lastUserMessage = messages.filter(m => m.role === 'user').pop();
|
|
111
|
+
const lastUserMessage = messages.filter((m) => m.role === 'user').pop();
|
|
105
112
|
|
|
106
113
|
if (!lastUserMessage) {
|
|
107
|
-
throw new CodexProviderError(
|
|
114
|
+
throw new CodexProviderError(
|
|
115
|
+
'No user message found in messages array',
|
|
116
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
117
|
+
);
|
|
108
118
|
}
|
|
109
119
|
|
|
110
120
|
// Extract text content from message
|
|
@@ -115,19 +125,26 @@ function convertMessagesToPrompt(messages) {
|
|
|
115
125
|
// Handle array content (multimodal format)
|
|
116
126
|
if (Array.isArray(lastUserMessage.content)) {
|
|
117
127
|
const textParts = lastUserMessage.content
|
|
118
|
-
.filter(item => item.type === 'text')
|
|
119
|
-
.map(item => item.text);
|
|
128
|
+
.filter((item) => item.type === 'text')
|
|
129
|
+
.map((item) => item.text);
|
|
120
130
|
|
|
121
131
|
// Log warning if images present (Codex doesn't support images)
|
|
122
|
-
const hasImages = lastUserMessage.content.some(
|
|
132
|
+
const hasImages = lastUserMessage.content.some(
|
|
133
|
+
(item) => item.type === 'image',
|
|
134
|
+
);
|
|
123
135
|
if (hasImages) {
|
|
124
|
-
debugLog(
|
|
136
|
+
debugLog(
|
|
137
|
+
'[Codex] Warning: Images in message will be ignored (Codex does not support multimodal input)',
|
|
138
|
+
);
|
|
125
139
|
}
|
|
126
140
|
|
|
127
141
|
return textParts.join('\n');
|
|
128
142
|
}
|
|
129
143
|
|
|
130
|
-
throw new CodexProviderError(
|
|
144
|
+
throw new CodexProviderError(
|
|
145
|
+
'Invalid message content format',
|
|
146
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
147
|
+
);
|
|
131
148
|
}
|
|
132
149
|
|
|
133
150
|
/**
|
|
@@ -148,15 +165,26 @@ async function getThreadIdFromContinuation(continuationId, continuationStore) {
|
|
|
148
165
|
* Create stream generator for Codex streaming responses
|
|
149
166
|
* Yields raw Codex SDK events that will be normalized by ProviderStreamNormalizer
|
|
150
167
|
*/
|
|
151
|
-
async function* createStreamingGenerator(
|
|
168
|
+
async function* createStreamingGenerator(
|
|
169
|
+
thread,
|
|
170
|
+
prompt,
|
|
171
|
+
signal,
|
|
172
|
+
runOptions = {},
|
|
173
|
+
) {
|
|
152
174
|
try {
|
|
153
175
|
// Try with runOptions, fallback without if SDK doesn't support them
|
|
154
176
|
let eventsPromise;
|
|
155
177
|
try {
|
|
156
178
|
eventsPromise = thread.runStreamed(prompt, runOptions);
|
|
157
179
|
} catch (error) {
|
|
158
|
-
if (
|
|
159
|
-
|
|
180
|
+
if (
|
|
181
|
+
runOptions.reasoningEffort &&
|
|
182
|
+
(error.message?.includes('reasoningEffort') ||
|
|
183
|
+
error.message?.includes('unknown option'))
|
|
184
|
+
) {
|
|
185
|
+
debugLog(
|
|
186
|
+
'[Codex] reasoning_effort not supported by this SDK version for streaming, retrying without it',
|
|
187
|
+
);
|
|
160
188
|
eventsPromise = thread.runStreamed(prompt);
|
|
161
189
|
} else {
|
|
162
190
|
throw error;
|
|
@@ -202,20 +230,27 @@ export const codexProvider = {
|
|
|
202
230
|
continuationStore,
|
|
203
231
|
reasoning_effort,
|
|
204
232
|
temperature,
|
|
205
|
-
use_websearch
|
|
233
|
+
use_websearch,
|
|
206
234
|
} = options;
|
|
207
235
|
|
|
208
236
|
// Validate configuration
|
|
209
237
|
if (!config) {
|
|
210
|
-
throw new CodexProviderError(
|
|
238
|
+
throw new CodexProviderError(
|
|
239
|
+
'Configuration is required',
|
|
240
|
+
ErrorCodes.MISSING_API_KEY,
|
|
241
|
+
);
|
|
211
242
|
}
|
|
212
243
|
|
|
213
244
|
// Log unsupported parameters at debug level
|
|
214
245
|
if (temperature !== undefined) {
|
|
215
|
-
debugLog(
|
|
246
|
+
debugLog(
|
|
247
|
+
'[Codex] Parameter "temperature" not supported by Codex (ignored)',
|
|
248
|
+
);
|
|
216
249
|
}
|
|
217
250
|
if (use_websearch) {
|
|
218
|
-
debugLog(
|
|
251
|
+
debugLog(
|
|
252
|
+
'[Codex] Parameter "use_websearch" not supported by Codex (ignored)',
|
|
253
|
+
);
|
|
219
254
|
}
|
|
220
255
|
|
|
221
256
|
try {
|
|
@@ -226,9 +261,13 @@ export const codexProvider = {
|
|
|
226
261
|
const prompt = convertMessagesToPrompt(messages);
|
|
227
262
|
|
|
228
263
|
// Get thread ID if resuming conversation
|
|
229
|
-
const threadId =
|
|
230
|
-
|
|
231
|
-
|
|
264
|
+
const threadId =
|
|
265
|
+
continuation_id && continuationStore
|
|
266
|
+
? await getThreadIdFromContinuation(
|
|
267
|
+
continuation_id,
|
|
268
|
+
continuationStore,
|
|
269
|
+
)
|
|
270
|
+
: null;
|
|
232
271
|
|
|
233
272
|
// Initialize Codex with API key if provided
|
|
234
273
|
const codexApiKey = config.providers?.codexapikey;
|
|
@@ -246,7 +285,10 @@ export const codexProvider = {
|
|
|
246
285
|
// Normalize Windows extended-length paths (\\?\C:\...) to regular paths
|
|
247
286
|
const workingDirectory = normalizeExtendedPath(rawWorkingDirectory);
|
|
248
287
|
const sandbox = config.providers?.codexsandboxmode || 'read-only';
|
|
249
|
-
const skipGitRepoCheck =
|
|
288
|
+
const skipGitRepoCheck =
|
|
289
|
+
config.providers?.codexskipgitcheck !== undefined
|
|
290
|
+
? config.providers.codexskipgitcheck
|
|
291
|
+
: true;
|
|
250
292
|
const approvalPolicy = config.providers?.codexapprovalpolicy || 'never';
|
|
251
293
|
|
|
252
294
|
// Create or resume thread
|
|
@@ -254,7 +296,7 @@ export const codexProvider = {
|
|
|
254
296
|
workingDirectory,
|
|
255
297
|
sandbox,
|
|
256
298
|
skipGitRepoCheck,
|
|
257
|
-
approvalPolicy
|
|
299
|
+
approvalPolicy,
|
|
258
300
|
};
|
|
259
301
|
const thread = threadId
|
|
260
302
|
? codex.resumeThread(threadId, threadOptions)
|
|
@@ -274,7 +316,12 @@ export const codexProvider = {
|
|
|
274
316
|
|
|
275
317
|
// Synchronous mode: consume streaming internally and return complete response
|
|
276
318
|
const startTime = Date.now();
|
|
277
|
-
const generator = createStreamingGenerator(
|
|
319
|
+
const generator = createStreamingGenerator(
|
|
320
|
+
thread,
|
|
321
|
+
prompt,
|
|
322
|
+
signal,
|
|
323
|
+
runOptions,
|
|
324
|
+
);
|
|
278
325
|
|
|
279
326
|
let content = '';
|
|
280
327
|
let usage = null;
|
|
@@ -283,13 +330,19 @@ export const codexProvider = {
|
|
|
283
330
|
for await (const event of generator) {
|
|
284
331
|
if (event?.type === 'thread.started') {
|
|
285
332
|
threadIdFromStream = event.thread_id;
|
|
286
|
-
} else if (
|
|
333
|
+
} else if (
|
|
334
|
+
event?.type === 'item.completed' &&
|
|
335
|
+
event.item?.type === 'agent_message'
|
|
336
|
+
) {
|
|
287
337
|
content += event.item.text || '';
|
|
288
338
|
} else if (event?.type === 'turn.completed') {
|
|
289
339
|
usage = event.usage;
|
|
290
340
|
break; // Exit after turn.completed
|
|
291
341
|
} else if (event?.type === 'turn.failed') {
|
|
292
|
-
throw new CodexProviderError(
|
|
342
|
+
throw new CodexProviderError(
|
|
343
|
+
event.error?.message || 'Turn failed',
|
|
344
|
+
'TURN_FAILED',
|
|
345
|
+
);
|
|
293
346
|
}
|
|
294
347
|
}
|
|
295
348
|
|
|
@@ -303,17 +356,19 @@ export const codexProvider = {
|
|
|
303
356
|
provider: 'codex',
|
|
304
357
|
model,
|
|
305
358
|
threadId: threadIdFromStream || thread.id,
|
|
306
|
-
usage: usage
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
359
|
+
usage: usage
|
|
360
|
+
? {
|
|
361
|
+
input_tokens: usage.input_tokens || 0,
|
|
362
|
+
output_tokens: usage.output_tokens || 0,
|
|
363
|
+
total_tokens:
|
|
364
|
+
(usage.input_tokens || 0) + (usage.output_tokens || 0),
|
|
365
|
+
cached_input_tokens: usage.cached_input_tokens || 0,
|
|
366
|
+
}
|
|
367
|
+
: null,
|
|
312
368
|
response_time_ms: responseTime,
|
|
313
|
-
finish_reason: 'stop'
|
|
314
|
-
}
|
|
369
|
+
finish_reason: 'stop',
|
|
370
|
+
},
|
|
315
371
|
};
|
|
316
|
-
|
|
317
372
|
} catch (error) {
|
|
318
373
|
debugError('[Codex] Execution error', error);
|
|
319
374
|
|
|
@@ -322,7 +377,7 @@ export const codexProvider = {
|
|
|
322
377
|
throw new CodexProviderError(
|
|
323
378
|
'Codex authentication failed. Ensure ChatGPT login or CODEX_API_KEY is set.',
|
|
324
379
|
ErrorCodes.INVALID_API_KEY,
|
|
325
|
-
error
|
|
380
|
+
error,
|
|
326
381
|
);
|
|
327
382
|
}
|
|
328
383
|
|
|
@@ -330,7 +385,7 @@ export const codexProvider = {
|
|
|
330
385
|
throw new CodexProviderError(
|
|
331
386
|
'Not a Git repository. Use CODEX_SKIP_GIT_CHECK=true or run \'git init\'',
|
|
332
387
|
'CONFIGURATION_ERROR',
|
|
333
|
-
error
|
|
388
|
+
error,
|
|
334
389
|
);
|
|
335
390
|
}
|
|
336
391
|
|
|
@@ -338,7 +393,7 @@ export const codexProvider = {
|
|
|
338
393
|
throw new CodexProviderError(
|
|
339
394
|
'Codex execution timeout',
|
|
340
395
|
ErrorCodes.TIMEOUT_ERROR,
|
|
341
|
-
error
|
|
396
|
+
error,
|
|
342
397
|
);
|
|
343
398
|
}
|
|
344
399
|
|
|
@@ -346,7 +401,7 @@ export const codexProvider = {
|
|
|
346
401
|
throw new CodexProviderError(
|
|
347
402
|
error.message || 'Codex execution failed',
|
|
348
403
|
ErrorCodes.API_ERROR,
|
|
349
|
-
error
|
|
404
|
+
error,
|
|
350
405
|
);
|
|
351
406
|
}
|
|
352
407
|
},
|
|
@@ -389,11 +444,14 @@ export const codexProvider = {
|
|
|
389
444
|
|
|
390
445
|
// Check aliases
|
|
391
446
|
for (const [_name, config] of Object.entries(SUPPORTED_MODELS)) {
|
|
392
|
-
if (
|
|
447
|
+
if (
|
|
448
|
+
config.aliases &&
|
|
449
|
+
config.aliases.some((alias) => alias.toLowerCase() === modelNameLower)
|
|
450
|
+
) {
|
|
393
451
|
return config;
|
|
394
452
|
}
|
|
395
453
|
}
|
|
396
454
|
|
|
397
455
|
return null;
|
|
398
|
-
}
|
|
456
|
+
},
|
|
399
457
|
};
|
|
@@ -25,8 +25,16 @@ const SUPPORTED_MODELS = {
|
|
|
25
25
|
supportsChatPrefixCompletion: true, // Beta
|
|
26
26
|
supportsFIMCompletion: true, // Beta
|
|
27
27
|
timeout: 300000,
|
|
28
|
-
description:
|
|
29
|
-
|
|
28
|
+
description:
|
|
29
|
+
'DeepSeek-V3-0324 - Strong MoE model with 671B total/37B active parameters',
|
|
30
|
+
aliases: [
|
|
31
|
+
'deepseek',
|
|
32
|
+
'chat',
|
|
33
|
+
'deepseek chat',
|
|
34
|
+
'deepseek-v3',
|
|
35
|
+
'deepseek-chat-v3',
|
|
36
|
+
'deepseek v3',
|
|
37
|
+
],
|
|
30
38
|
},
|
|
31
39
|
'deepseek-reasoner': {
|
|
32
40
|
modelName: 'deepseek-reasoner',
|
|
@@ -44,9 +52,18 @@ const SUPPORTED_MODELS = {
|
|
|
44
52
|
supportsFIMCompletion: false, // Not supported
|
|
45
53
|
supportsReasoning: true,
|
|
46
54
|
timeout: 600000, // Longer timeout for reasoning
|
|
47
|
-
description:
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
description:
|
|
56
|
+
'DeepSeek-R1-0528 - Advanced reasoning model with CoT capabilities',
|
|
57
|
+
aliases: [
|
|
58
|
+
'deepseek reasoner',
|
|
59
|
+
'reasoner',
|
|
60
|
+
'r1',
|
|
61
|
+
'deepseek r1',
|
|
62
|
+
'deepseek-r1',
|
|
63
|
+
'deepseek-reasoner-r1',
|
|
64
|
+
'deepseek-r1-0528',
|
|
65
|
+
],
|
|
66
|
+
},
|
|
50
67
|
};
|
|
51
68
|
|
|
52
69
|
/**
|
|
@@ -97,7 +114,6 @@ export const deepseekProvider = createOpenAICompatibleProvider({
|
|
|
97
114
|
// DeepSeek default parameters
|
|
98
115
|
top_p: 0.95,
|
|
99
116
|
frequency_penalty: 0,
|
|
100
|
-
presence_penalty: 0
|
|
101
|
-
}
|
|
117
|
+
presence_penalty: 0,
|
|
118
|
+
},
|
|
102
119
|
});
|
|
103
|
-
|