dialectic 0.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/.cursor/commands/setup-test.mdc +175 -0
- package/.cursor/rules/basic-code-cleanup.mdc +1110 -0
- package/.cursor/rules/riper5.mdc +96 -0
- package/.env.example +6 -0
- package/AGENTS.md +1052 -0
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/WARP.md +113 -0
- package/dialectic-1.0.0.tgz +0 -0
- package/dialectic.js +10 -0
- package/docs/commands.md +375 -0
- package/docs/configuration.md +882 -0
- package/docs/context_summarization.md +1023 -0
- package/docs/debate_flow.md +1127 -0
- package/docs/eval_flow.md +795 -0
- package/docs/evaluator.md +141 -0
- package/examples/debate-config-openrouter.json +48 -0
- package/examples/debate_config1.json +48 -0
- package/examples/eval/eval1/eval_config1.json +13 -0
- package/examples/eval/eval1/result1.json +62 -0
- package/examples/eval/eval1/result2.json +97 -0
- package/examples/eval_summary_format.md +11 -0
- package/examples/example3/debate-config.json +64 -0
- package/examples/example3/eval_config2.json +25 -0
- package/examples/example3/problem.md +17 -0
- package/examples/example3/rounds_test/eval_run.sh +16 -0
- package/examples/example3/rounds_test/run_test.sh +16 -0
- package/examples/kata1/architect-only-solution_2-rounds.json +121 -0
- package/examples/kata1/architect-perf-solution_2-rounds.json +234 -0
- package/examples/kata1/debate-config-kata1.json +54 -0
- package/examples/kata1/eval_architect-only_2-rounds.json +97 -0
- package/examples/kata1/eval_architect-perf_2-rounds.json +97 -0
- package/examples/kata1/kata1-report.md +12224 -0
- package/examples/kata1/kata1-report_temps-01_01_01_07.md +2451 -0
- package/examples/kata1/kata1.md +5 -0
- package/examples/kata1/meta.txt +1 -0
- package/examples/kata2/debate-config.json +54 -0
- package/examples/kata2/eval_config1.json +21 -0
- package/examples/kata2/eval_config2.json +25 -0
- package/examples/kata2/kata2.md +5 -0
- package/examples/kata2/only_architect/debate-config.json +45 -0
- package/examples/kata2/only_architect/eval_run.sh +11 -0
- package/examples/kata2/only_architect/run_test.sh +5 -0
- package/examples/kata2/rounds_test/eval_run.sh +11 -0
- package/examples/kata2/rounds_test/run_test.sh +5 -0
- package/examples/kata2/summary_length_test/eval_run.sh +11 -0
- package/examples/kata2/summary_length_test/eval_run_w_clarify.sh +7 -0
- package/examples/kata2/summary_length_test/run_test.sh +5 -0
- package/examples/task-queue/debate-config.json +76 -0
- package/examples/task-queue/debate_report.md +566 -0
- package/examples/task-queue/task-queue-system.md +25 -0
- package/jest.config.ts +13 -0
- package/multi_agent_debate_spec.md +2980 -0
- package/package.json +38 -0
- package/sanity-check-problem.txt +9 -0
- package/src/agents/prompts/architect-prompts.ts +203 -0
- package/src/agents/prompts/generalist-prompts.ts +157 -0
- package/src/agents/prompts/index.ts +41 -0
- package/src/agents/prompts/judge-prompts.ts +19 -0
- package/src/agents/prompts/kiss-prompts.ts +230 -0
- package/src/agents/prompts/performance-prompts.ts +142 -0
- package/src/agents/prompts/prompt-types.ts +68 -0
- package/src/agents/prompts/security-prompts.ts +149 -0
- package/src/agents/prompts/shared.ts +144 -0
- package/src/agents/prompts/testing-prompts.ts +149 -0
- package/src/agents/role-based-agent.ts +386 -0
- package/src/cli/commands/debate.ts +761 -0
- package/src/cli/commands/eval.ts +475 -0
- package/src/cli/commands/report.ts +265 -0
- package/src/cli/index.ts +79 -0
- package/src/core/agent.ts +198 -0
- package/src/core/clarifications.ts +34 -0
- package/src/core/judge.ts +257 -0
- package/src/core/orchestrator.ts +432 -0
- package/src/core/state-manager.ts +322 -0
- package/src/eval/evaluator-agent.ts +130 -0
- package/src/eval/prompts/system.md +41 -0
- package/src/eval/prompts/user.md +64 -0
- package/src/providers/llm-provider.ts +25 -0
- package/src/providers/openai-provider.ts +84 -0
- package/src/providers/openrouter-provider.ts +122 -0
- package/src/providers/provider-factory.ts +64 -0
- package/src/types/agent.types.ts +141 -0
- package/src/types/config.types.ts +47 -0
- package/src/types/debate.types.ts +237 -0
- package/src/types/eval.types.ts +85 -0
- package/src/utils/common.ts +104 -0
- package/src/utils/context-formatter.ts +102 -0
- package/src/utils/context-summarizer.ts +143 -0
- package/src/utils/env-loader.ts +46 -0
- package/src/utils/exit-codes.ts +5 -0
- package/src/utils/id.ts +11 -0
- package/src/utils/logger.ts +48 -0
- package/src/utils/paths.ts +10 -0
- package/src/utils/progress-ui.ts +313 -0
- package/src/utils/prompt-loader.ts +79 -0
- package/src/utils/report-generator.ts +301 -0
- package/tests/clarifications.spec.ts +128 -0
- package/tests/cli.debate.spec.ts +144 -0
- package/tests/config-loading.spec.ts +206 -0
- package/tests/context-summarizer.spec.ts +131 -0
- package/tests/debate-config-custom.json +38 -0
- package/tests/env-loader.spec.ts +149 -0
- package/tests/eval.command.spec.ts +1191 -0
- package/tests/logger.spec.ts +19 -0
- package/tests/openai-provider.spec.ts +26 -0
- package/tests/openrouter-provider.spec.ts +279 -0
- package/tests/orchestrator-summary.spec.ts +386 -0
- package/tests/orchestrator.spec.ts +207 -0
- package/tests/prompt-loader.spec.ts +52 -0
- package/tests/prompts/architect.md +16 -0
- package/tests/provider-factory.spec.ts +150 -0
- package/tests/report.command.spec.ts +546 -0
- package/tests/role-based-agent-summary.spec.ts +476 -0
- package/tests/security-agent.spec.ts +221 -0
- package/tests/shared-prompts.spec.ts +318 -0
- package/tests/state-manager.spec.ts +251 -0
- package/tests/summary-prompts.spec.ts +153 -0
- package/tsconfig.json +49 -0
|
@@ -0,0 +1,2980 @@
|
|
|
1
|
+
# Multi-Agent Debate System - Technical Specification
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document specifies a multi-agent debate system where AI agents collaboratively solve software design problems through structured debate.
|
|
6
|
+
The system starts as a CLI tool and is designed to extend to a web interface.
|
|
7
|
+
|
|
8
|
+
**Technology Stack**: TypeScript, Node.js, LLM APIs (OpenAI, Anthropic, etc.)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Core Concepts
|
|
13
|
+
|
|
14
|
+
### What is Multi-Agent Debate?
|
|
15
|
+
|
|
16
|
+
Multiple AI agents with different perspectives analyze a problem, propose solutions, critique each other, and iteratively refine their approaches until reaching a high-quality final solution.
|
|
17
|
+
|
|
18
|
+
**Example Flow**:
|
|
19
|
+
```
|
|
20
|
+
User: "Design a rate limiting system for an API"
|
|
21
|
+
├── Agent 1 (Architect): Proposes token bucket algorithm
|
|
22
|
+
├── Agent 2 (Security): Proposes Redis-based distributed solution
|
|
23
|
+
└── Agent 3 (Performance): Proposes in-memory solution with sync
|
|
24
|
+
|
|
25
|
+
Round 1 Debate:
|
|
26
|
+
├── Security critiques Agent 3's in-memory approach (no distribution)
|
|
27
|
+
├── Performance critiques Agent 2's Redis latency
|
|
28
|
+
└── Architect synthesizes: Token bucket + Redis with local cache
|
|
29
|
+
|
|
30
|
+
Final Solution: Hybrid approach with best of all perspectives
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## System Architecture
|
|
36
|
+
|
|
37
|
+
### High-Level Components
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
┌─────────────────────────────────────────────────────────┐
|
|
41
|
+
│ CLI Interface │
|
|
42
|
+
│ (commands: debate, configure, history, export) │
|
|
43
|
+
└────────────────────┬────────────────────────────────────┘
|
|
44
|
+
│
|
|
45
|
+
┌────────────────────▼────────────────────────────────────┐
|
|
46
|
+
│ Debate Orchestrator │
|
|
47
|
+
│ - Manages debate flow │
|
|
48
|
+
│ - Coordinates agents │
|
|
49
|
+
│ - Handles state transitions │
|
|
50
|
+
└────────────────────┬────────────────────────────────────┘
|
|
51
|
+
│
|
|
52
|
+
┌────────────┼────────────┐
|
|
53
|
+
│ │ │
|
|
54
|
+
┌───────▼──────┐ ┌──▼──────┐ ┌──▼──────────┐
|
|
55
|
+
│ Agent │ │ Agent │ │ Judge │
|
|
56
|
+
│ Manager │ │ Pool │ │ Service │
|
|
57
|
+
└───────┬──────┘ └──┬──────┘ └──┬──────────┘
|
|
58
|
+
│ │ │
|
|
59
|
+
┌───────▼───────────▼────────────▼──────────┐
|
|
60
|
+
│ State Manager │
|
|
61
|
+
│ - Conversation history │
|
|
62
|
+
│ - Proposals & critiques │
|
|
63
|
+
│ - Debate rounds │
|
|
64
|
+
└────────────────────┬───────────────────────┘
|
|
65
|
+
│
|
|
66
|
+
┌────────────────────▼───────────────────────┐
|
|
67
|
+
│ LLM Provider Layer │
|
|
68
|
+
│ (OpenAI, Anthropic, custom adapters) │
|
|
69
|
+
└────────────────────────────────────────────┘
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Directory Structure
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
multi-agent-debate/
|
|
76
|
+
├── src/
|
|
77
|
+
│ ├── cli/
|
|
78
|
+
│ │ ├── commands/
|
|
79
|
+
│ │ │ ├── debate.ts # Main debate command
|
|
80
|
+
│ │ │ ├── configure.ts # Configuration management
|
|
81
|
+
│ │ │ ├── history.ts # View past debates
|
|
82
|
+
│ │ │ └── export.ts # Export results
|
|
83
|
+
│ │ └── index.ts # CLI entry point
|
|
84
|
+
│ │
|
|
85
|
+
│ ├── core/
|
|
86
|
+
│ │ ├── orchestrator.ts # Debate orchestration logic
|
|
87
|
+
│ │ ├── agent.ts # Agent base class
|
|
88
|
+
│ │ ├── judge.ts # Judge/synthesizer
|
|
89
|
+
│ │ └── state-manager.ts # State management
|
|
90
|
+
│ │
|
|
91
|
+
│ ├── agents/
|
|
92
|
+
│ │ ├── architect-agent.ts # System design focus
|
|
93
|
+
│ │ ├── security-agent.ts # Security focus
|
|
94
|
+
│ │ ├── performance-agent.ts # Performance focus
|
|
95
|
+
│ │ └── testing-agent.ts # Testing focus
|
|
96
|
+
│ │
|
|
97
|
+
│ ├── providers/
|
|
98
|
+
│ │ ├── llm-provider.ts # Provider interface
|
|
99
|
+
│ │ ├── openai-provider.ts # OpenAI implementation
|
|
100
|
+
│ │ └── anthropic-provider.ts # Anthropic implementation
|
|
101
|
+
│ │
|
|
102
|
+
│ ├── utils/
|
|
103
|
+
│ │ ├── prompt-builder.ts # Prompt construction
|
|
104
|
+
│ │ ├── logger.ts # Logging utilities
|
|
105
|
+
│ │ └── storage.ts # File/DB storage
|
|
106
|
+
│ │
|
|
107
|
+
│ └── types/
|
|
108
|
+
│ ├── agent.types.ts
|
|
109
|
+
│ ├── debate.types.ts
|
|
110
|
+
│ └── config.types.ts
|
|
111
|
+
│
|
|
112
|
+
├── config/
|
|
113
|
+
│ └── default-config.json # Default configuration
|
|
114
|
+
│
|
|
115
|
+
├── tests/
|
|
116
|
+
│ ├── unit/
|
|
117
|
+
│ └── integration/
|
|
118
|
+
│
|
|
119
|
+
└── package.json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Core Data Models
|
|
125
|
+
|
|
126
|
+
### Agent Configuration
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
interface AgentConfig {
|
|
130
|
+
id: string; // Unique identifier
|
|
131
|
+
name: string; // Human-readable name
|
|
132
|
+
role: AgentRole; // Architect, Security, Performance, Testing
|
|
133
|
+
model: string; // e.g., "gpt-4", "claude-3-opus"
|
|
134
|
+
provider: "openai" | "anthropic";
|
|
135
|
+
temperature: number; // 0.0 - 1.0
|
|
136
|
+
systemPrompt: string; // Role-specific instructions
|
|
137
|
+
enabled: boolean; // Can be disabled
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type AgentRole = "architect" | "security" | "performance" | "testing" | "generalist";
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Example**:
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"id": "agent-architect-001",
|
|
147
|
+
"name": "System Architect",
|
|
148
|
+
"role": "architect",
|
|
149
|
+
"model": "gpt-4",
|
|
150
|
+
"provider": "openai",
|
|
151
|
+
"temperature": 0.7,
|
|
152
|
+
"systemPrompt": "You are an expert system architect...",
|
|
153
|
+
"enabled": true
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Debate Configuration
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
interface DebateConfig {
|
|
161
|
+
rounds: number; // Number of debate rounds (default: 3)
|
|
162
|
+
terminationCondition: {
|
|
163
|
+
type: "fixed" | "convergence" | "quality";
|
|
164
|
+
threshold?: number; // For convergence/quality
|
|
165
|
+
};
|
|
166
|
+
synthesisMethod: "judge" | "voting" | "merge";
|
|
167
|
+
includeFullHistory: boolean; // Full context vs summarized
|
|
168
|
+
timeoutPerRound: number; // Milliseconds
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Debate State
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
interface DebateState {
|
|
176
|
+
id: string; // Unique debate session ID
|
|
177
|
+
problem: string; // Original problem statement
|
|
178
|
+
context?: string; // Additional context
|
|
179
|
+
status: "pending" | "running" | "completed" | "failed";
|
|
180
|
+
currentRound: number;
|
|
181
|
+
rounds: DebateRound[];
|
|
182
|
+
finalSolution?: Solution;
|
|
183
|
+
createdAt: Date;
|
|
184
|
+
updatedAt: Date;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface DebateRound {
|
|
188
|
+
roundNumber: number;
|
|
189
|
+
phase: "proposal" | "critique" | "refinement";
|
|
190
|
+
contributions: Contribution[];
|
|
191
|
+
timestamp: Date;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
interface Contribution {
|
|
195
|
+
agentId: string;
|
|
196
|
+
agentRole: AgentRole;
|
|
197
|
+
type: "proposal" | "critique" | "refinement";
|
|
198
|
+
content: string;
|
|
199
|
+
targetAgentId?: string; // For critiques
|
|
200
|
+
metadata: {
|
|
201
|
+
tokensUsed: number;
|
|
202
|
+
latencyMs: number;
|
|
203
|
+
model: string;
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface Solution {
|
|
208
|
+
description: string;
|
|
209
|
+
implementation?: string; // Code if applicable
|
|
210
|
+
tradeoffs: string[];
|
|
211
|
+
recommendations: string[];
|
|
212
|
+
confidence: number; // 0-100
|
|
213
|
+
synthesizedBy: string; // Judge agent ID
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## High-Level Flows
|
|
220
|
+
|
|
221
|
+
### Flow 1: Simple Debate (Fixed Rounds)
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
┌─────────────────────────────────────────────────────────┐
|
|
225
|
+
│ 1. User submits problem via CLI │
|
|
226
|
+
│ $ debate "Design a caching layer for microservices" │
|
|
227
|
+
└────────────────┬────────────────────────────────────────┘
|
|
228
|
+
│
|
|
229
|
+
┌────────────────▼────────────────────────────────────────┐
|
|
230
|
+
│ 2. Orchestrator initializes debate │
|
|
231
|
+
│ - Create debate state │
|
|
232
|
+
│ - Load agent configurations │
|
|
233
|
+
│ - Validate inputs │
|
|
234
|
+
└────────────────┬────────────────────────────────────────┘
|
|
235
|
+
│
|
|
236
|
+
┌────────────────▼────────────────────────────────────────┐
|
|
237
|
+
│ 3. ROUND 1: Proposal Phase │
|
|
238
|
+
│ - Each agent analyzes problem independently │
|
|
239
|
+
│ - Generates initial solution proposal │
|
|
240
|
+
│ Output: │
|
|
241
|
+
│ Agent A: "Redis-based distributed cache..." │
|
|
242
|
+
│ Agent B: "Multi-tier caching with CDN..." │
|
|
243
|
+
│ Agent C: "In-memory cache with invalidation..." │
|
|
244
|
+
└────────────────┬────────────────────────────────────────┘
|
|
245
|
+
│
|
|
246
|
+
┌────────────────▼────────────────────────────────────────┐
|
|
247
|
+
│ 4. ROUND 2: Critique Phase │
|
|
248
|
+
│ - Each agent reviews others' proposals │
|
|
249
|
+
│ - Identifies strengths and weaknesses │
|
|
250
|
+
│ Output: │
|
|
251
|
+
│ Agent A critiques B: "CDN adds latency..." │
|
|
252
|
+
│ Agent B critiques C: "No distribution..." │
|
|
253
|
+
│ Agent C critiques A: "Redis SPOF concern..." │
|
|
254
|
+
└────────────────┬────────────────────────────────────────┘
|
|
255
|
+
│
|
|
256
|
+
┌────────────────▼────────────────────────────────────────┐
|
|
257
|
+
│ 5. ROUND 3: Refinement Phase │
|
|
258
|
+
│ - Each agent refines based on critiques │
|
|
259
|
+
│ - Addresses concerns raised │
|
|
260
|
+
│ Output: │
|
|
261
|
+
│ Agent A: "Redis cluster with sentinels..." │
|
|
262
|
+
│ Agent B: "CDN for static + Redis for dynamic..." │
|
|
263
|
+
│ Agent C: "Distributed in-memory with gossip..." │
|
|
264
|
+
└────────────────┬────────────────────────────────────────┘
|
|
265
|
+
│
|
|
266
|
+
┌────────────────▼────────────────────────────────────────┐
|
|
267
|
+
│ 6. Judge Synthesis │
|
|
268
|
+
│ - Judge agent reviews all rounds │
|
|
269
|
+
│ - Identifies best ideas from each proposal │
|
|
270
|
+
│ - Creates unified solution │
|
|
271
|
+
│ Output: "Hybrid approach: Local cache (L1) + │
|
|
272
|
+
│ Redis cluster (L2) + CDN (L3)..." │
|
|
273
|
+
└────────────────┬────────────────────────────────────────┘
|
|
274
|
+
│
|
|
275
|
+
┌────────────────▼────────────────────────────────────────┐
|
|
276
|
+
│ 7. Present Results │
|
|
277
|
+
│ - Display final solution │
|
|
278
|
+
│ - Show debate history (optional) │
|
|
279
|
+
│ - Save to storage │
|
|
280
|
+
│ - Export options (JSON, Markdown, etc.) │
|
|
281
|
+
└─────────────────────────────────────────────────────────┘
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Flow 2: Convergence-Based Debate
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
1. User submits problem
|
|
288
|
+
2. Orchestrator initializes with convergence detection
|
|
289
|
+
3. Round N:
|
|
290
|
+
├── Agents propose/critique/refine
|
|
291
|
+
├── Calculate similarity between proposals
|
|
292
|
+
│ (using embeddings or text similarity)
|
|
293
|
+
└── If similarity > threshold → converged
|
|
294
|
+
4. If converged → Judge synthesis
|
|
295
|
+
5. If not converged and rounds < max → Next round
|
|
296
|
+
6. Present results
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Convergence Detection**:
|
|
300
|
+
```typescript
|
|
301
|
+
function calculateConvergence(proposals: string[]): number {
|
|
302
|
+
// Option 1: Embedding similarity
|
|
303
|
+
const embeddings = await generateEmbeddings(proposals);
|
|
304
|
+
const similarity = cosineSimilarity(embeddings);
|
|
305
|
+
return similarity;
|
|
306
|
+
|
|
307
|
+
// Option 2: Key concept overlap
|
|
308
|
+
const concepts = proposals.map(extractKeyConcepts);
|
|
309
|
+
const overlap = calculateOverlap(concepts);
|
|
310
|
+
return overlap;
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Flow 3: Tournament-Style Debate
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
1. User submits problem
|
|
318
|
+
2. All agents propose independently (N proposals)
|
|
319
|
+
3. Pairwise comparisons:
|
|
320
|
+
├── Agent pairs debate each other
|
|
321
|
+
└── Judge picks winner of each pair
|
|
322
|
+
4. Winners advance to next round
|
|
323
|
+
5. Repeat until 1 winner or synthesis
|
|
324
|
+
6. Present results
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## CLI Interface Specification
|
|
330
|
+
|
|
331
|
+
### Commands
|
|
332
|
+
|
|
333
|
+
#### 1. `debate` - Start a new debate
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# Basic usage
|
|
337
|
+
$ debate "Design a rate limiting system"
|
|
338
|
+
|
|
339
|
+
# With options
|
|
340
|
+
$ debate "Design a rate limiting system" \
|
|
341
|
+
--agents architect,security,performance \
|
|
342
|
+
--rounds 3 \
|
|
343
|
+
--config custom-config.json \
|
|
344
|
+
--output debate-results.json
|
|
345
|
+
|
|
346
|
+
# Interactive mode
|
|
347
|
+
$ debate --interactive
|
|
348
|
+
? Enter your problem: Design a rate limiting system
|
|
349
|
+
? Select agents: [x] Architect [ ] Security [x] Performance
|
|
350
|
+
? Number of rounds: 3
|
|
351
|
+
? Enable detailed logging: Yes
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Options**:
|
|
355
|
+
- `--agents <list>`: Comma-separated agent roles (default: all enabled)
|
|
356
|
+
- `--rounds <n>`: Number of debate rounds (default: 3)
|
|
357
|
+
- `--config <path>`: Custom configuration file
|
|
358
|
+
- `--output <path>`: Save results to file
|
|
359
|
+
- `--interactive`: Interactive mode with prompts
|
|
360
|
+
- `--verbose`: Show detailed progress
|
|
361
|
+
- `--context <path>`: Additional context file
|
|
362
|
+
|
|
363
|
+
**Output**:
|
|
364
|
+
```
|
|
365
|
+
🤖 Multi-Agent Debate System
|
|
366
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
367
|
+
|
|
368
|
+
Problem: Design a rate limiting system
|
|
369
|
+
|
|
370
|
+
Active Agents:
|
|
371
|
+
✓ System Architect (GPT-4)
|
|
372
|
+
✓ Security Expert (Claude-3)
|
|
373
|
+
✓ Performance Engineer (GPT-4)
|
|
374
|
+
|
|
375
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
376
|
+
|
|
377
|
+
Round 1/3: Proposal Phase
|
|
378
|
+
[Architect] Analyzing problem... ✓ (2.3s)
|
|
379
|
+
[Security] Analyzing problem... ✓ (1.9s)
|
|
380
|
+
[Performance] Analyzing problem... ✓ (2.1s)
|
|
381
|
+
|
|
382
|
+
Round 2/3: Critique Phase
|
|
383
|
+
[Architect] Reviewing proposals... ✓ (1.8s)
|
|
384
|
+
[Security] Reviewing proposals... ✓ (2.0s)
|
|
385
|
+
[Performance] Reviewing proposals... ✓ (1.7s)
|
|
386
|
+
|
|
387
|
+
Round 3/3: Refinement Phase
|
|
388
|
+
[Architect] Refining solution... ✓ (2.2s)
|
|
389
|
+
[Security] Refining solution... ✓ (2.1s)
|
|
390
|
+
[Performance] Refining solution... ✓ (1.9s)
|
|
391
|
+
|
|
392
|
+
Synthesizing final solution... ✓ (3.1s)
|
|
393
|
+
|
|
394
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
395
|
+
|
|
396
|
+
FINAL SOLUTION
|
|
397
|
+
|
|
398
|
+
Recommended Approach: Token Bucket with Redis Backend
|
|
399
|
+
|
|
400
|
+
Overview:
|
|
401
|
+
Implement a distributed rate limiting system using the token
|
|
402
|
+
bucket algorithm with Redis as the shared state store and
|
|
403
|
+
local in-memory caching for performance.
|
|
404
|
+
|
|
405
|
+
Key Components:
|
|
406
|
+
1. Token Bucket Algorithm
|
|
407
|
+
- Configurable rates per user/API key
|
|
408
|
+
- Burst allowance for traffic spikes
|
|
409
|
+
|
|
410
|
+
2. Redis Cluster
|
|
411
|
+
- Distributed state management
|
|
412
|
+
- Lua scripts for atomic operations
|
|
413
|
+
- Failover with Sentinel
|
|
414
|
+
|
|
415
|
+
3. Local Cache Layer
|
|
416
|
+
- Reduces Redis load
|
|
417
|
+
- 1-second TTL for rate counters
|
|
418
|
+
- Eventual consistency acceptable
|
|
419
|
+
|
|
420
|
+
Trade-offs:
|
|
421
|
+
✓ Pros: Scalable, distributed, precise
|
|
422
|
+
✗ Cons: Redis dependency, slight complexity
|
|
423
|
+
|
|
424
|
+
Implementation Complexity: Medium
|
|
425
|
+
Confidence Score: 87/100
|
|
426
|
+
|
|
427
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
428
|
+
|
|
429
|
+
💾 Results saved to: ./debates/debate-20240315-143022.json
|
|
430
|
+
📊 View details: debate history show debate-20240315-143022
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
#### 2. `configure` - Manage configuration
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
# View current configuration
|
|
437
|
+
$ debate configure show
|
|
438
|
+
|
|
439
|
+
# Edit configuration
|
|
440
|
+
$ debate configure edit
|
|
441
|
+
|
|
442
|
+
# Add/modify agent
|
|
443
|
+
$ debate configure agent add \
|
|
444
|
+
--name "Code Reviewer" \
|
|
445
|
+
--role generalist \
|
|
446
|
+
--model gpt-4 \
|
|
447
|
+
--temperature 0.5
|
|
448
|
+
|
|
449
|
+
# Set default rounds
|
|
450
|
+
$ debate configure set rounds 5
|
|
451
|
+
|
|
452
|
+
# Reset to defaults
|
|
453
|
+
$ debate configure reset
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
#### 3. `history` - View past debates
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
# List all debates
|
|
460
|
+
$ debate history list
|
|
461
|
+
|
|
462
|
+
# Show specific debate
|
|
463
|
+
$ debate history show <debate-id>
|
|
464
|
+
|
|
465
|
+
# Filter by date
|
|
466
|
+
$ debate history list --from 2024-03-01 --to 2024-03-15
|
|
467
|
+
|
|
468
|
+
# Search by keyword
|
|
469
|
+
$ debate history search "rate limiting"
|
|
470
|
+
|
|
471
|
+
# Export history
|
|
472
|
+
$ debate history export --format csv --output debates.csv
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Example Output**:
|
|
476
|
+
```
|
|
477
|
+
Recent Debates:
|
|
478
|
+
|
|
479
|
+
ID Date Problem Agents Status
|
|
480
|
+
──────────────────────────────────────────────────────────────────────
|
|
481
|
+
deb-20240315 2024-03-15 Rate limiting system 3 ✓ Complete
|
|
482
|
+
deb-20240314 2024-03-14 Authentication service 4 ✓ Complete
|
|
483
|
+
deb-20240313 2024-03-13 Database sharding 3 ✗ Failed
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
#### 4. `export` - Export debate results
|
|
487
|
+
|
|
488
|
+
```bash
|
|
489
|
+
# Export as markdown
|
|
490
|
+
$ debate export <debate-id> --format markdown --output report.md
|
|
491
|
+
|
|
492
|
+
# Export as JSON
|
|
493
|
+
$ debate export <debate-id> --format json --output data.json
|
|
494
|
+
|
|
495
|
+
# Export with code samples
|
|
496
|
+
$ debate export <debate-id> --include-code --output solution.md
|
|
497
|
+
|
|
498
|
+
# Export comparison chart
|
|
499
|
+
$ debate export <debate-id> --format html --include-charts
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## Agent Specifications
|
|
505
|
+
|
|
506
|
+
### Base Agent Interface
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
abstract class Agent {
|
|
510
|
+
constructor(
|
|
511
|
+
protected config: AgentConfig,
|
|
512
|
+
protected provider: LLMProvider
|
|
513
|
+
) {}
|
|
514
|
+
|
|
515
|
+
// Generate initial solution proposal
|
|
516
|
+
abstract async propose(
|
|
517
|
+
problem: string,
|
|
518
|
+
context: DebateContext
|
|
519
|
+
): Promise<Proposal>;
|
|
520
|
+
|
|
521
|
+
// Critique another agent's proposal
|
|
522
|
+
abstract async critique(
|
|
523
|
+
proposal: Proposal,
|
|
524
|
+
context: DebateContext
|
|
525
|
+
): Promise<Critique>;
|
|
526
|
+
|
|
527
|
+
// Refine own proposal based on critiques
|
|
528
|
+
abstract async refine(
|
|
529
|
+
originalProposal: Proposal,
|
|
530
|
+
critiques: Critique[],
|
|
531
|
+
context: DebateContext
|
|
532
|
+
): Promise<Proposal>;
|
|
533
|
+
|
|
534
|
+
// Internal method to call LLM
|
|
535
|
+
protected async callLLM(prompt: string): Promise<string> {
|
|
536
|
+
return this.provider.complete({
|
|
537
|
+
model: this.config.model,
|
|
538
|
+
temperature: this.config.temperature,
|
|
539
|
+
systemPrompt: this.config.systemPrompt,
|
|
540
|
+
userPrompt: prompt,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### Specialized Agents
|
|
547
|
+
|
|
548
|
+
#### Architect Agent
|
|
549
|
+
|
|
550
|
+
**Role**: Focus on system design, scalability, architecture patterns
|
|
551
|
+
|
|
552
|
+
**System Prompt**:
|
|
553
|
+
```
|
|
554
|
+
You are an expert software architect specializing in distributed systems
|
|
555
|
+
and scalable architecture design. When analyzing problems:
|
|
556
|
+
|
|
557
|
+
1. Consider scalability and performance
|
|
558
|
+
2. Think about component boundaries and interfaces
|
|
559
|
+
3. Evaluate architectural patterns (microservices, event-driven, etc.)
|
|
560
|
+
4. Consider data flow and state management
|
|
561
|
+
5. Think about operational concerns (deployment, monitoring)
|
|
562
|
+
|
|
563
|
+
When proposing solutions:
|
|
564
|
+
- Start with high-level architecture
|
|
565
|
+
- Identify key components and their responsibilities
|
|
566
|
+
- Explain communication patterns
|
|
567
|
+
- Consider failure modes
|
|
568
|
+
- Provide clear diagrams or descriptions
|
|
569
|
+
|
|
570
|
+
When critiquing:
|
|
571
|
+
- Look for scalability bottlenecks
|
|
572
|
+
- Identify missing components
|
|
573
|
+
- Evaluate architectural coherence
|
|
574
|
+
- Consider operational complexity
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
#### Security Agent
|
|
578
|
+
|
|
579
|
+
**Role**: Focus on security, authentication, authorization, data protection
|
|
580
|
+
|
|
581
|
+
**System Prompt**:
|
|
582
|
+
```
|
|
583
|
+
You are a security expert specializing in application security, threat
|
|
584
|
+
modeling, and secure system design. When analyzing problems:
|
|
585
|
+
|
|
586
|
+
1. Identify potential security threats
|
|
587
|
+
2. Consider authentication and authorization
|
|
588
|
+
3. Evaluate data protection (encryption, privacy)
|
|
589
|
+
4. Think about attack vectors
|
|
590
|
+
5. Consider compliance requirements (GDPR, SOC2, etc.)
|
|
591
|
+
|
|
592
|
+
When proposing solutions:
|
|
593
|
+
- Identify security requirements
|
|
594
|
+
- Suggest security controls
|
|
595
|
+
- Consider defense in depth
|
|
596
|
+
- Evaluate trust boundaries
|
|
597
|
+
- Think about secrets management
|
|
598
|
+
|
|
599
|
+
When critiquing:
|
|
600
|
+
- Look for security vulnerabilities
|
|
601
|
+
- Identify missing security controls
|
|
602
|
+
- Evaluate authentication/authorization gaps
|
|
603
|
+
- Consider data exposure risks
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
#### Performance Agent
|
|
607
|
+
|
|
608
|
+
**Role**: Focus on performance, optimization, resource efficiency
|
|
609
|
+
|
|
610
|
+
**System Prompt**:
|
|
611
|
+
```
|
|
612
|
+
You are a performance engineer specializing in system optimization,
|
|
613
|
+
profiling, and resource management. When analyzing problems:
|
|
614
|
+
|
|
615
|
+
1. Consider performance characteristics (latency, throughput)
|
|
616
|
+
2. Think about resource utilization (CPU, memory, network)
|
|
617
|
+
3. Evaluate caching strategies
|
|
618
|
+
4. Consider algorithmic complexity
|
|
619
|
+
5. Think about performance testing and monitoring
|
|
620
|
+
|
|
621
|
+
When proposing solutions:
|
|
622
|
+
- Identify performance requirements
|
|
623
|
+
- Suggest optimization strategies
|
|
624
|
+
- Consider caching and precomputation
|
|
625
|
+
- Evaluate resource trade-offs
|
|
626
|
+
- Think about performance metrics
|
|
627
|
+
|
|
628
|
+
When critiquing:
|
|
629
|
+
- Look for performance bottlenecks
|
|
630
|
+
- Identify inefficient algorithms or data structures
|
|
631
|
+
- Evaluate resource usage
|
|
632
|
+
- Consider scalability limits
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
#### Testing Agent
|
|
636
|
+
|
|
637
|
+
**Role**: Focus on testability, quality assurance, reliability
|
|
638
|
+
|
|
639
|
+
**System Prompt**:
|
|
640
|
+
```
|
|
641
|
+
You are a quality engineer specializing in testing strategies, test
|
|
642
|
+
automation, and system reliability. When analyzing problems:
|
|
643
|
+
|
|
644
|
+
1. Consider testability of the solution
|
|
645
|
+
2. Think about test coverage and strategies
|
|
646
|
+
3. Evaluate error handling and edge cases
|
|
647
|
+
4. Consider observability and debugging
|
|
648
|
+
5. Think about reliability and fault tolerance
|
|
649
|
+
|
|
650
|
+
When proposing solutions:
|
|
651
|
+
- Identify testing requirements
|
|
652
|
+
- Suggest testing strategies (unit, integration, e2e)
|
|
653
|
+
- Consider error scenarios
|
|
654
|
+
- Evaluate observability needs
|
|
655
|
+
- Think about chaos testing
|
|
656
|
+
|
|
657
|
+
When critiquing:
|
|
658
|
+
- Look for untestable components
|
|
659
|
+
- Identify missing error handling
|
|
660
|
+
- Evaluate edge case coverage
|
|
661
|
+
- Consider debugging difficulty
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## Orchestrator Logic
|
|
667
|
+
|
|
668
|
+
### Orchestrator Class
|
|
669
|
+
|
|
670
|
+
```typescript
|
|
671
|
+
class DebateOrchestrator {
|
|
672
|
+
constructor(
|
|
673
|
+
private agents: Agent[],
|
|
674
|
+
private judge: JudgeAgent,
|
|
675
|
+
private stateManager: StateManager,
|
|
676
|
+
private config: DebateConfig
|
|
677
|
+
) {}
|
|
678
|
+
|
|
679
|
+
async runDebate(
|
|
680
|
+
problem: string,
|
|
681
|
+
context?: string
|
|
682
|
+
): Promise<DebateResult> {
|
|
683
|
+
// Initialize debate state
|
|
684
|
+
const state = await this.stateManager.createDebate(problem, context);
|
|
685
|
+
|
|
686
|
+
try {
|
|
687
|
+
// Main debate loop
|
|
688
|
+
for (let round = 1; round <= this.config.rounds; round++) {
|
|
689
|
+
console.log(`\nRound ${round}/${this.config.rounds}`);
|
|
690
|
+
|
|
691
|
+
// Phase 1: Proposal (first round) or Refinement (subsequent rounds)
|
|
692
|
+
if (round === 1) {
|
|
693
|
+
await this.proposalPhase(state);
|
|
694
|
+
} else {
|
|
695
|
+
await this.refinementPhase(state);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Phase 2: Critique (except last round)
|
|
699
|
+
if (round < this.config.rounds) {
|
|
700
|
+
await this.critiquePhase(state);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// Check termination conditions
|
|
704
|
+
if (await this.shouldTerminate(state)) {
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Synthesis
|
|
710
|
+
const solution = await this.synthesisPhase(state);
|
|
711
|
+
|
|
712
|
+
// Finalize
|
|
713
|
+
await this.stateManager.completeDebate(state.id, solution);
|
|
714
|
+
|
|
715
|
+
return {
|
|
716
|
+
debateId: state.id,
|
|
717
|
+
solution,
|
|
718
|
+
rounds: state.rounds,
|
|
719
|
+
metadata: {
|
|
720
|
+
totalRounds: state.currentRound,
|
|
721
|
+
totalTokens: this.calculateTotalTokens(state),
|
|
722
|
+
duration: Date.now() - state.createdAt.getTime(),
|
|
723
|
+
},
|
|
724
|
+
};
|
|
725
|
+
} catch (error) {
|
|
726
|
+
await this.stateManager.failDebate(state.id, error);
|
|
727
|
+
throw error;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
private async proposalPhase(state: DebateState): Promise<void> {
|
|
732
|
+
console.log(' Proposal Phase');
|
|
733
|
+
|
|
734
|
+
const proposals = await Promise.all(
|
|
735
|
+
this.agents.map(async (agent) => {
|
|
736
|
+
console.log(` [${agent.config.name}] Proposing solution...`);
|
|
737
|
+
|
|
738
|
+
const proposal = await agent.propose(
|
|
739
|
+
state.problem,
|
|
740
|
+
this.buildContext(state)
|
|
741
|
+
);
|
|
742
|
+
|
|
743
|
+
await this.stateManager.addContribution(state.id, {
|
|
744
|
+
agentId: agent.config.id,
|
|
745
|
+
agentRole: agent.config.role,
|
|
746
|
+
type: 'proposal',
|
|
747
|
+
content: proposal.content,
|
|
748
|
+
metadata: proposal.metadata,
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
return proposal;
|
|
752
|
+
})
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
private async critiquePhase(state: DebateState): Promise<void> {
|
|
757
|
+
console.log(' Critique Phase');
|
|
758
|
+
|
|
759
|
+
// Get all proposals from current round
|
|
760
|
+
const currentRound = state.rounds[state.currentRound - 1];
|
|
761
|
+
const proposals = currentRound.contributions.filter(
|
|
762
|
+
c => c.type === 'proposal'
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
// Each agent critiques others' proposals
|
|
766
|
+
for (const agent of this.agents) {
|
|
767
|
+
const otherProposals = proposals.filter(
|
|
768
|
+
p => p.agentId !== agent.config.id
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
for (const proposal of otherProposals) {
|
|
772
|
+
console.log(
|
|
773
|
+
` [${agent.config.name}] Critiquing ${proposal.agentId}...`
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
const critique = await agent.critique(
|
|
777
|
+
proposal,
|
|
778
|
+
this.buildContext(state)
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
await this.stateManager.addContribution(state.id, {
|
|
782
|
+
agentId: agent.config.id,
|
|
783
|
+
agentRole: agent.config.role,
|
|
784
|
+
type: 'critique',
|
|
785
|
+
content: critique.content,
|
|
786
|
+
targetAgentId: proposal.agentId,
|
|
787
|
+
metadata: critique.metadata,
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
private async refinementPhase(state: DebateState): Promise<void> {
|
|
794
|
+
console.log(' Refinement Phase');
|
|
795
|
+
|
|
796
|
+
// Get proposals and critiques from previous round
|
|
797
|
+
const prevRound = state.rounds[state.currentRound - 2];
|
|
798
|
+
|
|
799
|
+
for (const agent of this.agents) {
|
|
800
|
+
// Find agent's original proposal
|
|
801
|
+
const originalProposal = prevRound.contributions.find(
|
|
802
|
+
c => c.agentId === agent.config.id && c.type === 'proposal'
|
|
803
|
+
);
|
|
804
|
+
|
|
805
|
+
// Find critiques targeting this agent
|
|
806
|
+
const critiques = prevRound.contributions.filter(
|
|
807
|
+
c => c.type === 'critique' && c.targetAgentId === agent.config.id
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
console.log(` [${agent.config.name}] Refining solution...`);
|
|
811
|
+
|
|
812
|
+
const refinedProposal = await agent.refine(
|
|
813
|
+
originalProposal,
|
|
814
|
+
critiques,
|
|
815
|
+
this.buildContext(state)
|
|
816
|
+
);
|
|
817
|
+
|
|
818
|
+
await this.stateManager.addContribution(state.id, {
|
|
819
|
+
agentId: agent.config.id,
|
|
820
|
+
agentRole: agent.config.role,
|
|
821
|
+
type: 'proposal',
|
|
822
|
+
content: refinedProposal.content,
|
|
823
|
+
metadata: refinedProposal.metadata,
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
private async synthesisPhase(state: DebateState): Promise<Solution> {
|
|
829
|
+
console.log('\n Synthesizing final solution...');
|
|
830
|
+
|
|
831
|
+
const solution = await this.judge.synthesize(
|
|
832
|
+
state.problem,
|
|
833
|
+
state.rounds,
|
|
834
|
+
this.buildContext(state)
|
|
835
|
+
);
|
|
836
|
+
|
|
837
|
+
return solution;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
private async shouldTerminate(state: DebateState): Promise<boolean> {
|
|
841
|
+
switch (this.config.terminationCondition.type) {
|
|
842
|
+
case 'fixed':
|
|
843
|
+
return state.currentRound >= this.config.rounds;
|
|
844
|
+
|
|
845
|
+
case 'convergence':
|
|
846
|
+
return await this.checkConvergence(state);
|
|
847
|
+
|
|
848
|
+
case 'quality':
|
|
849
|
+
return await this.checkQualityThreshold(state);
|
|
850
|
+
|
|
851
|
+
default:
|
|
852
|
+
return false;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
private buildContext(state: DebateState): DebateContext {
|
|
857
|
+
if (this.config.includeFullHistory) {
|
|
858
|
+
return {
|
|
859
|
+
problem: state.problem,
|
|
860
|
+
context: state.context,
|
|
861
|
+
history: state.rounds,
|
|
862
|
+
};
|
|
863
|
+
} else {
|
|
864
|
+
// Summarized context
|
|
865
|
+
return {
|
|
866
|
+
problem: state.problem,
|
|
867
|
+
context: state.context,
|
|
868
|
+
summary: this.summarizeHistory(state.rounds),
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## Judge/Synthesizer Logic
|
|
878
|
+
|
|
879
|
+
```typescript
|
|
880
|
+
class JudgeAgent {
|
|
881
|
+
constructor(
|
|
882
|
+
private config: AgentConfig,
|
|
883
|
+
private provider: LLMProvider
|
|
884
|
+
) {}
|
|
885
|
+
|
|
886
|
+
async synthesize(
|
|
887
|
+
problem: string,
|
|
888
|
+
rounds: DebateRound[],
|
|
889
|
+
context: DebateContext
|
|
890
|
+
): Promise<Solution> {
|
|
891
|
+
const prompt = this.buildSynthesisPrompt(problem, rounds, context);
|
|
892
|
+
|
|
893
|
+
const response = await this.provider.complete({
|
|
894
|
+
model: this.config.model,
|
|
895
|
+
temperature: 0.3, // Lower temperature for consistency
|
|
896
|
+
systemPrompt: this.getJudgeSystemPrompt(),
|
|
897
|
+
userPrompt: prompt,
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
return this.parseSolution(response);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
private getJudgeSystemPrompt(): string {
|
|
904
|
+
return `
|
|
905
|
+
You are an expert technical judge responsible for synthesizing the best
|
|
906
|
+
solution from multiple agent proposals and debates.
|
|
907
|
+
|
|
908
|
+
Your role:
|
|
909
|
+
1. Review all proposals and critiques objectively
|
|
910
|
+
2. Identify the strongest ideas from each agent
|
|
911
|
+
3. Reconcile conflicting viewpoints
|
|
912
|
+
4. Create a unified, coherent solution
|
|
913
|
+
5. Acknowledge trade-offs and alternatives
|
|
914
|
+
|
|
915
|
+
When synthesizing:
|
|
916
|
+
- Be objective and evidence-based
|
|
917
|
+
- Consider all perspectives fairly
|
|
918
|
+
- Combine complementary ideas
|
|
919
|
+
- Address major concerns raised
|
|
920
|
+
- Provide clear recommendations
|
|
921
|
+
- Rate confidence in the solution
|
|
922
|
+
|
|
923
|
+
Output format:
|
|
924
|
+
- Solution description
|
|
925
|
+
- Key components
|
|
926
|
+
- Trade-offs
|
|
927
|
+
- Implementation recommendations
|
|
928
|
+
- Confidence score (0-100)
|
|
929
|
+
`;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
private buildSynthesisPrompt(
|
|
933
|
+
problem: string,
|
|
934
|
+
rounds: DebateRound[],
|
|
935
|
+
context: DebateContext
|
|
936
|
+
): string {
|
|
937
|
+
let prompt = `Problem: ${problem}\n\n`;
|
|
938
|
+
|
|
939
|
+
// Add debate history
|
|
940
|
+
rounds.forEach((round, idx) => {
|
|
941
|
+
prompt += `Round ${idx + 1}:\n`;
|
|
942
|
+
round.contributions.forEach((contrib) => {
|
|
943
|
+
prompt += `[${contrib.agentRole}] ${contrib.type}:\n`;
|
|
944
|
+
prompt += `${contrib.content}\n\n`;
|
|
945
|
+
});
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
prompt += `
|
|
949
|
+
Based on the above debate, synthesize the best solution that:
|
|
950
|
+
1. Incorporates the strongest ideas from all agents
|
|
951
|
+
2. Addresses the major concerns raised
|
|
952
|
+
3. Provides a practical, implementable approach
|
|
953
|
+
4. Acknowledges trade-offs
|
|
954
|
+
|
|
955
|
+
Provide a comprehensive final solution.
|
|
956
|
+
`;
|
|
957
|
+
|
|
958
|
+
return prompt;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
private parseSolution(response: string): Solution {
|
|
962
|
+
// Parse structured response
|
|
963
|
+
// Could use JSON mode or structured output parsing
|
|
964
|
+
return {
|
|
965
|
+
description: response,
|
|
966
|
+
tradeoffs: this.extractTradeoffs(response),
|
|
967
|
+
recommendations: this.extractRecommendations(response),
|
|
968
|
+
confidence: this.extractConfidence(response),
|
|
969
|
+
synthesizedBy: this.config.id,
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
---
|
|
976
|
+
|
|
977
|
+
## State Management
|
|
978
|
+
|
|
979
|
+
```typescript
|
|
980
|
+
class StateManager {
|
|
981
|
+
private debates: Map<string, DebateState> = new Map();
|
|
982
|
+
private storage: Storage;
|
|
983
|
+
|
|
984
|
+
constructor(storage: Storage) {
|
|
985
|
+
this.storage = storage;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
async createDebate(
|
|
989
|
+
problem: string,
|
|
990
|
+
context?: string
|
|
991
|
+
): Promise<DebateState> {
|
|
992
|
+
const state: DebateState = {
|
|
993
|
+
id: generateId(),
|
|
994
|
+
problem,
|
|
995
|
+
context,
|
|
996
|
+
status: 'running',
|
|
997
|
+
currentRound: 0,
|
|
998
|
+
rounds: [],
|
|
999
|
+
createdAt: new Date(),
|
|
1000
|
+
updatedAt: new Date(),
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
this.debates.set(state.id, state);
|
|
1004
|
+
await this.storage.save(state);
|
|
1005
|
+
|
|
1006
|
+
return state;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
async addContribution(
|
|
1010
|
+
debateId: string,
|
|
1011
|
+
contribution: Contribution
|
|
1012
|
+
): Promise<void> {
|
|
1013
|
+
const state = this.debates.get(debateId);
|
|
1014
|
+
if (!state) throw new Error(`Debate ${debateId} not found`);
|
|
1015
|
+
|
|
1016
|
+
// Get or create current round
|
|
1017
|
+
let currentRound = state.rounds[state.currentRound];
|
|
1018
|
+
if (!currentRound) {
|
|
1019
|
+
currentRound = {
|
|
1020
|
+
roundNumber: state.currentRound + 1,
|
|
1021
|
+
phase: contribution.type === 'proposal' ? 'proposal' : 'critique',
|
|
1022
|
+
contributions: [],
|
|
1023
|
+
timestamp: new Date(),
|
|
1024
|
+
};
|
|
1025
|
+
state.rounds.push(currentRound);
|
|
1026
|
+
state.currentRound = currentRound.roundNumber;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Add contribution
|
|
1030
|
+
currentRound.contributions.push({
|
|
1031
|
+
...contribution,
|
|
1032
|
+
metadata: {
|
|
1033
|
+
...contribution.metadata,
|
|
1034
|
+
timestamp: new Date(),
|
|
1035
|
+
},
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
state.updatedAt = new Date();
|
|
1039
|
+
await this.storage.save(state);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
async completeDebate(
|
|
1043
|
+
debateId: string,
|
|
1044
|
+
solution: Solution
|
|
1045
|
+
): Promise<void> {
|
|
1046
|
+
const state = this.debates.get(debateId);
|
|
1047
|
+
if (!state) throw new Error(`Debate ${debateId} not found`);
|
|
1048
|
+
|
|
1049
|
+
state.status = 'completed';
|
|
1050
|
+
state.finalSolution = solution;
|
|
1051
|
+
state.updatedAt = new Date();
|
|
1052
|
+
|
|
1053
|
+
await this.storage.save(state);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
async failDebate(debateId: string, error: Error): Promise<void> {
|
|
1057
|
+
const state = this.debates.get(debateId);
|
|
1058
|
+
if (!state) return;
|
|
1059
|
+
|
|
1060
|
+
state.status = 'failed';
|
|
1061
|
+
state.updatedAt = new Date();
|
|
1062
|
+
|
|
1063
|
+
await this.storage.save(state);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
async getDebate(debateId: string): Promise<DebateState | null> {
|
|
1067
|
+
if (this.debates.has(debateId)) {
|
|
1068
|
+
return this.debates.get(debateId)!;
|
|
1069
|
+
}
|
|
1070
|
+
return await this.storage.load(debateId);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
async listDebates(filter?: DebateFilter): Promise<DebateState[]> {
|
|
1074
|
+
return await this.storage.list(filter);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
---
|
|
1080
|
+
|
|
1081
|
+
## LLM Provider Layer
|
|
1082
|
+
|
|
1083
|
+
### Provider Interface
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
interface LLMProvider {
|
|
1087
|
+
complete(request: CompletionRequest): Promise<string>;
|
|
1088
|
+
stream(request: CompletionRequest): AsyncIterator<string>;
|
|
1089
|
+
generateEmbedding(text: string): Promise<number[]>;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
interface CompletionRequest {
|
|
1093
|
+
model: string;
|
|
1094
|
+
systemPrompt: string;
|
|
1095
|
+
userPrompt: string;
|
|
1096
|
+
temperature: number;
|
|
1097
|
+
maxTokens?: number;
|
|
1098
|
+
stopSequences?: string[];
|
|
1099
|
+
}
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
### OpenAI Provider Implementation
|
|
1103
|
+
|
|
1104
|
+
```typescript
|
|
1105
|
+
class OpenAIProvider implements LLMProvider {
|
|
1106
|
+
private client: OpenAI;
|
|
1107
|
+
|
|
1108
|
+
constructor(apiKey: string) {
|
|
1109
|
+
this.client = new OpenAI({ apiKey });
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
async complete(request: CompletionRequest): Promise<string> {
|
|
1113
|
+
const response = await this.client.chat.completions.create({
|
|
1114
|
+
model: request.model,
|
|
1115
|
+
messages: [
|
|
1116
|
+
{ role: 'system', content: request.systemPrompt },
|
|
1117
|
+
{ role: 'user', content: request.userPrompt },
|
|
1118
|
+
],
|
|
1119
|
+
temperature: request.temperature,
|
|
1120
|
+
max_tokens: request.maxTokens,
|
|
1121
|
+
stop: request.stopSequences,
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
return response.choices[0].message.content || '';
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
async *stream(request: CompletionRequest): AsyncIterator<string> {
|
|
1128
|
+
const stream = await this.client.chat.completions.create({
|
|
1129
|
+
model: request.model,
|
|
1130
|
+
messages: [
|
|
1131
|
+
{ role: 'system', content: request.systemPrompt },
|
|
1132
|
+
{ role: 'user', content: request.userPrompt },
|
|
1133
|
+
],
|
|
1134
|
+
temperature: request.temperature,
|
|
1135
|
+
stream: true,
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
for await (const chunk of stream) {
|
|
1139
|
+
const content = chunk.choices[0]?.delta?.content;
|
|
1140
|
+
if (content) yield content;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
async generateEmbedding(text: string): Promise<number[]> {
|
|
1145
|
+
const response = await this.client.embeddings.create({
|
|
1146
|
+
model: 'text-embedding-3-small',
|
|
1147
|
+
input: text,
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
return response.data[0].embedding;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
### Anthropic Provider Implementation
|
|
1156
|
+
|
|
1157
|
+
```typescript
|
|
1158
|
+
class AnthropicProvider implements LLMProvider {
|
|
1159
|
+
private client: Anthropic;
|
|
1160
|
+
|
|
1161
|
+
constructor(apiKey: string) {
|
|
1162
|
+
this.client = new Anthropic({ apiKey });
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
async complete(request: CompletionRequest): Promise<string> {
|
|
1166
|
+
const response = await this.client.messages.create({
|
|
1167
|
+
model: request.model,
|
|
1168
|
+
max_tokens: request.maxTokens || 4096,
|
|
1169
|
+
system: request.systemPrompt,
|
|
1170
|
+
messages: [
|
|
1171
|
+
{ role: 'user', content: request.userPrompt },
|
|
1172
|
+
],
|
|
1173
|
+
temperature: request.temperature,
|
|
1174
|
+
stop_sequences: request.stopSequences,
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
return response.content[0].type === 'text'
|
|
1178
|
+
? response.content[0].text
|
|
1179
|
+
: '';
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
async *stream(request: CompletionRequest): AsyncIterator<string> {
|
|
1183
|
+
const stream = await this.client.messages.stream({
|
|
1184
|
+
model: request.model,
|
|
1185
|
+
max_tokens: request.maxTokens || 4096,
|
|
1186
|
+
system: request.systemPrompt,
|
|
1187
|
+
messages: [
|
|
1188
|
+
{ role: 'user', content: request.userPrompt },
|
|
1189
|
+
],
|
|
1190
|
+
temperature: request.temperature,
|
|
1191
|
+
});
|
|
1192
|
+
|
|
1193
|
+
for await (const event of stream) {
|
|
1194
|
+
if (event.type === 'content_block_delta' &&
|
|
1195
|
+
event.delta.type === 'text_delta') {
|
|
1196
|
+
yield event.delta.text;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
async generateEmbedding(text: string): Promise<number[]> {
|
|
1202
|
+
// Anthropic doesn't provide embeddings, use OpenAI or other service
|
|
1203
|
+
throw new Error('Embeddings not supported by Anthropic provider');
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
```
|
|
1207
|
+
|
|
1208
|
+
---
|
|
1209
|
+
|
|
1210
|
+
## Storage Implementation
|
|
1211
|
+
|
|
1212
|
+
### File-Based Storage
|
|
1213
|
+
|
|
1214
|
+
```typescript
|
|
1215
|
+
class FileStorage implements Storage {
|
|
1216
|
+
private baseDir: string;
|
|
1217
|
+
|
|
1218
|
+
constructor(baseDir: string = './debates') {
|
|
1219
|
+
this.baseDir = baseDir;
|
|
1220
|
+
this.ensureDirectoryExists();
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
async save(state: DebateState): Promise<void> {
|
|
1224
|
+
const filePath = path.join(this.baseDir, `${state.id}.json`);
|
|
1225
|
+
await fs.promises.writeFile(
|
|
1226
|
+
filePath,
|
|
1227
|
+
JSON.stringify(state, null, 2),
|
|
1228
|
+
'utf-8'
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
async load(debateId: string): Promise<DebateState | null> {
|
|
1233
|
+
const filePath = path.join(this.baseDir, `${debateId}.json`);
|
|
1234
|
+
|
|
1235
|
+
try {
|
|
1236
|
+
const content = await fs.promises.readFile(filePath, 'utf-8');
|
|
1237
|
+
return JSON.parse(content);
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
if (error.code === 'ENOENT') return null;
|
|
1240
|
+
throw error;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
async list(filter?: DebateFilter): Promise<DebateState[]> {
|
|
1245
|
+
const files = await fs.promises.readdir(this.baseDir);
|
|
1246
|
+
const debates: DebateState[] = [];
|
|
1247
|
+
|
|
1248
|
+
for (const file of files) {
|
|
1249
|
+
if (!file.endsWith('.json')) continue;
|
|
1250
|
+
|
|
1251
|
+
const debate = await this.load(file.replace('.json', ''));
|
|
1252
|
+
if (debate && this.matchesFilter(debate, filter)) {
|
|
1253
|
+
debates.push(debate);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
return debates.sort((a, b) =>
|
|
1258
|
+
b.createdAt.getTime() - a.createdAt.getTime()
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
private matchesFilter(
|
|
1263
|
+
debate: DebateState,
|
|
1264
|
+
filter?: DebateFilter
|
|
1265
|
+
): boolean {
|
|
1266
|
+
if (!filter) return true;
|
|
1267
|
+
|
|
1268
|
+
if (filter.status && debate.status !== filter.status) {
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
if (filter.from && debate.createdAt < filter.from) {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
if (filter.to && debate.createdAt > filter.to) {
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
if (filter.searchTerm) {
|
|
1281
|
+
const searchLower = filter.searchTerm.toLowerCase();
|
|
1282
|
+
if (!debate.problem.toLowerCase().includes(searchLower)) {
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
return true;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
private ensureDirectoryExists(): void {
|
|
1291
|
+
if (!fs.existsSync(this.baseDir)) {
|
|
1292
|
+
fs.mkdirSync(this.baseDir, { recursive: true });
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
---
|
|
1299
|
+
|
|
1300
|
+
## Configuration Management
|
|
1301
|
+
|
|
1302
|
+
### Default Configuration File
|
|
1303
|
+
|
|
1304
|
+
```json
|
|
1305
|
+
{
|
|
1306
|
+
"debate": {
|
|
1307
|
+
"rounds": 3,
|
|
1308
|
+
"terminationCondition": {
|
|
1309
|
+
"type": "fixed"
|
|
1310
|
+
},
|
|
1311
|
+
"synthesisMethod": "judge",
|
|
1312
|
+
"includeFullHistory": true,
|
|
1313
|
+
"timeoutPerRound": 300000
|
|
1314
|
+
},
|
|
1315
|
+
"agents": [
|
|
1316
|
+
{
|
|
1317
|
+
"id": "agent-architect",
|
|
1318
|
+
"name": "System Architect",
|
|
1319
|
+
"role": "architect",
|
|
1320
|
+
"model": "gpt-4",
|
|
1321
|
+
"provider": "openai",
|
|
1322
|
+
"temperature": 0.7,
|
|
1323
|
+
"enabled": true
|
|
1324
|
+
},
|
|
1325
|
+
{
|
|
1326
|
+
"id": "agent-security",
|
|
1327
|
+
"name": "Security Expert",
|
|
1328
|
+
"role": "security",
|
|
1329
|
+
"model": "claude-3-opus",
|
|
1330
|
+
"provider": "anthropic",
|
|
1331
|
+
"temperature": 0.6,
|
|
1332
|
+
"enabled": true
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
"id": "agent-performance",
|
|
1336
|
+
"name": "Performance Engineer",
|
|
1337
|
+
"role": "performance",
|
|
1338
|
+
"model": "gpt-4",
|
|
1339
|
+
"provider": "openai",
|
|
1340
|
+
"temperature": 0.7,
|
|
1341
|
+
"enabled": true
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
"id": "agent-testing",
|
|
1345
|
+
"name": "Quality Engineer",
|
|
1346
|
+
"role": "testing",
|
|
1347
|
+
"model": "gpt-4",
|
|
1348
|
+
"provider": "openai",
|
|
1349
|
+
"temperature": 0.6,
|
|
1350
|
+
"enabled": false
|
|
1351
|
+
}
|
|
1352
|
+
],
|
|
1353
|
+
"judge": {
|
|
1354
|
+
"id": "judge-main",
|
|
1355
|
+
"name": "Technical Judge",
|
|
1356
|
+
"model": "gpt-4",
|
|
1357
|
+
"provider": "openai",
|
|
1358
|
+
"temperature": 0.3
|
|
1359
|
+
},
|
|
1360
|
+
"providers": {
|
|
1361
|
+
"openai": {
|
|
1362
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
1363
|
+
},
|
|
1364
|
+
"anthropic": {
|
|
1365
|
+
"apiKeyEnv": "ANTHROPIC_API_KEY"
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
```
|
|
1370
|
+
|
|
1371
|
+
### Configuration Loader
|
|
1372
|
+
|
|
1373
|
+
```typescript
|
|
1374
|
+
class ConfigurationManager {
|
|
1375
|
+
private config: SystemConfig;
|
|
1376
|
+
private configPath: string;
|
|
1377
|
+
|
|
1378
|
+
constructor(configPath?: string) {
|
|
1379
|
+
this.configPath = configPath || './config/default-config.json';
|
|
1380
|
+
this.config = this.loadConfig();
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
private loadConfig(): SystemConfig {
|
|
1384
|
+
if (fs.existsSync(this.configPath)) {
|
|
1385
|
+
const content = fs.readFileSync(this.configPath, 'utf-8');
|
|
1386
|
+
return JSON.parse(content);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
return this.getDefaultConfig();
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
async saveConfig(): Promise<void> {
|
|
1393
|
+
const content = JSON.stringify(this.config, null, 2);
|
|
1394
|
+
await fs.promises.writeFile(this.configPath, content, 'utf-8');
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
getDebateConfig(): DebateConfig {
|
|
1398
|
+
return this.config.debate;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
getAgentConfigs(): AgentConfig[] {
|
|
1402
|
+
return this.config.agents.filter(a => a.enabled);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
getJudgeConfig(): AgentConfig {
|
|
1406
|
+
return this.config.judge;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
updateAgent(agentId: string, updates: Partial<AgentConfig>): void {
|
|
1410
|
+
const agent = this.config.agents.find(a => a.id === agentId);
|
|
1411
|
+
if (agent) {
|
|
1412
|
+
Object.assign(agent, updates);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
addAgent(agent: AgentConfig): void {
|
|
1417
|
+
this.config.agents.push(agent);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
removeAgent(agentId: string): void {
|
|
1421
|
+
this.config.agents = this.config.agents.filter(
|
|
1422
|
+
a => a.id !== agentId
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
private getDefaultConfig(): SystemConfig {
|
|
1427
|
+
// Return built-in defaults if no config file exists
|
|
1428
|
+
return require('../config/default-config.json');
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1433
|
+
---
|
|
1434
|
+
|
|
1435
|
+
## Utility Functions
|
|
1436
|
+
|
|
1437
|
+
### Prompt Builder
|
|
1438
|
+
|
|
1439
|
+
```typescript
|
|
1440
|
+
class PromptBuilder {
|
|
1441
|
+
static buildProposalPrompt(
|
|
1442
|
+
problem: string,
|
|
1443
|
+
role: AgentRole,
|
|
1444
|
+
context?: DebateContext
|
|
1445
|
+
): string {
|
|
1446
|
+
let prompt = `Problem to solve:\n${problem}\n\n`;
|
|
1447
|
+
|
|
1448
|
+
if (context?.context) {
|
|
1449
|
+
prompt += `Additional context:\n${context.context}\n\n`;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
prompt += `As a ${role} expert, propose a comprehensive solution. Include:
|
|
1453
|
+
1. Your recommended approach
|
|
1454
|
+
2. Key components or considerations
|
|
1455
|
+
3. Potential challenges
|
|
1456
|
+
4. Why this approach is suitable
|
|
1457
|
+
|
|
1458
|
+
Be specific and detailed in your proposal.`;
|
|
1459
|
+
|
|
1460
|
+
return prompt;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
static buildCritiquePrompt(
|
|
1464
|
+
proposal: Proposal,
|
|
1465
|
+
proposerRole: AgentRole,
|
|
1466
|
+
criticRole: AgentRole
|
|
1467
|
+
): string {
|
|
1468
|
+
return `You are reviewing a proposal from a ${proposerRole} expert.
|
|
1469
|
+
|
|
1470
|
+
Their proposal:
|
|
1471
|
+
${proposal.content}
|
|
1472
|
+
|
|
1473
|
+
As a ${criticRole} expert, provide constructive critique:
|
|
1474
|
+
1. Identify strengths of the proposal
|
|
1475
|
+
2. Identify weaknesses or concerns from your perspective
|
|
1476
|
+
3. Suggest specific improvements
|
|
1477
|
+
4. Highlight any critical issues
|
|
1478
|
+
|
|
1479
|
+
Be objective and constructive in your critique.`;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
static buildRefinementPrompt(
|
|
1483
|
+
originalProposal: Proposal,
|
|
1484
|
+
critiques: Critique[],
|
|
1485
|
+
role: AgentRole
|
|
1486
|
+
): string {
|
|
1487
|
+
let prompt = `Your original proposal:\n${originalProposal.content}\n\n`;
|
|
1488
|
+
|
|
1489
|
+
prompt += `Critiques from other experts:\n`;
|
|
1490
|
+
critiques.forEach((critique, idx) => {
|
|
1491
|
+
prompt += `\nCritique ${idx + 1}:\n${critique.content}\n`;
|
|
1492
|
+
});
|
|
1493
|
+
|
|
1494
|
+
prompt += `\nAs a ${role} expert, refine your proposal by:
|
|
1495
|
+
1. Addressing valid concerns raised
|
|
1496
|
+
2. Incorporating good suggestions
|
|
1497
|
+
3. Defending aspects you still believe are correct
|
|
1498
|
+
4. Providing a stronger, more complete solution
|
|
1499
|
+
|
|
1500
|
+
Produce an improved version of your proposal.`;
|
|
1501
|
+
|
|
1502
|
+
return prompt;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
static buildSummaryPrompt(rounds: DebateRound[]): string {
|
|
1506
|
+
return `Summarize the following debate rounds concisely, highlighting:
|
|
1507
|
+
1. Main proposals from each agent
|
|
1508
|
+
2. Key points of agreement
|
|
1509
|
+
3. Key points of disagreement
|
|
1510
|
+
4. Evolution of ideas across rounds
|
|
1511
|
+
|
|
1512
|
+
Keep the summary under 500 words.
|
|
1513
|
+
|
|
1514
|
+
Debate rounds:
|
|
1515
|
+
${this.formatRounds(rounds)}`;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
private static formatRounds(rounds: DebateRound[]): string {
|
|
1519
|
+
return rounds
|
|
1520
|
+
.map((round, idx) => {
|
|
1521
|
+
const contributions = round.contributions
|
|
1522
|
+
.map(c => `[${c.agentRole}] ${c.type}: ${c.content}`)
|
|
1523
|
+
.join('\n');
|
|
1524
|
+
return `Round ${idx + 1}:\n${contributions}`;
|
|
1525
|
+
})
|
|
1526
|
+
.join('\n\n');
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
```
|
|
1530
|
+
|
|
1531
|
+
### Logger
|
|
1532
|
+
|
|
1533
|
+
```typescript
|
|
1534
|
+
class Logger {
|
|
1535
|
+
private verbose: boolean;
|
|
1536
|
+
|
|
1537
|
+
constructor(verbose: boolean = false) {
|
|
1538
|
+
this.verbose = verbose;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
info(message: string): void {
|
|
1542
|
+
console.log(`ℹ️ ${message}`);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
success(message: string): void {
|
|
1546
|
+
console.log(`✅ ${message}`);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
error(message: string): void {
|
|
1550
|
+
console.error(`❌ ${message}`);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
warn(message: string): void {
|
|
1554
|
+
console.warn(`⚠️ ${message}`);
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
debug(message: string): void {
|
|
1558
|
+
if (this.verbose) {
|
|
1559
|
+
console.log(`🔍 ${message}`);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
agentAction(agentName: string, action: string): void {
|
|
1564
|
+
console.log(` [${agentName}] ${action}`);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
progress(message: string, current: number, total: number): void {
|
|
1568
|
+
const percent = Math.round((current / total) * 100);
|
|
1569
|
+
console.log(` ${message} [${current}/${total}] ${percent}%`);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
separator(): void {
|
|
1573
|
+
console.log('━'.repeat(60));
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
```
|
|
1577
|
+
|
|
1578
|
+
---
|
|
1579
|
+
|
|
1580
|
+
## Export Functionality
|
|
1581
|
+
|
|
1582
|
+
### Markdown Exporter
|
|
1583
|
+
|
|
1584
|
+
```typescript
|
|
1585
|
+
class MarkdownExporter {
|
|
1586
|
+
async export(
|
|
1587
|
+
debate: DebateState,
|
|
1588
|
+
options: ExportOptions
|
|
1589
|
+
): Promise<string> {
|
|
1590
|
+
let markdown = '';
|
|
1591
|
+
|
|
1592
|
+
// Header
|
|
1593
|
+
markdown += `# Debate Report\n\n`;
|
|
1594
|
+
markdown += `**Problem**: ${debate.problem}\n\n`;
|
|
1595
|
+
markdown += `**Date**: ${debate.createdAt.toLocaleString()}\n`;
|
|
1596
|
+
markdown += `**Status**: ${debate.status}\n`;
|
|
1597
|
+
markdown += `**Rounds**: ${debate.currentRound}\n\n`;
|
|
1598
|
+
|
|
1599
|
+
markdown += `---\n\n`;
|
|
1600
|
+
|
|
1601
|
+
// Debate rounds
|
|
1602
|
+
markdown += `## Debate History\n\n`;
|
|
1603
|
+
|
|
1604
|
+
for (const round of debate.rounds) {
|
|
1605
|
+
markdown += `### Round ${round.roundNumber} - ${round.phase}\n\n`;
|
|
1606
|
+
|
|
1607
|
+
for (const contrib of round.contributions) {
|
|
1608
|
+
markdown += `#### ${contrib.agentRole} (${contrib.type})\n\n`;
|
|
1609
|
+
markdown += `${contrib.content}\n\n`;
|
|
1610
|
+
|
|
1611
|
+
if (options.includeMetadata) {
|
|
1612
|
+
markdown += `*Tokens: ${contrib.metadata.tokensUsed}, `;
|
|
1613
|
+
markdown += `Latency: ${contrib.metadata.latencyMs}ms*\n\n`;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// Final solution
|
|
1619
|
+
if (debate.finalSolution) {
|
|
1620
|
+
markdown += `---\n\n`;
|
|
1621
|
+
markdown += `## Final Solution\n\n`;
|
|
1622
|
+
markdown += `${debate.finalSolution.description}\n\n`;
|
|
1623
|
+
|
|
1624
|
+
if (debate.finalSolution.tradeoffs.length > 0) {
|
|
1625
|
+
markdown += `### Trade-offs\n\n`;
|
|
1626
|
+
debate.finalSolution.tradeoffs.forEach(tradeoff => {
|
|
1627
|
+
markdown += `- ${tradeoff}\n`;
|
|
1628
|
+
});
|
|
1629
|
+
markdown += `\n`;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
if (debate.finalSolution.recommendations.length > 0) {
|
|
1633
|
+
markdown += `### Recommendations\n\n`;
|
|
1634
|
+
debate.finalSolution.recommendations.forEach(rec => {
|
|
1635
|
+
markdown += `- ${rec}\n`;
|
|
1636
|
+
});
|
|
1637
|
+
markdown += `\n`;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
markdown += `**Confidence**: ${debate.finalSolution.confidence}/100\n\n`;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
return markdown;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
```
|
|
1647
|
+
|
|
1648
|
+
### JSON Exporter
|
|
1649
|
+
|
|
1650
|
+
```typescript
|
|
1651
|
+
class JSONExporter {
|
|
1652
|
+
async export(
|
|
1653
|
+
debate: DebateState,
|
|
1654
|
+
options: ExportOptions
|
|
1655
|
+
): Promise<string> {
|
|
1656
|
+
const exportData: any = {
|
|
1657
|
+
id: debate.id,
|
|
1658
|
+
problem: debate.problem,
|
|
1659
|
+
context: debate.context,
|
|
1660
|
+
status: debate.status,
|
|
1661
|
+
createdAt: debate.createdAt,
|
|
1662
|
+
updatedAt: debate.updatedAt,
|
|
1663
|
+
rounds: debate.rounds,
|
|
1664
|
+
finalSolution: debate.finalSolution,
|
|
1665
|
+
};
|
|
1666
|
+
|
|
1667
|
+
if (!options.includeMetadata) {
|
|
1668
|
+
// Remove metadata from contributions
|
|
1669
|
+
exportData.rounds = debate.rounds.map(round => ({
|
|
1670
|
+
...round,
|
|
1671
|
+
contributions: round.contributions.map(({ metadata, ...rest }) => rest),
|
|
1672
|
+
}));
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
return JSON.stringify(exportData, null, 2);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
```
|
|
1679
|
+
|
|
1680
|
+
---
|
|
1681
|
+
|
|
1682
|
+
## Web Interface Extension (Future)
|
|
1683
|
+
|
|
1684
|
+
### Architecture for Web Extension
|
|
1685
|
+
|
|
1686
|
+
```
|
|
1687
|
+
Web Frontend (React/Vue)
|
|
1688
|
+
│
|
|
1689
|
+
├── WebSocket Connection (real-time updates)
|
|
1690
|
+
│
|
|
1691
|
+
▼
|
|
1692
|
+
┌─────────────────────────────────────┐
|
|
1693
|
+
│ API Server (Express) │
|
|
1694
|
+
│ │
|
|
1695
|
+
│ Routes: │
|
|
1696
|
+
│ - POST /api/debates │
|
|
1697
|
+
│ - GET /api/debates/:id │
|
|
1698
|
+
│ - GET /api/debates │
|
|
1699
|
+
│ - WS /api/debates/:id/stream │
|
|
1700
|
+
│ - GET /api/config │
|
|
1701
|
+
│ - PUT /api/config │
|
|
1702
|
+
└─────────┬───────────────────────────┘
|
|
1703
|
+
│
|
|
1704
|
+
▼
|
|
1705
|
+
┌─────────────────────────────────────┐
|
|
1706
|
+
│ Debate Orchestrator (Core Logic) │
|
|
1707
|
+
└─────────────────────────────────────┘
|
|
1708
|
+
```
|
|
1709
|
+
|
|
1710
|
+
### API Endpoints
|
|
1711
|
+
|
|
1712
|
+
```typescript
|
|
1713
|
+
// Express routes
|
|
1714
|
+
app.post('/api/debates', async (req, res) => {
|
|
1715
|
+
const { problem, context, config } = req.body;
|
|
1716
|
+
|
|
1717
|
+
const debateId = await orchestrator.startDebate(problem, context, config);
|
|
1718
|
+
|
|
1719
|
+
res.json({ debateId });
|
|
1720
|
+
});
|
|
1721
|
+
|
|
1722
|
+
app.get('/api/debates/:id', async (req, res) => {
|
|
1723
|
+
const debate = await stateManager.getDebate(req.params.id);
|
|
1724
|
+
res.json(debate);
|
|
1725
|
+
});
|
|
1726
|
+
|
|
1727
|
+
app.get('/api/debates/:id/stream', (req, res) => {
|
|
1728
|
+
// Setup Server-Sent Events for real-time updates
|
|
1729
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
1730
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
1731
|
+
res.setHeader('Connection', 'keep-alive');
|
|
1732
|
+
|
|
1733
|
+
const listener = (update) => {
|
|
1734
|
+
res.write(`data: ${JSON.stringify(update)}\n\n`);
|
|
1735
|
+
};
|
|
1736
|
+
|
|
1737
|
+
orchestrator.on('update', listener);
|
|
1738
|
+
|
|
1739
|
+
req.on('close', () => {
|
|
1740
|
+
orchestrator.off('update', listener);
|
|
1741
|
+
});
|
|
1742
|
+
});
|
|
1743
|
+
```
|
|
1744
|
+
|
|
1745
|
+
### UI Components
|
|
1746
|
+
|
|
1747
|
+
**Dashboard**:
|
|
1748
|
+
- List of recent debates
|
|
1749
|
+
- Quick start debate button
|
|
1750
|
+
- Configuration settings
|
|
1751
|
+
|
|
1752
|
+
**Debate View**:
|
|
1753
|
+
- Real-time progress indicator
|
|
1754
|
+
- Current round/phase display
|
|
1755
|
+
- Agent activity log
|
|
1756
|
+
- Collapsible proposal/critique cards
|
|
1757
|
+
- Final solution display
|
|
1758
|
+
|
|
1759
|
+
**Configuration Panel**:
|
|
1760
|
+
- Agent enable/disable toggles
|
|
1761
|
+
- Model selection dropdowns
|
|
1762
|
+
- Temperature sliders
|
|
1763
|
+
- Round count input
|
|
1764
|
+
|
|
1765
|
+
---
|
|
1766
|
+
|
|
1767
|
+
## Error Handling
|
|
1768
|
+
|
|
1769
|
+
### Error Types
|
|
1770
|
+
|
|
1771
|
+
```typescript
|
|
1772
|
+
class DebateError extends Error {
|
|
1773
|
+
constructor(message: string, public code: string) {
|
|
1774
|
+
super(message);
|
|
1775
|
+
this.name = 'DebateError';
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
class AgentError extends DebateError {
|
|
1780
|
+
constructor(
|
|
1781
|
+
message: string,
|
|
1782
|
+
public agentId: string,
|
|
1783
|
+
public phase: string
|
|
1784
|
+
) {
|
|
1785
|
+
super(message, 'AGENT_ERROR');
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
class ProviderError extends DebateError {
|
|
1790
|
+
constructor(
|
|
1791
|
+
message: string,
|
|
1792
|
+
public provider: string,
|
|
1793
|
+
public originalError?: Error
|
|
1794
|
+
) {
|
|
1795
|
+
super(message, 'PROVIDER_ERROR');
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
class ConfigurationError extends DebateError {
|
|
1800
|
+
constructor(message: string) {
|
|
1801
|
+
super(message, 'CONFIG_ERROR');
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
```
|
|
1805
|
+
|
|
1806
|
+
### Error Handling Strategy
|
|
1807
|
+
|
|
1808
|
+
```typescript
|
|
1809
|
+
class ErrorHandler {
|
|
1810
|
+
async handleAgentError(
|
|
1811
|
+
error: AgentError,
|
|
1812
|
+
state: DebateState
|
|
1813
|
+
): Promise<void> {
|
|
1814
|
+
// Log error
|
|
1815
|
+
logger.error(`Agent ${error.agentId} failed in ${error.phase}: ${error.message}`);
|
|
1816
|
+
|
|
1817
|
+
// Try to continue with other agents
|
|
1818
|
+
const remainingAgents = this.getRemainingAgents(error.agentId);
|
|
1819
|
+
|
|
1820
|
+
if (remainingAgents.length < 2) {
|
|
1821
|
+
throw new DebateError(
|
|
1822
|
+
'Insufficient agents to continue debate',
|
|
1823
|
+
'INSUFFICIENT_AGENTS'
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
// Mark agent as failed in this round
|
|
1828
|
+
await stateManager.markAgentFailed(state.id, error.agentId);
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
async handleProviderError(
|
|
1832
|
+
error: ProviderError,
|
|
1833
|
+
retryCount: number = 0
|
|
1834
|
+
): Promise<any> {
|
|
1835
|
+
const maxRetries = 3;
|
|
1836
|
+
|
|
1837
|
+
if (retryCount >= maxRetries) {
|
|
1838
|
+
throw error;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
// Exponential backoff
|
|
1842
|
+
const delay = Math.pow(2, retryCount) * 1000;
|
|
1843
|
+
await this.sleep(delay);
|
|
1844
|
+
|
|
1845
|
+
// Retry the operation
|
|
1846
|
+
logger.warn(`Retrying after provider error (attempt ${retryCount + 1}/${maxRetries})`);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
private sleep(ms: number): Promise<void> {
|
|
1850
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
```
|
|
1854
|
+
|
|
1855
|
+
---
|
|
1856
|
+
|
|
1857
|
+
## Testing Strategy
|
|
1858
|
+
|
|
1859
|
+
### Unit Tests
|
|
1860
|
+
|
|
1861
|
+
```typescript
|
|
1862
|
+
describe('DebateOrchestrator', () => {
|
|
1863
|
+
let orchestrator: DebateOrchestrator;
|
|
1864
|
+
let mockAgents: Agent[];
|
|
1865
|
+
let mockJudge: JudgeAgent;
|
|
1866
|
+
let mockStateManager: StateManager;
|
|
1867
|
+
|
|
1868
|
+
beforeEach(() => {
|
|
1869
|
+
mockAgents = [
|
|
1870
|
+
createMockAgent('architect'),
|
|
1871
|
+
createMockAgent('security'),
|
|
1872
|
+
];
|
|
1873
|
+
mockJudge = createMockJudge();
|
|
1874
|
+
mockStateManager = createMockStateManager();
|
|
1875
|
+
|
|
1876
|
+
orchestrator = new DebateOrchestrator(
|
|
1877
|
+
mockAgents,
|
|
1878
|
+
mockJudge,
|
|
1879
|
+
mockStateManager,
|
|
1880
|
+
defaultConfig
|
|
1881
|
+
);
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
it('should run complete debate flow', async () => {
|
|
1885
|
+
const result = await orchestrator.runDebate(
|
|
1886
|
+
'Design a caching system'
|
|
1887
|
+
);
|
|
1888
|
+
|
|
1889
|
+
expect(result.debateId).toBeDefined();
|
|
1890
|
+
expect(result.solution).toBeDefined();
|
|
1891
|
+
expect(result.rounds.length).toBe(3);
|
|
1892
|
+
});
|
|
1893
|
+
|
|
1894
|
+
it('should handle agent failures gracefully', async () => {
|
|
1895
|
+
mockAgents[0].propose = jest.fn().mockRejectedValue(
|
|
1896
|
+
new Error('Agent failed')
|
|
1897
|
+
);
|
|
1898
|
+
|
|
1899
|
+
const result = await orchestrator.runDebate('Test problem');
|
|
1900
|
+
|
|
1901
|
+
// Should continue with remaining agent
|
|
1902
|
+
expect(result.solution).toBeDefined();
|
|
1903
|
+
});
|
|
1904
|
+
});
|
|
1905
|
+
```
|
|
1906
|
+
|
|
1907
|
+
### Integration Tests
|
|
1908
|
+
|
|
1909
|
+
```typescript
|
|
1910
|
+
describe('End-to-End Debate', () => {
|
|
1911
|
+
it('should complete debate with real LLM providers', async () => {
|
|
1912
|
+
const config = loadTestConfig();
|
|
1913
|
+
const orchestrator = createOrchestrator(config);
|
|
1914
|
+
|
|
1915
|
+
const result = await orchestrator.runDebate(
|
|
1916
|
+
'Design a simple rate limiting system for an API'
|
|
1917
|
+
);
|
|
1918
|
+
|
|
1919
|
+
expect(result.solution.description).toContain('rate limit');
|
|
1920
|
+
expect(result.solution.confidence).toBeGreaterThan(50);
|
|
1921
|
+
}, 120000); // 2 minute timeout for LLM calls
|
|
1922
|
+
});
|
|
1923
|
+
```
|
|
1924
|
+
|
|
1925
|
+
---
|
|
1926
|
+
|
|
1927
|
+
## Performance Considerations
|
|
1928
|
+
|
|
1929
|
+
### Parallel Execution
|
|
1930
|
+
|
|
1931
|
+
```typescript
|
|
1932
|
+
// Execute agent proposals in parallel
|
|
1933
|
+
const proposals = await Promise.all(
|
|
1934
|
+
this.agents.map(agent => agent.propose(problem, context))
|
|
1935
|
+
);
|
|
1936
|
+
|
|
1937
|
+
// With timeout and error handling
|
|
1938
|
+
const proposals = await Promise.allSettled(
|
|
1939
|
+
this.agents.map(agent =>
|
|
1940
|
+
this.withTimeout(
|
|
1941
|
+
agent.propose(problem, context),
|
|
1942
|
+
this.config.timeoutPerRound
|
|
1943
|
+
)
|
|
1944
|
+
)
|
|
1945
|
+
);
|
|
1946
|
+
```
|
|
1947
|
+
|
|
1948
|
+
### Caching
|
|
1949
|
+
|
|
1950
|
+
```typescript
|
|
1951
|
+
class CachedLLMProvider implements LLMProvider {
|
|
1952
|
+
private cache: Map<string, string> = new Map();
|
|
1953
|
+
|
|
1954
|
+
async complete(request: CompletionRequest): Promise<string> {
|
|
1955
|
+
const cacheKey = this.getCacheKey(request);
|
|
1956
|
+
|
|
1957
|
+
if (this.cache.has(cacheKey)) {
|
|
1958
|
+
return this.cache.get(cacheKey)!;
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
const response = await this.provider.complete(request);
|
|
1962
|
+
this.cache.set(cacheKey, response);
|
|
1963
|
+
|
|
1964
|
+
return response;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
private getCacheKey(request: CompletionRequest): string {
|
|
1968
|
+
return JSON.stringify({
|
|
1969
|
+
model: request.model,
|
|
1970
|
+
system: request.systemPrompt,
|
|
1971
|
+
user: request.userPrompt,
|
|
1972
|
+
temp: request.temperature,
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
```
|
|
1977
|
+
|
|
1978
|
+
### Token Management
|
|
1979
|
+
|
|
1980
|
+
```typescript
|
|
1981
|
+
class TokenTracker {
|
|
1982
|
+
private totalTokens: number = 0;
|
|
1983
|
+
private costEstimate: number = 0;
|
|
1984
|
+
|
|
1985
|
+
trackUsage(model: string, tokens: number): void {
|
|
1986
|
+
this.totalTokens += tokens;
|
|
1987
|
+
this.costEstimate += this.calculateCost(model, tokens);
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
private calculateCost(model: string, tokens: number): number {
|
|
1991
|
+
const rates = {
|
|
1992
|
+
'gpt-4': 0.03 / 1000, // $0.03 per 1K tokens
|
|
1993
|
+
'gpt-3.5-turbo': 0.002 / 1000,
|
|
1994
|
+
'claude-3-opus': 0.015 / 1000,
|
|
1995
|
+
};
|
|
1996
|
+
|
|
1997
|
+
return (rates[model] || 0) * tokens;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
getReport(): TokenReport {
|
|
2001
|
+
return {
|
|
2002
|
+
totalTokens: this.totalTokens,
|
|
2003
|
+
estimatedCost: this.costEstimate,
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
```
|
|
2008
|
+
|
|
2009
|
+
---
|
|
2010
|
+
|
|
2011
|
+
## Deployment
|
|
2012
|
+
|
|
2013
|
+
### Environment Variables
|
|
2014
|
+
|
|
2015
|
+
```bash
|
|
2016
|
+
# .env file
|
|
2017
|
+
OPENAI_API_KEY=sk-...
|
|
2018
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
2019
|
+
|
|
2020
|
+
# Optional
|
|
2021
|
+
DEBATE_STORAGE_PATH=./debates
|
|
2022
|
+
DEBATE_CONFIG_PATH=./config/custom-config.json
|
|
2023
|
+
LOG_LEVEL=info
|
|
2024
|
+
```
|
|
2025
|
+
|
|
2026
|
+
### Docker Support
|
|
2027
|
+
|
|
2028
|
+
```dockerfile
|
|
2029
|
+
FROM node:18-alpine
|
|
2030
|
+
|
|
2031
|
+
WORKDIR /app
|
|
2032
|
+
|
|
2033
|
+
COPY package*.json ./
|
|
2034
|
+
RUN npm ci --only=production
|
|
2035
|
+
|
|
2036
|
+
COPY dist ./dist
|
|
2037
|
+
COPY config ./config
|
|
2038
|
+
|
|
2039
|
+
ENV NODE_ENV=production
|
|
2040
|
+
|
|
2041
|
+
ENTRYPOINT ["node", "dist/cli/index.js"]
|
|
2042
|
+
CMD ["--help"]
|
|
2043
|
+
```
|
|
2044
|
+
|
|
2045
|
+
### NPM Package
|
|
2046
|
+
|
|
2047
|
+
```json
|
|
2048
|
+
{
|
|
2049
|
+
"name": "multi-agent-debate",
|
|
2050
|
+
"version": "1.0.0",
|
|
2051
|
+
"bin": {
|
|
2052
|
+
"debate": "./dist/cli/index.js"
|
|
2053
|
+
},
|
|
2054
|
+
"scripts": {
|
|
2055
|
+
"build": "tsc",
|
|
2056
|
+
"dev": "ts-node src/cli/index.ts",
|
|
2057
|
+
"test": "jest",
|
|
2058
|
+
"lint": "eslint src/**/*.ts"
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
```
|
|
2062
|
+
|
|
2063
|
+
---
|
|
2064
|
+
|
|
2065
|
+
## Example Usage Scenarios
|
|
2066
|
+
|
|
2067
|
+
### Scenario 1: Software Architecture Design
|
|
2068
|
+
|
|
2069
|
+
```bash
|
|
2070
|
+
$ debate "Design a microservices architecture for an e-commerce platform" \
|
|
2071
|
+
--agents architect,security,performance \
|
|
2072
|
+
--rounds 3 \
|
|
2073
|
+
--output ecommerce-architecture.md
|
|
2074
|
+
```
|
|
2075
|
+
|
|
2076
|
+
Expected outcome:
|
|
2077
|
+
- Architect proposes service boundaries
|
|
2078
|
+
- Security evaluates auth/authorization
|
|
2079
|
+
- Performance analyzes scalability
|
|
2080
|
+
- Final solution: Balanced architecture with security and performance considerations
|
|
2081
|
+
|
|
2082
|
+
### Scenario 2: API Design
|
|
2083
|
+
|
|
2084
|
+
```bash
|
|
2085
|
+
$ debate "Design a RESTful API for a social media platform" \
|
|
2086
|
+
--context api-requirements.txt \
|
|
2087
|
+
--agents architect,security \
|
|
2088
|
+
--rounds 2
|
|
2089
|
+
```
|
|
2090
|
+
|
|
2091
|
+
### Scenario 3: Database Schema
|
|
2092
|
+
|
|
2093
|
+
```bash
|
|
2094
|
+
$ debate "Design a database schema for a multi-tenant SaaS application" \
|
|
2095
|
+
--agents architect,performance,security \
|
|
2096
|
+
--rounds 4
|
|
2097
|
+
```
|
|
2098
|
+
|
|
2099
|
+
---
|
|
2100
|
+
|
|
2101
|
+
## Future Enhancements
|
|
2102
|
+
|
|
2103
|
+
### Phase 2 Features
|
|
2104
|
+
|
|
2105
|
+
1. **Code Generation**: Generate actual code implementations
|
|
2106
|
+
2. **Diagram Generation**: Auto-generate architecture diagrams
|
|
2107
|
+
3. **Cost Optimization**: Smart agent selection based on budget
|
|
2108
|
+
4. **Template Library**: Pre-built problem templates
|
|
2109
|
+
5. **Agent Personalities**: Customizable agent behaviors
|
|
2110
|
+
6. **Multi-language Support**: Internationalization
|
|
2111
|
+
7. **Collaboration**: Multiple users can influence debate
|
|
2112
|
+
8. **Learning**: Agents learn from past debates
|
|
2113
|
+
|
|
2114
|
+
### Phase 3 Features
|
|
2115
|
+
|
|
2116
|
+
1. **Visual Debate Flow**: Interactive visualization
|
|
2117
|
+
2. **Voice Integration**: Speak problems, hear solutions
|
|
2118
|
+
3. **Integration**: Jira, GitHub, Slack integrations
|
|
2119
|
+
4. **Advanced Analytics**: Debate quality metrics
|
|
2120
|
+
5. **Agent Marketplace**: Community-contributed agents
|
|
2121
|
+
6. **Hybrid Debates**: Mix AI and human participants
|
|
2122
|
+
|
|
2123
|
+
---
|
|
2124
|
+
|
|
2125
|
+
## Conclusion
|
|
2126
|
+
|
|
2127
|
+
This specification provides a complete blueprint for building a multi-agent debate system. The architecture is:
|
|
2128
|
+
|
|
2129
|
+
- **Modular**: Easy to add new agents, providers, or storage backends
|
|
2130
|
+
- **Extensible**: CLI can extend to web interface with minimal changes
|
|
2131
|
+
- **Testable**: Clear separation of concerns enables comprehensive testing
|
|
2132
|
+
- **Production-ready**: Includes error handling, logging, and performance considerations
|
|
2133
|
+
|
|
2134
|
+
---
|
|
2135
|
+
|
|
2136
|
+
## Implementation Roadmap
|
|
2137
|
+
|
|
2138
|
+
### Phase 1: Core CLI (Weeks 1-3)
|
|
2139
|
+
|
|
2140
|
+
**Week 1: Foundation**
|
|
2141
|
+
- Set up TypeScript project structure
|
|
2142
|
+
- Implement core data models and types
|
|
2143
|
+
- Create LLM provider abstractions
|
|
2144
|
+
- Implement OpenAI and Anthropic providers
|
|
2145
|
+
- Basic configuration system
|
|
2146
|
+
|
|
2147
|
+
**Week 2: Core Logic**
|
|
2148
|
+
- Implement Agent base class
|
|
2149
|
+
- Create specialized agents (Architect, Security, Performance)
|
|
2150
|
+
- Implement DebateOrchestrator
|
|
2151
|
+
- Implement JudgeAgent
|
|
2152
|
+
- Create StateManager with file storage
|
|
2153
|
+
|
|
2154
|
+
**Week 3: CLI & Polish**
|
|
2155
|
+
- Implement CLI commands (debate, configure, history, export)
|
|
2156
|
+
- Add logging and progress indicators
|
|
2157
|
+
- Implement export functionality (Markdown, JSON)
|
|
2158
|
+
- Error handling and validation
|
|
2159
|
+
- Documentation and examples
|
|
2160
|
+
|
|
2161
|
+
### Phase 2: Advanced Features (Weeks 4-6)
|
|
2162
|
+
|
|
2163
|
+
**Week 4: Debate Enhancements**
|
|
2164
|
+
- Convergence detection
|
|
2165
|
+
- Tournament-style debates
|
|
2166
|
+
- Context summarization
|
|
2167
|
+
- Performance optimization (parallel execution, caching)
|
|
2168
|
+
|
|
2169
|
+
**Week 5: Usability**
|
|
2170
|
+
- Interactive mode
|
|
2171
|
+
- Configuration UI (CLI-based)
|
|
2172
|
+
- Better output formatting
|
|
2173
|
+
- Template system for common problems
|
|
2174
|
+
|
|
2175
|
+
**Week 6: Testing & Reliability**
|
|
2176
|
+
- Comprehensive unit tests
|
|
2177
|
+
- Integration tests with real LLMs
|
|
2178
|
+
- Error recovery mechanisms
|
|
2179
|
+
- Performance benchmarks
|
|
2180
|
+
|
|
2181
|
+
### Phase 3: Web Interface (Weeks 7-10)
|
|
2182
|
+
|
|
2183
|
+
**Week 7: API Server**
|
|
2184
|
+
- Express.js server setup
|
|
2185
|
+
- REST API endpoints
|
|
2186
|
+
- WebSocket/SSE for real-time updates
|
|
2187
|
+
- Authentication (if needed)
|
|
2188
|
+
|
|
2189
|
+
**Week 8-9: Frontend**
|
|
2190
|
+
- React/Vue application
|
|
2191
|
+
- Dashboard with debate list
|
|
2192
|
+
- Real-time debate viewer
|
|
2193
|
+
- Configuration management UI
|
|
2194
|
+
- Export and sharing features
|
|
2195
|
+
|
|
2196
|
+
**Week 10: Deployment**
|
|
2197
|
+
- Docker containerization
|
|
2198
|
+
- CI/CD pipeline
|
|
2199
|
+
- Documentation
|
|
2200
|
+
- Demo videos and tutorials
|
|
2201
|
+
|
|
2202
|
+
---
|
|
2203
|
+
|
|
2204
|
+
## Sample Implementation Files
|
|
2205
|
+
|
|
2206
|
+
### package.json
|
|
2207
|
+
|
|
2208
|
+
```json
|
|
2209
|
+
{
|
|
2210
|
+
"name": "multi-agent-debate",
|
|
2211
|
+
"version": "1.0.0",
|
|
2212
|
+
"description": "Multi-agent debate system for software design problems",
|
|
2213
|
+
"main": "dist/index.js",
|
|
2214
|
+
"bin": {
|
|
2215
|
+
"debate": "./dist/cli/index.js"
|
|
2216
|
+
},
|
|
2217
|
+
"scripts": {
|
|
2218
|
+
"build": "tsc",
|
|
2219
|
+
"dev": "ts-node src/cli/index.ts",
|
|
2220
|
+
"test": "jest",
|
|
2221
|
+
"test:watch": "jest --watch",
|
|
2222
|
+
"lint": "eslint src/**/*.ts",
|
|
2223
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
2224
|
+
"prepare": "npm run build"
|
|
2225
|
+
},
|
|
2226
|
+
"keywords": [
|
|
2227
|
+
"ai",
|
|
2228
|
+
"multi-agent",
|
|
2229
|
+
"debate",
|
|
2230
|
+
"llm",
|
|
2231
|
+
"software-design"
|
|
2232
|
+
],
|
|
2233
|
+
"author": "Your Name",
|
|
2234
|
+
"license": "MIT",
|
|
2235
|
+
"dependencies": {
|
|
2236
|
+
"commander": "^11.0.0",
|
|
2237
|
+
"openai": "^4.20.0",
|
|
2238
|
+
"@anthropic-ai/sdk": "^0.9.0",
|
|
2239
|
+
"chalk": "^5.3.0",
|
|
2240
|
+
"inquirer": "^9.2.0",
|
|
2241
|
+
"ora": "^7.0.0",
|
|
2242
|
+
"dotenv": "^16.3.0",
|
|
2243
|
+
"uuid": "^9.0.0"
|
|
2244
|
+
},
|
|
2245
|
+
"devDependencies": {
|
|
2246
|
+
"@types/node": "^20.0.0",
|
|
2247
|
+
"@types/jest": "^29.5.0",
|
|
2248
|
+
"@types/inquirer": "^9.0.0",
|
|
2249
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
2250
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
2251
|
+
"eslint": "^8.50.0",
|
|
2252
|
+
"jest": "^29.7.0",
|
|
2253
|
+
"prettier": "^3.0.0",
|
|
2254
|
+
"ts-jest": "^29.1.0",
|
|
2255
|
+
"ts-node": "^10.9.0",
|
|
2256
|
+
"typescript": "^5.2.0"
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
```
|
|
2260
|
+
|
|
2261
|
+
### tsconfig.json
|
|
2262
|
+
|
|
2263
|
+
```json
|
|
2264
|
+
{
|
|
2265
|
+
"compilerOptions": {
|
|
2266
|
+
"target": "ES2020",
|
|
2267
|
+
"module": "commonjs",
|
|
2268
|
+
"lib": ["ES2020"],
|
|
2269
|
+
"outDir": "./dist",
|
|
2270
|
+
"rootDir": "./src",
|
|
2271
|
+
"strict": true,
|
|
2272
|
+
"esModuleInterop": true,
|
|
2273
|
+
"skipLibCheck": true,
|
|
2274
|
+
"forceConsistentCasingInFileNames": true,
|
|
2275
|
+
"resolveJsonModule": true,
|
|
2276
|
+
"declaration": true,
|
|
2277
|
+
"declarationMap": true,
|
|
2278
|
+
"sourceMap": true,
|
|
2279
|
+
"moduleResolution": "node"
|
|
2280
|
+
},
|
|
2281
|
+
"include": ["src/**/*"],
|
|
2282
|
+
"exclude": ["node_modules", "dist", "tests"]
|
|
2283
|
+
}
|
|
2284
|
+
```
|
|
2285
|
+
|
|
2286
|
+
### CLI Entry Point (src/cli/index.ts)
|
|
2287
|
+
|
|
2288
|
+
```typescript
|
|
2289
|
+
#!/usr/bin/env node
|
|
2290
|
+
import { Command } from 'commander';
|
|
2291
|
+
import chalk from 'chalk';
|
|
2292
|
+
import { debateCommand } from './commands/debate';
|
|
2293
|
+
import { configureCommand } from './commands/configure';
|
|
2294
|
+
import { historyCommand } from './commands/history';
|
|
2295
|
+
import { exportCommand } from './commands/export';
|
|
2296
|
+
import { loadEnvironment } from '../utils/environment';
|
|
2297
|
+
|
|
2298
|
+
// Load environment variables
|
|
2299
|
+
loadEnvironment();
|
|
2300
|
+
|
|
2301
|
+
const program = new Command();
|
|
2302
|
+
|
|
2303
|
+
program
|
|
2304
|
+
.name('debate')
|
|
2305
|
+
.description('Multi-agent debate system for software design problems')
|
|
2306
|
+
.version('1.0.0');
|
|
2307
|
+
|
|
2308
|
+
// ASCII art banner
|
|
2309
|
+
const banner = `
|
|
2310
|
+
╔═══════════════════════════════════════════════════╗
|
|
2311
|
+
║ ║
|
|
2312
|
+
║ Multi-Agent Debate System ║
|
|
2313
|
+
║ Collaborative AI Problem Solving ║
|
|
2314
|
+
║ ║
|
|
2315
|
+
╚═══════════════════════════════════════════════════╝
|
|
2316
|
+
`;
|
|
2317
|
+
|
|
2318
|
+
console.log(chalk.cyan(banner));
|
|
2319
|
+
|
|
2320
|
+
// Register commands
|
|
2321
|
+
debateCommand(program);
|
|
2322
|
+
configureCommand(program);
|
|
2323
|
+
historyCommand(program);
|
|
2324
|
+
exportCommand(program);
|
|
2325
|
+
|
|
2326
|
+
// Parse arguments
|
|
2327
|
+
program.parse(process.argv);
|
|
2328
|
+
|
|
2329
|
+
// Show help if no command provided
|
|
2330
|
+
if (!process.argv.slice(2).length) {
|
|
2331
|
+
program.outputHelp();
|
|
2332
|
+
}
|
|
2333
|
+
```
|
|
2334
|
+
|
|
2335
|
+
### Main Debate Command (src/cli/commands/debate.ts)
|
|
2336
|
+
|
|
2337
|
+
```typescript
|
|
2338
|
+
import { Command } from 'commander';
|
|
2339
|
+
import chalk from 'chalk';
|
|
2340
|
+
import ora from 'ora';
|
|
2341
|
+
import inquirer from 'inquirer';
|
|
2342
|
+
import { DebateOrchestrator } from '../../core/orchestrator';
|
|
2343
|
+
import { ConfigurationManager } from '../../core/config-manager';
|
|
2344
|
+
import { StateManager } from '../../core/state-manager';
|
|
2345
|
+
import { FileStorage } from '../../utils/storage';
|
|
2346
|
+
import { createProviders, createAgents, createJudge } from '../../core/factory';
|
|
2347
|
+
import { Logger } from '../../utils/logger';
|
|
2348
|
+
|
|
2349
|
+
export function debateCommand(program: Command): void {
|
|
2350
|
+
program
|
|
2351
|
+
.command('debate')
|
|
2352
|
+
.argument('[problem]', 'Problem statement to debate')
|
|
2353
|
+
.option('-a, --agents <agents>', 'Comma-separated list of agent roles')
|
|
2354
|
+
.option('-r, --rounds <number>', 'Number of debate rounds', '3')
|
|
2355
|
+
.option('-c, --config <path>', 'Path to configuration file')
|
|
2356
|
+
.option('-o, --output <path>', 'Output file for results')
|
|
2357
|
+
.option('-i, --interactive', 'Interactive mode')
|
|
2358
|
+
.option('-v, --verbose', 'Verbose logging')
|
|
2359
|
+
.option('--context <path>', 'Path to context file')
|
|
2360
|
+
.description('Start a new debate')
|
|
2361
|
+
.action(async (problem, options) => {
|
|
2362
|
+
const logger = new Logger(options.verbose);
|
|
2363
|
+
|
|
2364
|
+
try {
|
|
2365
|
+
// Interactive mode
|
|
2366
|
+
if (options.interactive || !problem) {
|
|
2367
|
+
const answers = await inquirer.prompt([
|
|
2368
|
+
{
|
|
2369
|
+
type: 'input',
|
|
2370
|
+
name: 'problem',
|
|
2371
|
+
message: 'Enter the problem to debate:',
|
|
2372
|
+
default: problem,
|
|
2373
|
+
validate: (input) => input.length > 0 || 'Problem cannot be empty',
|
|
2374
|
+
},
|
|
2375
|
+
{
|
|
2376
|
+
type: 'checkbox',
|
|
2377
|
+
name: 'agents',
|
|
2378
|
+
message: 'Select agents to participate:',
|
|
2379
|
+
choices: [
|
|
2380
|
+
{ name: 'System Architect', value: 'architect', checked: true },
|
|
2381
|
+
{ name: 'Security Expert', value: 'security', checked: true },
|
|
2382
|
+
{ name: 'Performance Engineer', value: 'performance', checked: true },
|
|
2383
|
+
{ name: 'Quality Engineer', value: 'testing', checked: false },
|
|
2384
|
+
],
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
type: 'number',
|
|
2388
|
+
name: 'rounds',
|
|
2389
|
+
message: 'Number of debate rounds:',
|
|
2390
|
+
default: parseInt(options.rounds),
|
|
2391
|
+
validate: (input) => input > 0 || 'Must be at least 1 round',
|
|
2392
|
+
},
|
|
2393
|
+
]);
|
|
2394
|
+
|
|
2395
|
+
problem = answers.problem;
|
|
2396
|
+
options.agents = answers.agents.join(',');
|
|
2397
|
+
options.rounds = answers.rounds.toString();
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
logger.separator();
|
|
2401
|
+
logger.info(chalk.bold('Starting Multi-Agent Debate'));
|
|
2402
|
+
logger.separator();
|
|
2403
|
+
logger.info(`Problem: ${chalk.yellow(problem)}`);
|
|
2404
|
+
|
|
2405
|
+
// Load configuration
|
|
2406
|
+
const configManager = new ConfigurationManager(options.config);
|
|
2407
|
+
const debateConfig = configManager.getDebateConfig();
|
|
2408
|
+
debateConfig.rounds = parseInt(options.rounds);
|
|
2409
|
+
|
|
2410
|
+
// Filter agents if specified
|
|
2411
|
+
let agentConfigs = configManager.getAgentConfigs();
|
|
2412
|
+
if (options.agents) {
|
|
2413
|
+
const requestedRoles = options.agents.split(',');
|
|
2414
|
+
agentConfigs = agentConfigs.filter(a =>
|
|
2415
|
+
requestedRoles.includes(a.role)
|
|
2416
|
+
);
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
logger.info(`\nActive Agents:`);
|
|
2420
|
+
agentConfigs.forEach(agent => {
|
|
2421
|
+
logger.info(` ✓ ${agent.name} (${agent.model})`);
|
|
2422
|
+
});
|
|
2423
|
+
|
|
2424
|
+
// Load context if provided
|
|
2425
|
+
let context: string | undefined;
|
|
2426
|
+
if (options.context) {
|
|
2427
|
+
const fs = require('fs');
|
|
2428
|
+
context = fs.readFileSync(options.context, 'utf-8');
|
|
2429
|
+
logger.info(`\nContext loaded from: ${options.context}`);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
logger.separator();
|
|
2433
|
+
|
|
2434
|
+
// Initialize system
|
|
2435
|
+
const storage = new FileStorage();
|
|
2436
|
+
const stateManager = new StateManager(storage);
|
|
2437
|
+
const providers = createProviders(configManager);
|
|
2438
|
+
const agents = createAgents(agentConfigs, providers);
|
|
2439
|
+
const judge = createJudge(configManager.getJudgeConfig(), providers);
|
|
2440
|
+
|
|
2441
|
+
const orchestrator = new DebateOrchestrator(
|
|
2442
|
+
agents,
|
|
2443
|
+
judge,
|
|
2444
|
+
stateManager,
|
|
2445
|
+
debateConfig
|
|
2446
|
+
);
|
|
2447
|
+
|
|
2448
|
+
// Run debate with progress indicators
|
|
2449
|
+
const spinner = ora('Initializing debate...').start();
|
|
2450
|
+
|
|
2451
|
+
orchestrator.on('round-start', (round) => {
|
|
2452
|
+
spinner.stop();
|
|
2453
|
+
logger.info(`\n${chalk.bold(`Round ${round.number}/${debateConfig.rounds}`)}: ${round.phase}`);
|
|
2454
|
+
});
|
|
2455
|
+
|
|
2456
|
+
orchestrator.on('agent-start', ({ agent, action }) => {
|
|
2457
|
+
spinner.text = `[${agent.name}] ${action}...`;
|
|
2458
|
+
spinner.start();
|
|
2459
|
+
});
|
|
2460
|
+
|
|
2461
|
+
orchestrator.on('agent-complete', ({ agent, duration }) => {
|
|
2462
|
+
spinner.succeed(`[${agent.name}] Complete (${(duration / 1000).toFixed(1)}s)`);
|
|
2463
|
+
});
|
|
2464
|
+
|
|
2465
|
+
orchestrator.on('synthesis-start', () => {
|
|
2466
|
+
spinner.text = 'Synthesizing final solution...';
|
|
2467
|
+
spinner.start();
|
|
2468
|
+
});
|
|
2469
|
+
|
|
2470
|
+
const result = await orchestrator.runDebate(problem, context);
|
|
2471
|
+
|
|
2472
|
+
spinner.succeed('Debate complete!');
|
|
2473
|
+
|
|
2474
|
+
// Display results
|
|
2475
|
+
logger.separator();
|
|
2476
|
+
logger.success(chalk.bold.green('FINAL SOLUTION'));
|
|
2477
|
+
logger.separator();
|
|
2478
|
+
|
|
2479
|
+
console.log('\n' + result.solution.description + '\n');
|
|
2480
|
+
|
|
2481
|
+
if (result.solution.tradeoffs.length > 0) {
|
|
2482
|
+
logger.info(chalk.bold('Trade-offs:'));
|
|
2483
|
+
result.solution.tradeoffs.forEach(tradeoff => {
|
|
2484
|
+
logger.info(` • ${tradeoff}`);
|
|
2485
|
+
});
|
|
2486
|
+
console.log();
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
if (result.solution.recommendations.length > 0) {
|
|
2490
|
+
logger.info(chalk.bold('Recommendations:'));
|
|
2491
|
+
result.solution.recommendations.forEach(rec => {
|
|
2492
|
+
logger.info(` • ${rec}`);
|
|
2493
|
+
});
|
|
2494
|
+
console.log();
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
logger.info(`${chalk.bold('Confidence Score:')} ${result.solution.confidence}/100`);
|
|
2498
|
+
logger.info(`${chalk.bold('Total Rounds:')} ${result.metadata.totalRounds}`);
|
|
2499
|
+
logger.info(`${chalk.bold('Duration:')} ${(result.metadata.duration / 1000).toFixed(1)}s`);
|
|
2500
|
+
logger.info(`${chalk.bold('Total Tokens:')} ${result.metadata.totalTokens.toLocaleString()}`);
|
|
2501
|
+
|
|
2502
|
+
logger.separator();
|
|
2503
|
+
|
|
2504
|
+
// Save or export results
|
|
2505
|
+
if (options.output) {
|
|
2506
|
+
const fs = require('fs');
|
|
2507
|
+
const path = require('path');
|
|
2508
|
+
const ext = path.extname(options.output);
|
|
2509
|
+
|
|
2510
|
+
if (ext === '.json') {
|
|
2511
|
+
const debate = await stateManager.getDebate(result.debateId);
|
|
2512
|
+
fs.writeFileSync(options.output, JSON.stringify(debate, null, 2));
|
|
2513
|
+
} else {
|
|
2514
|
+
// Default to markdown
|
|
2515
|
+
const { MarkdownExporter } = require('../../utils/exporters');
|
|
2516
|
+
const exporter = new MarkdownExporter();
|
|
2517
|
+
const debate = await stateManager.getDebate(result.debateId);
|
|
2518
|
+
const markdown = await exporter.export(debate, { includeMetadata: true });
|
|
2519
|
+
fs.writeFileSync(options.output, markdown);
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
logger.success(`Results saved to: ${options.output}`);
|
|
2523
|
+
} else {
|
|
2524
|
+
logger.info(`💾 Debate saved with ID: ${chalk.cyan(result.debateId)}`);
|
|
2525
|
+
logger.info(`📊 View details: ${chalk.cyan(`debate history show ${result.debateId}`)}`);
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
} catch (error) {
|
|
2529
|
+
logger.error(`Debate failed: ${error.message}`);
|
|
2530
|
+
if (options.verbose) {
|
|
2531
|
+
console.error(error);
|
|
2532
|
+
}
|
|
2533
|
+
process.exit(1);
|
|
2534
|
+
}
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
```
|
|
2538
|
+
|
|
2539
|
+
### Factory Pattern for Creating Components
|
|
2540
|
+
|
|
2541
|
+
```typescript
|
|
2542
|
+
// src/core/factory.ts
|
|
2543
|
+
import { AgentConfig } from '../types/agent.types';
|
|
2544
|
+
import { LLMProvider } from '../providers/llm-provider';
|
|
2545
|
+
import { OpenAIProvider } from '../providers/openai-provider';
|
|
2546
|
+
import { AnthropicProvider } from '../providers/anthropic-provider';
|
|
2547
|
+
import { ArchitectAgent } from '../agents/architect-agent';
|
|
2548
|
+
import { SecurityAgent } from '../agents/security-agent';
|
|
2549
|
+
import { PerformanceAgent } from '../agents/performance-agent';
|
|
2550
|
+
import { TestingAgent } from '../agents/testing-agent';
|
|
2551
|
+
import { JudgeAgent } from '../core/judge';
|
|
2552
|
+
import { Agent } from '../core/agent';
|
|
2553
|
+
import { ConfigurationManager } from './config-manager';
|
|
2554
|
+
|
|
2555
|
+
export function createProviders(
|
|
2556
|
+
configManager: ConfigurationManager
|
|
2557
|
+
): Map<string, LLMProvider> {
|
|
2558
|
+
const providers = new Map<string, LLMProvider>();
|
|
2559
|
+
|
|
2560
|
+
const providerConfigs = configManager.getProviderConfigs();
|
|
2561
|
+
|
|
2562
|
+
for (const [name, config] of Object.entries(providerConfigs)) {
|
|
2563
|
+
const apiKey = process.env[config.apiKeyEnv];
|
|
2564
|
+
|
|
2565
|
+
if (!apiKey) {
|
|
2566
|
+
console.warn(`Warning: API key not found for ${name} (${config.apiKeyEnv})`);
|
|
2567
|
+
continue;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
switch (name) {
|
|
2571
|
+
case 'openai':
|
|
2572
|
+
providers.set('openai', new OpenAIProvider(apiKey));
|
|
2573
|
+
break;
|
|
2574
|
+
case 'anthropic':
|
|
2575
|
+
providers.set('anthropic', new AnthropicProvider(apiKey));
|
|
2576
|
+
break;
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
return providers;
|
|
2581
|
+
}
|
|
2582
|
+
|
|
2583
|
+
export function createAgents(
|
|
2584
|
+
agentConfigs: AgentConfig[],
|
|
2585
|
+
providers: Map<string, LLMProvider>
|
|
2586
|
+
): Agent[] {
|
|
2587
|
+
const agents: Agent[] = [];
|
|
2588
|
+
|
|
2589
|
+
for (const config of agentConfigs) {
|
|
2590
|
+
const provider = providers.get(config.provider);
|
|
2591
|
+
|
|
2592
|
+
if (!provider) {
|
|
2593
|
+
console.warn(`Provider ${config.provider} not available for agent ${config.name}`);
|
|
2594
|
+
continue;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
let agent: Agent;
|
|
2598
|
+
|
|
2599
|
+
switch (config.role) {
|
|
2600
|
+
case 'architect':
|
|
2601
|
+
agent = new ArchitectAgent(config, provider);
|
|
2602
|
+
break;
|
|
2603
|
+
case 'security':
|
|
2604
|
+
agent = new SecurityAgent(config, provider);
|
|
2605
|
+
break;
|
|
2606
|
+
case 'performance':
|
|
2607
|
+
agent = new PerformanceAgent(config, provider);
|
|
2608
|
+
break;
|
|
2609
|
+
case 'testing':
|
|
2610
|
+
agent = new TestingAgent(config, provider);
|
|
2611
|
+
break;
|
|
2612
|
+
default:
|
|
2613
|
+
// Fallback to base agent
|
|
2614
|
+
agent = new ArchitectAgent(config, provider);
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
agents.push(agent);
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
return agents;
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
export function createJudge(
|
|
2624
|
+
judgeConfig: AgentConfig,
|
|
2625
|
+
providers: Map<string, LLMProvider>
|
|
2626
|
+
): JudgeAgent {
|
|
2627
|
+
const provider = providers.get(judgeConfig.provider);
|
|
2628
|
+
|
|
2629
|
+
if (!provider) {
|
|
2630
|
+
throw new Error(`Provider ${judgeConfig.provider} not available for judge`);
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
return new JudgeAgent(judgeConfig, provider);
|
|
2634
|
+
}
|
|
2635
|
+
```
|
|
2636
|
+
|
|
2637
|
+
---
|
|
2638
|
+
|
|
2639
|
+
## Advanced Examples
|
|
2640
|
+
|
|
2641
|
+
### Example 1: Custom Agent with Specific Expertise
|
|
2642
|
+
|
|
2643
|
+
```typescript
|
|
2644
|
+
// src/agents/database-agent.ts
|
|
2645
|
+
import { Agent } from '../core/agent';
|
|
2646
|
+
import { AgentConfig } from '../types/agent.types';
|
|
2647
|
+
import { LLMProvider } from '../providers/llm-provider';
|
|
2648
|
+
|
|
2649
|
+
export class DatabaseAgent extends Agent {
|
|
2650
|
+
protected getSystemPrompt(): string {
|
|
2651
|
+
return `
|
|
2652
|
+
You are a database expert specializing in database design, optimization,
|
|
2653
|
+
and data modeling. Your expertise includes:
|
|
2654
|
+
|
|
2655
|
+
- Relational and NoSQL databases
|
|
2656
|
+
- Indexing strategies
|
|
2657
|
+
- Query optimization
|
|
2658
|
+
- Normalization and denormalization
|
|
2659
|
+
- Sharding and partitioning
|
|
2660
|
+
- Replication and consistency
|
|
2661
|
+
- Transaction management
|
|
2662
|
+
|
|
2663
|
+
When analyzing problems:
|
|
2664
|
+
1. Consider data modeling and relationships
|
|
2665
|
+
2. Evaluate query patterns and access patterns
|
|
2666
|
+
3. Think about scalability and data volume
|
|
2667
|
+
4. Consider data integrity and consistency
|
|
2668
|
+
5. Evaluate backup and recovery strategies
|
|
2669
|
+
|
|
2670
|
+
When proposing solutions:
|
|
2671
|
+
- Design appropriate schema
|
|
2672
|
+
- Suggest indexing strategy
|
|
2673
|
+
- Consider partitioning if needed
|
|
2674
|
+
- Evaluate consistency requirements
|
|
2675
|
+
- Think about migration strategies
|
|
2676
|
+
|
|
2677
|
+
When critiquing:
|
|
2678
|
+
- Look for inefficient data models
|
|
2679
|
+
- Identify missing indexes or over-indexing
|
|
2680
|
+
- Evaluate scalability bottlenecks
|
|
2681
|
+
- Consider data integrity issues
|
|
2682
|
+
`;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
async propose(problem: string, context: any): Promise<any> {
|
|
2686
|
+
const prompt = `
|
|
2687
|
+
Problem: ${problem}
|
|
2688
|
+
|
|
2689
|
+
As a database expert, propose a comprehensive database solution that addresses:
|
|
2690
|
+
1. Data model and schema design
|
|
2691
|
+
2. Database technology choice (SQL vs NoSQL)
|
|
2692
|
+
3. Indexing strategy
|
|
2693
|
+
4. Scalability considerations
|
|
2694
|
+
5. Consistency and availability trade-offs
|
|
2695
|
+
|
|
2696
|
+
Provide a detailed proposal.
|
|
2697
|
+
`;
|
|
2698
|
+
|
|
2699
|
+
const response = await this.callLLM(prompt);
|
|
2700
|
+
|
|
2701
|
+
return {
|
|
2702
|
+
content: response,
|
|
2703
|
+
metadata: {
|
|
2704
|
+
tokensUsed: this.estimateTokens(response),
|
|
2705
|
+
latencyMs: Date.now(),
|
|
2706
|
+
model: this.config.model,
|
|
2707
|
+
},
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
```
|
|
2712
|
+
|
|
2713
|
+
### Example 2: Problem Templates
|
|
2714
|
+
|
|
2715
|
+
```typescript
|
|
2716
|
+
// src/templates/problem-templates.ts
|
|
2717
|
+
export const problemTemplates = {
|
|
2718
|
+
'rate-limiting': {
|
|
2719
|
+
name: 'Rate Limiting System',
|
|
2720
|
+
template: `Design a rate limiting system for a {service_type} with the following requirements:
|
|
2721
|
+
- Support {rate} requests per {time_period}
|
|
2722
|
+
- Handle {concurrent_users} concurrent users
|
|
2723
|
+
- Distributed across {num_instances} instances
|
|
2724
|
+
- Requirements: {requirements}`,
|
|
2725
|
+
variables: ['service_type', 'rate', 'time_period', 'concurrent_users', 'num_instances', 'requirements'],
|
|
2726
|
+
suggestedAgents: ['architect', 'performance', 'security'],
|
|
2727
|
+
},
|
|
2728
|
+
|
|
2729
|
+
'caching-layer': {
|
|
2730
|
+
name: 'Caching Layer',
|
|
2731
|
+
template: `Design a caching layer for {application_type} that:
|
|
2732
|
+
- Caches {data_types}
|
|
2733
|
+
- Supports {cache_size} of data
|
|
2734
|
+
- Has {ttl} TTL requirements
|
|
2735
|
+
- Needs to handle {consistency_level} consistency
|
|
2736
|
+
- Additional requirements: {requirements}`,
|
|
2737
|
+
variables: ['application_type', 'data_types', 'cache_size', 'ttl', 'consistency_level', 'requirements'],
|
|
2738
|
+
suggestedAgents: ['architect', 'performance'],
|
|
2739
|
+
},
|
|
2740
|
+
|
|
2741
|
+
'authentication-service': {
|
|
2742
|
+
name: 'Authentication Service',
|
|
2743
|
+
template: `Design an authentication service for {application_type} that:
|
|
2744
|
+
- Supports {auth_methods}
|
|
2745
|
+
- Handles {user_count} users
|
|
2746
|
+
- Requires {security_level} security level
|
|
2747
|
+
- Needs {compliance} compliance
|
|
2748
|
+
- Additional requirements: {requirements}`,
|
|
2749
|
+
variables: ['application_type', 'auth_methods', 'user_count', 'security_level', 'compliance', 'requirements'],
|
|
2750
|
+
suggestedAgents: ['architect', 'security'],
|
|
2751
|
+
},
|
|
2752
|
+
|
|
2753
|
+
'microservices-architecture': {
|
|
2754
|
+
name: 'Microservices Architecture',
|
|
2755
|
+
template: `Design a microservices architecture for {application_domain} that:
|
|
2756
|
+
- Includes {services_list} services
|
|
2757
|
+
- Handles {traffic_volume} traffic
|
|
2758
|
+
- Requires {availability} availability
|
|
2759
|
+
- Communication pattern: {communication_pattern}
|
|
2760
|
+
- Additional requirements: {requirements}`,
|
|
2761
|
+
variables: ['application_domain', 'services_list', 'traffic_volume', 'availability', 'communication_pattern', 'requirements'],
|
|
2762
|
+
suggestedAgents: ['architect', 'performance', 'security'],
|
|
2763
|
+
},
|
|
2764
|
+
};
|
|
2765
|
+
|
|
2766
|
+
// Usage in CLI
|
|
2767
|
+
export function getTemplate(templateName: string): any {
|
|
2768
|
+
return problemTemplates[templateName];
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
export function fillTemplate(templateName: string, variables: Record<string, string>): string {
|
|
2772
|
+
const template = problemTemplates[templateName];
|
|
2773
|
+
if (!template) throw new Error(`Template ${templateName} not found`);
|
|
2774
|
+
|
|
2775
|
+
let problem = template.template;
|
|
2776
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
2777
|
+
problem = problem.replace(`{${key}}`, value);
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
return problem;
|
|
2781
|
+
}
|
|
2782
|
+
```
|
|
2783
|
+
|
|
2784
|
+
### Example 3: Debate Visualization (for web interface)
|
|
2785
|
+
|
|
2786
|
+
```typescript
|
|
2787
|
+
// Component for visualizing debate flow
|
|
2788
|
+
interface DebateVisualizationProps {
|
|
2789
|
+
debate: DebateState;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
export const DebateVisualization: React.FC<DebateVisualizationProps> = ({ debate }) => {
|
|
2793
|
+
return (
|
|
2794
|
+
<div className="debate-visualization">
|
|
2795
|
+
<div className="timeline">
|
|
2796
|
+
{debate.rounds.map((round, idx) => (
|
|
2797
|
+
<div key={idx} className="round-section">
|
|
2798
|
+
<div className="round-header">
|
|
2799
|
+
<h3>Round {round.roundNumber}</h3>
|
|
2800
|
+
<span className="phase-badge">{round.phase}</span>
|
|
2801
|
+
</div>
|
|
2802
|
+
|
|
2803
|
+
<div className="contributions-grid">
|
|
2804
|
+
{round.contributions.map((contrib, cidx) => (
|
|
2805
|
+
<div
|
|
2806
|
+
key={cidx}
|
|
2807
|
+
className={`contribution-card ${contrib.type}`}
|
|
2808
|
+
data-agent={contrib.agentRole}
|
|
2809
|
+
>
|
|
2810
|
+
<div className="contribution-header">
|
|
2811
|
+
<span className="agent-name">{contrib.agentRole}</span>
|
|
2812
|
+
<span className="contribution-type">{contrib.type}</span>
|
|
2813
|
+
</div>
|
|
2814
|
+
|
|
2815
|
+
<div className="contribution-content">
|
|
2816
|
+
{contrib.content}
|
|
2817
|
+
</div>
|
|
2818
|
+
|
|
2819
|
+
<div className="contribution-metadata">
|
|
2820
|
+
<span>{contrib.metadata.tokensUsed} tokens</span>
|
|
2821
|
+
<span>{contrib.metadata.latencyMs}ms</span>
|
|
2822
|
+
</div>
|
|
2823
|
+
</div>
|
|
2824
|
+
))}
|
|
2825
|
+
</div>
|
|
2826
|
+
</div>
|
|
2827
|
+
))}
|
|
2828
|
+
</div>
|
|
2829
|
+
|
|
2830
|
+
{debate.finalSolution && (
|
|
2831
|
+
<div className="final-solution-section">
|
|
2832
|
+
<h2>Final Solution</h2>
|
|
2833
|
+
<div className="solution-content">
|
|
2834
|
+
{debate.finalSolution.description}
|
|
2835
|
+
</div>
|
|
2836
|
+
<div className="solution-metadata">
|
|
2837
|
+
<span>Confidence: {debate.finalSolution.confidence}/100</span>
|
|
2838
|
+
</div>
|
|
2839
|
+
</div>
|
|
2840
|
+
)}
|
|
2841
|
+
</div>
|
|
2842
|
+
);
|
|
2843
|
+
};
|
|
2844
|
+
```
|
|
2845
|
+
|
|
2846
|
+
---
|
|
2847
|
+
|
|
2848
|
+
## Best Practices
|
|
2849
|
+
|
|
2850
|
+
### 1. Prompt Engineering
|
|
2851
|
+
|
|
2852
|
+
**Do:**
|
|
2853
|
+
- Be specific and detailed in system prompts
|
|
2854
|
+
- Provide clear role definitions
|
|
2855
|
+
- Include examples when helpful
|
|
2856
|
+
- Structure prompts with numbered lists
|
|
2857
|
+
- Request specific output formats
|
|
2858
|
+
|
|
2859
|
+
**Don't:**
|
|
2860
|
+
- Use vague or ambiguous language
|
|
2861
|
+
- Overload prompts with too many instructions
|
|
2862
|
+
- Assume agents understand implicit context
|
|
2863
|
+
- Use overly complex nested instructions
|
|
2864
|
+
|
|
2865
|
+
### 2. Error Handling
|
|
2866
|
+
|
|
2867
|
+
**Do:**
|
|
2868
|
+
- Handle LLM API errors gracefully
|
|
2869
|
+
- Implement retries with exponential backoff
|
|
2870
|
+
- Provide meaningful error messages
|
|
2871
|
+
- Log errors for debugging
|
|
2872
|
+
- Allow debates to continue with fewer agents if one fails
|
|
2873
|
+
|
|
2874
|
+
**Don't:**
|
|
2875
|
+
- Fail entire debate on single agent error
|
|
2876
|
+
- Retry indefinitely
|
|
2877
|
+
- Hide error details from users
|
|
2878
|
+
- Ignore rate limits
|
|
2879
|
+
|
|
2880
|
+
### 3. Performance Optimization
|
|
2881
|
+
|
|
2882
|
+
**Do:**
|
|
2883
|
+
- Execute agent calls in parallel when possible
|
|
2884
|
+
- Cache similar requests
|
|
2885
|
+
- Use streaming for better UX
|
|
2886
|
+
- Monitor token usage
|
|
2887
|
+
- Set reasonable timeouts
|
|
2888
|
+
|
|
2889
|
+
**Don't:**
|
|
2890
|
+
- Make unnecessary API calls
|
|
2891
|
+
- Ignore rate limits
|
|
2892
|
+
- Block on sequential operations unnecessarily
|
|
2893
|
+
- Store excessive history in memory
|
|
2894
|
+
|
|
2895
|
+
### 4. Configuration Management
|
|
2896
|
+
|
|
2897
|
+
**Do:**
|
|
2898
|
+
- Use environment variables for secrets
|
|
2899
|
+
- Provide sensible defaults
|
|
2900
|
+
- Validate configuration on load
|
|
2901
|
+
- Document all options
|
|
2902
|
+
- Support multiple configuration formats
|
|
2903
|
+
|
|
2904
|
+
**Don't:**
|
|
2905
|
+
- Hardcode API keys
|
|
2906
|
+
- Require configuration for everything
|
|
2907
|
+
- Ignore invalid configuration silently
|
|
2908
|
+
- Mix configuration concerns
|
|
2909
|
+
|
|
2910
|
+
---
|
|
2911
|
+
|
|
2912
|
+
## Glossary
|
|
2913
|
+
|
|
2914
|
+
**Agent**: An AI entity with a specific role and expertise that participates in debates
|
|
2915
|
+
|
|
2916
|
+
**Debate**: A structured conversation where multiple agents analyze and solve a problem
|
|
2917
|
+
|
|
2918
|
+
**Round**: One iteration of the debate process (proposal, critique, or refinement)
|
|
2919
|
+
|
|
2920
|
+
**Orchestrator**: The component that manages the debate flow and coordinates agents
|
|
2921
|
+
|
|
2922
|
+
**Judge**: A specialized agent that synthesizes final solutions from debate rounds
|
|
2923
|
+
|
|
2924
|
+
**Provider**: An abstraction layer for different LLM APIs (OpenAI, Anthropic, etc.)
|
|
2925
|
+
|
|
2926
|
+
**Contribution**: A single piece of input from an agent (proposal, critique, or refinement)
|
|
2927
|
+
|
|
2928
|
+
**Synthesis**: The process of combining multiple agent perspectives into a unified solution
|
|
2929
|
+
|
|
2930
|
+
**Convergence**: When agents' proposals become sufficiently similar, indicating consensus
|
|
2931
|
+
|
|
2932
|
+
---
|
|
2933
|
+
|
|
2934
|
+
## References and Resources
|
|
2935
|
+
|
|
2936
|
+
### Documentation
|
|
2937
|
+
- OpenAI API: https://platform.openai.com/docs
|
|
2938
|
+
- Anthropic API: https://docs.anthropic.com
|
|
2939
|
+
- Commander.js: https://github.com/tj/commander.js
|
|
2940
|
+
- Inquirer.js: https://github.com/SBoudrias/Inquirer.js
|
|
2941
|
+
|
|
2942
|
+
### Research Papers
|
|
2943
|
+
- "Improving Factuality and Reasoning in Language Models through Multiagent Debate" (Du et al., 2023)
|
|
2944
|
+
- "Multi-Agent Collaboration: Harnessing the Power of Intelligent LLM Agents" (Zhang et al., 2023)
|
|
2945
|
+
- "AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation" (Wu et al., 2023)
|
|
2946
|
+
|
|
2947
|
+
### Similar Projects
|
|
2948
|
+
- Microsoft AutoGen: https://github.com/microsoft/autogen
|
|
2949
|
+
- LangGraph: https://github.com/langchain-ai/langgraph
|
|
2950
|
+
- CrewAI: https://github.com/joaomdmoura/crewAI
|
|
2951
|
+
- ChatDev: https://github.com/OpenBMB/ChatDev
|
|
2952
|
+
|
|
2953
|
+
---
|
|
2954
|
+
|
|
2955
|
+
## Support and Contribution
|
|
2956
|
+
|
|
2957
|
+
### Getting Help
|
|
2958
|
+
- Check documentation and examples
|
|
2959
|
+
- Search existing issues on GitHub
|
|
2960
|
+
- Ask questions in discussions
|
|
2961
|
+
- Review troubleshooting guide
|
|
2962
|
+
|
|
2963
|
+
### Contributing
|
|
2964
|
+
- Fork the repository
|
|
2965
|
+
- Create a feature branch
|
|
2966
|
+
- Write tests for new features
|
|
2967
|
+
- Submit pull request with clear description
|
|
2968
|
+
- Follow code style guidelines
|
|
2969
|
+
|
|
2970
|
+
### Reporting Issues
|
|
2971
|
+
- Use issue templates
|
|
2972
|
+
- Provide minimal reproduction steps
|
|
2973
|
+
- Include environment details
|
|
2974
|
+
- Attach relevant logs (without API keys!)
|
|
2975
|
+
|
|
2976
|
+
---
|
|
2977
|
+
|
|
2978
|
+
**End of Specification**
|
|
2979
|
+
|
|
2980
|
+
This comprehensive specification provides everything needed to build a production-ready multi-agent debate system. The design emphasizes modularity, extensibility, and real-world usability while maintaining clean architecture principles.
|