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
package/src/tools/consensus.js
CHANGED
|
@@ -5,9 +5,19 @@
|
|
|
5
5
|
* Calls all available providers simultaneously and aggregates responses.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import {
|
|
9
|
+
createToolResponse,
|
|
10
|
+
createToolError,
|
|
11
|
+
formatFailureDetails,
|
|
12
|
+
} from './index.js';
|
|
13
|
+
import {
|
|
14
|
+
processUnifiedContext,
|
|
15
|
+
createFileContext,
|
|
16
|
+
} from '../utils/contextProcessor.js';
|
|
17
|
+
import {
|
|
18
|
+
generateContinuationId,
|
|
19
|
+
addMessageToHistory,
|
|
20
|
+
} from '../continuationStore.js';
|
|
11
21
|
import { debugLog, debugError } from '../utils/console.js';
|
|
12
22
|
import { createLogger } from '../utils/logger.js';
|
|
13
23
|
import { CONSENSUS_PROMPT } from '../systemPrompts.js';
|
|
@@ -25,15 +35,28 @@ const logger = createLogger('consensus');
|
|
|
25
35
|
*/
|
|
26
36
|
export async function consensusTool(args, dependencies) {
|
|
27
37
|
try {
|
|
28
|
-
const {
|
|
38
|
+
const {
|
|
39
|
+
config,
|
|
40
|
+
providers,
|
|
41
|
+
continuationStore,
|
|
42
|
+
contextProcessor,
|
|
43
|
+
jobRunner,
|
|
44
|
+
providerStreamNormalizer,
|
|
45
|
+
} = dependencies;
|
|
29
46
|
|
|
30
47
|
// Validate required arguments
|
|
31
48
|
if (!args.prompt || typeof args.prompt !== 'string') {
|
|
32
49
|
return createToolError('Prompt is required and must be a string');
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
52
|
+
if (
|
|
53
|
+
!args.models ||
|
|
54
|
+
!Array.isArray(args.models) ||
|
|
55
|
+
args.models.length === 0
|
|
56
|
+
) {
|
|
57
|
+
return createToolError(
|
|
58
|
+
'Models array is required and must contain at least one model',
|
|
59
|
+
);
|
|
37
60
|
}
|
|
38
61
|
|
|
39
62
|
// Extract and validate arguments
|
|
@@ -48,14 +71,16 @@ export async function consensusTool(args, dependencies) {
|
|
|
48
71
|
temperature = 0.2,
|
|
49
72
|
reasoning_effort = 'medium',
|
|
50
73
|
use_websearch = false,
|
|
51
|
-
async = false
|
|
74
|
+
async = false,
|
|
52
75
|
} = args;
|
|
53
76
|
|
|
54
77
|
// Handle async execution mode
|
|
55
78
|
if (async) {
|
|
56
79
|
// Validate async dependencies are available
|
|
57
80
|
if (!jobRunner || !providerStreamNormalizer) {
|
|
58
|
-
return createToolError(
|
|
81
|
+
return createToolError(
|
|
82
|
+
'Async execution not available - missing async dependencies',
|
|
83
|
+
);
|
|
59
84
|
}
|
|
60
85
|
|
|
61
86
|
// Generate continuation ID for background execution result
|
|
@@ -69,9 +94,14 @@ export async function consensusTool(args, dependencies) {
|
|
|
69
94
|
let title = null;
|
|
70
95
|
try {
|
|
71
96
|
title = await summarizationService.generateTitle(prompt);
|
|
72
|
-
debugLog(
|
|
97
|
+
debugLog(
|
|
98
|
+
`Consensus: Generated title for initial response - "${title}"`,
|
|
99
|
+
);
|
|
73
100
|
} catch (error) {
|
|
74
|
-
debugError(
|
|
101
|
+
debugError(
|
|
102
|
+
'Consensus: Failed to generate title for initial response',
|
|
103
|
+
error,
|
|
104
|
+
);
|
|
75
105
|
title = prompt.substring(0, 50);
|
|
76
106
|
}
|
|
77
107
|
|
|
@@ -85,8 +115,8 @@ export async function consensusTool(args, dependencies) {
|
|
|
85
115
|
...args,
|
|
86
116
|
jobId: bgContinuationId, // Use continuation ID as job ID
|
|
87
117
|
models_list: modelsList, // Add models list for status display
|
|
88
|
-
title // Pass the generated title
|
|
89
|
-
}
|
|
118
|
+
title, // Pass the generated title
|
|
119
|
+
},
|
|
90
120
|
},
|
|
91
121
|
async (context) => {
|
|
92
122
|
// Execute consensus in background using stream normalizer
|
|
@@ -95,23 +125,25 @@ export async function consensusTool(args, dependencies) {
|
|
|
95
125
|
{
|
|
96
126
|
...dependencies,
|
|
97
127
|
continuationId: bgContinuationId,
|
|
98
|
-
title // Pass title to execution context
|
|
128
|
+
title, // Pass title to execution context
|
|
99
129
|
},
|
|
100
|
-
context
|
|
130
|
+
context,
|
|
101
131
|
);
|
|
102
|
-
}
|
|
132
|
+
},
|
|
103
133
|
);
|
|
104
134
|
|
|
105
135
|
// Format initial response like check_status output
|
|
106
|
-
const startTime = new Date()
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
136
|
+
const startTime = new Date()
|
|
137
|
+
.toLocaleString('en-GB', {
|
|
138
|
+
day: '2-digit',
|
|
139
|
+
month: '2-digit',
|
|
140
|
+
year: 'numeric',
|
|
141
|
+
hour: '2-digit',
|
|
142
|
+
minute: '2-digit',
|
|
143
|
+
second: '2-digit',
|
|
144
|
+
hour12: false,
|
|
145
|
+
})
|
|
146
|
+
.replace(',', '');
|
|
115
147
|
|
|
116
148
|
const statusLine = `⏳ SUBMITTED | CONSENSUS | ${bgContinuationId} | 1/1 | Started: ${startTime} | "${title || 'Processing...'}" | ${modelsList}`;
|
|
117
149
|
|
|
@@ -119,12 +151,11 @@ export async function consensusTool(args, dependencies) {
|
|
|
119
151
|
return createToolResponse({
|
|
120
152
|
content: `${statusLine}\ncontinuation_id: ${bgContinuationId}`,
|
|
121
153
|
continuation: {
|
|
122
|
-
id: bgContinuationId,
|
|
123
|
-
status: 'processing'
|
|
154
|
+
id: bgContinuationId, // Use continuation_id as the primary ID
|
|
155
|
+
status: 'processing',
|
|
124
156
|
},
|
|
125
|
-
async_execution: true
|
|
157
|
+
async_execution: true,
|
|
126
158
|
});
|
|
127
|
-
|
|
128
159
|
} catch (error) {
|
|
129
160
|
logger.error('Failed to submit async consensus job', { error });
|
|
130
161
|
return createToolError(`Async execution failed: ${error.message}`);
|
|
@@ -137,7 +168,8 @@ export async function consensusTool(args, dependencies) {
|
|
|
137
168
|
// Load existing conversation if continuation_id provided
|
|
138
169
|
if (continuationId) {
|
|
139
170
|
try {
|
|
140
|
-
const existingState =
|
|
171
|
+
const existingState =
|
|
172
|
+
await dependencies.continuationStore.get(continuationId);
|
|
141
173
|
if (existingState) {
|
|
142
174
|
conversationHistory = existingState.messages || [];
|
|
143
175
|
} else {
|
|
@@ -156,10 +188,13 @@ export async function consensusTool(args, dependencies) {
|
|
|
156
188
|
|
|
157
189
|
// Validate file paths before processing
|
|
158
190
|
if (files.length > 0 || images.length > 0) {
|
|
159
|
-
const validation = await validateAllPaths(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
191
|
+
const validation = await validateAllPaths(
|
|
192
|
+
{
|
|
193
|
+
files,
|
|
194
|
+
images,
|
|
195
|
+
},
|
|
196
|
+
{ clientCwd: config.server?.client_cwd },
|
|
197
|
+
);
|
|
163
198
|
if (!validation.valid) {
|
|
164
199
|
logger.error('File validation failed', { errors: validation.errors });
|
|
165
200
|
return validation.errorResponse;
|
|
@@ -172,24 +207,29 @@ export async function consensusTool(args, dependencies) {
|
|
|
172
207
|
try {
|
|
173
208
|
const contextRequest = {
|
|
174
209
|
files: Array.isArray(files) ? files : [],
|
|
175
|
-
images: Array.isArray(images) ? images : []
|
|
210
|
+
images: Array.isArray(images) ? images : [],
|
|
176
211
|
};
|
|
177
212
|
|
|
178
|
-
const contextResult = await contextProcessor.processUnifiedContext(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
213
|
+
const contextResult = await contextProcessor.processUnifiedContext(
|
|
214
|
+
contextRequest,
|
|
215
|
+
{
|
|
216
|
+
enforceSecurityCheck: false, // Allow files from any location
|
|
217
|
+
skipSecurityCheck: true, // Legacy flag for backward compatibility
|
|
218
|
+
clientCwd: config.server?.client_cwd, // Use auto-detected client working directory
|
|
219
|
+
},
|
|
220
|
+
);
|
|
183
221
|
|
|
184
222
|
// Create context message from files and images
|
|
185
|
-
const allProcessedFiles = [
|
|
223
|
+
const allProcessedFiles = [
|
|
224
|
+
...contextResult.files,
|
|
225
|
+
...contextResult.images,
|
|
226
|
+
];
|
|
186
227
|
if (allProcessedFiles.length > 0) {
|
|
187
228
|
contextMessage = createFileContext(allProcessedFiles, {
|
|
188
229
|
includeMetadata: true,
|
|
189
|
-
includeErrors: true
|
|
230
|
+
includeErrors: true,
|
|
190
231
|
});
|
|
191
232
|
}
|
|
192
|
-
|
|
193
233
|
} catch (error) {
|
|
194
234
|
logger.error('Error processing context', { error });
|
|
195
235
|
// Continue without context if processing fails
|
|
@@ -202,7 +242,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
202
242
|
// Add system prompt
|
|
203
243
|
messages.push({
|
|
204
244
|
role: 'system',
|
|
205
|
-
content: CONSENSUS_PROMPT
|
|
245
|
+
content: CONSENSUS_PROMPT,
|
|
206
246
|
});
|
|
207
247
|
|
|
208
248
|
// Add conversation history
|
|
@@ -211,7 +251,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
211
251
|
// Add user prompt with context
|
|
212
252
|
const userMessage = {
|
|
213
253
|
role: 'user',
|
|
214
|
-
content: prompt // default to simple string content
|
|
254
|
+
content: prompt, // default to simple string content
|
|
215
255
|
};
|
|
216
256
|
|
|
217
257
|
// If we have context (files/images), create complex content array
|
|
@@ -219,7 +259,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
219
259
|
// Create complex content array
|
|
220
260
|
userMessage.content = [
|
|
221
261
|
...contextMessage.content, // Include all file/image parts
|
|
222
|
-
{ type: 'text', text: prompt } // Add the user prompt as text
|
|
262
|
+
{ type: 'text', text: prompt }, // Add the user prompt as text
|
|
223
263
|
];
|
|
224
264
|
}
|
|
225
265
|
|
|
@@ -234,7 +274,15 @@ export async function consensusTool(args, dependencies) {
|
|
|
234
274
|
if (models.length === 1 && models[0].toLowerCase() === 'auto') {
|
|
235
275
|
// Find first 3 available providers
|
|
236
276
|
const availableProviders = [];
|
|
237
|
-
const providerOrder = [
|
|
277
|
+
const providerOrder = [
|
|
278
|
+
'openai',
|
|
279
|
+
'google',
|
|
280
|
+
'xai',
|
|
281
|
+
'anthropic',
|
|
282
|
+
'mistral',
|
|
283
|
+
'deepseek',
|
|
284
|
+
'openrouter',
|
|
285
|
+
];
|
|
238
286
|
|
|
239
287
|
for (const providerName of providerOrder) {
|
|
240
288
|
if (availableProviders.length >= 3) break;
|
|
@@ -245,19 +293,21 @@ export async function consensusTool(args, dependencies) {
|
|
|
245
293
|
}
|
|
246
294
|
|
|
247
295
|
if (availableProviders.length === 0) {
|
|
248
|
-
return createToolError(
|
|
296
|
+
return createToolError(
|
|
297
|
+
'No providers available. Please configure at least one API key.',
|
|
298
|
+
);
|
|
249
299
|
}
|
|
250
300
|
|
|
251
301
|
// Create model names for each available provider with their default model
|
|
252
|
-
modelsToProcess = availableProviders.map(providerName =>
|
|
253
|
-
getDefaultModelForProvider(providerName)
|
|
302
|
+
modelsToProcess = availableProviders.map((providerName) =>
|
|
303
|
+
getDefaultModelForProvider(providerName),
|
|
254
304
|
);
|
|
255
305
|
|
|
256
306
|
logger.debug('Auto-expanded to providers', {
|
|
257
307
|
data: {
|
|
258
308
|
providers: availableProviders,
|
|
259
|
-
models: modelsToProcess
|
|
260
|
-
}
|
|
309
|
+
models: modelsToProcess,
|
|
310
|
+
},
|
|
261
311
|
});
|
|
262
312
|
}
|
|
263
313
|
|
|
@@ -266,7 +316,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
266
316
|
failedModels.push({
|
|
267
317
|
model: modelName || 'unknown',
|
|
268
318
|
error: 'Invalid model specification',
|
|
269
|
-
status: 'failed'
|
|
319
|
+
status: 'failed',
|
|
270
320
|
});
|
|
271
321
|
continue;
|
|
272
322
|
}
|
|
@@ -279,7 +329,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
279
329
|
model: modelName,
|
|
280
330
|
provider: providerName,
|
|
281
331
|
error: `Provider not found: ${providerName}`,
|
|
282
|
-
status: 'failed'
|
|
332
|
+
status: 'failed',
|
|
283
333
|
});
|
|
284
334
|
continue;
|
|
285
335
|
}
|
|
@@ -289,7 +339,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
289
339
|
model: modelName,
|
|
290
340
|
provider: providerName,
|
|
291
341
|
error: `Provider ${providerName} not available (check API key)`,
|
|
292
|
-
status: 'failed'
|
|
342
|
+
status: 'failed',
|
|
293
343
|
});
|
|
294
344
|
continue;
|
|
295
345
|
}
|
|
@@ -303,30 +353,35 @@ export async function consensusTool(args, dependencies) {
|
|
|
303
353
|
reasoning_effort,
|
|
304
354
|
use_websearch,
|
|
305
355
|
config,
|
|
306
|
-
model: resolvedModelName // Use resolved model name for API call
|
|
307
|
-
}
|
|
356
|
+
model: resolvedModelName, // Use resolved model name for API call
|
|
357
|
+
},
|
|
308
358
|
});
|
|
309
359
|
}
|
|
310
360
|
|
|
311
361
|
if (providerCalls.length === 0) {
|
|
312
362
|
return createToolError(
|
|
313
|
-
`No valid providers available for the specified models. Failed models: ${failedModels.map(f => f.model).join(', ')}
|
|
363
|
+
`No valid providers available for the specified models. Failed models: ${failedModels.map((f) => f.model).join(', ')}`,
|
|
314
364
|
);
|
|
315
365
|
}
|
|
316
366
|
|
|
317
367
|
// Phase 1: Initial parallel provider calls
|
|
318
|
-
logger.debug('Calling providers in parallel', {
|
|
368
|
+
logger.debug('Calling providers in parallel', {
|
|
369
|
+
data: { providerCount: providerCalls.length },
|
|
370
|
+
});
|
|
319
371
|
const consensusStartTime = Date.now();
|
|
320
372
|
const initialResults = await Promise.allSettled(
|
|
321
373
|
providerCalls.map(async (call) => {
|
|
322
374
|
try {
|
|
323
|
-
const response = await call.providerInstance.invoke(
|
|
375
|
+
const response = await call.providerInstance.invoke(
|
|
376
|
+
messages,
|
|
377
|
+
call.options,
|
|
378
|
+
);
|
|
324
379
|
return {
|
|
325
380
|
model: call.model,
|
|
326
381
|
provider: call.provider,
|
|
327
382
|
status: 'success',
|
|
328
383
|
response: response.content,
|
|
329
|
-
metadata: response.metadata || {}
|
|
384
|
+
metadata: response.metadata || {},
|
|
330
385
|
};
|
|
331
386
|
} catch (error) {
|
|
332
387
|
return {
|
|
@@ -334,16 +389,16 @@ export async function consensusTool(args, dependencies) {
|
|
|
334
389
|
provider: call.provider,
|
|
335
390
|
status: 'failed',
|
|
336
391
|
error: error.message,
|
|
337
|
-
metadata: {}
|
|
392
|
+
metadata: {},
|
|
338
393
|
};
|
|
339
394
|
}
|
|
340
|
-
})
|
|
395
|
+
}),
|
|
341
396
|
);
|
|
342
397
|
|
|
343
398
|
// Process initial results
|
|
344
399
|
const initialPhase = {
|
|
345
400
|
successful: [],
|
|
346
|
-
failed: []
|
|
401
|
+
failed: [],
|
|
347
402
|
};
|
|
348
403
|
|
|
349
404
|
initialResults.forEach((result, index) => {
|
|
@@ -359,7 +414,7 @@ export async function consensusTool(args, dependencies) {
|
|
|
359
414
|
provider: providerCalls[index].provider,
|
|
360
415
|
status: 'failed',
|
|
361
416
|
error: result.reason.message || 'Unknown error',
|
|
362
|
-
metadata: {}
|
|
417
|
+
metadata: {},
|
|
363
418
|
});
|
|
364
419
|
}
|
|
365
420
|
});
|
|
@@ -371,10 +426,13 @@ export async function consensusTool(args, dependencies) {
|
|
|
371
426
|
|
|
372
427
|
// Phase 2: Cross-feedback (if enabled and we have multiple successful responses)
|
|
373
428
|
if (enable_cross_feedback && initialPhase.successful.length > 1) {
|
|
374
|
-
logger.debug('Running cross-feedback phase', {
|
|
429
|
+
logger.debug('Running cross-feedback phase', {
|
|
430
|
+
data: { responseCount: initialPhase.successful.length },
|
|
431
|
+
});
|
|
375
432
|
|
|
376
433
|
// Create cross-feedback prompt
|
|
377
|
-
const feedbackPrompt =
|
|
434
|
+
const feedbackPrompt =
|
|
435
|
+
cross_feedback_prompt ||
|
|
378
436
|
`Based on the other AI responses below, please refine your answer to the original question. Consider different perspectives and provide your final response:
|
|
379
437
|
|
|
380
438
|
Original Question: ${prompt}
|
|
@@ -391,29 +449,34 @@ Please provide your refined response:`;
|
|
|
391
449
|
const refinementResults = await Promise.allSettled(
|
|
392
450
|
initialPhase.successful.map(async (initialResult) => {
|
|
393
451
|
try {
|
|
394
|
-
const call = providerCalls.find(
|
|
452
|
+
const call = providerCalls.find(
|
|
453
|
+
(c) => c.model === initialResult.model,
|
|
454
|
+
);
|
|
395
455
|
|
|
396
456
|
// Build model-specific feedback messages with the assistant's initial response
|
|
397
457
|
const modelFeedbackMessages = [...messages];
|
|
398
458
|
// Add the assistant's initial response
|
|
399
459
|
modelFeedbackMessages.push({
|
|
400
460
|
role: 'assistant',
|
|
401
|
-
content: initialResult.response
|
|
461
|
+
content: initialResult.response,
|
|
402
462
|
});
|
|
403
463
|
// Now add the feedback prompt
|
|
404
464
|
modelFeedbackMessages.push({
|
|
405
465
|
role: 'user',
|
|
406
|
-
content: feedbackPrompt
|
|
466
|
+
content: feedbackPrompt,
|
|
407
467
|
});
|
|
408
468
|
|
|
409
|
-
const response = await call.providerInstance.invoke(
|
|
469
|
+
const response = await call.providerInstance.invoke(
|
|
470
|
+
modelFeedbackMessages,
|
|
471
|
+
call.options,
|
|
472
|
+
);
|
|
410
473
|
|
|
411
474
|
return {
|
|
412
475
|
...initialResult,
|
|
413
476
|
refined_response: response.content,
|
|
414
477
|
refined_metadata: response.metadata || {},
|
|
415
478
|
initial_response: initialResult.response,
|
|
416
|
-
status: 'success'
|
|
479
|
+
status: 'success',
|
|
417
480
|
};
|
|
418
481
|
} catch (error) {
|
|
419
482
|
return {
|
|
@@ -421,10 +484,10 @@ Please provide your refined response:`;
|
|
|
421
484
|
refined_response: null,
|
|
422
485
|
refined_error: error.message,
|
|
423
486
|
initial_response: initialResult.response,
|
|
424
|
-
status: 'partial' // Had initial success but refinement failed
|
|
487
|
+
status: 'partial', // Had initial success but refinement failed
|
|
425
488
|
};
|
|
426
489
|
}
|
|
427
|
-
})
|
|
490
|
+
}),
|
|
428
491
|
);
|
|
429
492
|
|
|
430
493
|
// Process refinement results
|
|
@@ -439,7 +502,7 @@ Please provide your refined response:`;
|
|
|
439
502
|
...originalResult,
|
|
440
503
|
refined_response: null,
|
|
441
504
|
refined_error: 'Refinement phase failed unexpectedly',
|
|
442
|
-
status: 'partial'
|
|
505
|
+
status: 'partial',
|
|
443
506
|
});
|
|
444
507
|
}
|
|
445
508
|
});
|
|
@@ -449,8 +512,11 @@ Please provide your refined response:`;
|
|
|
449
512
|
try {
|
|
450
513
|
const consensusMessage = {
|
|
451
514
|
role: 'assistant',
|
|
452
|
-
content:
|
|
453
|
-
|
|
515
|
+
content:
|
|
516
|
+
`Consensus completed with ${initialPhase.successful.length} successful responses` +
|
|
517
|
+
(refinedPhase
|
|
518
|
+
? ` and ${refinedPhase.filter((r) => r.status === 'success').length} refined responses`
|
|
519
|
+
: ''),
|
|
454
520
|
};
|
|
455
521
|
|
|
456
522
|
const conversationState = {
|
|
@@ -461,11 +527,14 @@ Please provide your refined response:`;
|
|
|
461
527
|
modelsRequested: models.length,
|
|
462
528
|
providersSuccessful: initialPhase.successful.length,
|
|
463
529
|
providersFailed: initialPhase.failed.length,
|
|
464
|
-
crossFeedbackEnabled: enable_cross_feedback
|
|
465
|
-
}
|
|
530
|
+
crossFeedbackEnabled: enable_cross_feedback,
|
|
531
|
+
},
|
|
466
532
|
};
|
|
467
533
|
|
|
468
|
-
await dependencies.continuationStore.set(
|
|
534
|
+
await dependencies.continuationStore.set(
|
|
535
|
+
continuationId,
|
|
536
|
+
conversationState,
|
|
537
|
+
);
|
|
469
538
|
} catch (error) {
|
|
470
539
|
logger.error('Error saving consensus conversation', { error });
|
|
471
540
|
// Continue even if save fails
|
|
@@ -479,17 +548,19 @@ Please provide your refined response:`;
|
|
|
479
548
|
|
|
480
549
|
if (enable_cross_feedback && refinedPhase) {
|
|
481
550
|
// When cross-feedback is enabled, count only models that succeeded in both phases
|
|
482
|
-
finalSuccessCount = refinedPhase.filter(
|
|
551
|
+
finalSuccessCount = refinedPhase.filter(
|
|
552
|
+
(r) => r.status === 'success',
|
|
553
|
+
).length;
|
|
483
554
|
|
|
484
555
|
// Collect detailed failure information
|
|
485
|
-
refinedPhase.forEach(result => {
|
|
556
|
+
refinedPhase.forEach((result) => {
|
|
486
557
|
if (result.status === 'partial') {
|
|
487
558
|
failureDetails.push(`${result.model} (refinement failed)`);
|
|
488
559
|
}
|
|
489
560
|
});
|
|
490
561
|
|
|
491
562
|
// Add models that failed in initial phase
|
|
492
|
-
initialPhase.failed.forEach(failure => {
|
|
563
|
+
initialPhase.failed.forEach((failure) => {
|
|
493
564
|
failureDetails.push(`${failure.model} (initial failed)`);
|
|
494
565
|
});
|
|
495
566
|
} else {
|
|
@@ -497,21 +568,23 @@ Please provide your refined response:`;
|
|
|
497
568
|
finalSuccessCount = initialPhase.successful.length;
|
|
498
569
|
|
|
499
570
|
// Collect initial failure information
|
|
500
|
-
initialPhase.failed.forEach(failure => {
|
|
571
|
+
initialPhase.failed.forEach((failure) => {
|
|
501
572
|
failureDetails.push(`${failure.model} (${failure.error})`);
|
|
502
573
|
});
|
|
503
574
|
}
|
|
504
575
|
|
|
505
576
|
// Create models list string for display
|
|
506
|
-
const modelsList = providerCalls.map(call => call.model).join(', ');
|
|
507
|
-
|
|
577
|
+
const modelsList = providerCalls.map((call) => call.model).join(', ');
|
|
508
578
|
|
|
509
579
|
// Create unified status line (similar to async status display)
|
|
510
|
-
const finalCount = refinedPhase
|
|
580
|
+
const finalCount = refinedPhase
|
|
581
|
+
? refinedPhase.filter((r) => r.status === 'success').length
|
|
582
|
+
: initialPhase.successful.length;
|
|
511
583
|
const totalCount = providerCalls.length;
|
|
512
|
-
const statusLine =
|
|
513
|
-
|
|
514
|
-
|
|
584
|
+
const statusLine =
|
|
585
|
+
config.environment?.nodeEnv !== 'test'
|
|
586
|
+
? `✅ COMPLETED | CONSENSUS | ${continuationId} | ${consensusExecutionTime.toFixed(1)}s elapsed | ${finalCount}/${totalCount} succeeded | ${modelsList}\n`
|
|
587
|
+
: '';
|
|
515
588
|
|
|
516
589
|
// Always include continuation_id line for clarity
|
|
517
590
|
const continuationIdLine = `continuation_id: ${continuationId}\n\n`;
|
|
@@ -522,21 +595,23 @@ Please provide your refined response:`;
|
|
|
522
595
|
models_consulted: models.length,
|
|
523
596
|
successful_initial_responses: initialPhase.successful.length,
|
|
524
597
|
failed_responses: initialPhase.failed.length,
|
|
525
|
-
refined_responses: refinedPhase
|
|
598
|
+
refined_responses: refinedPhase
|
|
599
|
+
? refinedPhase.filter((r) => r.status === 'success').length
|
|
600
|
+
: 0,
|
|
526
601
|
phases: {
|
|
527
602
|
initial: initialPhase.successful,
|
|
528
603
|
...(refinedPhase !== null && { refined: refinedPhase }),
|
|
529
|
-
failed: initialPhase.failed
|
|
604
|
+
failed: initialPhase.failed,
|
|
530
605
|
},
|
|
531
606
|
continuation: {
|
|
532
607
|
id: continuationId,
|
|
533
|
-
messageCount: messages.length + 1
|
|
608
|
+
messageCount: messages.length + 1,
|
|
534
609
|
},
|
|
535
610
|
settings: {
|
|
536
611
|
enable_cross_feedback,
|
|
537
612
|
temperature,
|
|
538
|
-
models_requested: models
|
|
539
|
-
}
|
|
613
|
+
models_requested: models,
|
|
614
|
+
},
|
|
540
615
|
};
|
|
541
616
|
|
|
542
617
|
// Apply token limiting to the final response
|
|
@@ -559,10 +634,9 @@ Please provide your refined response:`;
|
|
|
559
634
|
content: finalContent,
|
|
560
635
|
continuation: {
|
|
561
636
|
id: continuationId,
|
|
562
|
-
messageCount: messages.length + 1
|
|
563
|
-
}
|
|
637
|
+
messageCount: messages.length + 1,
|
|
638
|
+
},
|
|
564
639
|
});
|
|
565
|
-
|
|
566
640
|
} catch (error) {
|
|
567
641
|
logger.error('Consensus tool error', { error });
|
|
568
642
|
return createToolError('Consensus tool failed', error);
|
|
@@ -579,13 +653,13 @@ Please provide your refined response:`;
|
|
|
579
653
|
*/
|
|
580
654
|
function getDefaultModelForProvider(providerName) {
|
|
581
655
|
const defaults = {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
656
|
+
openai: 'gpt-5',
|
|
657
|
+
xai: 'grok-4-0709',
|
|
658
|
+
google: 'gemini-2.5-pro',
|
|
659
|
+
anthropic: 'claude-sonnet-4-20250514',
|
|
660
|
+
mistral: 'magistral-medium-2506',
|
|
661
|
+
deepseek: 'deepseek-reasoner',
|
|
662
|
+
openrouter: 'qwen/qwen3-coder',
|
|
589
663
|
};
|
|
590
664
|
|
|
591
665
|
return defaults[providerName] || 'gpt-5';
|
|
@@ -611,8 +685,12 @@ function mapModelToProvider(model, providers) {
|
|
|
611
685
|
}
|
|
612
686
|
|
|
613
687
|
// Check OpenRouter-specific patterns first
|
|
614
|
-
if (
|
|
615
|
-
|
|
688
|
+
if (
|
|
689
|
+
modelLower === 'openrouter auto' ||
|
|
690
|
+
modelLower === 'auto router' ||
|
|
691
|
+
modelLower === 'auto-router' ||
|
|
692
|
+
modelLower === 'openrouter-auto'
|
|
693
|
+
) {
|
|
616
694
|
return 'openrouter';
|
|
617
695
|
}
|
|
618
696
|
|
|
@@ -622,7 +700,11 @@ function mapModelToProvider(model, providers) {
|
|
|
622
700
|
for (const [providerName, provider] of Object.entries(providers)) {
|
|
623
701
|
if (provider && provider.getModelConfig) {
|
|
624
702
|
const modelConfig = provider.getModelConfig(model);
|
|
625
|
-
if (
|
|
703
|
+
if (
|
|
704
|
+
modelConfig &&
|
|
705
|
+
!modelConfig.isDynamic &&
|
|
706
|
+
!modelConfig.needsApiUpdate
|
|
707
|
+
) {
|
|
626
708
|
// Model exists in this provider's static list
|
|
627
709
|
return providerName;
|
|
628
710
|
}
|
|
@@ -635,8 +717,12 @@ function mapModelToProvider(model, providers) {
|
|
|
635
717
|
// For non-slash models, use keyword matching as before
|
|
636
718
|
|
|
637
719
|
// OpenAI models
|
|
638
|
-
if (
|
|
639
|
-
|
|
720
|
+
if (
|
|
721
|
+
modelLower.includes('gpt') ||
|
|
722
|
+
modelLower.includes('o1') ||
|
|
723
|
+
modelLower.includes('o3') ||
|
|
724
|
+
modelLower.includes('o4')
|
|
725
|
+
) {
|
|
640
726
|
return 'openai';
|
|
641
727
|
}
|
|
642
728
|
|
|
@@ -646,14 +732,22 @@ function mapModelToProvider(model, providers) {
|
|
|
646
732
|
}
|
|
647
733
|
|
|
648
734
|
// Google models
|
|
649
|
-
if (
|
|
650
|
-
|
|
735
|
+
if (
|
|
736
|
+
modelLower.includes('gemini') ||
|
|
737
|
+
modelLower.includes('flash') ||
|
|
738
|
+
modelLower.includes('pro') ||
|
|
739
|
+
modelLower === 'google'
|
|
740
|
+
) {
|
|
651
741
|
return 'google';
|
|
652
742
|
}
|
|
653
743
|
|
|
654
744
|
// Anthropic models
|
|
655
|
-
if (
|
|
656
|
-
|
|
745
|
+
if (
|
|
746
|
+
modelLower.includes('claude') ||
|
|
747
|
+
modelLower.includes('opus') ||
|
|
748
|
+
modelLower.includes('sonnet') ||
|
|
749
|
+
modelLower.includes('haiku')
|
|
750
|
+
) {
|
|
657
751
|
return 'anthropic';
|
|
658
752
|
}
|
|
659
753
|
|
|
@@ -663,14 +757,22 @@ function mapModelToProvider(model, providers) {
|
|
|
663
757
|
}
|
|
664
758
|
|
|
665
759
|
// DeepSeek models
|
|
666
|
-
if (
|
|
667
|
-
|
|
760
|
+
if (
|
|
761
|
+
modelLower.includes('deepseek') ||
|
|
762
|
+
modelLower === 'reasoner' ||
|
|
763
|
+
modelLower === 'r1' ||
|
|
764
|
+
modelLower === 'chat'
|
|
765
|
+
) {
|
|
668
766
|
return 'deepseek';
|
|
669
767
|
}
|
|
670
768
|
|
|
671
769
|
// OpenRouter models (specific model patterns)
|
|
672
|
-
if (
|
|
673
|
-
|
|
770
|
+
if (
|
|
771
|
+
modelLower.includes('qwen') ||
|
|
772
|
+
modelLower.includes('kimi') ||
|
|
773
|
+
modelLower.includes('moonshot') ||
|
|
774
|
+
modelLower === 'k2'
|
|
775
|
+
) {
|
|
674
776
|
return 'openrouter';
|
|
675
777
|
}
|
|
676
778
|
|
|
@@ -693,7 +795,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
693
795
|
contextProcessor,
|
|
694
796
|
providerStreamNormalizer,
|
|
695
797
|
continuationId,
|
|
696
|
-
title: passedTitle // Title passed from initial submission
|
|
798
|
+
title: passedTitle, // Title passed from initial submission
|
|
697
799
|
} = dependencies;
|
|
698
800
|
|
|
699
801
|
const {
|
|
@@ -705,7 +807,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
705
807
|
cross_feedback_prompt,
|
|
706
808
|
temperature = 0.2,
|
|
707
809
|
reasoning_effort = 'medium',
|
|
708
|
-
use_websearch = false
|
|
810
|
+
use_websearch = false,
|
|
709
811
|
} = args;
|
|
710
812
|
|
|
711
813
|
let conversationHistory = [];
|
|
@@ -725,13 +827,18 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
725
827
|
|
|
726
828
|
// Validate file paths before processing
|
|
727
829
|
if (files.length > 0 || images.length > 0) {
|
|
728
|
-
const validation = await validateAllPaths(
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
830
|
+
const validation = await validateAllPaths(
|
|
831
|
+
{
|
|
832
|
+
files,
|
|
833
|
+
images,
|
|
834
|
+
},
|
|
835
|
+
{ clientCwd: config.server?.client_cwd },
|
|
836
|
+
);
|
|
732
837
|
if (!validation.valid) {
|
|
733
838
|
logger.error('File validation failed', { errors: validation.errors });
|
|
734
|
-
throw new Error(
|
|
839
|
+
throw new Error(
|
|
840
|
+
`File validation failed: ${validation.errors.join(', ')}`,
|
|
841
|
+
);
|
|
735
842
|
}
|
|
736
843
|
}
|
|
737
844
|
|
|
@@ -741,24 +848,29 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
741
848
|
try {
|
|
742
849
|
const contextRequest = {
|
|
743
850
|
files: Array.isArray(files) ? files : [],
|
|
744
|
-
images: Array.isArray(images) ? images : []
|
|
851
|
+
images: Array.isArray(images) ? images : [],
|
|
745
852
|
};
|
|
746
853
|
|
|
747
|
-
const contextResult = await contextProcessor.processUnifiedContext(
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
854
|
+
const contextResult = await contextProcessor.processUnifiedContext(
|
|
855
|
+
contextRequest,
|
|
856
|
+
{
|
|
857
|
+
enforceSecurityCheck: false,
|
|
858
|
+
skipSecurityCheck: true,
|
|
859
|
+
clientCwd: config.server?.client_cwd,
|
|
860
|
+
},
|
|
861
|
+
);
|
|
752
862
|
|
|
753
863
|
// Create context message from files and images
|
|
754
|
-
const allProcessedFiles = [
|
|
864
|
+
const allProcessedFiles = [
|
|
865
|
+
...contextResult.files,
|
|
866
|
+
...contextResult.images,
|
|
867
|
+
];
|
|
755
868
|
if (allProcessedFiles.length > 0) {
|
|
756
869
|
contextMessage = createFileContext(allProcessedFiles, {
|
|
757
870
|
includeMetadata: true,
|
|
758
|
-
includeErrors: true
|
|
871
|
+
includeErrors: true,
|
|
759
872
|
});
|
|
760
873
|
}
|
|
761
|
-
|
|
762
874
|
} catch (error) {
|
|
763
875
|
logger.error('Error processing context', { error });
|
|
764
876
|
// Continue without context if processing fails
|
|
@@ -771,7 +883,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
771
883
|
// Add system prompt
|
|
772
884
|
messages.push({
|
|
773
885
|
role: 'system',
|
|
774
|
-
content: CONSENSUS_PROMPT
|
|
886
|
+
content: CONSENSUS_PROMPT,
|
|
775
887
|
});
|
|
776
888
|
|
|
777
889
|
// Add conversation history
|
|
@@ -780,14 +892,14 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
780
892
|
// Add user prompt with context
|
|
781
893
|
const userMessage = {
|
|
782
894
|
role: 'user',
|
|
783
|
-
content: prompt
|
|
895
|
+
content: prompt,
|
|
784
896
|
};
|
|
785
897
|
|
|
786
898
|
// If we have context (files/images), create complex content array
|
|
787
899
|
if (contextMessage && contextMessage.content) {
|
|
788
900
|
userMessage.content = [
|
|
789
901
|
...contextMessage.content,
|
|
790
|
-
{ type: 'text', text: prompt }
|
|
902
|
+
{ type: 'text', text: prompt },
|
|
791
903
|
];
|
|
792
904
|
}
|
|
793
905
|
|
|
@@ -801,7 +913,15 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
801
913
|
let modelsToProcess = models;
|
|
802
914
|
if (models.length === 1 && models[0].toLowerCase() === 'auto') {
|
|
803
915
|
const availableProviders = [];
|
|
804
|
-
const providerOrder = [
|
|
916
|
+
const providerOrder = [
|
|
917
|
+
'openai',
|
|
918
|
+
'google',
|
|
919
|
+
'xai',
|
|
920
|
+
'anthropic',
|
|
921
|
+
'mistral',
|
|
922
|
+
'deepseek',
|
|
923
|
+
'openrouter',
|
|
924
|
+
];
|
|
805
925
|
|
|
806
926
|
for (const providerName of providerOrder) {
|
|
807
927
|
if (availableProviders.length >= 3) break;
|
|
@@ -812,18 +932,20 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
812
932
|
}
|
|
813
933
|
|
|
814
934
|
if (availableProviders.length === 0) {
|
|
815
|
-
throw new Error(
|
|
935
|
+
throw new Error(
|
|
936
|
+
'No providers available. Please configure at least one API key.',
|
|
937
|
+
);
|
|
816
938
|
}
|
|
817
939
|
|
|
818
|
-
modelsToProcess = availableProviders.map(providerName =>
|
|
819
|
-
getDefaultModelForProvider(providerName)
|
|
940
|
+
modelsToProcess = availableProviders.map((providerName) =>
|
|
941
|
+
getDefaultModelForProvider(providerName),
|
|
820
942
|
);
|
|
821
943
|
|
|
822
944
|
logger.debug('Auto-expanded to providers', {
|
|
823
945
|
data: {
|
|
824
946
|
providers: availableProviders,
|
|
825
|
-
models: modelsToProcess
|
|
826
|
-
}
|
|
947
|
+
models: modelsToProcess,
|
|
948
|
+
},
|
|
827
949
|
});
|
|
828
950
|
}
|
|
829
951
|
|
|
@@ -833,7 +955,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
833
955
|
failedModels.push({
|
|
834
956
|
model: modelName || 'unknown',
|
|
835
957
|
error: 'Invalid model specification',
|
|
836
|
-
status: 'failed'
|
|
958
|
+
status: 'failed',
|
|
837
959
|
});
|
|
838
960
|
continue;
|
|
839
961
|
}
|
|
@@ -847,7 +969,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
847
969
|
model: modelName,
|
|
848
970
|
provider: providerName,
|
|
849
971
|
error: `Provider not found: ${providerName}`,
|
|
850
|
-
status: 'failed'
|
|
972
|
+
status: 'failed',
|
|
851
973
|
});
|
|
852
974
|
continue;
|
|
853
975
|
}
|
|
@@ -857,7 +979,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
857
979
|
model: modelName,
|
|
858
980
|
provider: providerName,
|
|
859
981
|
error: `Provider ${providerName} not available (check API key)`,
|
|
860
|
-
status: 'failed'
|
|
982
|
+
status: 'failed',
|
|
861
983
|
});
|
|
862
984
|
continue;
|
|
863
985
|
}
|
|
@@ -872,19 +994,19 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
872
994
|
use_websearch,
|
|
873
995
|
signal: context?.signal, // Pass AbortSignal for cancellation support
|
|
874
996
|
config,
|
|
875
|
-
model: resolvedModelName
|
|
876
|
-
}
|
|
997
|
+
model: resolvedModelName,
|
|
998
|
+
},
|
|
877
999
|
});
|
|
878
1000
|
}
|
|
879
1001
|
|
|
880
1002
|
if (providerCalls.length === 0) {
|
|
881
1003
|
throw new Error(
|
|
882
|
-
`No valid providers available for the specified models. Failed models: ${failedModels.map(f => f.model).join(', ')}
|
|
1004
|
+
`No valid providers available for the specified models. Failed models: ${failedModels.map((f) => f.model).join(', ')}`,
|
|
883
1005
|
);
|
|
884
1006
|
}
|
|
885
1007
|
|
|
886
1008
|
// Create models list string for display
|
|
887
|
-
const modelsList = providerCalls.map(call => call.model).join(', ');
|
|
1009
|
+
const modelsList = providerCalls.map((call) => call.model).join(', ');
|
|
888
1010
|
|
|
889
1011
|
// Initialize SummarizationService
|
|
890
1012
|
const summarizationService = new SummarizationService(providers, config);
|
|
@@ -914,27 +1036,29 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
914
1036
|
total_providers: providerCalls.length,
|
|
915
1037
|
completed_providers: 0,
|
|
916
1038
|
failed_providers: failedModels.length,
|
|
917
|
-
provider_status: {}
|
|
918
|
-
}
|
|
1039
|
+
provider_status: {},
|
|
1040
|
+
},
|
|
919
1041
|
});
|
|
920
1042
|
|
|
921
1043
|
const consensusStartTime = Date.now();
|
|
922
1044
|
|
|
923
1045
|
// Phase 1: Initial parallel provider calls with streaming
|
|
924
|
-
logger.debug('Calling providers in parallel with streaming', {
|
|
1046
|
+
logger.debug('Calling providers in parallel with streaming', {
|
|
1047
|
+
data: { providerCount: providerCalls.length },
|
|
1048
|
+
});
|
|
925
1049
|
|
|
926
1050
|
const initialResults = await executeConsensusPhaseWithStreaming(
|
|
927
1051
|
providerCalls,
|
|
928
1052
|
messages,
|
|
929
1053
|
'initial',
|
|
930
1054
|
context,
|
|
931
|
-
providerStreamNormalizer
|
|
1055
|
+
providerStreamNormalizer,
|
|
932
1056
|
);
|
|
933
1057
|
|
|
934
1058
|
// Process initial results
|
|
935
1059
|
const initialPhase = {
|
|
936
1060
|
successful: [],
|
|
937
|
-
failed: []
|
|
1061
|
+
failed: [],
|
|
938
1062
|
};
|
|
939
1063
|
|
|
940
1064
|
initialResults.forEach((result) => {
|
|
@@ -952,7 +1076,9 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
952
1076
|
|
|
953
1077
|
// Phase 2: Cross-feedback (if enabled and we have multiple successful responses)
|
|
954
1078
|
if (enable_cross_feedback && initialPhase.successful.length > 1) {
|
|
955
|
-
logger.debug('Running cross-feedback phase with streaming', {
|
|
1079
|
+
logger.debug('Running cross-feedback phase with streaming', {
|
|
1080
|
+
data: { responseCount: initialPhase.successful.length },
|
|
1081
|
+
});
|
|
956
1082
|
|
|
957
1083
|
// Update job status for phase 2
|
|
958
1084
|
await context.updateJob({
|
|
@@ -960,12 +1086,13 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
960
1086
|
phase: 'cross_feedback',
|
|
961
1087
|
total_providers: initialPhase.successful.length,
|
|
962
1088
|
completed_providers: 0,
|
|
963
|
-
provider_status: {}
|
|
964
|
-
}
|
|
1089
|
+
provider_status: {},
|
|
1090
|
+
},
|
|
965
1091
|
});
|
|
966
1092
|
|
|
967
1093
|
// Create cross-feedback prompt
|
|
968
|
-
const feedbackPrompt =
|
|
1094
|
+
const feedbackPrompt =
|
|
1095
|
+
cross_feedback_prompt ||
|
|
969
1096
|
`Based on the other AI responses below, please refine your answer to the original question. Consider different perspectives and provide your final response:
|
|
970
1097
|
|
|
971
1098
|
Original Question: ${prompt}
|
|
@@ -977,23 +1104,23 @@ Please provide your refined response:`;
|
|
|
977
1104
|
|
|
978
1105
|
// Build model-specific feedback calls
|
|
979
1106
|
const feedbackCalls = initialPhase.successful.map((initialResult) => {
|
|
980
|
-
const call = providerCalls.find(c => c.model === initialResult.model);
|
|
1107
|
+
const call = providerCalls.find((c) => c.model === initialResult.model);
|
|
981
1108
|
|
|
982
1109
|
// Build model-specific feedback messages with the assistant's initial response
|
|
983
1110
|
const modelFeedbackMessages = [...messages];
|
|
984
1111
|
modelFeedbackMessages.push({
|
|
985
1112
|
role: 'assistant',
|
|
986
|
-
content: initialResult.response
|
|
1113
|
+
content: initialResult.response,
|
|
987
1114
|
});
|
|
988
1115
|
modelFeedbackMessages.push({
|
|
989
1116
|
role: 'user',
|
|
990
|
-
content: feedbackPrompt
|
|
1117
|
+
content: feedbackPrompt,
|
|
991
1118
|
});
|
|
992
1119
|
|
|
993
1120
|
return {
|
|
994
1121
|
...call,
|
|
995
1122
|
messages: modelFeedbackMessages,
|
|
996
|
-
initialResult
|
|
1123
|
+
initialResult,
|
|
997
1124
|
};
|
|
998
1125
|
});
|
|
999
1126
|
|
|
@@ -1003,7 +1130,7 @@ Please provide your refined response:`;
|
|
|
1003
1130
|
null, // messages already embedded in feedbackCalls
|
|
1004
1131
|
'refinement',
|
|
1005
1132
|
context,
|
|
1006
|
-
providerStreamNormalizer
|
|
1133
|
+
providerStreamNormalizer,
|
|
1007
1134
|
);
|
|
1008
1135
|
|
|
1009
1136
|
// Process refinement results
|
|
@@ -1015,7 +1142,7 @@ Please provide your refined response:`;
|
|
|
1015
1142
|
refined_metadata: result.status === 'success' ? result.metadata : {},
|
|
1016
1143
|
refined_error: result.status === 'failed' ? result.error : null,
|
|
1017
1144
|
initial_response: initialResult.response,
|
|
1018
|
-
status: result.status === 'success' ? 'success' : 'partial'
|
|
1145
|
+
status: result.status === 'success' ? 'success' : 'partial',
|
|
1019
1146
|
};
|
|
1020
1147
|
});
|
|
1021
1148
|
}
|
|
@@ -1024,8 +1151,11 @@ Please provide your refined response:`;
|
|
|
1024
1151
|
try {
|
|
1025
1152
|
const consensusMessage = {
|
|
1026
1153
|
role: 'assistant',
|
|
1027
|
-
content:
|
|
1028
|
-
|
|
1154
|
+
content:
|
|
1155
|
+
`Consensus completed with ${initialPhase.successful.length} successful responses` +
|
|
1156
|
+
(refinedPhase
|
|
1157
|
+
? ` and ${refinedPhase.filter((r) => r.status === 'success').length} refined responses`
|
|
1158
|
+
: ''),
|
|
1029
1159
|
};
|
|
1030
1160
|
|
|
1031
1161
|
const conversationState = {
|
|
@@ -1036,8 +1166,8 @@ Please provide your refined response:`;
|
|
|
1036
1166
|
modelsRequested: models.length,
|
|
1037
1167
|
providersSuccessful: initialPhase.successful.length,
|
|
1038
1168
|
providersFailed: initialPhase.failed.length,
|
|
1039
|
-
crossFeedbackEnabled: enable_cross_feedback
|
|
1040
|
-
}
|
|
1169
|
+
crossFeedbackEnabled: enable_cross_feedback,
|
|
1170
|
+
},
|
|
1041
1171
|
};
|
|
1042
1172
|
|
|
1043
1173
|
await continuationStore.set(continuationId, conversationState);
|
|
@@ -1054,7 +1184,7 @@ Please provide your refined response:`;
|
|
|
1054
1184
|
// Collect all successful responses for summary generation
|
|
1055
1185
|
if (refinedPhase) {
|
|
1056
1186
|
// Use refined responses when available
|
|
1057
|
-
refinedPhase.forEach(result => {
|
|
1187
|
+
refinedPhase.forEach((result) => {
|
|
1058
1188
|
if (result.status === 'success' && result.refined_response) {
|
|
1059
1189
|
combinedResponses.push(`${result.model}:\n${result.refined_response}`);
|
|
1060
1190
|
} else if (result.initial_response) {
|
|
@@ -1064,7 +1194,7 @@ Please provide your refined response:`;
|
|
|
1064
1194
|
});
|
|
1065
1195
|
} else {
|
|
1066
1196
|
// Use initial responses
|
|
1067
|
-
initialPhase.successful.forEach(result => {
|
|
1197
|
+
initialPhase.successful.forEach((result) => {
|
|
1068
1198
|
if (result.response) {
|
|
1069
1199
|
combinedResponses.push(`${result.model}:\n${result.response}`);
|
|
1070
1200
|
}
|
|
@@ -1076,12 +1206,13 @@ Please provide your refined response:`;
|
|
|
1076
1206
|
const combinedContent = combinedResponses.join('\n\n---\n\n');
|
|
1077
1207
|
if (combinedContent.length > 100) {
|
|
1078
1208
|
try {
|
|
1079
|
-
finalSummary =
|
|
1209
|
+
finalSummary =
|
|
1210
|
+
await summarizationService.generateFinalSummary(combinedContent);
|
|
1080
1211
|
debugLog(`Consensus: Generated final summary - "${finalSummary}"`);
|
|
1081
1212
|
|
|
1082
1213
|
// Update job with final summary
|
|
1083
1214
|
await context.updateJob({
|
|
1084
|
-
final_summary: finalSummary
|
|
1215
|
+
final_summary: finalSummary,
|
|
1085
1216
|
});
|
|
1086
1217
|
} catch (error) {
|
|
1087
1218
|
debugError('Consensus: Error generating final summary', error);
|
|
@@ -1095,20 +1226,22 @@ Please provide your refined response:`;
|
|
|
1095
1226
|
const failureDetails = [];
|
|
1096
1227
|
|
|
1097
1228
|
if (enable_cross_feedback && refinedPhase) {
|
|
1098
|
-
finalSuccessCount = refinedPhase.filter(
|
|
1229
|
+
finalSuccessCount = refinedPhase.filter(
|
|
1230
|
+
(r) => r.status === 'success',
|
|
1231
|
+
).length;
|
|
1099
1232
|
|
|
1100
|
-
refinedPhase.forEach(result => {
|
|
1233
|
+
refinedPhase.forEach((result) => {
|
|
1101
1234
|
if (result.status === 'partial') {
|
|
1102
1235
|
failureDetails.push(`${result.model} (refinement failed)`);
|
|
1103
1236
|
}
|
|
1104
1237
|
});
|
|
1105
1238
|
|
|
1106
|
-
initialPhase.failed.forEach(failure => {
|
|
1239
|
+
initialPhase.failed.forEach((failure) => {
|
|
1107
1240
|
failureDetails.push(`${failure.model} (initial failed)`);
|
|
1108
1241
|
});
|
|
1109
1242
|
} else {
|
|
1110
1243
|
finalSuccessCount = initialPhase.successful.length;
|
|
1111
|
-
initialPhase.failed.forEach(failure => {
|
|
1244
|
+
initialPhase.failed.forEach((failure) => {
|
|
1112
1245
|
failureDetails.push(`${failure.model} (${failure.error})`);
|
|
1113
1246
|
});
|
|
1114
1247
|
}
|
|
@@ -1119,20 +1252,22 @@ Please provide your refined response:`;
|
|
|
1119
1252
|
models_consulted: models.length,
|
|
1120
1253
|
successful_initial_responses: initialPhase.successful.length,
|
|
1121
1254
|
failed_responses: initialPhase.failed.length,
|
|
1122
|
-
refined_responses: refinedPhase
|
|
1255
|
+
refined_responses: refinedPhase
|
|
1256
|
+
? refinedPhase.filter((r) => r.status === 'success').length
|
|
1257
|
+
: 0,
|
|
1123
1258
|
phases: {
|
|
1124
1259
|
initial: initialPhase.successful,
|
|
1125
1260
|
...(refinedPhase !== null && { refined: refinedPhase }),
|
|
1126
|
-
failed: initialPhase.failed
|
|
1261
|
+
failed: initialPhase.failed,
|
|
1127
1262
|
},
|
|
1128
1263
|
continuation: {
|
|
1129
1264
|
id: continuationId,
|
|
1130
|
-
messageCount: messages.length + 1
|
|
1265
|
+
messageCount: messages.length + 1,
|
|
1131
1266
|
},
|
|
1132
1267
|
settings: {
|
|
1133
1268
|
enable_cross_feedback,
|
|
1134
1269
|
temperature,
|
|
1135
|
-
models_requested: models
|
|
1270
|
+
models_requested: models,
|
|
1136
1271
|
},
|
|
1137
1272
|
metadata: {
|
|
1138
1273
|
execution_time: consensusExecutionTime,
|
|
@@ -1141,8 +1276,8 @@ Please provide your refined response:`;
|
|
|
1141
1276
|
total_models: models.length,
|
|
1142
1277
|
failure_details: failureDetails,
|
|
1143
1278
|
title,
|
|
1144
|
-
final_summary: finalSummary
|
|
1145
|
-
}
|
|
1279
|
+
final_summary: finalSummary,
|
|
1280
|
+
},
|
|
1146
1281
|
};
|
|
1147
1282
|
}
|
|
1148
1283
|
|
|
@@ -1155,7 +1290,13 @@ Please provide your refined response:`;
|
|
|
1155
1290
|
* @param {object} streamNormalizer - Stream normalizer instance
|
|
1156
1291
|
* @returns {Promise<Array>} Results from all providers
|
|
1157
1292
|
*/
|
|
1158
|
-
async function executeConsensusPhaseWithStreaming(
|
|
1293
|
+
async function executeConsensusPhaseWithStreaming(
|
|
1294
|
+
providerCalls,
|
|
1295
|
+
messages,
|
|
1296
|
+
phase,
|
|
1297
|
+
context,
|
|
1298
|
+
streamNormalizer,
|
|
1299
|
+
) {
|
|
1159
1300
|
let completedCount = 0;
|
|
1160
1301
|
const totalCount = providerCalls.length;
|
|
1161
1302
|
const providerContents = {}; // Store accumulated content per provider
|
|
@@ -1172,21 +1313,31 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1172
1313
|
await context.updateJob({
|
|
1173
1314
|
progress: {
|
|
1174
1315
|
[`provider_${index}_status`]: 'prompting',
|
|
1175
|
-
[`provider_${index}_model`]: call.model
|
|
1176
|
-
}
|
|
1316
|
+
[`provider_${index}_model`]: call.model,
|
|
1317
|
+
},
|
|
1177
1318
|
});
|
|
1178
1319
|
|
|
1179
1320
|
const messagesToSend = call.messages || messages;
|
|
1180
1321
|
let response;
|
|
1181
1322
|
|
|
1182
1323
|
// Check if provider supports streaming
|
|
1183
|
-
if (
|
|
1324
|
+
if (
|
|
1325
|
+
call.providerInstance.stream &&
|
|
1326
|
+
typeof call.providerInstance.stream === 'function'
|
|
1327
|
+
) {
|
|
1184
1328
|
// Use streaming with normalization
|
|
1185
|
-
const stream = call.providerInstance.stream(
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1329
|
+
const stream = call.providerInstance.stream(
|
|
1330
|
+
messagesToSend,
|
|
1331
|
+
call.options,
|
|
1332
|
+
);
|
|
1333
|
+
const normalizedStream = streamNormalizer.normalize(
|
|
1334
|
+
call.provider,
|
|
1335
|
+
stream,
|
|
1336
|
+
{
|
|
1337
|
+
model: call.options.model,
|
|
1338
|
+
requestId: `${context.jobId}-${phase}-${index}`,
|
|
1339
|
+
},
|
|
1340
|
+
);
|
|
1190
1341
|
|
|
1191
1342
|
// Process normalized stream
|
|
1192
1343
|
let accumulatedContent = '';
|
|
@@ -1194,7 +1345,7 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1194
1345
|
let finalMetadata = {};
|
|
1195
1346
|
|
|
1196
1347
|
await context.updateJob({
|
|
1197
|
-
progress: { [`provider_${index}_status`]: 'streaming' }
|
|
1348
|
+
progress: { [`provider_${index}_status`]: 'streaming' },
|
|
1198
1349
|
});
|
|
1199
1350
|
|
|
1200
1351
|
for await (const event of normalizedStream) {
|
|
@@ -1210,15 +1361,16 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1210
1361
|
|
|
1211
1362
|
// Combine all provider contents for unified accumulated_content
|
|
1212
1363
|
const combinedContent = Object.values(providerContents)
|
|
1213
|
-
.filter(content => content && content.length > 0)
|
|
1364
|
+
.filter((content) => content && content.length > 0)
|
|
1214
1365
|
.join('\n\n---\n\n');
|
|
1215
1366
|
|
|
1216
1367
|
// Update with both provider preview and combined accumulated content
|
|
1217
1368
|
await context.updateJob({
|
|
1218
|
-
[`provider_${index}_preview`]:
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1369
|
+
[`provider_${index}_preview`]:
|
|
1370
|
+
accumulatedContent.length > 150
|
|
1371
|
+
? accumulatedContent.substring(0, 150) + '...'
|
|
1372
|
+
: accumulatedContent,
|
|
1373
|
+
accumulated_content: combinedContent, // Full combined content from all providers
|
|
1222
1374
|
});
|
|
1223
1375
|
break;
|
|
1224
1376
|
case 'usage':
|
|
@@ -1239,16 +1391,18 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1239
1391
|
metadata: {
|
|
1240
1392
|
...finalMetadata,
|
|
1241
1393
|
usage: finalUsage,
|
|
1242
|
-
streaming: true
|
|
1243
|
-
}
|
|
1394
|
+
streaming: true,
|
|
1395
|
+
},
|
|
1244
1396
|
};
|
|
1245
1397
|
|
|
1246
1398
|
// Store final provider content
|
|
1247
1399
|
providerContents[index] = accumulatedContent;
|
|
1248
|
-
|
|
1249
1400
|
} else {
|
|
1250
1401
|
// Fall back to regular invoke
|
|
1251
|
-
response = await call.providerInstance.invoke(
|
|
1402
|
+
response = await call.providerInstance.invoke(
|
|
1403
|
+
messagesToSend,
|
|
1404
|
+
call.options,
|
|
1405
|
+
);
|
|
1252
1406
|
|
|
1253
1407
|
// Store provider content for non-streaming response
|
|
1254
1408
|
if (response && response.content) {
|
|
@@ -1256,29 +1410,30 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1256
1410
|
|
|
1257
1411
|
// Update accumulated content for non-streaming provider
|
|
1258
1412
|
const combinedContent = Object.values(providerContents)
|
|
1259
|
-
.filter(content => content && content.length > 0)
|
|
1413
|
+
.filter((content) => content && content.length > 0)
|
|
1260
1414
|
.join('\n\n---\n\n');
|
|
1261
1415
|
|
|
1262
1416
|
await context.updateJob({
|
|
1263
|
-
accumulated_content: combinedContent
|
|
1417
|
+
accumulated_content: combinedContent,
|
|
1264
1418
|
});
|
|
1265
1419
|
}
|
|
1266
1420
|
}
|
|
1267
1421
|
|
|
1268
1422
|
// Update provider status to 'finished'
|
|
1269
1423
|
completedCount++;
|
|
1270
|
-
const progressText =
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1424
|
+
const progressText =
|
|
1425
|
+
phase === 'initial'
|
|
1426
|
+
? `${completedCount}/${totalCount} initial`
|
|
1427
|
+
: phase === 'refinement'
|
|
1428
|
+
? `${completedCount}/${totalCount} refined`
|
|
1429
|
+
: `${completedCount}/${totalCount} responded`;
|
|
1275
1430
|
|
|
1276
1431
|
await context.updateJob({
|
|
1277
1432
|
consensus_progress: progressText,
|
|
1278
1433
|
progress: {
|
|
1279
1434
|
[`provider_${index}_status`]: 'finished',
|
|
1280
|
-
completed_providers: completedCount
|
|
1281
|
-
}
|
|
1435
|
+
completed_providers: completedCount,
|
|
1436
|
+
},
|
|
1282
1437
|
});
|
|
1283
1438
|
|
|
1284
1439
|
return {
|
|
@@ -1286,16 +1441,15 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1286
1441
|
provider: call.provider,
|
|
1287
1442
|
status: 'success',
|
|
1288
1443
|
response: response.content,
|
|
1289
|
-
metadata: response.metadata || {}
|
|
1444
|
+
metadata: response.metadata || {},
|
|
1290
1445
|
};
|
|
1291
|
-
|
|
1292
1446
|
} catch (error) {
|
|
1293
1447
|
// Update provider status to 'failed'
|
|
1294
1448
|
await context.updateJob({
|
|
1295
1449
|
progress: {
|
|
1296
1450
|
[`provider_${index}_status`]: 'failed',
|
|
1297
|
-
[`provider_${index}_error`]: error.message
|
|
1298
|
-
}
|
|
1451
|
+
[`provider_${index}_error`]: error.message,
|
|
1452
|
+
},
|
|
1299
1453
|
});
|
|
1300
1454
|
|
|
1301
1455
|
return {
|
|
@@ -1303,20 +1457,20 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1303
1457
|
provider: call.provider,
|
|
1304
1458
|
status: 'failed',
|
|
1305
1459
|
error: error.message,
|
|
1306
|
-
metadata: {}
|
|
1460
|
+
metadata: {},
|
|
1307
1461
|
};
|
|
1308
1462
|
}
|
|
1309
|
-
})
|
|
1463
|
+
}),
|
|
1310
1464
|
);
|
|
1311
1465
|
|
|
1312
1466
|
// After all providers complete, update with final combined content
|
|
1313
1467
|
const finalCombinedContent = Object.values(providerContents)
|
|
1314
|
-
.filter(content => content && content.length > 0)
|
|
1468
|
+
.filter((content) => content && content.length > 0)
|
|
1315
1469
|
.join('\n\n---\n\n');
|
|
1316
1470
|
|
|
1317
1471
|
if (finalCombinedContent) {
|
|
1318
1472
|
await context.updateJob({
|
|
1319
|
-
accumulated_content: finalCombinedContent
|
|
1473
|
+
accumulated_content: finalCombinedContent,
|
|
1320
1474
|
});
|
|
1321
1475
|
}
|
|
1322
1476
|
|
|
@@ -1329,14 +1483,15 @@ async function executeConsensusPhaseWithStreaming(providerCalls, messages, phase
|
|
|
1329
1483
|
provider: providerCalls[index].provider,
|
|
1330
1484
|
status: 'failed',
|
|
1331
1485
|
error: result.reason.message || 'Unknown error',
|
|
1332
|
-
metadata: {}
|
|
1486
|
+
metadata: {},
|
|
1333
1487
|
};
|
|
1334
1488
|
}
|
|
1335
1489
|
});
|
|
1336
1490
|
}
|
|
1337
1491
|
|
|
1338
1492
|
// Tool metadata
|
|
1339
|
-
consensusTool.description =
|
|
1493
|
+
consensusTool.description =
|
|
1494
|
+
'PARALLEL CONSENSUS WITH CROSS-MODEL FEEDBACK - Query multiple models simultaneously, then optionally refine responses based on cross-feedback. For complex decisions, architectural choices, technical evaluations. Use models: ["auto"] for automatic selection.';
|
|
1340
1495
|
consensusTool.inputSchema = {
|
|
1341
1496
|
type: 'object',
|
|
1342
1497
|
properties: {
|
|
@@ -1344,34 +1499,41 @@ consensusTool.inputSchema = {
|
|
|
1344
1499
|
type: 'array',
|
|
1345
1500
|
items: { type: 'string' },
|
|
1346
1501
|
minItems: 1,
|
|
1347
|
-
description:
|
|
1502
|
+
description:
|
|
1503
|
+
'List of models to consult. Example: ["gpt-5", "gemini-2.5-pro", "grok-4-0709"]',
|
|
1348
1504
|
},
|
|
1349
1505
|
files: {
|
|
1350
1506
|
type: 'array',
|
|
1351
1507
|
items: { type: 'string' },
|
|
1352
|
-
description:
|
|
1508
|
+
description:
|
|
1509
|
+
'File paths for additional context (absolute or relative paths). Example: ["C:\\Users\\username\\project\\architecture.md", "./requirements.txt"]',
|
|
1353
1510
|
},
|
|
1354
1511
|
images: {
|
|
1355
1512
|
type: 'array',
|
|
1356
1513
|
items: { type: 'string' },
|
|
1357
|
-
description:
|
|
1514
|
+
description:
|
|
1515
|
+
'Image paths for visual context (absolute or relative paths, or base64). Example: ["C:\\Users\\username\\current_architecture.png", "./user_flow.jpg"]',
|
|
1358
1516
|
},
|
|
1359
1517
|
continuation_id: {
|
|
1360
1518
|
type: 'string',
|
|
1361
|
-
description:
|
|
1519
|
+
description:
|
|
1520
|
+
'Thread continuation ID for multi-turn conversations. Example: "consensus_1703123456789_xyz789"',
|
|
1362
1521
|
},
|
|
1363
1522
|
enable_cross_feedback: {
|
|
1364
1523
|
type: 'boolean',
|
|
1365
|
-
description:
|
|
1524
|
+
description:
|
|
1525
|
+
'Enable refinement phase where models see others\' responses and can improve their answers. Example: true (recommended), false (faster single-phase only). Default: true',
|
|
1366
1526
|
default: true,
|
|
1367
1527
|
},
|
|
1368
1528
|
cross_feedback_prompt: {
|
|
1369
1529
|
type: 'string',
|
|
1370
|
-
description:
|
|
1530
|
+
description:
|
|
1531
|
+
'Custom prompt for refinement phase. Example: "Focus on scalability trade-offs in your refinement" or leave empty for default cross-feedback prompt',
|
|
1371
1532
|
},
|
|
1372
1533
|
temperature: {
|
|
1373
1534
|
type: 'number',
|
|
1374
|
-
description:
|
|
1535
|
+
description:
|
|
1536
|
+
'Response randomness (0.0-1.0). Examples: 0.1 (very focused), 0.2 (analytical - default), 0.5 (balanced). Default: 0.2',
|
|
1375
1537
|
minimum: 0.0,
|
|
1376
1538
|
maximum: 1.0,
|
|
1377
1539
|
default: 0.2,
|
|
@@ -1379,22 +1541,26 @@ consensusTool.inputSchema = {
|
|
|
1379
1541
|
reasoning_effort: {
|
|
1380
1542
|
type: 'string',
|
|
1381
1543
|
enum: ['none', 'minimal', 'low', 'medium', 'high', 'max'],
|
|
1382
|
-
description:
|
|
1383
|
-
|
|
1544
|
+
description:
|
|
1545
|
+
'Reasoning depth for thinking models. Examples: "none" (no reasoning, fastest - GPT-5.1+ only), "low" (light analysis), "medium" (balanced), "high" (complex analysis). Default: "medium"',
|
|
1546
|
+
default: 'medium',
|
|
1384
1547
|
},
|
|
1385
1548
|
use_websearch: {
|
|
1386
1549
|
type: 'boolean',
|
|
1387
|
-
description:
|
|
1388
|
-
|
|
1550
|
+
description:
|
|
1551
|
+
'Enable web search for current information. Only works with models that support web search (OpenAI, XAI, Google). Example: true for recent developments or up to date documentation. Default: false',
|
|
1552
|
+
default: false,
|
|
1389
1553
|
},
|
|
1390
1554
|
async: {
|
|
1391
1555
|
type: 'boolean',
|
|
1392
|
-
description:
|
|
1393
|
-
|
|
1556
|
+
description:
|
|
1557
|
+
'Execute consensus in background with detailed progress tracking. When true, returns continuation_id immediately and processes request asynchronously with per-provider status updates. Default: false',
|
|
1558
|
+
default: false,
|
|
1394
1559
|
},
|
|
1395
1560
|
prompt: {
|
|
1396
1561
|
type: 'string',
|
|
1397
|
-
description:
|
|
1562
|
+
description:
|
|
1563
|
+
'The problem or proposal to gather consensus on. Include context and specific questions. Example: "Should we use microservices or monolith architecture for our e-commerce platform with 100k users?"',
|
|
1398
1564
|
},
|
|
1399
1565
|
},
|
|
1400
1566
|
required: ['prompt', 'models'],
|