@gotza02/seq-thinking 1.1.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 +149 -0
- package/SYSTEM_INSTRUCTIONS.md +50 -0
- package/agents_test.log +15 -0
- package/dist/__tests__/agents.test.d.ts +2 -0
- package/dist/__tests__/agents.test.d.ts.map +1 -0
- package/dist/__tests__/agents.test.js +673 -0
- package/dist/__tests__/agents.test.js.map +1 -0
- package/dist/__tests__/mcp-server.test.d.ts +2 -0
- package/dist/__tests__/mcp-server.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-server.test.js +315 -0
- package/dist/__tests__/mcp-server.test.js.map +1 -0
- package/dist/__tests__/sequential-thinking.test.d.ts +2 -0
- package/dist/__tests__/sequential-thinking.test.d.ts.map +1 -0
- package/dist/__tests__/sequential-thinking.test.js +545 -0
- package/dist/__tests__/sequential-thinking.test.js.map +1 -0
- package/dist/__tests__/swarm-coordinator.test.d.ts +2 -0
- package/dist/__tests__/swarm-coordinator.test.d.ts.map +1 -0
- package/dist/__tests__/swarm-coordinator.test.js +606 -0
- package/dist/__tests__/swarm-coordinator.test.js.map +1 -0
- package/dist/__tests__/types.test.d.ts +2 -0
- package/dist/__tests__/types.test.d.ts.map +1 -0
- package/dist/__tests__/types.test.js +741 -0
- package/dist/__tests__/types.test.js.map +1 -0
- package/dist/__tests__/utils.test.d.ts +2 -0
- package/dist/__tests__/utils.test.d.ts.map +1 -0
- package/dist/__tests__/utils.test.js +264 -0
- package/dist/__tests__/utils.test.js.map +1 -0
- package/dist/agents/base-agent.d.ts +126 -0
- package/dist/agents/base-agent.d.ts.map +1 -0
- package/dist/agents/base-agent.js +214 -0
- package/dist/agents/base-agent.js.map +1 -0
- package/dist/agents/critic-agent.d.ts +134 -0
- package/dist/agents/critic-agent.d.ts.map +1 -0
- package/dist/agents/critic-agent.js +484 -0
- package/dist/agents/critic-agent.js.map +1 -0
- package/dist/agents/index.d.ts +11 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +11 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/meta-reasoning-agent.d.ts +143 -0
- package/dist/agents/meta-reasoning-agent.d.ts.map +1 -0
- package/dist/agents/meta-reasoning-agent.js +532 -0
- package/dist/agents/meta-reasoning-agent.js.map +1 -0
- package/dist/agents/reasoner-agent.d.ts +75 -0
- package/dist/agents/reasoner-agent.d.ts.map +1 -0
- package/dist/agents/reasoner-agent.js +226 -0
- package/dist/agents/reasoner-agent.js.map +1 -0
- package/dist/agents/synthesizer-agent.d.ts +174 -0
- package/dist/agents/synthesizer-agent.d.ts.map +1 -0
- package/dist/agents/synthesizer-agent.js +583 -0
- package/dist/agents/synthesizer-agent.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +823 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +377 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/sequential-thinking.d.ts +91 -0
- package/dist/sequential-thinking.d.ts.map +1 -0
- package/dist/sequential-thinking.js +540 -0
- package/dist/sequential-thinking.js.map +1 -0
- package/dist/swarm-coordinator.d.ts +188 -0
- package/dist/swarm-coordinator.d.ts.map +1 -0
- package/dist/swarm-coordinator.js +627 -0
- package/dist/swarm-coordinator.js.map +1 -0
- package/dist/types/index.d.ts +806 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +279 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +421 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +864 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/llm-adapter.d.ts +23 -0
- package/dist/utils/llm-adapter.d.ts.map +1 -0
- package/dist/utils/llm-adapter.js +68 -0
- package/dist/utils/llm-adapter.js.map +1 -0
- package/dist/utils/persistence.d.ts +33 -0
- package/dist/utils/persistence.d.ts.map +1 -0
- package/dist/utils/persistence.js +108 -0
- package/dist/utils/persistence.js.map +1 -0
- package/package.json +41 -0
- package/src/__tests__/agents.test.ts +858 -0
- package/src/__tests__/mcp-server.test.ts +380 -0
- package/src/__tests__/sequential-thinking.test.ts +687 -0
- package/src/__tests__/swarm-coordinator.test.ts +903 -0
- package/src/__tests__/types.test.ts +839 -0
- package/src/__tests__/utils.test.ts +322 -0
- package/src/agents/base-agent.ts +285 -0
- package/src/agents/critic-agent.ts +582 -0
- package/src/agents/index.ts +11 -0
- package/src/agents/meta-reasoning-agent.ts +672 -0
- package/src/agents/reasoner-agent.ts +312 -0
- package/src/agents/synthesizer-agent.ts +758 -0
- package/src/index.ts +118 -0
- package/src/mcp-server.ts +387 -0
- package/src/sequential-thinking.ts +560 -0
- package/src/swarm-coordinator.ts +744 -0
- package/src/types/index.ts +915 -0
- package/src/utils/index.ts +1004 -0
- package/src/utils/llm-adapter.ts +76 -0
- package/src/utils/persistence.ts +108 -0
- package/test_output.log +0 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthesizer Agent Implementation
|
|
3
|
+
* @module agents/synthesizer-agent
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BaseAgent } from './base-agent.js';
|
|
8
|
+
import {
|
|
9
|
+
AgentType,
|
|
10
|
+
SynthesizerType,
|
|
11
|
+
type Task,
|
|
12
|
+
type TaskResult,
|
|
13
|
+
type AgentCapability
|
|
14
|
+
} from '../types/index.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Synthesis input
|
|
18
|
+
*/
|
|
19
|
+
interface SynthesisInput {
|
|
20
|
+
outputs: Array<{
|
|
21
|
+
agentId: string;
|
|
22
|
+
output: unknown;
|
|
23
|
+
confidence: number;
|
|
24
|
+
}>;
|
|
25
|
+
context?: unknown;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Synthesis result
|
|
30
|
+
*/
|
|
31
|
+
interface Synthesis {
|
|
32
|
+
synthesizedOutput: unknown;
|
|
33
|
+
confidence: number;
|
|
34
|
+
contributingAgents: string[];
|
|
35
|
+
synthesisMethod: string;
|
|
36
|
+
consensusLevel?: number;
|
|
37
|
+
dissentPoints?: unknown[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Synthesizer agent that combines multiple agent outputs
|
|
42
|
+
*/
|
|
43
|
+
export class SynthesizerAgent extends BaseAgent {
|
|
44
|
+
/** Synthesizer type */
|
|
45
|
+
private synthesizerType: SynthesizerType;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create a new synthesizer agent
|
|
49
|
+
* @param config - Agent configuration
|
|
50
|
+
*/
|
|
51
|
+
constructor(config: {
|
|
52
|
+
name: string;
|
|
53
|
+
synthesizerType?: SynthesizerType;
|
|
54
|
+
capabilities?: AgentCapability[];
|
|
55
|
+
}) {
|
|
56
|
+
const defaultCapabilities: AgentCapability[] = [
|
|
57
|
+
{
|
|
58
|
+
name: 'consensus_building',
|
|
59
|
+
description: 'Build consensus from multiple outputs',
|
|
60
|
+
confidence: 0.85,
|
|
61
|
+
performanceMetrics: { tasksCompleted: 0, averageQuality: 0, averageTimeMs: 0 }
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'conflict_resolution',
|
|
65
|
+
description: 'Resolve conflicts between outputs',
|
|
66
|
+
confidence: 0.8,
|
|
67
|
+
performanceMetrics: { tasksCompleted: 0, averageQuality: 0, averageTimeMs: 0 }
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'creative_synthesis',
|
|
71
|
+
description: 'Create creative combinations',
|
|
72
|
+
confidence: 0.75,
|
|
73
|
+
performanceMetrics: { tasksCompleted: 0, averageQuality: 0, averageTimeMs: 0 }
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'integration',
|
|
77
|
+
description: 'Integrate multiple perspectives',
|
|
78
|
+
confidence: 0.85,
|
|
79
|
+
performanceMetrics: { tasksCompleted: 0, averageQuality: 0, averageTimeMs: 0 }
|
|
80
|
+
}
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
super({
|
|
84
|
+
name: config.name,
|
|
85
|
+
type: AgentType.SYNTHESIZER,
|
|
86
|
+
subtype: config.synthesizerType || SynthesizerType.CONSENSUS,
|
|
87
|
+
capabilities: config.capabilities || defaultCapabilities,
|
|
88
|
+
maxConcurrentTasks: 3,
|
|
89
|
+
confidenceThreshold: 0.7
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
this.synthesizerType = config.synthesizerType || SynthesizerType.CONSENSUS;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get agent type
|
|
97
|
+
* @returns Agent type
|
|
98
|
+
*/
|
|
99
|
+
getType(): string {
|
|
100
|
+
return AgentType.SYNTHESIZER;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get agent capabilities
|
|
105
|
+
* @returns Array of capabilities
|
|
106
|
+
*/
|
|
107
|
+
getCapabilities(): AgentCapability[] {
|
|
108
|
+
return this.config.capabilities;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Process a task - synthesize inputs
|
|
113
|
+
* @param task - Task to process
|
|
114
|
+
* @returns Task result
|
|
115
|
+
*/
|
|
116
|
+
async process(task: Task): Promise<TaskResult> {
|
|
117
|
+
const startTime = Date.now();
|
|
118
|
+
const input = task.input as SynthesisInput;
|
|
119
|
+
|
|
120
|
+
let result: Synthesis;
|
|
121
|
+
|
|
122
|
+
switch (this.synthesizerType) {
|
|
123
|
+
case SynthesizerType.CONSENSUS:
|
|
124
|
+
result = await this.buildConsensus(input);
|
|
125
|
+
break;
|
|
126
|
+
case SynthesizerType.CREATIVE:
|
|
127
|
+
result = await this.creativeSynthesis(input);
|
|
128
|
+
break;
|
|
129
|
+
case SynthesizerType.CONFLICT_RESOLUTION:
|
|
130
|
+
result = await this.resolveConflicts(input);
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
result = await this.buildConsensus(input);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return this.createTaskResult(
|
|
137
|
+
task.id,
|
|
138
|
+
result,
|
|
139
|
+
result.confidence,
|
|
140
|
+
Date.now() - startTime,
|
|
141
|
+
{
|
|
142
|
+
reasoningSteps: input.outputs.length,
|
|
143
|
+
intermediateResults: input.outputs.map(o => o.output)
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Build consensus from multiple outputs
|
|
150
|
+
* @param input - Synthesis input
|
|
151
|
+
* @returns Synthesis result
|
|
152
|
+
*/
|
|
153
|
+
private async buildConsensus(input: SynthesisInput): Promise<Synthesis> {
|
|
154
|
+
const { outputs } = input;
|
|
155
|
+
|
|
156
|
+
if (outputs.length === 0) {
|
|
157
|
+
return {
|
|
158
|
+
synthesizedOutput: null,
|
|
159
|
+
confidence: 0,
|
|
160
|
+
contributingAgents: [],
|
|
161
|
+
synthesisMethod: 'consensus'
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (outputs.length === 1) {
|
|
166
|
+
return {
|
|
167
|
+
synthesizedOutput: outputs[0].output,
|
|
168
|
+
confidence: outputs[0].confidence,
|
|
169
|
+
contributingAgents: [outputs[0].agentId],
|
|
170
|
+
synthesisMethod: 'consensus'
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Extract key points from each output
|
|
175
|
+
const keyPoints = outputs.map(o => this.extractKeyPoints(o.output));
|
|
176
|
+
|
|
177
|
+
// Find consensus points (common across multiple outputs)
|
|
178
|
+
const consensusPoints = this.findConsensusPoints(keyPoints);
|
|
179
|
+
|
|
180
|
+
// Find points of divergence
|
|
181
|
+
const divergencePoints = this.findDivergencePoints(keyPoints);
|
|
182
|
+
|
|
183
|
+
// Weight by confidence
|
|
184
|
+
const weightedConsensus = this.applyConfidenceWeights(consensusPoints, outputs);
|
|
185
|
+
|
|
186
|
+
// Calculate consensus level
|
|
187
|
+
const consensusLevel = consensusPoints.length / Math.max(...keyPoints.map(kp => kp.length));
|
|
188
|
+
|
|
189
|
+
// Generate unified output
|
|
190
|
+
const unified = this.generateUnifiedOutput(weightedConsensus, divergencePoints);
|
|
191
|
+
|
|
192
|
+
// Calculate overall confidence
|
|
193
|
+
const avgConfidence = outputs.reduce((sum, o) => sum + o.confidence, 0) / outputs.length;
|
|
194
|
+
const consensusBoost = consensusLevel * 0.1;
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
synthesizedOutput: unified,
|
|
198
|
+
confidence: Math.min(1, avgConfidence + consensusBoost),
|
|
199
|
+
contributingAgents: outputs.map(o => o.agentId),
|
|
200
|
+
synthesisMethod: 'consensus',
|
|
201
|
+
consensusLevel,
|
|
202
|
+
dissentPoints: divergencePoints
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Creative synthesis
|
|
208
|
+
* @param input - Synthesis input
|
|
209
|
+
* @returns Synthesis result
|
|
210
|
+
*/
|
|
211
|
+
private async creativeSynthesis(input: SynthesisInput): Promise<Synthesis> {
|
|
212
|
+
const { outputs } = input;
|
|
213
|
+
|
|
214
|
+
if (outputs.length === 0) {
|
|
215
|
+
return {
|
|
216
|
+
synthesizedOutput: null,
|
|
217
|
+
confidence: 0,
|
|
218
|
+
contributingAgents: [],
|
|
219
|
+
synthesisMethod: 'creative_combination'
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Extract creative elements
|
|
224
|
+
const creativeElements = outputs.map(o => this.extractCreativeElements(o.output));
|
|
225
|
+
|
|
226
|
+
// Find unexpected connections
|
|
227
|
+
const connections = this.findUnexpectedConnections(creativeElements);
|
|
228
|
+
|
|
229
|
+
// Generate novel combinations
|
|
230
|
+
const combinations = this.generateNovelCombinations(creativeElements, connections);
|
|
231
|
+
|
|
232
|
+
// Create creative output
|
|
233
|
+
const creativeOutput = {
|
|
234
|
+
combinations,
|
|
235
|
+
connections,
|
|
236
|
+
originalElements: creativeElements,
|
|
237
|
+
novelInsights: this.generateNovelInsights(combinations)
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Calculate confidence based on diversity and novelty
|
|
241
|
+
const diversityScore = this.calculateDiversity(creativeElements);
|
|
242
|
+
const noveltyScore = connections.length > 0 ? 0.8 : 0.5;
|
|
243
|
+
const confidence = (diversityScore + noveltyScore) / 2;
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
synthesizedOutput: creativeOutput,
|
|
247
|
+
confidence,
|
|
248
|
+
contributingAgents: outputs.map(o => o.agentId),
|
|
249
|
+
synthesisMethod: 'creative_combination'
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Resolve conflicts between outputs
|
|
255
|
+
* @param input - Synthesis input
|
|
256
|
+
* @returns Synthesis result
|
|
257
|
+
*/
|
|
258
|
+
private async resolveConflicts(input: SynthesisInput): Promise<Synthesis> {
|
|
259
|
+
const { outputs } = input;
|
|
260
|
+
|
|
261
|
+
if (outputs.length === 0) {
|
|
262
|
+
return {
|
|
263
|
+
synthesizedOutput: null,
|
|
264
|
+
confidence: 0,
|
|
265
|
+
contributingAgents: [],
|
|
266
|
+
synthesisMethod: 'conflict_resolution'
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (outputs.length === 1) {
|
|
271
|
+
return {
|
|
272
|
+
synthesizedOutput: outputs[0].output,
|
|
273
|
+
confidence: outputs[0].confidence,
|
|
274
|
+
contributingAgents: [outputs[0].agentId],
|
|
275
|
+
synthesisMethod: 'conflict_resolution'
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Identify conflicts
|
|
280
|
+
const conflicts = this.identifyConflicts(outputs);
|
|
281
|
+
|
|
282
|
+
if (conflicts.length === 0) {
|
|
283
|
+
// No conflicts, use consensus
|
|
284
|
+
return this.buildConsensus(input);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Resolve each conflict
|
|
288
|
+
const resolutions = conflicts.map(conflict => ({
|
|
289
|
+
conflict,
|
|
290
|
+
resolution: this.resolveConflict(conflict, outputs)
|
|
291
|
+
}));
|
|
292
|
+
|
|
293
|
+
// Merge resolved conflicts with non-conflicting content
|
|
294
|
+
const finalOutput = this.mergeResolutions(outputs, resolutions);
|
|
295
|
+
|
|
296
|
+
// Calculate confidence
|
|
297
|
+
const avgConfidence = outputs.reduce((sum, o) => sum + o.confidence, 0) / outputs.length;
|
|
298
|
+
const resolutionQuality = resolutions.length > 0
|
|
299
|
+
? resolutions.reduce((sum, r) => sum + r.resolution.confidence, 0) / resolutions.length
|
|
300
|
+
: 1;
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
synthesizedOutput: finalOutput,
|
|
304
|
+
confidence: (avgConfidence + resolutionQuality) / 2,
|
|
305
|
+
contributingAgents: outputs.map(o => o.agentId),
|
|
306
|
+
synthesisMethod: 'conflict_resolution',
|
|
307
|
+
dissentPoints: conflicts.map(c => c.description)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ============================================================================
|
|
312
|
+
// Helper Methods
|
|
313
|
+
// ============================================================================
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Extract key points from output
|
|
317
|
+
* @param output - Output to extract from
|
|
318
|
+
* @returns Array of key points
|
|
319
|
+
*/
|
|
320
|
+
private extractKeyPoints(output: unknown): string[] {
|
|
321
|
+
if (typeof output === 'string') {
|
|
322
|
+
return output.split(/[.!?]+/).filter(s => s.trim().length > 10);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (output && typeof output === 'object') {
|
|
326
|
+
const obj = output as Record<string, unknown>;
|
|
327
|
+
|
|
328
|
+
if ('conclusion' in obj && typeof obj.conclusion === 'string') {
|
|
329
|
+
return [obj.conclusion];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if ('keyPoints' in obj && Array.isArray(obj.keyPoints)) {
|
|
333
|
+
return obj.keyPoints as string[];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return [JSON.stringify(output)];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return [String(output)];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Find consensus points
|
|
344
|
+
* @param keyPointsArray - Array of key points arrays
|
|
345
|
+
* @returns Consensus points
|
|
346
|
+
*/
|
|
347
|
+
private findConsensusPoints(keyPointsArray: string[][]): string[] {
|
|
348
|
+
if (keyPointsArray.length === 0) return [];
|
|
349
|
+
if (keyPointsArray.length === 1) return keyPointsArray[0];
|
|
350
|
+
|
|
351
|
+
const consensus: string[] = [];
|
|
352
|
+
const firstSet = keyPointsArray[0];
|
|
353
|
+
|
|
354
|
+
for (const point of firstSet) {
|
|
355
|
+
const normalizedPoint = this.normalizePoint(point);
|
|
356
|
+
let matchCount = 1;
|
|
357
|
+
|
|
358
|
+
for (let i = 1; i < keyPointsArray.length; i++) {
|
|
359
|
+
const otherSet = keyPointsArray[i];
|
|
360
|
+
const hasMatch = otherSet.some(otherPoint =>
|
|
361
|
+
this.pointsAreSimilar(normalizedPoint, this.normalizePoint(otherPoint))
|
|
362
|
+
);
|
|
363
|
+
if (hasMatch) matchCount++;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Point is in consensus if it appears in majority
|
|
367
|
+
if (matchCount > keyPointsArray.length / 2) {
|
|
368
|
+
consensus.push(point);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return consensus;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Find divergence points
|
|
377
|
+
* @param keyPointsArray - Array of key points arrays
|
|
378
|
+
* @returns Divergence points
|
|
379
|
+
*/
|
|
380
|
+
private findDivergencePoints(keyPointsArray: string[][]): string[] {
|
|
381
|
+
if (keyPointsArray.length <= 1) return [];
|
|
382
|
+
|
|
383
|
+
const allPoints = keyPointsArray.flat();
|
|
384
|
+
const uniquePoints = [...new Set(allPoints.map(p => this.normalizePoint(p)))];
|
|
385
|
+
const divergence: string[] = [];
|
|
386
|
+
|
|
387
|
+
for (const point of uniquePoints) {
|
|
388
|
+
let matchCount = 0;
|
|
389
|
+
|
|
390
|
+
for (const pointSet of keyPointsArray) {
|
|
391
|
+
const hasMatch = pointSet.some(p =>
|
|
392
|
+
this.pointsAreSimilar(point, this.normalizePoint(p))
|
|
393
|
+
);
|
|
394
|
+
if (hasMatch) matchCount++;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Point diverges if not in majority
|
|
398
|
+
if (matchCount <= keyPointsArray.length / 2) {
|
|
399
|
+
const original = allPoints.find(p => this.normalizePoint(p) === point);
|
|
400
|
+
if (original) divergence.push(original);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return divergence;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Normalize a point for comparison
|
|
409
|
+
* @param point - Point to normalize
|
|
410
|
+
* @returns Normalized point
|
|
411
|
+
*/
|
|
412
|
+
private normalizePoint(point: string): string {
|
|
413
|
+
return point.toLowerCase().trim().replace(/\s+/g, ' ');
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Check if two points are similar
|
|
418
|
+
* @param a - First point
|
|
419
|
+
* @param b - Second point
|
|
420
|
+
* @returns True if similar
|
|
421
|
+
*/
|
|
422
|
+
private pointsAreSimilar(a: string, b: string): boolean {
|
|
423
|
+
// Simple similarity check
|
|
424
|
+
if (a === b) return true;
|
|
425
|
+
|
|
426
|
+
const wordsA = new Set(a.split(' '));
|
|
427
|
+
const wordsB = new Set(b.split(' '));
|
|
428
|
+
const intersection = [...wordsA].filter(w => wordsB.has(w));
|
|
429
|
+
const union = new Set([...wordsA, ...wordsB]);
|
|
430
|
+
|
|
431
|
+
return union.size > 0 && intersection.length / union.size > 0.6;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Apply confidence weights to points
|
|
436
|
+
* @param points - Points to weight
|
|
437
|
+
* @param outputs - Outputs with confidence
|
|
438
|
+
* @returns Weighted points
|
|
439
|
+
*/
|
|
440
|
+
private applyConfidenceWeights(
|
|
441
|
+
points: string[],
|
|
442
|
+
outputs: Array<{ confidence: number }>
|
|
443
|
+
): Array<{ point: string; weight: number }> {
|
|
444
|
+
const avgConfidence = outputs.reduce((sum, o) => sum + o.confidence, 0) / outputs.length;
|
|
445
|
+
|
|
446
|
+
return points.map(point => ({
|
|
447
|
+
point,
|
|
448
|
+
weight: avgConfidence
|
|
449
|
+
}));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Generate unified output
|
|
454
|
+
* @param weightedPoints - Weighted points
|
|
455
|
+
* @param divergencePoints - Divergence points
|
|
456
|
+
* @returns Unified output
|
|
457
|
+
*/
|
|
458
|
+
private generateUnifiedOutput(
|
|
459
|
+
weightedPoints: Array<{ point: string; weight: number }>,
|
|
460
|
+
divergencePoints: string[]
|
|
461
|
+
): Record<string, unknown> {
|
|
462
|
+
return {
|
|
463
|
+
consensus: weightedPoints.map(wp => wp.point),
|
|
464
|
+
consensusWeights: weightedPoints.map(wp => wp.weight),
|
|
465
|
+
pointsOfDivergence: divergencePoints,
|
|
466
|
+
summary: `Consensus reached on ${weightedPoints.length} points with ${divergencePoints.length} points of divergence`
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Extract creative elements
|
|
472
|
+
* @param output - Output to extract from
|
|
473
|
+
* @returns Creative elements
|
|
474
|
+
*/
|
|
475
|
+
private extractCreativeElements(output: unknown): string[] {
|
|
476
|
+
if (typeof output === 'string') {
|
|
477
|
+
// Extract novel phrases, metaphors, etc.
|
|
478
|
+
return output.split(/[.!?]+/).filter(s => s.trim().length > 5);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (output && typeof output === 'object') {
|
|
482
|
+
const obj = output as Record<string, unknown>;
|
|
483
|
+
|
|
484
|
+
if ('creativeElements' in obj && Array.isArray(obj.creativeElements)) {
|
|
485
|
+
return obj.creativeElements as string[];
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if ('ideas' in obj && Array.isArray(obj.ideas)) {
|
|
489
|
+
return obj.ideas as string[];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return [String(output)];
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Find unexpected connections
|
|
498
|
+
* @param elementsArray - Array of element arrays
|
|
499
|
+
* @returns Connections
|
|
500
|
+
*/
|
|
501
|
+
private findUnexpectedConnections(elementsArray: string[][]): Array<{
|
|
502
|
+
elements: [string, string];
|
|
503
|
+
connection: string;
|
|
504
|
+
}> {
|
|
505
|
+
const connections: Array<{ elements: [string, string]; connection: string }> = [];
|
|
506
|
+
|
|
507
|
+
// Compare elements from different sources
|
|
508
|
+
for (let i = 0; i < elementsArray.length; i++) {
|
|
509
|
+
for (let j = i + 1; j < elementsArray.length; j++) {
|
|
510
|
+
const setA = elementsArray[i];
|
|
511
|
+
const setB = elementsArray[j];
|
|
512
|
+
|
|
513
|
+
for (const elemA of setA) {
|
|
514
|
+
for (const elemB of setB) {
|
|
515
|
+
const connection = this.findConnection(elemA, elemB);
|
|
516
|
+
if (connection) {
|
|
517
|
+
connections.push({
|
|
518
|
+
elements: [elemA, elemB],
|
|
519
|
+
connection
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return connections;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Find connection between two elements
|
|
532
|
+
* @param a - First element
|
|
533
|
+
* @param b - Second element
|
|
534
|
+
* @returns Connection description or null
|
|
535
|
+
*/
|
|
536
|
+
private findConnection(a: string, b: string): string | null {
|
|
537
|
+
const wordsA = new Set(a.toLowerCase().split(/\s+/));
|
|
538
|
+
const wordsB = new Set(b.toLowerCase().split(/\s+/));
|
|
539
|
+
const common = [...wordsA].filter(w => wordsB.has(w) && w.length > 3);
|
|
540
|
+
|
|
541
|
+
if (common.length > 0) {
|
|
542
|
+
return `Connected through: ${common.join(', ')}`;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Generate novel combinations
|
|
550
|
+
* @param elementsArray - Array of element arrays
|
|
551
|
+
* @param connections - Connections
|
|
552
|
+
* @returns Combinations
|
|
553
|
+
*/
|
|
554
|
+
private generateNovelCombinations(
|
|
555
|
+
elementsArray: string[][],
|
|
556
|
+
connections: Array<{ elements: [string, string]; connection: string }>
|
|
557
|
+
): string[] {
|
|
558
|
+
const combinations: string[] = [];
|
|
559
|
+
|
|
560
|
+
for (const connection of connections) {
|
|
561
|
+
const [elemA, elemB] = connection.elements;
|
|
562
|
+
combinations.push(`Combining "${elemA.substring(0, 30)}..." with "${elemB.substring(0, 30)}..."`);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Cross-pollinate ideas
|
|
566
|
+
for (let i = 0; i < elementsArray.length && i < 3; i++) {
|
|
567
|
+
for (let j = i + 1; j < elementsArray.length && j < 3; j++) {
|
|
568
|
+
const elemA = elementsArray[i][0];
|
|
569
|
+
const elemB = elementsArray[j][0];
|
|
570
|
+
if (elemA && elemB) {
|
|
571
|
+
combinations.push(`Cross: ${elemA.substring(0, 20)}... + ${elemB.substring(0, 20)}...`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return combinations;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Generate novel insights
|
|
581
|
+
* @param combinations - Combinations
|
|
582
|
+
* @returns Insights
|
|
583
|
+
*/
|
|
584
|
+
private generateNovelInsights(combinations: string[]): string[] {
|
|
585
|
+
return combinations.map((combo, i) =>
|
|
586
|
+
`Insight ${i + 1}: ${combo} suggests a new approach`
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Calculate diversity score
|
|
592
|
+
* @param elementsArray - Array of element arrays
|
|
593
|
+
* @returns Diversity score (0-1)
|
|
594
|
+
*/
|
|
595
|
+
private calculateDiversity(elementsArray: string[][]): number {
|
|
596
|
+
const allElements = elementsArray.flat();
|
|
597
|
+
const uniqueElements = new Set(allElements);
|
|
598
|
+
|
|
599
|
+
if (allElements.length === 0) return 0;
|
|
600
|
+
|
|
601
|
+
return uniqueElements.size / allElements.length;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Identify conflicts
|
|
606
|
+
* @param outputs - Outputs to analyze
|
|
607
|
+
* @returns Conflicts
|
|
608
|
+
*/
|
|
609
|
+
private identifyConflicts(outputs: Array<{ agentId: string; output: unknown }>): Array<{
|
|
610
|
+
type: string;
|
|
611
|
+
description: string;
|
|
612
|
+
involvedAgents: string[];
|
|
613
|
+
}> {
|
|
614
|
+
const conflicts: Array<{
|
|
615
|
+
type: string;
|
|
616
|
+
description: string;
|
|
617
|
+
involvedAgents: string[];
|
|
618
|
+
}> = [];
|
|
619
|
+
|
|
620
|
+
// Check for contradictory conclusions
|
|
621
|
+
const conclusions: Array<{ agentId: string; conclusion: string }> = [];
|
|
622
|
+
|
|
623
|
+
for (const output of outputs) {
|
|
624
|
+
const conclusion = this.extractConclusion(output.output);
|
|
625
|
+
if (conclusion) {
|
|
626
|
+
conclusions.push({ agentId: output.agentId, conclusion });
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Find contradictions
|
|
631
|
+
for (let i = 0; i < conclusions.length; i++) {
|
|
632
|
+
for (let j = i + 1; j < conclusions.length; j++) {
|
|
633
|
+
const a = conclusions[i];
|
|
634
|
+
const b = conclusions[j];
|
|
635
|
+
|
|
636
|
+
if (this.areContradictory(a.conclusion, b.conclusion)) {
|
|
637
|
+
conflicts.push({
|
|
638
|
+
type: 'contradiction',
|
|
639
|
+
description: `Contradictory conclusions: "${a.conclusion.substring(0, 30)}..." vs "${b.conclusion.substring(0, 30)}..."`,
|
|
640
|
+
involvedAgents: [a.agentId, b.agentId]
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return conflicts;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Extract conclusion from output
|
|
651
|
+
* @param output - Output to extract from
|
|
652
|
+
* @returns Conclusion string or null
|
|
653
|
+
*/
|
|
654
|
+
private extractConclusion(output: unknown): string | null {
|
|
655
|
+
if (typeof output === 'string') return output;
|
|
656
|
+
|
|
657
|
+
if (output && typeof output === 'object') {
|
|
658
|
+
const obj = output as Record<string, unknown>;
|
|
659
|
+
|
|
660
|
+
if ('conclusion' in obj && typeof obj.conclusion === 'string') {
|
|
661
|
+
return obj.conclusion;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Check if two conclusions are contradictory
|
|
670
|
+
* @param a - First conclusion
|
|
671
|
+
* @param b - Second conclusion
|
|
672
|
+
* @returns True if contradictory
|
|
673
|
+
*/
|
|
674
|
+
private areContradictory(a: string, b: string): boolean {
|
|
675
|
+
const lowerA = a.toLowerCase();
|
|
676
|
+
const lowerB = b.toLowerCase();
|
|
677
|
+
|
|
678
|
+
// Check for direct opposites
|
|
679
|
+
const oppositePatterns = [
|
|
680
|
+
{ pos: /\b(is|are|was|were)\b/gi, neg: /\b(is not|are not|was not|were not)\b/gi },
|
|
681
|
+
{ pos: /\bshould\b/gi, neg: /\bshould not\b/gi },
|
|
682
|
+
{ pos: /\bcan\b/gi, neg: /\bcannot\b/gi }
|
|
683
|
+
];
|
|
684
|
+
|
|
685
|
+
for (const { pos, neg } of oppositePatterns) {
|
|
686
|
+
const aHasPos = pos.test(lowerA);
|
|
687
|
+
const aHasNeg = neg.test(lowerA);
|
|
688
|
+
const bHasPos = pos.test(lowerB);
|
|
689
|
+
const bHasNeg = neg.test(lowerB);
|
|
690
|
+
|
|
691
|
+
if ((aHasPos && bHasNeg) || (aHasNeg && bHasPos)) {
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Resolve a conflict
|
|
701
|
+
* @param conflict - Conflict to resolve
|
|
702
|
+
* @param outputs - All outputs
|
|
703
|
+
* @returns Resolution
|
|
704
|
+
*/
|
|
705
|
+
private resolveConflict(
|
|
706
|
+
conflict: { type: string; involvedAgents: string[] },
|
|
707
|
+
outputs: Array<{ agentId: string; output: unknown; confidence: number }>
|
|
708
|
+
): { resolution: unknown; confidence: number } {
|
|
709
|
+
// Get conflicting outputs
|
|
710
|
+
const conflictingOutputs = outputs.filter(o =>
|
|
711
|
+
conflict.involvedAgents.includes(o.agentId)
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
// Select based on confidence
|
|
715
|
+
const best = conflictingOutputs.reduce((max, o) =>
|
|
716
|
+
o.confidence > max.confidence ? o : max,
|
|
717
|
+
conflictingOutputs[0]
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
if (!best) {
|
|
721
|
+
return { resolution: null, confidence: 0 };
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
return {
|
|
725
|
+
resolution: best.output,
|
|
726
|
+
confidence: best.confidence
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Merge resolutions with non-conflicting content
|
|
732
|
+
* @param outputs - All outputs
|
|
733
|
+
* @param resolutions - Resolutions
|
|
734
|
+
* @returns Merged output
|
|
735
|
+
*/
|
|
736
|
+
private mergeResolutions(
|
|
737
|
+
outputs: Array<{ agentId: string; output: unknown }>,
|
|
738
|
+
resolutions: Array<{ conflict: { involvedAgents: string[] }; resolution: { resolution: unknown } }>
|
|
739
|
+
): Record<string, unknown> {
|
|
740
|
+
const merged: Record<string, unknown> = {
|
|
741
|
+
resolvedConflicts: resolutions.length,
|
|
742
|
+
agentOutputs: {}
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
// Add all outputs
|
|
746
|
+
for (const output of outputs) {
|
|
747
|
+
(merged.agentOutputs as Record<string, unknown>)[output.agentId] = output.output;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Add resolutions
|
|
751
|
+
merged.resolutions = resolutions.map(r => ({
|
|
752
|
+
conflict: r.conflict,
|
|
753
|
+
selectedResolution: r.resolution.resolution
|
|
754
|
+
}));
|
|
755
|
+
|
|
756
|
+
return merged;
|
|
757
|
+
}
|
|
758
|
+
}
|