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,1127 @@
|
|
|
1
|
+
# Debate Flow Documentation
|
|
2
|
+
|
|
3
|
+
This document provides a detailed explanation of the execution flow for the debate command, from CLI invocation through to final output.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The debate system orchestrates multi-agent discussions to solve software design problems. The flow involves configuration loading, agent initialization, an optional pre-debate clarifications phase, multiple debate rounds (each executing proposal, critique, and refinement phases), judge synthesis, and result output. Each round is a complete cycle where agents propose solutions, critique each other's proposals, and refine their own proposals based on feedback.
|
|
8
|
+
|
|
9
|
+
## Sequence Diagram
|
|
10
|
+
|
|
11
|
+
The following diagram illustrates the complete flow of a debate execution:
|
|
12
|
+
|
|
13
|
+
```mermaid
|
|
14
|
+
sequenceDiagram
|
|
15
|
+
participant CLI as CLI Entry Point
|
|
16
|
+
participant Cmd as debateCommand
|
|
17
|
+
participant Config as loadConfig
|
|
18
|
+
participant Builder as buildAgents
|
|
19
|
+
participant Provider as OpenAIProvider
|
|
20
|
+
participant Agents as Agent Instances
|
|
21
|
+
participant Judge as JudgeAgent
|
|
22
|
+
participant SM as StateManager
|
|
23
|
+
participant Orch as DebateOrchestrator
|
|
24
|
+
participant FS as File System
|
|
25
|
+
|
|
26
|
+
CLI->>Cmd: runCli(argv)
|
|
27
|
+
Cmd->>Cmd: parse arguments
|
|
28
|
+
Cmd->>Cmd: resolveProblemDescription(problem, options)
|
|
29
|
+
alt problem from string
|
|
30
|
+
Cmd->>Cmd: trim and return string
|
|
31
|
+
else problem from file
|
|
32
|
+
Cmd->>FS: validate file exists
|
|
33
|
+
Cmd->>FS: read file content (UTF-8)
|
|
34
|
+
Cmd->>Cmd: validate content non-empty
|
|
35
|
+
end
|
|
36
|
+
Cmd->>Cmd: validate API key
|
|
37
|
+
Cmd->>Config: loadConfig(configPath)
|
|
38
|
+
Config->>FS: read config file
|
|
39
|
+
Config-->>Cmd: SystemConfig
|
|
40
|
+
Cmd->>Cmd: debateConfigFromSysConfig()
|
|
41
|
+
Cmd->>Cmd: agentConfigsFromSysConfig()
|
|
42
|
+
Cmd->>Provider: new OpenAIProvider(apiKey)
|
|
43
|
+
Cmd->>Builder: buildAgents(configs, provider)
|
|
44
|
+
Builder->>Agents: RoleBasedAgent.create() (for each role)
|
|
45
|
+
Builder-->>Cmd: agents[]
|
|
46
|
+
Cmd->>Judge: new JudgeAgent(config, provider)
|
|
47
|
+
Cmd->>SM: new StateManager()
|
|
48
|
+
SM->>FS: ensure debates/ directory exists
|
|
49
|
+
Cmd->>Orch: new DebateOrchestrator(agents, judge, sm, config)
|
|
50
|
+
|
|
51
|
+
opt clarifications enabled (--clarify or config.interactiveClarifications)
|
|
52
|
+
Cmd->>Cmd: collectClarifications(problem, agents, maxPerAgent)
|
|
53
|
+
loop For each agent
|
|
54
|
+
Cmd->>Agents: agent.askClarifyingQuestions(problem, context)
|
|
55
|
+
Agents->>Provider: complete(systemPrompt, clarificationPrompt)
|
|
56
|
+
Provider-->>Agents: {text, usage, latency}
|
|
57
|
+
Agents-->>Cmd: {questions: [{id, text}]}
|
|
58
|
+
end
|
|
59
|
+
Cmd->>Cmd: collectAndAnswerClarifications()
|
|
60
|
+
loop For each agent's questions
|
|
61
|
+
Cmd->>CLI: prompt user for answer
|
|
62
|
+
CLI-->>Cmd: user input (empty = "NA")
|
|
63
|
+
end
|
|
64
|
+
Cmd->>Cmd: build AgentClarifications[] with answers
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Cmd->>Orch: runDebate(problem, context?, clarifications?)
|
|
68
|
+
|
|
69
|
+
Orch->>SM: createDebate(problem, context)
|
|
70
|
+
SM->>FS: save initial state JSON
|
|
71
|
+
SM-->>Orch: DebateState
|
|
72
|
+
|
|
73
|
+
opt clarifications provided
|
|
74
|
+
Orch->>SM: setClarifications(debateId, clarifications)
|
|
75
|
+
SM->>FS: save updated state JSON
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
loop For each round (1 to N)
|
|
79
|
+
Orch->>SM: beginRound(debateId)
|
|
80
|
+
SM->>SM: create new DebateRound
|
|
81
|
+
SM->>FS: save updated state JSON
|
|
82
|
+
|
|
83
|
+
Orch->>Orch: summarizationPhase(state, roundNumber)
|
|
84
|
+
loop For each agent
|
|
85
|
+
Orch->>Agents: agent.prepareContext(context, roundNumber)
|
|
86
|
+
Agents->>Agents: shouldSummarize(context)
|
|
87
|
+
alt Summarization needed
|
|
88
|
+
Agents->>Agents: filter history to perspective
|
|
89
|
+
Agents->>Provider: complete(systemPrompt, summaryPrompt)
|
|
90
|
+
Provider-->>Agents: summary text
|
|
91
|
+
Agents-->>Orch: {context, summary}
|
|
92
|
+
Orch->>SM: addSummary(debateId, summary)
|
|
93
|
+
SM->>FS: save updated state JSON
|
|
94
|
+
else No summarization
|
|
95
|
+
Agents-->>Orch: {context}
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
Orch->>Orch: proposalPhase(state, preparedContexts)
|
|
100
|
+
alt Round 1
|
|
101
|
+
loop For each agent
|
|
102
|
+
Orch->>Agents: agent.propose(problem, preparedContext)
|
|
103
|
+
Agents->>Agents: prepare prompts
|
|
104
|
+
Agents->>Provider: complete(systemPrompt, userPrompt)
|
|
105
|
+
Provider->>Provider: try Responses API
|
|
106
|
+
alt Responses API available
|
|
107
|
+
Provider->>Provider: call responses.create()
|
|
108
|
+
else Fallback
|
|
109
|
+
Provider->>Provider: call chat.completions.create()
|
|
110
|
+
end
|
|
111
|
+
Provider-->>Agents: {text, usage, latency}
|
|
112
|
+
Agents-->>Orch: Proposal {content, metadata}
|
|
113
|
+
Orch->>SM: addContribution(debateId, contribution)
|
|
114
|
+
SM->>FS: save updated state JSON
|
|
115
|
+
end
|
|
116
|
+
else Rounds ≥ 2
|
|
117
|
+
loop For each agent
|
|
118
|
+
Orch->>SM: read previous round refinement (agent)
|
|
119
|
+
alt Refinement found
|
|
120
|
+
Orch->>Orch: convert refinement → proposal (tokens=0, latency=0)
|
|
121
|
+
Orch->>SM: addContribution(debateId, proposal)
|
|
122
|
+
SM->>FS: save updated state JSON
|
|
123
|
+
else Refinement missing
|
|
124
|
+
Orch-->>CLI: writeStderr("Warning: Missing previous refinement; falling back to LLM proposal")
|
|
125
|
+
Orch->>Agents: agent.propose(problem, preparedContext)
|
|
126
|
+
Agents->>Provider: complete(systemPrompt, userPrompt)
|
|
127
|
+
Provider-->>Agents: {text, usage, latency}
|
|
128
|
+
Agents-->>Orch: Proposal {content, metadata}
|
|
129
|
+
Orch->>SM: addContribution(debateId, contribution)
|
|
130
|
+
SM->>FS: save updated state JSON
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
Orch->>Orch: critiquePhase(state)
|
|
136
|
+
loop For each agent
|
|
137
|
+
loop For each other agent's proposal
|
|
138
|
+
Orch->>Agents: agent.critique(proposal, context)
|
|
139
|
+
Agents->>Provider: complete(systemPrompt, userPrompt)
|
|
140
|
+
Provider-->>Agents: {text, usage, latency}
|
|
141
|
+
Agents-->>Orch: Critique {content, metadata}
|
|
142
|
+
Orch->>SM: addContribution(debateId, contribution)
|
|
143
|
+
SM->>FS: save updated state JSON
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
Orch->>Orch: refinementPhase(state)
|
|
148
|
+
loop For each agent
|
|
149
|
+
Orch->>Agents: agent.refine(original, critiques, context)
|
|
150
|
+
Agents->>Provider: complete(systemPrompt, userPrompt)
|
|
151
|
+
Provider-->>Agents: {text, usage, latency}
|
|
152
|
+
Agents-->>Orch: Refinement {content, metadata}
|
|
153
|
+
Orch->>SM: addContribution(debateId, contribution)
|
|
154
|
+
SM->>FS: save updated state JSON
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
Orch->>Orch: synthesisPhase(state)
|
|
159
|
+
Orch->>Judge: prepareContext(rounds)
|
|
160
|
+
alt Judge summarization needed
|
|
161
|
+
Judge->>Judge: shouldSummarize(rounds)
|
|
162
|
+
Judge->>Judge: getFinalRoundRelevantContent()
|
|
163
|
+
Judge->>Provider: complete(systemPrompt, summaryPrompt)
|
|
164
|
+
Provider-->>Judge: {text, usage, latency}
|
|
165
|
+
Judge-->>Orch: {context, summary}
|
|
166
|
+
Orch->>SM: addJudgeSummary(debateId, summary)
|
|
167
|
+
SM->>FS: save updated state JSON
|
|
168
|
+
else No judge summarization
|
|
169
|
+
Judge-->>Orch: {context}
|
|
170
|
+
end
|
|
171
|
+
Orch->>Judge: synthesize(problem, rounds, context)
|
|
172
|
+
Judge->>Judge: buildSynthesisPrompt()
|
|
173
|
+
Judge->>Provider: complete(systemPrompt, userPrompt)
|
|
174
|
+
Provider-->>Judge: {text, usage, latency}
|
|
175
|
+
Judge-->>Orch: Solution
|
|
176
|
+
Orch->>SM: completeDebate(debateId, solution)
|
|
177
|
+
SM->>FS: save final state JSON
|
|
178
|
+
|
|
179
|
+
Orch-->>Cmd: DebateResult
|
|
180
|
+
Cmd->>Cmd: outputResults(result, stateManager, options)
|
|
181
|
+
alt output to file
|
|
182
|
+
Cmd->>FS: write result to file
|
|
183
|
+
else output to stdout
|
|
184
|
+
Cmd->>CLI: write to stdout
|
|
185
|
+
end
|
|
186
|
+
opt report requested (--report)
|
|
187
|
+
Cmd->>Cmd: generateReport(result, stateManager, agentConfigs, judgeConfig, problem, options)
|
|
188
|
+
Cmd->>FS: write Markdown report (.md)
|
|
189
|
+
Cmd-->>CLI: infoUser("Generated report: <path>")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
Cmd-->>CLI: exit code 0
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Detailed Flow Description
|
|
196
|
+
|
|
197
|
+
### 1. CLI Entry Point
|
|
198
|
+
|
|
199
|
+
**Function**: `runCli(argv: string[])`
|
|
200
|
+
**Location**: `src/cli/index.ts`
|
|
201
|
+
|
|
202
|
+
The entry point for the debate system. This function:
|
|
203
|
+
- Creates a Commander program instance
|
|
204
|
+
- Sets program metadata (name, description, version)
|
|
205
|
+
- Registers the debate command via `debateCommand(program)`
|
|
206
|
+
- Parses command line arguments
|
|
207
|
+
- Handles top-level errors and maps them to exit codes
|
|
208
|
+
|
|
209
|
+
**Parameters**:
|
|
210
|
+
- `argv`: Array of command-line arguments (excluding node and script name)
|
|
211
|
+
|
|
212
|
+
**Returns**: Promise that resolves on success or rejects with an error containing an exit code
|
|
213
|
+
|
|
214
|
+
### 2. Command Registration
|
|
215
|
+
|
|
216
|
+
**Function**: `debateCommand(program: Command)`
|
|
217
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
218
|
+
|
|
219
|
+
Registers the debate command and its action handler with Commander. Defines:
|
|
220
|
+
- Command name and argument: `debate [problem]` (optional problem string)
|
|
221
|
+
- Options: `--problemDescription`, `--agents`, `--rounds`, `--config`, `--output`, `--verbose`, `--report`, `--clarify`
|
|
222
|
+
- Action handler that executes when the command is invoked
|
|
223
|
+
|
|
224
|
+
**Parameters**:
|
|
225
|
+
- `program`: Commander instance to register the command with
|
|
226
|
+
|
|
227
|
+
### 3. Problem Resolution
|
|
228
|
+
|
|
229
|
+
**Function**: `resolveProblemDescription(problem: string | undefined, options: any)`
|
|
230
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
231
|
+
|
|
232
|
+
Resolves the problem description from either command line string or file path.
|
|
233
|
+
|
|
234
|
+
**Parameters**:
|
|
235
|
+
- `problem`: Optional problem string from command line argument
|
|
236
|
+
- `options`: CLI options containing optional problemDescription file path
|
|
237
|
+
|
|
238
|
+
**Returns**: Promise resolving to resolved problem description string
|
|
239
|
+
|
|
240
|
+
**Behavior**:
|
|
241
|
+
- **Mutual exclusivity validation**: Ensures exactly one of problem string or problemDescription file is provided
|
|
242
|
+
- **String mode**: If problem string provided, trims and returns it
|
|
243
|
+
- **File mode**: If problemDescription option provided:
|
|
244
|
+
- Resolves file path relative to current working directory
|
|
245
|
+
- Validates file exists and is not a directory
|
|
246
|
+
- Reads file content as UTF-8
|
|
247
|
+
- Validates content is non-empty after trimming (whitespace-only = empty)
|
|
248
|
+
- Returns raw content (preserving original formatting)
|
|
249
|
+
- **Error handling**: Throws validation errors with appropriate exit codes:
|
|
250
|
+
- Both provided: EXIT_INVALID_ARGS
|
|
251
|
+
- Neither provided: EXIT_INVALID_ARGS
|
|
252
|
+
- File not found: EXIT_INVALID_ARGS
|
|
253
|
+
- File is directory: EXIT_INVALID_ARGS
|
|
254
|
+
- File empty: EXIT_INVALID_ARGS
|
|
255
|
+
- Read error: EXIT_GENERAL_ERROR
|
|
256
|
+
|
|
257
|
+
### 4. Additional Validation
|
|
258
|
+
|
|
259
|
+
After problem resolution, additional validation occurs:
|
|
260
|
+
- **OPENAI_API_KEY**: Must be set in environment variables
|
|
261
|
+
|
|
262
|
+
If validation fails, throws an error with appropriate exit code (EXIT_CONFIG_ERROR).
|
|
263
|
+
|
|
264
|
+
### 4. Configuration Loading
|
|
265
|
+
|
|
266
|
+
**Function**: `loadConfig(configPath?: string)`
|
|
267
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
268
|
+
|
|
269
|
+
Loads system configuration from a JSON file or uses built-in defaults.
|
|
270
|
+
|
|
271
|
+
**Parameters**:
|
|
272
|
+
- `configPath`: Optional path to configuration file (default: `./debate-config.json`)
|
|
273
|
+
|
|
274
|
+
**Returns**: Promise resolving to `SystemConfig` object containing:
|
|
275
|
+
- `agents`: Array of agent configurations
|
|
276
|
+
- `judge`: Judge agent configuration
|
|
277
|
+
- `debate`: Debate execution settings
|
|
278
|
+
|
|
279
|
+
**Behavior**:
|
|
280
|
+
- If file does not exist, returns built-in defaults with warning to stderr
|
|
281
|
+
- If file exists but missing agents, returns built-in defaults with warning
|
|
282
|
+
- If file missing judge or debate config, fills in those sections from defaults with warning
|
|
283
|
+
- Reads and parses JSON, validates basic structure
|
|
284
|
+
|
|
285
|
+
### 5. Debate Configuration Creation
|
|
286
|
+
|
|
287
|
+
**Function**: `debateConfigFromSysConfig(sysConfig: SystemConfig, options: any)`
|
|
288
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
289
|
+
|
|
290
|
+
Creates debate configuration by merging system config with CLI options.
|
|
291
|
+
|
|
292
|
+
**Parameters**:
|
|
293
|
+
- `sysConfig`: Loaded system configuration
|
|
294
|
+
- `options`: CLI options from Commander
|
|
295
|
+
|
|
296
|
+
**Returns**: `DebateConfig` object containing:
|
|
297
|
+
- `rounds`: Number from CLI option or config or default (3)
|
|
298
|
+
- `terminationCondition`: From system config
|
|
299
|
+
- `synthesisMethod`: From system config
|
|
300
|
+
- `includeFullHistory`: From system config
|
|
301
|
+
- `timeoutPerRound`: From system config
|
|
302
|
+
|
|
303
|
+
**Validation**: Ensures rounds >= 1, throws error if invalid
|
|
304
|
+
|
|
305
|
+
### 6. Agent Configuration Filtering
|
|
306
|
+
|
|
307
|
+
**Function**: `agentConfigsFromSysConfig(sysConfig: SystemConfig, options: any)`
|
|
308
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
309
|
+
|
|
310
|
+
Filters agent configurations based on CLI options.
|
|
311
|
+
|
|
312
|
+
**Parameters**:
|
|
313
|
+
- `sysConfig`: Loaded system configuration
|
|
314
|
+
- `options`: CLI options from Commander
|
|
315
|
+
|
|
316
|
+
**Returns**: Array of `AgentConfig` objects
|
|
317
|
+
|
|
318
|
+
**Behavior**:
|
|
319
|
+
- Filters out agents where `enabled: false`
|
|
320
|
+
- If `--agents` option provided, filters by matching roles
|
|
321
|
+
- If no agents remain after filtering, falls back to default agents (architect, performance)
|
|
322
|
+
|
|
323
|
+
### 7. Provider Initialization
|
|
324
|
+
|
|
325
|
+
**Factory Function**: `createProvider(providerType: string)`
|
|
326
|
+
**Location**: `src/providers/provider-factory.ts`
|
|
327
|
+
|
|
328
|
+
Creates LLM provider instances based on configuration.
|
|
329
|
+
|
|
330
|
+
**Parameters**:
|
|
331
|
+
- `providerType`: Provider type ("openai" or "openrouter")
|
|
332
|
+
|
|
333
|
+
**Supported Providers**:
|
|
334
|
+
- **OpenAI Provider**: Direct integration with OpenAI API
|
|
335
|
+
- **OpenRouter Provider**: Integration with OpenRouter API using OpenAI SDK
|
|
336
|
+
|
|
337
|
+
**Method**: `complete(request: CompletionRequest)`
|
|
338
|
+
|
|
339
|
+
Both providers make LLM completion requests with fallback strategy:
|
|
340
|
+
1. **Primary**: Attempts to use Responses API
|
|
341
|
+
- Builds payload with input array format
|
|
342
|
+
- Calls `client.responses.create()`
|
|
343
|
+
2. **Fallback**: Uses Chat Completions API
|
|
344
|
+
- Builds payload with messages array format
|
|
345
|
+
- Calls `client.chat.completions.create()`
|
|
346
|
+
|
|
347
|
+
**Returns**: `CompletionResponse` containing:
|
|
348
|
+
- `text`: Generated text from the model
|
|
349
|
+
- `usage`: Token usage statistics (input, output, total)
|
|
350
|
+
|
|
351
|
+
### 8. Agent Instantiation
|
|
352
|
+
|
|
353
|
+
**Function**: `buildAgents(agentConfigs: AgentConfig[], configDir: string, systemSummaryConfig: SummarizationConfig, collect: { agents: AgentPromptMetadata[] })`
|
|
354
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
355
|
+
|
|
356
|
+
Creates concrete agent instances based on configurations using the `RoleBasedAgent` class.
|
|
357
|
+
|
|
358
|
+
**Parameters**:
|
|
359
|
+
- `agentConfigs`: Array of agent configurations
|
|
360
|
+
- `configDir`: Configuration file directory for resolving prompt paths
|
|
361
|
+
- `systemSummaryConfig`: System-wide summarization configuration
|
|
362
|
+
- `collect`: Object to collect prompt source metadata
|
|
363
|
+
|
|
364
|
+
**Returns**: Array of Agent instances
|
|
365
|
+
|
|
366
|
+
**Provider Selection**: Each agent gets its own provider instance based on the `provider` field in its configuration. This allows for mixed provider configurations where different agents can use different LLM providers.
|
|
367
|
+
|
|
368
|
+
**Behavior**:
|
|
369
|
+
The system uses a single `RoleBasedAgent` class for all roles (architect, performance, security, etc.) rather than separate agent classes. Each agent is created via `RoleBasedAgent.create(config, provider, resolvedSystemPrompt, promptSource)`.
|
|
370
|
+
|
|
371
|
+
**Role-Based Prompt System**:
|
|
372
|
+
- Prompts are organized in `src/agents/prompts/` with separate files per role (architect-prompts.ts, performance-prompts.ts, security-prompts.ts)
|
|
373
|
+
- Each prompt file exports a `RolePrompts` object containing:
|
|
374
|
+
- `systemPrompt`: The agent's system instructions
|
|
375
|
+
- `proposePrompt()`: Function to generate proposal user prompts
|
|
376
|
+
- `critiquePrompt()`: Function to generate critique user prompts
|
|
377
|
+
- `refinePrompt()`: Function to generate refinement user prompts
|
|
378
|
+
- A central registry (`src/agents/prompts/index.ts`) maps roles to their prompt configurations
|
|
379
|
+
- Unknown roles default to architect prompts for backward compatibility
|
|
380
|
+
|
|
381
|
+
**Prompt source resolution** occurs at initialization:
|
|
382
|
+
- If `systemPromptPath` is set on the agent, the CLI resolves it relative to the configuration file directory and attempts to read the entire file (UTF-8)
|
|
383
|
+
- If the file is missing/unreadable/empty, a warning is printed to stderr and the built-in prompt is used instead
|
|
384
|
+
- Built-in prompts are retrieved via `RoleBasedAgent.defaultSystemPrompt(role)`, which looks up the role's default prompt from the registry
|
|
385
|
+
- The chosen source (built-in or absolute file path) is persisted once per debate in `DebateState.promptSources`
|
|
386
|
+
|
|
387
|
+
Each agent instance is initialized with:
|
|
388
|
+
- Configuration (id, name, role, model, temperature, systemPrompt)
|
|
389
|
+
- Provider reference for making LLM calls
|
|
390
|
+
- Role-specific prompts loaded from the prompt registry
|
|
391
|
+
|
|
392
|
+
### 9. Judge Instantiation
|
|
393
|
+
|
|
394
|
+
**Class**: `JudgeAgent`
|
|
395
|
+
**Location**: `src/core/judge.ts`
|
|
396
|
+
|
|
397
|
+
Creates the judge agent responsible for synthesis.
|
|
398
|
+
|
|
399
|
+
Prompt source resolution for the judge:
|
|
400
|
+
- If `systemPromptPath` is set on the judge, it is resolved relative to the configuration file directory and read as UTF-8. Invalid/empty files cause a warning and fallback to the built-in judge prompt.
|
|
401
|
+
- The chosen source is also recorded in `DebateState.promptSources.judge`.
|
|
402
|
+
|
|
403
|
+
**Constructor Parameters**:
|
|
404
|
+
- `config`: Agent configuration (typically role: "generalist", lower temperature)
|
|
405
|
+
- `provider`: LLM provider instance (created via provider factory)
|
|
406
|
+
|
|
407
|
+
**Key Method**: `synthesize(problem: string, rounds: DebateRound[], context: DebateContext)`
|
|
408
|
+
|
|
409
|
+
Synthesizes final solution from debate history:
|
|
410
|
+
- Builds comprehensive prompt from problem statement and all rounds
|
|
411
|
+
- Calls LLM with synthesis instructions
|
|
412
|
+
- Returns `Solution` object with description, tradeoffs, recommendations, confidence score
|
|
413
|
+
|
|
414
|
+
### 10. State Manager Initialization
|
|
415
|
+
|
|
416
|
+
**Class**: `StateManager`
|
|
417
|
+
**Location**: `src/core/state-manager.ts`
|
|
418
|
+
|
|
419
|
+
Manages debate state persistence to disk.
|
|
420
|
+
|
|
421
|
+
**Constructor Parameters**:
|
|
422
|
+
- `baseDir`: Directory for storing debate files (default: `./debates`)
|
|
423
|
+
|
|
424
|
+
**Behavior**:
|
|
425
|
+
- Ensures debates directory exists on initialization
|
|
426
|
+
- Maintains in-memory map of active debates
|
|
427
|
+
- Automatically saves state to JSON files on updates
|
|
428
|
+
|
|
429
|
+
**Key Methods**:
|
|
430
|
+
|
|
431
|
+
- `createDebate(problem: string, context?: string)`: Creates initial debate state
|
|
432
|
+
- Generates unique ID with timestamp format: `deb-YYYYMMDD-HHMMSS-RAND`
|
|
433
|
+
- Initializes state with status "running" and currentRound 0
|
|
434
|
+
- Saves to disk immediately
|
|
435
|
+
- Returns `DebateState`
|
|
436
|
+
|
|
437
|
+
- `beginRound(debateId: string)`: Begins a new round
|
|
438
|
+
- Creates a new `DebateRound` object with incremented round number
|
|
439
|
+
- Appends the round to state.rounds array
|
|
440
|
+
- Updates state.currentRound to the new round number
|
|
441
|
+
- Saves updated state to disk
|
|
442
|
+
- Returns the newly created `DebateRound`
|
|
443
|
+
|
|
444
|
+
- `addContribution(debateId: string, contribution: Contribution)`: Adds contribution to current round
|
|
445
|
+
- Requires that a round has been started via `beginRound()`
|
|
446
|
+
- Throws error if no active round exists
|
|
447
|
+
- Appends contribution to the current round's contributions array
|
|
448
|
+
- Saves updated state to disk
|
|
449
|
+
|
|
450
|
+
- `completeDebate(debateId: string, solution: Solution)`: Marks debate complete
|
|
451
|
+
- Sets status to "completed"
|
|
452
|
+
- Attaches final solution
|
|
453
|
+
- Saves final state to disk
|
|
454
|
+
|
|
455
|
+
- `failDebate(debateId: string, error: Error)`: Marks debate as failed
|
|
456
|
+
- Sets status to "failed"
|
|
457
|
+
- Saves updated state to disk
|
|
458
|
+
|
|
459
|
+
- `getDebate(debateId: string)`: Retrieves debate state
|
|
460
|
+
- Checks in-memory cache first
|
|
461
|
+
- Falls back to reading from disk
|
|
462
|
+
- Revives Date objects from JSON
|
|
463
|
+
|
|
464
|
+
- `listDebates()`: Lists all debates
|
|
465
|
+
- Reads all JSON files from debates directory
|
|
466
|
+
- Returns array of DebateState objects sorted by creation time
|
|
467
|
+
|
|
468
|
+
### 11. Orchestrator Initialization
|
|
469
|
+
|
|
470
|
+
**Class**: `DebateOrchestrator`
|
|
471
|
+
**Location**: `src/core/orchestrator.ts`
|
|
472
|
+
|
|
473
|
+
Coordinates the multi-round debate flow, executing N complete rounds where each round consists of proposal, critique, and refinement phases.
|
|
474
|
+
|
|
475
|
+
**Constructor Parameters**:
|
|
476
|
+
- `agents`: Array of initialized agent instances
|
|
477
|
+
- `judge`: Initialized judge agent
|
|
478
|
+
- `stateManager`: State manager instance
|
|
479
|
+
- `config`: Debate configuration (includes number of rounds)
|
|
480
|
+
- `hooks`: Optional hooks object for progress notifications
|
|
481
|
+
|
|
482
|
+
**Orchestrator Hooks**:
|
|
483
|
+
The orchestrator supports optional hooks for receiving real-time progress notifications:
|
|
484
|
+
- `onRoundStart(roundNumber, totalRounds)`: Called when a round begins
|
|
485
|
+
- `onPhaseStart(roundNumber, phase, expectedTaskCount)`: Called when a phase begins with task count
|
|
486
|
+
- `onAgentStart(agentName, activity)`: Called when an agent starts an activity
|
|
487
|
+
- `onAgentComplete(agentName, activity)`: Called when an agent completes an activity
|
|
488
|
+
- `onPhaseComplete(roundNumber, phase)`: Called after each phase completes (legacy)
|
|
489
|
+
- `onSummarizationStart(agentName)`: Called when an agent begins context summarization
|
|
490
|
+
- `onSummarizationComplete(agentName, beforeChars, afterChars)`: Called after successful summarization with character counts
|
|
491
|
+
- `onSynthesisStart()`: Called when synthesis begins
|
|
492
|
+
- `onSynthesisComplete()`: Called when synthesis completes
|
|
493
|
+
|
|
494
|
+
**Behavior**:
|
|
495
|
+
- Executes `config.rounds` complete cycles of proposal → critique → refinement
|
|
496
|
+
- Calls `stateManager.beginRound()` at the start of each round
|
|
497
|
+
- All three phases execute in every round
|
|
498
|
+
- Invokes hooks at appropriate points for progress tracking (used by CLI progress UI)
|
|
499
|
+
|
|
500
|
+
### 11.1. Progress UI Integration
|
|
501
|
+
|
|
502
|
+
**Class**: `DebateProgressUI`
|
|
503
|
+
**Location**: `src/utils/progress-ui.ts`
|
|
504
|
+
|
|
505
|
+
Manages the real-time progress display for debate execution in the CLI.
|
|
506
|
+
|
|
507
|
+
**Features**:
|
|
508
|
+
- Shows current round and phase information
|
|
509
|
+
- Displays individual agent activities as they happen
|
|
510
|
+
- Updates progress counts for each phase
|
|
511
|
+
- Uses ANSI escape codes for in-place terminal updates
|
|
512
|
+
- Writes all output to stderr (maintaining stdout for results)
|
|
513
|
+
|
|
514
|
+
**Integration**:
|
|
515
|
+
The CLI (`src/cli/commands/debate.ts`) creates a `DebateProgressUI` instance and connects it to the orchestrator via hooks:
|
|
516
|
+
1. Instantiate `DebateProgressUI` before debate execution
|
|
517
|
+
2. Initialize with total rounds: `progressUI.initialize(totalRounds)`
|
|
518
|
+
3. Create hook handlers that call progress UI methods
|
|
519
|
+
4. Pass hooks to `DebateOrchestrator` constructor
|
|
520
|
+
5. Start progress UI before `orchestrator.runDebate()`
|
|
521
|
+
6. Complete progress UI after debate finishes
|
|
522
|
+
|
|
523
|
+
**Display Format**:
|
|
524
|
+
```
|
|
525
|
+
┌─ Round 2/3
|
|
526
|
+
│ Proposals (2/2)
|
|
527
|
+
│ ⠋ System Architect proposing...
|
|
528
|
+
└─
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
**Progress Tracking**:
|
|
532
|
+
- Round indicators show current/total (e.g., "Round 2/3")
|
|
533
|
+
- Phase progress shows completed/total tasks (e.g., "Proposals (2/2)")
|
|
534
|
+
- Active agents shown with spinner (⠋) and activity description
|
|
535
|
+
- Display updates in-place using ANSI cursor movement codes
|
|
536
|
+
- Automatically clears when debate completes
|
|
537
|
+
|
|
538
|
+
### 12. Clarifications Phase (Optional)
|
|
539
|
+
|
|
540
|
+
**Function**: `collectAndAnswerClarifications(resolvedProblem: string, agents: Agent[], maxPerAgent: number)`
|
|
541
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
542
|
+
|
|
543
|
+
When the `--clarify` option is provided or `debate.interactiveClarifications` is enabled in configuration, the system runs a pre-debate clarifications phase where agents can ask clarifying questions about the problem statement.
|
|
544
|
+
|
|
545
|
+
**Parameters**:
|
|
546
|
+
- `resolvedProblem`: The resolved problem statement
|
|
547
|
+
- `agents`: Array of participating agents
|
|
548
|
+
- `maxPerAgent`: Maximum questions per agent (default: 5)
|
|
549
|
+
|
|
550
|
+
**Returns**: `AgentClarifications[]` containing grouped questions and answers
|
|
551
|
+
|
|
552
|
+
**Execution Flow**:
|
|
553
|
+
|
|
554
|
+
#### 12.1 Question Collection
|
|
555
|
+
1. **Function**: `collectClarifications(problem, agents, maxPerAgent, warn)`
|
|
556
|
+
- Calls `agent.askClarifyingQuestions(problem, context)` for each agent
|
|
557
|
+
- Each agent generates role-specific clarifying questions using their clarification prompt
|
|
558
|
+
- Questions are truncated to `maxPerAgent` limit with warnings if exceeded
|
|
559
|
+
- Returns grouped questions without answers
|
|
560
|
+
|
|
561
|
+
#### 12.2 Interactive Q&A Session
|
|
562
|
+
1. **User Interface**: Creates readline interface for interactive input
|
|
563
|
+
2. **Question Presentation**: For each agent with questions:
|
|
564
|
+
- Displays agent name and role
|
|
565
|
+
- Shows each question with ID: `Q (q1): What is the expected load?`
|
|
566
|
+
- Prompts user for answer: `> `
|
|
567
|
+
3. **Answer Collection**:
|
|
568
|
+
- User can provide an answer or press Enter to skip
|
|
569
|
+
- Empty input is recorded as "NA"
|
|
570
|
+
- Each answer is stored with the corresponding question
|
|
571
|
+
|
|
572
|
+
#### 12.3 Clarifications Persistence
|
|
573
|
+
1. **State Storage**: Clarifications are passed to `orchestrator.runDebate()`
|
|
574
|
+
2. **Persistence**: Orchestrator calls `stateManager.setClarifications()` to store Q&A
|
|
575
|
+
3. **Context Integration**: Clarifications are included in agent contexts for round 1
|
|
576
|
+
|
|
577
|
+
**Configuration Options**:
|
|
578
|
+
- `debate.interactiveClarifications`: Enable by default (boolean, default: false)
|
|
579
|
+
- `debate.clarificationsMaxPerAgent`: Maximum questions per agent (number, default: 5)
|
|
580
|
+
- `AgentConfig.clarificationPromptPath`: Custom clarification prompt for specific agents
|
|
581
|
+
|
|
582
|
+
**Error Handling**:
|
|
583
|
+
- If agent returns malformed JSON: warning printed, empty question list used
|
|
584
|
+
- If agent exceeds limit: warning printed, questions truncated
|
|
585
|
+
- If no questions generated: clarifications phase skipped
|
|
586
|
+
|
|
587
|
+
### 13. Debate Execution
|
|
588
|
+
|
|
589
|
+
**Method**: `orchestrator.runDebate(problem: string, context?: string, clarifications?: AgentClarifications[])`
|
|
590
|
+
**Location**: `src/core/orchestrator.ts`
|
|
591
|
+
|
|
592
|
+
Main orchestration method that executes the complete debate workflow.
|
|
593
|
+
|
|
594
|
+
**Parameters**:
|
|
595
|
+
- `problem`: The problem statement to debate
|
|
596
|
+
- `context`: Optional additional context
|
|
597
|
+
- `clarifications`: Optional clarifications from pre-debate phase
|
|
598
|
+
|
|
599
|
+
**Returns**: `DebateResult` containing:
|
|
600
|
+
- `debateId`: Unique identifier
|
|
601
|
+
- `solution`: Final synthesized solution
|
|
602
|
+
- `rounds`: All debate rounds
|
|
603
|
+
- `metadata`: Total rounds, duration, token counts
|
|
604
|
+
|
|
605
|
+
**Execution Flow**:
|
|
606
|
+
|
|
607
|
+
#### 13.1 State Creation
|
|
608
|
+
Calls `stateManager.createDebate()` to initialize debate state and persist initial JSON file.
|
|
609
|
+
|
|
610
|
+
#### 13.2 Clarifications Persistence (if provided)
|
|
611
|
+
If clarifications are provided:
|
|
612
|
+
1. Calls `stateManager.setClarifications(debateId, clarifications)`
|
|
613
|
+
2. Clarifications are stored in `DebateState.clarifications`
|
|
614
|
+
3. Updated state is persisted to disk
|
|
615
|
+
|
|
616
|
+
#### 13.3 Round Loop
|
|
617
|
+
The orchestrator executes N complete rounds, where N is specified by `config.rounds`. Each round performs all three phases in sequence: proposal → critique → refinement.
|
|
618
|
+
|
|
619
|
+
**For each round (1 to N)**:
|
|
620
|
+
|
|
621
|
+
##### 13.3.1 Begin Round
|
|
622
|
+
1. **Hook Invoked**: `onRoundStart(roundNumber, totalRounds)` - Notifies progress UI that a new round is starting
|
|
623
|
+
2. Calls `stateManager.beginRound(debateId)` to create a new round object and increment the current round counter
|
|
624
|
+
3. The round is persisted immediately to disk
|
|
625
|
+
|
|
626
|
+
##### 13.3.2 Summarization Phase (Optional)
|
|
627
|
+
**Method**: `summarizationPhase(state: DebateState, roundNumber: number)`
|
|
628
|
+
|
|
629
|
+
Each agent independently prepares and potentially summarizes their debate history before the proposal phase.
|
|
630
|
+
|
|
631
|
+
**Purpose**: Manage debate history length to avoid context window limitations by allowing agents to summarize their perspective-based history when it exceeds configured thresholds.
|
|
632
|
+
|
|
633
|
+
**Phase Start**:
|
|
634
|
+
1. Builds base `DebateContext` from current state (includes full history if configured)
|
|
635
|
+
2. Creates empty map to store prepared contexts (agentId → context)
|
|
636
|
+
|
|
637
|
+
**For each agent (sequential)**:
|
|
638
|
+
1. **Hook Invoked**: `onSummarizationStart(agentName)` - Notifies progress UI that agent is starting summarization
|
|
639
|
+
2. Calls `agent.prepareContext(context, roundNumber)`
|
|
640
|
+
- Agent calls `shouldSummarize(context)` to evaluate if summarization is needed:
|
|
641
|
+
- Checks if summarization is enabled in agent's config
|
|
642
|
+
- Filters history to agent's perspective (proposals + received critiques + refinements)
|
|
643
|
+
- Calculates total character count of filtered history
|
|
644
|
+
- Returns true if count >= threshold, false otherwise
|
|
645
|
+
- If summarization not needed:
|
|
646
|
+
- Returns original context unchanged
|
|
647
|
+
- No summary created
|
|
648
|
+
- If summarization needed:
|
|
649
|
+
- Filters debate history to agent's perspective
|
|
650
|
+
- Converts filtered history to text format
|
|
651
|
+
- Generates summary prompt using role-specific template
|
|
652
|
+
- Calls `summarizer.summarize()` which invokes LLM provider
|
|
653
|
+
- Measures latency and token usage
|
|
654
|
+
- Truncates result to maxLength if needed
|
|
655
|
+
- Builds `DebateSummary` object with metadata (beforeChars, afterChars, method, timestamp, latency, tokens)
|
|
656
|
+
- **Note**: Context is NOT modified - returned unchanged
|
|
657
|
+
- Returns {context: originalContext, summary: debateSummary}
|
|
658
|
+
3. If summary was created:
|
|
659
|
+
- Calls `stateManager.addSummary(debateId, summary)` to persist summary
|
|
660
|
+
- StateManager stores summary as `round.summaries[agentId] = summary` (keyed by agent ID)
|
|
661
|
+
- **Hook Invoked**: `onSummarizationComplete(agentName, beforeChars, afterChars)` - Notifies progress UI with character counts
|
|
662
|
+
4. Stores prepared context in map: `preparedContexts.set(agentId, preparedContext)`
|
|
663
|
+
|
|
664
|
+
**Returns**: Map of agentId → prepared context for use in subsequent debate phases
|
|
665
|
+
|
|
666
|
+
**Error Handling**:
|
|
667
|
+
- If summarization fails (LLM error, timeout, etc.):
|
|
668
|
+
- Agent logs warning to stderr with error details
|
|
669
|
+
- Falls back to original context with full history
|
|
670
|
+
- Debate continues normally
|
|
671
|
+
- No summary is persisted
|
|
672
|
+
|
|
673
|
+
**Persistence**:
|
|
674
|
+
- Summaries stored in current round's `summaries` Record, keyed by agent ID
|
|
675
|
+
- Structure: `round.summaries[agentId] = debateSummary`
|
|
676
|
+
- Each `DebateSummary` includes:
|
|
677
|
+
- `agentId`: Agent identifier
|
|
678
|
+
- `agentRole`: Agent's role
|
|
679
|
+
- `summary`: The summarized text (actual text sent to LLM in prompts)
|
|
680
|
+
- `metadata`: Summarization metadata
|
|
681
|
+
- `beforeChars`: Character count before summarization
|
|
682
|
+
- `afterChars`: Character count after summarization
|
|
683
|
+
- `method`: Summarization method used (e.g., "length-based")
|
|
684
|
+
- `timestamp`: When summarization occurred
|
|
685
|
+
- `latencyMs`: LLM call latency
|
|
686
|
+
- `tokensUsed`: Tokens consumed by summarization
|
|
687
|
+
|
|
688
|
+
**Context Usage**:
|
|
689
|
+
- Context object is never modified during summarization
|
|
690
|
+
- When generating prompts (propose, critique, refine):
|
|
691
|
+
1. If clarifications exist, they are rendered first in the context via `formatClarifications()`
|
|
692
|
+
2. Prompt formatter searches backwards through `context.history`
|
|
693
|
+
3. Looks for `round.summaries[agentId]` in each round
|
|
694
|
+
4. Uses most recent summary if found
|
|
695
|
+
5. Falls back to full history if no summary exists
|
|
696
|
+
|
|
697
|
+
**Configuration**:
|
|
698
|
+
- System-wide defaults: `debate.summarization` in config file
|
|
699
|
+
- Per-agent overrides: `AgentConfig.summarization`
|
|
700
|
+
- Default values: enabled=true, threshold=5000, maxLength=2500, method="length-based"
|
|
701
|
+
- Agent-level settings override system-wide settings
|
|
702
|
+
|
|
703
|
+
**Verbose Mode**: When `--verbose` is enabled, summarization details are displayed:
|
|
704
|
+
- System-wide config at debate start
|
|
705
|
+
- Per-round: which agents summarized and character count reduction
|
|
706
|
+
- In round summary: latency and token usage for each summary
|
|
707
|
+
|
|
708
|
+
##### 13.3.3 Proposal Phase
|
|
709
|
+
**Method**: `proposalPhase(state: DebateState, roundNumber: number, preparedContexts: Map<string, DebateContext>)`
|
|
710
|
+
|
|
711
|
+
All agents produce proposals in parallel for this round.
|
|
712
|
+
|
|
713
|
+
**Phase Start**:
|
|
714
|
+
1. Builds `DebateContext` from current state (includes full history if configured)
|
|
715
|
+
2. **Hook Invoked**: `onPhaseStart(roundNumber, 'proposal', agentCount)` - Notifies progress UI with expected task count
|
|
716
|
+
|
|
717
|
+
**For each agent (parallel execution)**:
|
|
718
|
+
1. **Hook Invoked**: `onAgentStart(agentName, 'proposing')` - Notifies progress UI that agent is starting
|
|
719
|
+
2. Behavior by round:
|
|
720
|
+
- Round 1: Calls `agent.propose(problem, context)`
|
|
721
|
+
- Agent prepares role-specific prompts
|
|
722
|
+
- Calls `proposeImpl()` which invokes `callLLM()`
|
|
723
|
+
- `callLLM()` measures latency and calls `provider.complete()`
|
|
724
|
+
- Returns `Proposal` with content and metadata (tokens, latency, model)
|
|
725
|
+
- Rounds ≥ 2: Uses the agent's refinement from the previous round as the proposal (no LLM call)
|
|
726
|
+
- Finds previous round refinement for the same agent
|
|
727
|
+
- Creates a new `proposal` contribution whose content equals that refinement
|
|
728
|
+
- Metadata is set with `tokensUsed=0`, `latencyMs=0`, and `model` recorded
|
|
729
|
+
- If a prior refinement is missing, a warning is written to stderr and the system falls back to `agent.propose(problem, context)` for that agent only
|
|
730
|
+
3. Builds `Contribution` object with type "proposal" and normalized metadata
|
|
731
|
+
4. Calls `stateManager.addContribution()` to persist contribution to current round
|
|
732
|
+
5. State manager saves updated JSON to disk
|
|
733
|
+
6. **Hook Invoked**: `onAgentComplete(agentName, 'proposing')` - Notifies progress UI that agent finished
|
|
734
|
+
|
|
735
|
+
**Phase Complete**:
|
|
736
|
+
7. **Hook Invoked**: `onPhaseComplete(roundNumber, 'proposal')` - Notifies progress UI that phase is complete
|
|
737
|
+
|
|
738
|
+
**Concurrency**: All agent proposals run in parallel via `Promise.all()`
|
|
739
|
+
|
|
740
|
+
##### 13.3.4 Critique Phase
|
|
741
|
+
**Method**: `critiquePhase(state: DebateState, roundNumber: number)`
|
|
742
|
+
|
|
743
|
+
Each agent critiques proposals from other agents within the current round.
|
|
744
|
+
|
|
745
|
+
**Phase Start**:
|
|
746
|
+
1. Retrieves proposals from current round (just added in proposal phase)
|
|
747
|
+
2. Calculates total critique tasks: `agents × (agents - 1)`
|
|
748
|
+
3. **Hook Invoked**: `onPhaseStart(roundNumber, 'critique', totalCritiques)` - Notifies progress UI with expected task count
|
|
749
|
+
|
|
750
|
+
**For each agent (sequential)**:
|
|
751
|
+
1. Filters to get proposals from other agents only
|
|
752
|
+
2. **For each other agent's proposal**:
|
|
753
|
+
- **Hook Invoked**: `onAgentStart(agentName, 'critiquing {targetRole}')` - Notifies progress UI
|
|
754
|
+
- Calls `agent.critique(proposal, context)`
|
|
755
|
+
- Agent builds critique-specific prompts
|
|
756
|
+
- Calls `critiqueImpl()` which invokes `callLLM()`
|
|
757
|
+
- `callLLM()` measures latency and calls `provider.complete()`
|
|
758
|
+
- Returns `Critique` with content and metadata
|
|
759
|
+
- Builds `Contribution` with type "critique" and target agent ID
|
|
760
|
+
- Calls `stateManager.addContribution()` to persist to current round
|
|
761
|
+
- State manager saves updated JSON to disk
|
|
762
|
+
- **Hook Invoked**: `onAgentComplete(agentName, 'critiquing {targetRole}')` - Notifies progress UI
|
|
763
|
+
|
|
764
|
+
**Phase Complete**:
|
|
765
|
+
3. **Hook Invoked**: `onPhaseComplete(roundNumber, 'critique')` - Notifies progress UI that phase is complete
|
|
766
|
+
|
|
767
|
+
**Concurrency**: Critiques are processed sequentially (outer loop) but could be parallelized
|
|
768
|
+
|
|
769
|
+
##### 13.3.5 Refinement Phase
|
|
770
|
+
**Method**: `refinementPhase(state: DebateState, roundNumber: number)`
|
|
771
|
+
|
|
772
|
+
Each agent refines their proposal based on critiques received within the current round.
|
|
773
|
+
|
|
774
|
+
**Phase Start**:
|
|
775
|
+
1. Retrieves previous round data
|
|
776
|
+
2. **Hook Invoked**: `onPhaseStart(roundNumber, 'refinement', agentCount)` - Notifies progress UI with expected task count
|
|
777
|
+
|
|
778
|
+
**For each agent (parallel execution)**:
|
|
779
|
+
1. **Hook Invoked**: `onAgentStart(agentName, 'refining')` - Notifies progress UI that agent is starting
|
|
780
|
+
2. Retrieves agent's proposal from current round
|
|
781
|
+
3. Retrieves all critiques targeting this agent from current round
|
|
782
|
+
4. Maps critique contributions to `Critique` objects (extracting content and metadata)
|
|
783
|
+
5. Calls `agent.refine(original, critiques, context)`
|
|
784
|
+
- Agent builds refinement prompts including original and all critiques
|
|
785
|
+
- Calls `refineImpl()` which invokes `callLLM()`
|
|
786
|
+
- `callLLM()` measures latency and calls `provider.complete()`
|
|
787
|
+
- Returns refined content with updated metadata
|
|
788
|
+
6. Builds `Contribution` with type "refinement"
|
|
789
|
+
7. Calls `stateManager.addContribution()` to persist to current round
|
|
790
|
+
8. State manager saves updated JSON to disk
|
|
791
|
+
9. **Hook Invoked**: `onAgentComplete(agentName, 'refining')` - Notifies progress UI that agent finished
|
|
792
|
+
|
|
793
|
+
**Phase Complete**:
|
|
794
|
+
10. **Hook Invoked**: `onPhaseComplete(roundNumber, 'refinement')` - Notifies progress UI that phase is complete
|
|
795
|
+
|
|
796
|
+
**Concurrency**: All agent refinements run in parallel via `Promise.all()`
|
|
797
|
+
|
|
798
|
+
#### 13.4 Synthesis Phase
|
|
799
|
+
**Method**: `synthesisPhase(state: DebateState)`
|
|
800
|
+
|
|
801
|
+
Judge synthesizes the final solution from all debate rounds, with optional summarization of the final round's content.
|
|
802
|
+
|
|
803
|
+
**Process**:
|
|
804
|
+
1. **Hook Invoked**: `onSynthesisStart()` - Notifies progress UI that synthesis is starting
|
|
805
|
+
2. **Judge Context Preparation**: Calls `judge.prepareContext(rounds)` to potentially summarize final round content:
|
|
806
|
+
- Judge evaluates if final round's proposals and refinements exceed threshold
|
|
807
|
+
- If summarization needed: generates summary of final round's key contributions
|
|
808
|
+
- If summary created: stores it in `DebateState.judgeSummary` via `stateManager.addJudgeSummary()`
|
|
809
|
+
- Falls back to final round's proposals and refinements if summarization fails
|
|
810
|
+
3. Builds `DebateContext` with full history
|
|
811
|
+
4. Calls `judge.synthesize(problem, rounds, context)`
|
|
812
|
+
5. Judge builds comprehensive synthesis prompt:
|
|
813
|
+
- Includes problem statement
|
|
814
|
+
- If summarization was used: includes only final round's key contributions
|
|
815
|
+
- If no summarization: includes all rounds with each contribution labeled by role and type
|
|
816
|
+
- Adds synthesis instructions
|
|
817
|
+
6. Calls `provider.complete()` with judge's system prompt and synthesis prompt
|
|
818
|
+
7. Provider returns generated text
|
|
819
|
+
8. Judge wraps text in `Solution` object with:
|
|
820
|
+
- `description`: LLM-generated solution text
|
|
821
|
+
- `tradeoffs`: Empty array (future enhancement)
|
|
822
|
+
- `recommendations`: Empty array (future enhancement)
|
|
823
|
+
- `confidence`: Default score of 75 (future enhancement)
|
|
824
|
+
- `synthesizedBy`: Judge agent ID
|
|
825
|
+
9. **Hook Invoked**: `onSynthesisComplete()` - Notifies progress UI that synthesis is complete
|
|
826
|
+
|
|
827
|
+
**Returns**: `Solution` object
|
|
828
|
+
|
|
829
|
+
#### 13.5 Debate Completion
|
|
830
|
+
1. Calls `stateManager.completeDebate(debateId, solution)`
|
|
831
|
+
2. State manager updates status to "completed"
|
|
832
|
+
3. Attaches final solution to state
|
|
833
|
+
4. Saves final complete state to JSON file
|
|
834
|
+
5. Returns `DebateResult` with solution, rounds, and metadata
|
|
835
|
+
|
|
836
|
+
### 14. Result Output and Report Generation
|
|
837
|
+
|
|
838
|
+
**Function**: `outputResults(result: DebateResult, stateManager: StateManager, options: any)`
|
|
839
|
+
**Location**: `src/cli/commands/debate.ts`
|
|
840
|
+
|
|
841
|
+
Handles output of debate results based on options.
|
|
842
|
+
|
|
843
|
+
**Parameters**:
|
|
844
|
+
- `result`: The debate result object
|
|
845
|
+
- `stateManager`: State manager for retrieving full state
|
|
846
|
+
- `options`: CLI options containing output path and verbose flag
|
|
847
|
+
|
|
848
|
+
**Behavior**:
|
|
849
|
+
|
|
850
|
+
**Progress UI Cleanup**:
|
|
851
|
+
- Progress UI automatically clears itself before result output
|
|
852
|
+
- Ensures clean separation between progress display and results
|
|
853
|
+
|
|
854
|
+
**If output path specified** (`--output <path>`):
|
|
855
|
+
- **If path ends with `.json`**:
|
|
856
|
+
- Retrieves full debate state via `stateManager.getDebate()`
|
|
857
|
+
- Writes complete JSON (all rounds, contributions, metadata) to file
|
|
858
|
+
- **Otherwise**:
|
|
859
|
+
- Writes only final solution text to file
|
|
860
|
+
|
|
861
|
+
**If no output path** (default):
|
|
862
|
+
- Writes final solution text to stdout
|
|
863
|
+
- **If verbose mode** (`--verbose`):
|
|
864
|
+
- Writes detailed summary to stderr:
|
|
865
|
+
- Round-by-round breakdown
|
|
866
|
+
- Each contribution with first line preview
|
|
867
|
+
- Metadata (latency, tokens) per contribution
|
|
868
|
+
- Total statistics (rounds, duration, tokens)
|
|
869
|
+
- Prints which system prompt is used per agent and judge: either "built-in default" or the resolved absolute file path.
|
|
870
|
+
- Progress UI remains visible during execution, verbose summary appears after completion
|
|
871
|
+
|
|
872
|
+
**Always**: Writes save path notice to stderr: `Saved debate to ./debates/<debate-id>.json`
|
|
873
|
+
|
|
874
|
+
#### Report Generation (optional)
|
|
875
|
+
If `--report <path>` is provided, the CLI generates a comprehensive Markdown report after outputting the results:
|
|
876
|
+
|
|
877
|
+
- Ensures the path ends with `.md` (appends if missing)
|
|
878
|
+
- Retrieves full debate state via `stateManager.getDebate()`
|
|
879
|
+
- Builds the report via `generateDebateReport(state, agentConfigs, judgeConfig, problem, { verbose })`
|
|
880
|
+
- Creates parent directories as needed and writes the file (UTF-8)
|
|
881
|
+
- On success: prints `Generated report: <path>` to stderr; failures are non-fatal and logged as warnings
|
|
882
|
+
|
|
883
|
+
**Report Content with Clarifications**:
|
|
884
|
+
- If clarifications exist, they are included in a dedicated "## Clarifications" section
|
|
885
|
+
- Clarifications appear before the "## Rounds" section
|
|
886
|
+
- Each agent's questions and answers are grouped under "### {Agent Name} ({role})"
|
|
887
|
+
- Questions and answers are rendered in fenced code blocks
|
|
888
|
+
- "NA" responses are included for skipped questions
|
|
889
|
+
|
|
890
|
+
### 15. Error Handling
|
|
891
|
+
|
|
892
|
+
The system uses structured error handling with exit codes:
|
|
893
|
+
|
|
894
|
+
**Exit Codes**:
|
|
895
|
+
- `0`: Success
|
|
896
|
+
- `1`: General error (EXIT_GENERAL_ERROR)
|
|
897
|
+
- `2`: Invalid arguments (EXIT_INVALID_ARGS)
|
|
898
|
+
- `3`: Provider error (EXIT_PROVIDER_ERROR, reserved)
|
|
899
|
+
- `4`: Configuration error (EXIT_CONFIG_ERROR)
|
|
900
|
+
|
|
901
|
+
**Error Flow**:
|
|
902
|
+
1. Errors thrown in action handler are caught
|
|
903
|
+
2. Exit code extracted from error object if present, otherwise defaults to EXIT_GENERAL_ERROR
|
|
904
|
+
3. Error message written to stderr
|
|
905
|
+
4. Error re-thrown to top-level CLI handler
|
|
906
|
+
5. Top-level handler extracts code and calls `process.exit(code)`
|
|
907
|
+
|
|
908
|
+
## Key Data Structures
|
|
909
|
+
|
|
910
|
+
### DebateState
|
|
911
|
+
Represents the complete state of a debate:
|
|
912
|
+
- `id`: Unique identifier
|
|
913
|
+
- `problem`: Problem statement
|
|
914
|
+
- `context`: Optional additional context
|
|
915
|
+
- `status`: "pending" | "running" | "completed" | "failed"
|
|
916
|
+
- `currentRound`: Current round number (0 when no rounds started, 1-indexed after beginRound())
|
|
917
|
+
- `rounds`: Array of `DebateRound` objects
|
|
918
|
+
- `clarifications`: Optional array of `AgentClarifications` (from pre-debate phase)
|
|
919
|
+
- `finalSolution`: Solution object (when complete)
|
|
920
|
+
- `createdAt`: Creation timestamp
|
|
921
|
+
- `updatedAt`: Last update timestamp
|
|
922
|
+
|
|
923
|
+
### DebateRound
|
|
924
|
+
Represents a single round of debate:
|
|
925
|
+
- `roundNumber`: Round number (1-indexed)
|
|
926
|
+
- `contributions`: Array of `Contribution` objects (includes proposals, critiques, and refinements)
|
|
927
|
+
- `timestamp`: Round start time
|
|
928
|
+
|
|
929
|
+
### Contribution
|
|
930
|
+
Represents a single agent contribution:
|
|
931
|
+
- `agentId`: Agent identifier
|
|
932
|
+
- `agentRole`: Agent role
|
|
933
|
+
- `type`: "proposal" | "critique" | "refinement"
|
|
934
|
+
- "proposal": Initial solution proposal
|
|
935
|
+
- "critique": Critical analysis of another agent's proposal
|
|
936
|
+
- "refinement": Refined version of the agent's own proposal based on received critiques
|
|
937
|
+
- `content`: Text content
|
|
938
|
+
- `targetAgentId`: Target agent (only populated for critiques)
|
|
939
|
+
- `metadata`: Object containing:
|
|
940
|
+
- `tokensUsed`: Token count (optional)
|
|
941
|
+
- `latencyMs`: Latency in milliseconds (optional)
|
|
942
|
+
- `model`: Model used (optional)
|
|
943
|
+
|
|
944
|
+
### Solution
|
|
945
|
+
Represents the final synthesized solution:
|
|
946
|
+
- `description`: Solution text
|
|
947
|
+
- `implementation`: Implementation details (optional)
|
|
948
|
+
- `tradeoffs`: Array of tradeoff descriptions
|
|
949
|
+
- `recommendations`: Array of recommendations
|
|
950
|
+
- `confidence`: Confidence score (0-100)
|
|
951
|
+
- `synthesizedBy`: Judge agent ID
|
|
952
|
+
|
|
953
|
+
### AgentClarifications
|
|
954
|
+
Represents clarifications collected from a specific agent:
|
|
955
|
+
- `agentId`: Agent identifier
|
|
956
|
+
- `agentName`: Agent display name
|
|
957
|
+
- `role`: Agent role
|
|
958
|
+
- `items`: Array of `ClarificationItem` objects
|
|
959
|
+
|
|
960
|
+
### ClarificationItem
|
|
961
|
+
Represents a single question-answer pair:
|
|
962
|
+
- `id`: Unique identifier for the question (e.g., "q1", "q2")
|
|
963
|
+
- `question`: The clarifying question text
|
|
964
|
+
- `answer`: The user's answer (or "NA" if skipped)
|
|
965
|
+
|
|
966
|
+
## Phase Execution Rules
|
|
967
|
+
|
|
968
|
+
The debate system executes N complete rounds, where N is specified by `config.rounds` (minimum 1).
|
|
969
|
+
|
|
970
|
+
### Round Structure
|
|
971
|
+
Each round consists of three phases executed in sequence:
|
|
972
|
+
1. **Proposal Phase**: All agents produce proposals in parallel
|
|
973
|
+
2. **Critique Phase**: Each agent critiques proposals from other agents
|
|
974
|
+
3. **Refinement Phase**: Each agent refines their proposal based on received critiques
|
|
975
|
+
|
|
976
|
+
All three phases execute in every round, regardless of the round count.
|
|
977
|
+
|
|
978
|
+
### Multiple Rounds
|
|
979
|
+
- **1 Round**: Single cycle of proposal → critique → refinement → synthesis
|
|
980
|
+
- Agents propose fresh ideas (LLM-generated)
|
|
981
|
+
- Critique each other's proposals
|
|
982
|
+
- Refine based on critiques
|
|
983
|
+
- Judge synthesizes final solution
|
|
984
|
+
- **Use case**: Standard debate with peer review and refinement
|
|
985
|
+
|
|
986
|
+
- **2 Rounds**: Two complete cycles of proposal → critique → refinement → synthesis
|
|
987
|
+
- Round 1: Initial proposals (LLM), critiques, and refinements
|
|
988
|
+
- Round 2: Proposals are the prior round's refinements (no LLM), then new critiques and refinements
|
|
989
|
+
- Missing prior refinement for an agent triggers a warning and falls back to an LLM proposal for that agent
|
|
990
|
+
- Judge synthesizes from all rounds
|
|
991
|
+
- **Use case**: Iterative exploration with two passes
|
|
992
|
+
|
|
993
|
+
- **3+ Rounds**: Multiple complete cycles
|
|
994
|
+
- Round 1 proposals are LLM-generated; for subsequent rounds, proposals are carried over from the previous round's refinements (no LLM)
|
|
995
|
+
- Full history can be included in context (via `includeFullHistory: true`)
|
|
996
|
+
- Agents can build on previous rounds when history is enabled
|
|
997
|
+
- Judge synthesizes from complete debate history
|
|
998
|
+
- **Use case**: Deep iterative refinement and exploration of solution space
|
|
999
|
+
|
|
1000
|
+
## LLM Provider Integration
|
|
1001
|
+
|
|
1002
|
+
### OpenAI Provider Strategy
|
|
1003
|
+
|
|
1004
|
+
The `OpenAIProvider` implements a two-tier fallback strategy for maximum compatibility:
|
|
1005
|
+
|
|
1006
|
+
**Primary Strategy**: Responses API
|
|
1007
|
+
- Newer API with improved interface
|
|
1008
|
+
- Uses `input` array format for messages
|
|
1009
|
+
- Maps `max_output_tokens` for token limits
|
|
1010
|
+
- Returns structured response with output text
|
|
1011
|
+
|
|
1012
|
+
**Fallback Strategy**: Chat Completions API
|
|
1013
|
+
- Standard OpenAI API
|
|
1014
|
+
- Uses `messages` array format
|
|
1015
|
+
- Maps `max_tokens` for token limits
|
|
1016
|
+
- Returns choice-based response format
|
|
1017
|
+
|
|
1018
|
+
**Error Handling**: If Responses API fails (not available, error, unexpected format), automatically falls back to Chat Completions API.
|
|
1019
|
+
|
|
1020
|
+
### Token Usage Tracking
|
|
1021
|
+
|
|
1022
|
+
Both APIs return usage statistics that are captured and propagated:
|
|
1023
|
+
- Input tokens (prompt tokens)
|
|
1024
|
+
- Output tokens (completion tokens)
|
|
1025
|
+
- Total tokens
|
|
1026
|
+
|
|
1027
|
+
Usage data flows through the system:
|
|
1028
|
+
1. Provider captures from API response
|
|
1029
|
+
2. Agent includes in contribution metadata
|
|
1030
|
+
3. State manager persists in contribution
|
|
1031
|
+
4. Final result aggregates across all contributions
|
|
1032
|
+
|
|
1033
|
+
### Latency Measurement
|
|
1034
|
+
|
|
1035
|
+
Latency is measured at multiple levels:
|
|
1036
|
+
1. **Provider level**: `callLLM()` measures wall-clock time around provider call
|
|
1037
|
+
2. **Orchestrator level**: Captures start time before agent call, uses as fallback if provider doesn't report latency
|
|
1038
|
+
3. **Contribution metadata**: Always includes latency, either from provider or calculated fallback
|
|
1039
|
+
|
|
1040
|
+
## File System Interactions
|
|
1041
|
+
|
|
1042
|
+
### Debate Persistence
|
|
1043
|
+
|
|
1044
|
+
**Directory**: `./debates/` (created automatically if missing)
|
|
1045
|
+
|
|
1046
|
+
**File Format**: JSON files with naming pattern: `deb-YYYYMMDD-HHMMSS-RAND.json`
|
|
1047
|
+
- Date and time of creation embedded in filename
|
|
1048
|
+
- Random suffix for uniqueness
|
|
1049
|
+
|
|
1050
|
+
**Persistence Points**:
|
|
1051
|
+
- After initial debate creation
|
|
1052
|
+
- After each round is begun (via `beginRound()`)
|
|
1053
|
+
- After each contribution is added
|
|
1054
|
+
- After debate completion with final solution
|
|
1055
|
+
|
|
1056
|
+
**Serialization**: Full `DebateState` object serialized as formatted JSON (2-space indent)
|
|
1057
|
+
|
|
1058
|
+
### Configuration Loading
|
|
1059
|
+
|
|
1060
|
+
**File**: `./debate-config.json` (default) or custom path via `--config`
|
|
1061
|
+
|
|
1062
|
+
**Format**: JSON object with SystemConfig structure
|
|
1063
|
+
|
|
1064
|
+
**Error Handling**: If file missing or malformed, uses built-in defaults with warning to stderr
|
|
1065
|
+
|
|
1066
|
+
### Output Files
|
|
1067
|
+
|
|
1068
|
+
**When `--output` specified**:
|
|
1069
|
+
- JSON output: Complete `DebateState` serialized to file
|
|
1070
|
+
- Text output: Only final solution description
|
|
1071
|
+
|
|
1072
|
+
**Encoding**: All files written as UTF-8
|
|
1073
|
+
|
|
1074
|
+
## Concurrency Model
|
|
1075
|
+
|
|
1076
|
+
### Parallel Operations
|
|
1077
|
+
The following operations run concurrently:
|
|
1078
|
+
- Proposal generation (all agents in parallel)
|
|
1079
|
+
- Refinement generation (all agents in parallel)
|
|
1080
|
+
- File system saves (non-blocking async writes)
|
|
1081
|
+
|
|
1082
|
+
### Sequential Operations
|
|
1083
|
+
The following operations run sequentially:
|
|
1084
|
+
- Debate rounds (round 1 → round 2 → ... → round N → synthesis)
|
|
1085
|
+
- Phases within each round (proposal → critique → refinement)
|
|
1086
|
+
- Critique generation (agent by agent, though could be parallelized)
|
|
1087
|
+
- Provider API calls (one at a time per agent)
|
|
1088
|
+
|
|
1089
|
+
### Thread Safety
|
|
1090
|
+
The system is single-threaded (Node.js) but uses async/await patterns:
|
|
1091
|
+
- In-memory state map maintained by StateManager
|
|
1092
|
+
- File writes are atomic at OS level
|
|
1093
|
+
- No race conditions within single debate execution
|
|
1094
|
+
|
|
1095
|
+
## Performance Considerations
|
|
1096
|
+
|
|
1097
|
+
### Token Usage
|
|
1098
|
+
- Full history mode (`includeFullHistory: true`) sends complete debate history to each agent
|
|
1099
|
+
- This increases context size and token usage exponentially with rounds
|
|
1100
|
+
- Trade-off: More context improves quality but costs more
|
|
1101
|
+
|
|
1102
|
+
### Latency
|
|
1103
|
+
- Total latency is primarily dominated by LLM API calls
|
|
1104
|
+
- Each round latency = proposal phase + critique phase + refinement phase:
|
|
1105
|
+
- Proposal phase latency = max(agent latencies) due to parallel execution
|
|
1106
|
+
- Critique phase latency = sum(all critique latencies) due to sequential execution
|
|
1107
|
+
- Refinement phase latency = max(agent latencies) due to parallel execution
|
|
1108
|
+
- Total debate latency = sum(all round latencies) + synthesis phase latency
|
|
1109
|
+
- Synthesis phase latency = judge synthesis latency
|
|
1110
|
+
|
|
1111
|
+
### File System
|
|
1112
|
+
- Debate state saved after each contribution
|
|
1113
|
+
- For debates with many contributions, this results in frequent writes
|
|
1114
|
+
- Consider batching writes for high-throughput scenarios
|
|
1115
|
+
|
|
1116
|
+
## Extension Points
|
|
1117
|
+
|
|
1118
|
+
The architecture supports extension through:
|
|
1119
|
+
|
|
1120
|
+
1. **New Agent Roles**: Add new roles by creating a prompt file in `src/agents/prompts/` implementing the `RolePrompts` interface, then register it in the prompt registry. No new agent classes needed.
|
|
1121
|
+
2. **New Providers**: Implement `LLMProvider` interface for other LLM services
|
|
1122
|
+
3. **Custom Synthesis**: Extend `JudgeAgent` or create alternative synthesis methods
|
|
1123
|
+
4. **Alternative Storage**: Replace `StateManager` for different persistence strategies
|
|
1124
|
+
5. **Additional Phases**: Extend `DebateOrchestrator` to add new debate phases
|
|
1125
|
+
6. **Custom Progress UI**: Replace or extend `DebateProgressUI` to implement alternative progress displays (e.g., web-based, GUI, different terminal formats)
|
|
1126
|
+
7. **Hook-Based Extensions**: Add custom hooks to `OrchestratorHooks` interface for additional monitoring, logging, or integration needs
|
|
1127
|
+
|