@defai.digital/discussion-domain 13.0.3
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/LICENSE +214 -0
- package/dist/consensus/index.d.ts +23 -0
- package/dist/consensus/index.d.ts.map +1 -0
- package/dist/consensus/index.js +45 -0
- package/dist/consensus/index.js.map +1 -0
- package/dist/consensus/moderator.d.ts +15 -0
- package/dist/consensus/moderator.d.ts.map +1 -0
- package/dist/consensus/moderator.js +201 -0
- package/dist/consensus/moderator.js.map +1 -0
- package/dist/consensus/synthesis.d.ts +15 -0
- package/dist/consensus/synthesis.d.ts.map +1 -0
- package/dist/consensus/synthesis.js +161 -0
- package/dist/consensus/synthesis.js.map +1 -0
- package/dist/consensus/voting.d.ts +17 -0
- package/dist/consensus/voting.d.ts.map +1 -0
- package/dist/consensus/voting.js +168 -0
- package/dist/consensus/voting.js.map +1 -0
- package/dist/executor.d.ts +73 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +223 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/critique.d.ts +20 -0
- package/dist/patterns/critique.d.ts.map +1 -0
- package/dist/patterns/critique.js +338 -0
- package/dist/patterns/critique.js.map +1 -0
- package/dist/patterns/debate.d.ts +20 -0
- package/dist/patterns/debate.d.ts.map +1 -0
- package/dist/patterns/debate.js +236 -0
- package/dist/patterns/debate.js.map +1 -0
- package/dist/patterns/index.d.ts +25 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +49 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/round-robin.d.ts +13 -0
- package/dist/patterns/round-robin.d.ts.map +1 -0
- package/dist/patterns/round-robin.js +160 -0
- package/dist/patterns/round-robin.js.map +1 -0
- package/dist/patterns/synthesis.d.ts +20 -0
- package/dist/patterns/synthesis.d.ts.map +1 -0
- package/dist/patterns/synthesis.js +250 -0
- package/dist/patterns/synthesis.js.map +1 -0
- package/dist/patterns/voting.d.ts +19 -0
- package/dist/patterns/voting.d.ts.map +1 -0
- package/dist/patterns/voting.js +186 -0
- package/dist/patterns/voting.js.map +1 -0
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +21 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/templates.d.ts +55 -0
- package/dist/prompts/templates.d.ts.map +1 -0
- package/dist/prompts/templates.js +346 -0
- package/dist/prompts/templates.js.map +1 -0
- package/dist/provider-bridge.d.ts +115 -0
- package/dist/provider-bridge.d.ts.map +1 -0
- package/dist/provider-bridge.js +215 -0
- package/dist/provider-bridge.js.map +1 -0
- package/dist/types.d.ts +201 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +102 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
- package/src/consensus/index.ts +52 -0
- package/src/consensus/moderator.ts +242 -0
- package/src/consensus/synthesis.ts +202 -0
- package/src/consensus/voting.ts +221 -0
- package/src/executor.ts +338 -0
- package/src/index.ts +69 -0
- package/src/patterns/critique.ts +465 -0
- package/src/patterns/debate.ts +340 -0
- package/src/patterns/index.ts +56 -0
- package/src/patterns/round-robin.ts +223 -0
- package/src/patterns/synthesis.ts +353 -0
- package/src/patterns/voting.ts +266 -0
- package/src/prompts/index.ts +41 -0
- package/src/prompts/templates.ts +381 -0
- package/src/provider-bridge.ts +346 -0
- package/src/types.ts +375 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Critique Pattern Executor
|
|
3
|
+
*
|
|
4
|
+
* One model proposes, others critique, author refines.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. Round 1: First provider proposes solution
|
|
8
|
+
* 2. Round 2: Other providers critique the proposal
|
|
9
|
+
* 3. Round 3: Original proposer revises based on feedback
|
|
10
|
+
* 4. (Optional) Additional critique-revision cycles
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { DiscussionRound, DebateRole } from '@defai.digital/contracts';
|
|
14
|
+
import type {
|
|
15
|
+
PatternExecutor,
|
|
16
|
+
PatternExecutionContext,
|
|
17
|
+
PatternExecutionResult,
|
|
18
|
+
} from '../types.js';
|
|
19
|
+
import {
|
|
20
|
+
CRITIQUE_PROPOSAL,
|
|
21
|
+
CRITIQUE_REVIEW,
|
|
22
|
+
CRITIQUE_REVISION,
|
|
23
|
+
interpolate,
|
|
24
|
+
formatPreviousResponses,
|
|
25
|
+
getProviderSystemPrompt,
|
|
26
|
+
} from '../prompts/templates.js';
|
|
27
|
+
|
|
28
|
+
// Local type for discussion DiscussionProviderResponse (avoids conflict with provider/v1 DiscussionProviderResponse)
|
|
29
|
+
interface DiscussionProviderResponse {
|
|
30
|
+
provider: string;
|
|
31
|
+
content: string;
|
|
32
|
+
round: number;
|
|
33
|
+
role?: DebateRole | undefined;
|
|
34
|
+
confidence?: number | undefined;
|
|
35
|
+
vote?: string | undefined;
|
|
36
|
+
timestamp: string;
|
|
37
|
+
durationMs: number;
|
|
38
|
+
tokenCount?: number | undefined;
|
|
39
|
+
truncated?: boolean | undefined;
|
|
40
|
+
error?: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class CritiquePattern implements PatternExecutor {
|
|
44
|
+
readonly pattern = 'critique' as const;
|
|
45
|
+
|
|
46
|
+
async execute(context: PatternExecutionContext): Promise<PatternExecutionResult> {
|
|
47
|
+
const startTime = Date.now();
|
|
48
|
+
const { config, providerExecutor, availableProviders, abortSignal, onProgress } = context;
|
|
49
|
+
|
|
50
|
+
const rounds: DiscussionRound[] = [];
|
|
51
|
+
const participatingProviders = new Set<string>();
|
|
52
|
+
const failedProviders = new Set<string>();
|
|
53
|
+
|
|
54
|
+
// Filter to available providers
|
|
55
|
+
const providers = config.providers.filter(p => availableProviders.includes(p));
|
|
56
|
+
|
|
57
|
+
if (providers.length < config.minProviders) {
|
|
58
|
+
return {
|
|
59
|
+
rounds: [],
|
|
60
|
+
participatingProviders: [],
|
|
61
|
+
failedProviders: config.providers.filter(p => !availableProviders.includes(p)),
|
|
62
|
+
totalDurationMs: Date.now() - startTime,
|
|
63
|
+
success: false,
|
|
64
|
+
error: `Only ${providers.length} providers available, need ${config.minProviders}`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// First provider is the proposer (guaranteed to exist since we checked providers.length >= minProviders)
|
|
69
|
+
const proposerId = providers[0]!;
|
|
70
|
+
const critiquers = providers.slice(1);
|
|
71
|
+
|
|
72
|
+
let currentProposal = '';
|
|
73
|
+
|
|
74
|
+
// Round 1: Initial proposal
|
|
75
|
+
onProgress?.({
|
|
76
|
+
type: 'round_start',
|
|
77
|
+
round: 1,
|
|
78
|
+
message: `${proposerId} creating initial proposal`,
|
|
79
|
+
timestamp: new Date().toISOString(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const proposalRound = await this.executeProposalRound(
|
|
83
|
+
1,
|
|
84
|
+
proposerId,
|
|
85
|
+
config,
|
|
86
|
+
providerExecutor,
|
|
87
|
+
abortSignal,
|
|
88
|
+
onProgress
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
rounds.push(proposalRound.round);
|
|
92
|
+
if (proposalRound.success) {
|
|
93
|
+
participatingProviders.add(proposerId);
|
|
94
|
+
currentProposal = proposalRound.content;
|
|
95
|
+
} else {
|
|
96
|
+
failedProviders.add(proposerId);
|
|
97
|
+
return {
|
|
98
|
+
rounds,
|
|
99
|
+
participatingProviders: Array.from(participatingProviders),
|
|
100
|
+
failedProviders: Array.from(failedProviders),
|
|
101
|
+
totalDurationMs: Date.now() - startTime,
|
|
102
|
+
success: false,
|
|
103
|
+
error: 'Proposer failed to create initial proposal',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Critique-Revision cycles
|
|
108
|
+
const cycles = Math.floor((config.rounds - 1) / 2);
|
|
109
|
+
let allCritiques: DiscussionProviderResponse[] = [];
|
|
110
|
+
|
|
111
|
+
for (let cycle = 0; cycle < cycles; cycle++) {
|
|
112
|
+
if (abortSignal?.aborted) break;
|
|
113
|
+
|
|
114
|
+
const critiqueRoundNum = 2 + cycle * 2;
|
|
115
|
+
const revisionRoundNum = critiqueRoundNum + 1;
|
|
116
|
+
|
|
117
|
+
// Critique round
|
|
118
|
+
onProgress?.({
|
|
119
|
+
type: 'round_start',
|
|
120
|
+
round: critiqueRoundNum,
|
|
121
|
+
message: 'Gathering critiques',
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const critiqueRound = await this.executeCritiqueRound(
|
|
126
|
+
critiqueRoundNum,
|
|
127
|
+
critiquers.filter(c => !failedProviders.has(c)),
|
|
128
|
+
currentProposal,
|
|
129
|
+
config,
|
|
130
|
+
providerExecutor,
|
|
131
|
+
abortSignal,
|
|
132
|
+
onProgress
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
rounds.push(critiqueRound.round);
|
|
136
|
+
critiqueRound.succeeded.forEach(p => participatingProviders.add(p));
|
|
137
|
+
critiqueRound.failed.forEach(p => failedProviders.add(p));
|
|
138
|
+
allCritiques = critiqueRound.round.responses;
|
|
139
|
+
|
|
140
|
+
onProgress?.({
|
|
141
|
+
type: 'round_complete',
|
|
142
|
+
round: critiqueRoundNum,
|
|
143
|
+
message: `Received ${critiqueRound.succeeded.length} critiques`,
|
|
144
|
+
timestamp: new Date().toISOString(),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Check if we have enough critiques
|
|
148
|
+
if (critiqueRound.succeeded.length === 0) {
|
|
149
|
+
break; // No valid critiques to incorporate
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Revision round
|
|
153
|
+
if (revisionRoundNum <= config.rounds) {
|
|
154
|
+
onProgress?.({
|
|
155
|
+
type: 'round_start',
|
|
156
|
+
round: revisionRoundNum,
|
|
157
|
+
message: `${proposerId} revising proposal`,
|
|
158
|
+
timestamp: new Date().toISOString(),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const revisionRound = await this.executeRevisionRound(
|
|
162
|
+
revisionRoundNum,
|
|
163
|
+
proposerId,
|
|
164
|
+
currentProposal,
|
|
165
|
+
allCritiques,
|
|
166
|
+
config,
|
|
167
|
+
providerExecutor,
|
|
168
|
+
abortSignal,
|
|
169
|
+
onProgress
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
rounds.push(revisionRound.round);
|
|
173
|
+
if (revisionRound.success) {
|
|
174
|
+
currentProposal = revisionRound.content;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
onProgress?.({
|
|
178
|
+
type: 'round_complete',
|
|
179
|
+
round: revisionRoundNum,
|
|
180
|
+
message: 'Proposal revised',
|
|
181
|
+
timestamp: new Date().toISOString(),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
rounds,
|
|
188
|
+
participatingProviders: Array.from(participatingProviders),
|
|
189
|
+
failedProviders: Array.from(failedProviders),
|
|
190
|
+
totalDurationMs: Date.now() - startTime,
|
|
191
|
+
success: participatingProviders.size >= config.minProviders,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private async executeProposalRound(
|
|
196
|
+
roundNum: number,
|
|
197
|
+
proposerId: string,
|
|
198
|
+
config: PatternExecutionContext['config'],
|
|
199
|
+
providerExecutor: PatternExecutionContext['providerExecutor'],
|
|
200
|
+
abortSignal?: AbortSignal,
|
|
201
|
+
onProgress?: PatternExecutionContext['onProgress']
|
|
202
|
+
): Promise<{ round: DiscussionRound; success: boolean; content: string }> {
|
|
203
|
+
const roundStart = Date.now();
|
|
204
|
+
|
|
205
|
+
onProgress?.({
|
|
206
|
+
type: 'provider_start',
|
|
207
|
+
round: roundNum,
|
|
208
|
+
provider: proposerId,
|
|
209
|
+
timestamp: new Date().toISOString(),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const prompt = interpolate(CRITIQUE_PROPOSAL, {
|
|
214
|
+
topic: config.prompt,
|
|
215
|
+
context: config.context || '',
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const result = await providerExecutor.execute({
|
|
219
|
+
providerId: proposerId,
|
|
220
|
+
prompt,
|
|
221
|
+
systemPrompt: getProviderSystemPrompt(proposerId),
|
|
222
|
+
temperature: config.temperature,
|
|
223
|
+
timeoutMs: config.providerTimeout,
|
|
224
|
+
abortSignal,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const response: DiscussionProviderResponse = {
|
|
228
|
+
provider: proposerId,
|
|
229
|
+
content: result.success ? result.content || '' : '',
|
|
230
|
+
round: roundNum,
|
|
231
|
+
timestamp: new Date().toISOString(),
|
|
232
|
+
durationMs: result.durationMs,
|
|
233
|
+
tokenCount: result.tokenCount,
|
|
234
|
+
error: result.success ? undefined : result.error,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
onProgress?.({
|
|
238
|
+
type: 'provider_complete',
|
|
239
|
+
round: roundNum,
|
|
240
|
+
provider: proposerId,
|
|
241
|
+
timestamp: new Date().toISOString(),
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
onProgress?.({
|
|
245
|
+
type: 'round_complete',
|
|
246
|
+
round: roundNum,
|
|
247
|
+
timestamp: new Date().toISOString(),
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
round: {
|
|
252
|
+
roundNumber: roundNum,
|
|
253
|
+
responses: [response],
|
|
254
|
+
durationMs: Date.now() - roundStart,
|
|
255
|
+
},
|
|
256
|
+
success: result.success,
|
|
257
|
+
content: result.content || '',
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
} catch (error) {
|
|
261
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
round: {
|
|
265
|
+
roundNumber: roundNum,
|
|
266
|
+
responses: [{
|
|
267
|
+
provider: proposerId,
|
|
268
|
+
content: '',
|
|
269
|
+
round: roundNum,
|
|
270
|
+
timestamp: new Date().toISOString(),
|
|
271
|
+
durationMs: Date.now() - roundStart,
|
|
272
|
+
error: errorMessage,
|
|
273
|
+
}],
|
|
274
|
+
durationMs: Date.now() - roundStart,
|
|
275
|
+
},
|
|
276
|
+
success: false,
|
|
277
|
+
content: '',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private async executeCritiqueRound(
|
|
283
|
+
roundNum: number,
|
|
284
|
+
critiquers: string[],
|
|
285
|
+
proposal: string,
|
|
286
|
+
config: PatternExecutionContext['config'],
|
|
287
|
+
providerExecutor: PatternExecutionContext['providerExecutor'],
|
|
288
|
+
abortSignal?: AbortSignal,
|
|
289
|
+
onProgress?: PatternExecutionContext['onProgress']
|
|
290
|
+
): Promise<{ round: DiscussionRound; succeeded: string[]; failed: string[] }> {
|
|
291
|
+
const roundStart = Date.now();
|
|
292
|
+
const succeeded: string[] = [];
|
|
293
|
+
const failed: string[] = [];
|
|
294
|
+
|
|
295
|
+
const prompt = interpolate(CRITIQUE_REVIEW, {
|
|
296
|
+
topic: config.prompt,
|
|
297
|
+
proposal,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Execute critiques in parallel
|
|
301
|
+
const promises = critiquers.map(async (critiquerId) => {
|
|
302
|
+
if (abortSignal?.aborted) return null;
|
|
303
|
+
|
|
304
|
+
onProgress?.({
|
|
305
|
+
type: 'provider_start',
|
|
306
|
+
round: roundNum,
|
|
307
|
+
provider: critiquerId,
|
|
308
|
+
timestamp: new Date().toISOString(),
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
const responseStart = Date.now();
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
const result = await providerExecutor.execute({
|
|
315
|
+
providerId: critiquerId,
|
|
316
|
+
prompt,
|
|
317
|
+
systemPrompt: getProviderSystemPrompt(critiquerId),
|
|
318
|
+
temperature: config.temperature,
|
|
319
|
+
timeoutMs: config.providerTimeout,
|
|
320
|
+
abortSignal,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (result.success) {
|
|
324
|
+
succeeded.push(critiquerId);
|
|
325
|
+
} else {
|
|
326
|
+
failed.push(critiquerId);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
onProgress?.({
|
|
330
|
+
type: 'provider_complete',
|
|
331
|
+
round: roundNum,
|
|
332
|
+
provider: critiquerId,
|
|
333
|
+
timestamp: new Date().toISOString(),
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
provider: critiquerId,
|
|
338
|
+
content: result.success ? result.content || '' : '',
|
|
339
|
+
round: roundNum,
|
|
340
|
+
timestamp: new Date().toISOString(),
|
|
341
|
+
durationMs: result.durationMs,
|
|
342
|
+
tokenCount: result.tokenCount,
|
|
343
|
+
error: result.success ? undefined : result.error,
|
|
344
|
+
} as DiscussionProviderResponse;
|
|
345
|
+
|
|
346
|
+
} catch (error) {
|
|
347
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
348
|
+
failed.push(critiquerId);
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
provider: critiquerId,
|
|
352
|
+
content: '',
|
|
353
|
+
round: roundNum,
|
|
354
|
+
timestamp: new Date().toISOString(),
|
|
355
|
+
durationMs: Date.now() - responseStart,
|
|
356
|
+
error: errorMessage,
|
|
357
|
+
} as DiscussionProviderResponse;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const responses = await Promise.all(promises);
|
|
362
|
+
const validResponses = responses.filter((r): r is DiscussionProviderResponse => r !== null);
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
round: {
|
|
366
|
+
roundNumber: roundNum,
|
|
367
|
+
responses: validResponses,
|
|
368
|
+
durationMs: Date.now() - roundStart,
|
|
369
|
+
},
|
|
370
|
+
succeeded,
|
|
371
|
+
failed,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private async executeRevisionRound(
|
|
376
|
+
roundNum: number,
|
|
377
|
+
proposerId: string,
|
|
378
|
+
originalProposal: string,
|
|
379
|
+
critiques: DiscussionProviderResponse[],
|
|
380
|
+
config: PatternExecutionContext['config'],
|
|
381
|
+
providerExecutor: PatternExecutionContext['providerExecutor'],
|
|
382
|
+
abortSignal?: AbortSignal,
|
|
383
|
+
onProgress?: PatternExecutionContext['onProgress']
|
|
384
|
+
): Promise<{ round: DiscussionRound; success: boolean; content: string }> {
|
|
385
|
+
const roundStart = Date.now();
|
|
386
|
+
|
|
387
|
+
onProgress?.({
|
|
388
|
+
type: 'provider_start',
|
|
389
|
+
round: roundNum,
|
|
390
|
+
provider: proposerId,
|
|
391
|
+
timestamp: new Date().toISOString(),
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
try {
|
|
395
|
+
const formattedCritiques = formatPreviousResponses(
|
|
396
|
+
critiques.map(c => ({
|
|
397
|
+
provider: c.provider,
|
|
398
|
+
content: c.content,
|
|
399
|
+
}))
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
const prompt = interpolate(CRITIQUE_REVISION, {
|
|
403
|
+
topic: config.prompt,
|
|
404
|
+
originalProposal,
|
|
405
|
+
critiques: formattedCritiques,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const result = await providerExecutor.execute({
|
|
409
|
+
providerId: proposerId,
|
|
410
|
+
prompt,
|
|
411
|
+
systemPrompt: getProviderSystemPrompt(proposerId),
|
|
412
|
+
temperature: config.temperature,
|
|
413
|
+
timeoutMs: config.providerTimeout,
|
|
414
|
+
abortSignal,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
const response: DiscussionProviderResponse = {
|
|
418
|
+
provider: proposerId,
|
|
419
|
+
content: result.success ? result.content || '' : '',
|
|
420
|
+
round: roundNum,
|
|
421
|
+
timestamp: new Date().toISOString(),
|
|
422
|
+
durationMs: result.durationMs,
|
|
423
|
+
tokenCount: result.tokenCount,
|
|
424
|
+
error: result.success ? undefined : result.error,
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
onProgress?.({
|
|
428
|
+
type: 'provider_complete',
|
|
429
|
+
round: roundNum,
|
|
430
|
+
provider: proposerId,
|
|
431
|
+
timestamp: new Date().toISOString(),
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
round: {
|
|
436
|
+
roundNumber: roundNum,
|
|
437
|
+
responses: [response],
|
|
438
|
+
durationMs: Date.now() - roundStart,
|
|
439
|
+
},
|
|
440
|
+
success: result.success,
|
|
441
|
+
content: result.content || '',
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
} catch (error) {
|
|
445
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
round: {
|
|
449
|
+
roundNumber: roundNum,
|
|
450
|
+
responses: [{
|
|
451
|
+
provider: proposerId,
|
|
452
|
+
content: '',
|
|
453
|
+
round: roundNum,
|
|
454
|
+
timestamp: new Date().toISOString(),
|
|
455
|
+
durationMs: Date.now() - roundStart,
|
|
456
|
+
error: errorMessage,
|
|
457
|
+
}],
|
|
458
|
+
durationMs: Date.now() - roundStart,
|
|
459
|
+
},
|
|
460
|
+
success: false,
|
|
461
|
+
content: '',
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|