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.
Files changed (119) hide show
  1. package/.cursor/commands/setup-test.mdc +175 -0
  2. package/.cursor/rules/basic-code-cleanup.mdc +1110 -0
  3. package/.cursor/rules/riper5.mdc +96 -0
  4. package/.env.example +6 -0
  5. package/AGENTS.md +1052 -0
  6. package/LICENSE +21 -0
  7. package/README.md +93 -0
  8. package/WARP.md +113 -0
  9. package/dialectic-1.0.0.tgz +0 -0
  10. package/dialectic.js +10 -0
  11. package/docs/commands.md +375 -0
  12. package/docs/configuration.md +882 -0
  13. package/docs/context_summarization.md +1023 -0
  14. package/docs/debate_flow.md +1127 -0
  15. package/docs/eval_flow.md +795 -0
  16. package/docs/evaluator.md +141 -0
  17. package/examples/debate-config-openrouter.json +48 -0
  18. package/examples/debate_config1.json +48 -0
  19. package/examples/eval/eval1/eval_config1.json +13 -0
  20. package/examples/eval/eval1/result1.json +62 -0
  21. package/examples/eval/eval1/result2.json +97 -0
  22. package/examples/eval_summary_format.md +11 -0
  23. package/examples/example3/debate-config.json +64 -0
  24. package/examples/example3/eval_config2.json +25 -0
  25. package/examples/example3/problem.md +17 -0
  26. package/examples/example3/rounds_test/eval_run.sh +16 -0
  27. package/examples/example3/rounds_test/run_test.sh +16 -0
  28. package/examples/kata1/architect-only-solution_2-rounds.json +121 -0
  29. package/examples/kata1/architect-perf-solution_2-rounds.json +234 -0
  30. package/examples/kata1/debate-config-kata1.json +54 -0
  31. package/examples/kata1/eval_architect-only_2-rounds.json +97 -0
  32. package/examples/kata1/eval_architect-perf_2-rounds.json +97 -0
  33. package/examples/kata1/kata1-report.md +12224 -0
  34. package/examples/kata1/kata1-report_temps-01_01_01_07.md +2451 -0
  35. package/examples/kata1/kata1.md +5 -0
  36. package/examples/kata1/meta.txt +1 -0
  37. package/examples/kata2/debate-config.json +54 -0
  38. package/examples/kata2/eval_config1.json +21 -0
  39. package/examples/kata2/eval_config2.json +25 -0
  40. package/examples/kata2/kata2.md +5 -0
  41. package/examples/kata2/only_architect/debate-config.json +45 -0
  42. package/examples/kata2/only_architect/eval_run.sh +11 -0
  43. package/examples/kata2/only_architect/run_test.sh +5 -0
  44. package/examples/kata2/rounds_test/eval_run.sh +11 -0
  45. package/examples/kata2/rounds_test/run_test.sh +5 -0
  46. package/examples/kata2/summary_length_test/eval_run.sh +11 -0
  47. package/examples/kata2/summary_length_test/eval_run_w_clarify.sh +7 -0
  48. package/examples/kata2/summary_length_test/run_test.sh +5 -0
  49. package/examples/task-queue/debate-config.json +76 -0
  50. package/examples/task-queue/debate_report.md +566 -0
  51. package/examples/task-queue/task-queue-system.md +25 -0
  52. package/jest.config.ts +13 -0
  53. package/multi_agent_debate_spec.md +2980 -0
  54. package/package.json +38 -0
  55. package/sanity-check-problem.txt +9 -0
  56. package/src/agents/prompts/architect-prompts.ts +203 -0
  57. package/src/agents/prompts/generalist-prompts.ts +157 -0
  58. package/src/agents/prompts/index.ts +41 -0
  59. package/src/agents/prompts/judge-prompts.ts +19 -0
  60. package/src/agents/prompts/kiss-prompts.ts +230 -0
  61. package/src/agents/prompts/performance-prompts.ts +142 -0
  62. package/src/agents/prompts/prompt-types.ts +68 -0
  63. package/src/agents/prompts/security-prompts.ts +149 -0
  64. package/src/agents/prompts/shared.ts +144 -0
  65. package/src/agents/prompts/testing-prompts.ts +149 -0
  66. package/src/agents/role-based-agent.ts +386 -0
  67. package/src/cli/commands/debate.ts +761 -0
  68. package/src/cli/commands/eval.ts +475 -0
  69. package/src/cli/commands/report.ts +265 -0
  70. package/src/cli/index.ts +79 -0
  71. package/src/core/agent.ts +198 -0
  72. package/src/core/clarifications.ts +34 -0
  73. package/src/core/judge.ts +257 -0
  74. package/src/core/orchestrator.ts +432 -0
  75. package/src/core/state-manager.ts +322 -0
  76. package/src/eval/evaluator-agent.ts +130 -0
  77. package/src/eval/prompts/system.md +41 -0
  78. package/src/eval/prompts/user.md +64 -0
  79. package/src/providers/llm-provider.ts +25 -0
  80. package/src/providers/openai-provider.ts +84 -0
  81. package/src/providers/openrouter-provider.ts +122 -0
  82. package/src/providers/provider-factory.ts +64 -0
  83. package/src/types/agent.types.ts +141 -0
  84. package/src/types/config.types.ts +47 -0
  85. package/src/types/debate.types.ts +237 -0
  86. package/src/types/eval.types.ts +85 -0
  87. package/src/utils/common.ts +104 -0
  88. package/src/utils/context-formatter.ts +102 -0
  89. package/src/utils/context-summarizer.ts +143 -0
  90. package/src/utils/env-loader.ts +46 -0
  91. package/src/utils/exit-codes.ts +5 -0
  92. package/src/utils/id.ts +11 -0
  93. package/src/utils/logger.ts +48 -0
  94. package/src/utils/paths.ts +10 -0
  95. package/src/utils/progress-ui.ts +313 -0
  96. package/src/utils/prompt-loader.ts +79 -0
  97. package/src/utils/report-generator.ts +301 -0
  98. package/tests/clarifications.spec.ts +128 -0
  99. package/tests/cli.debate.spec.ts +144 -0
  100. package/tests/config-loading.spec.ts +206 -0
  101. package/tests/context-summarizer.spec.ts +131 -0
  102. package/tests/debate-config-custom.json +38 -0
  103. package/tests/env-loader.spec.ts +149 -0
  104. package/tests/eval.command.spec.ts +1191 -0
  105. package/tests/logger.spec.ts +19 -0
  106. package/tests/openai-provider.spec.ts +26 -0
  107. package/tests/openrouter-provider.spec.ts +279 -0
  108. package/tests/orchestrator-summary.spec.ts +386 -0
  109. package/tests/orchestrator.spec.ts +207 -0
  110. package/tests/prompt-loader.spec.ts +52 -0
  111. package/tests/prompts/architect.md +16 -0
  112. package/tests/provider-factory.spec.ts +150 -0
  113. package/tests/report.command.spec.ts +546 -0
  114. package/tests/role-based-agent-summary.spec.ts +476 -0
  115. package/tests/security-agent.spec.ts +221 -0
  116. package/tests/shared-prompts.spec.ts +318 -0
  117. package/tests/state-manager.spec.ts +251 -0
  118. package/tests/summary-prompts.spec.ts +153 -0
  119. 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
+