aegiscode 3.1.10 → 3.2.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 (209) hide show
  1. package/bin/aegis-cli-linux-x64 +0 -0
  2. package/bin/cli.js +68 -0
  3. package/package.json +11 -48
  4. package/scripts/download-binary.mjs +155 -0
  5. package/dist/main.js +0 -2171
  6. package/gui/run-gui.cjs +0 -13
  7. package/src/agent/Agent.ts +0 -903
  8. package/src/agent/SimpleAgent.ts +0 -48
  9. package/src/agent/index.ts +0 -54
  10. package/src/agent/orchestrator/AppBuilder.ts +0 -443
  11. package/src/agent/orchestrator/CouncilAgent.ts +0 -310
  12. package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
  13. package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
  14. package/src/agent/orchestrator/index.ts +0 -38
  15. package/src/agent/orchestrator/utils.ts +0 -397
  16. package/src/agent/pricing.ts +0 -115
  17. package/src/agent/router.ts +0 -74
  18. package/src/agent/routerStats.ts +0 -121
  19. package/src/agent/types.ts +0 -318
  20. package/src/auth/login.ts +0 -383
  21. package/src/cli/config.ts +0 -189
  22. package/src/cli/index.ts +0 -17
  23. package/src/cli/middleware.ts +0 -119
  24. package/src/cli/types.ts +0 -75
  25. package/src/config/ConfigManager.ts +0 -587
  26. package/src/config/index.ts +0 -7
  27. package/src/config/types.ts +0 -584
  28. package/src/context/CompactionService.ts +0 -300
  29. package/src/context/ContextManager.ts +0 -450
  30. package/src/context/FileAnalyzer.ts +0 -267
  31. package/src/context/TokenCounter.ts +0 -265
  32. package/src/context/index.ts +0 -27
  33. package/src/context/storage/CacheStore.ts +0 -176
  34. package/src/context/storage/JSONLStore.ts +0 -201
  35. package/src/context/storage/MemoryStore.ts +0 -205
  36. package/src/context/storage/PersistentStore.ts +0 -327
  37. package/src/context/storage/index.ts +0 -9
  38. package/src/context/storage/pathUtils.ts +0 -114
  39. package/src/context/test.ts +0 -309
  40. package/src/context/types.ts +0 -268
  41. package/src/hooks/HookExecutor.ts +0 -434
  42. package/src/hooks/HookManager.ts +0 -596
  43. package/src/hooks/HookService.ts +0 -269
  44. package/src/hooks/Matcher.ts +0 -157
  45. package/src/hooks/index.ts +0 -63
  46. package/src/hooks/types.ts +0 -424
  47. package/src/main.tsx +0 -596
  48. package/src/mcp/HealthMonitor.ts +0 -150
  49. package/src/mcp/McpClient.ts +0 -491
  50. package/src/mcp/McpRegistry.ts +0 -321
  51. package/src/mcp/createMcpTool.ts +0 -251
  52. package/src/mcp/index.ts +0 -15
  53. package/src/mcp/server.ts +0 -334
  54. package/src/mcp/test-server.ts +0 -88
  55. package/src/mcp/test.ts +0 -372
  56. package/src/mcp/types.ts +0 -247
  57. package/src/memory/AgentMemoryBus.ts +0 -432
  58. package/src/memory/CloudSync.ts +0 -99
  59. package/src/memory/DriveSync.ts +0 -106
  60. package/src/memory/SharedMemory.ts +0 -951
  61. package/src/memory/index.ts +0 -14
  62. package/src/memory/machineFingerprint.ts +0 -40
  63. package/src/orchestrator/SubAgentMetadata.ts +0 -136
  64. package/src/prompts/builder.ts +0 -213
  65. package/src/prompts/default.ts +0 -144
  66. package/src/prompts/index.ts +0 -16
  67. package/src/prompts/plan.ts +0 -64
  68. package/src/prompts/test.ts +0 -78
  69. package/src/services/AnthropicChatService.ts +0 -341
  70. package/src/services/ChatService.ts +0 -347
  71. package/src/services/ClaudeCliChatService.ts +0 -256
  72. package/src/services/CloudSync.ts +0 -168
  73. package/src/services/CostLedger.ts +0 -211
  74. package/src/services/Heartbeat.ts +0 -135
  75. package/src/services/LearningCollector.ts +0 -291
  76. package/src/services/OllamaInstaller.ts +0 -342
  77. package/src/services/VersionChecker.ts +0 -445
  78. package/src/services/index.ts +0 -57
  79. package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
  80. package/src/services/streaming/RenderingProfile.ts +0 -90
  81. package/src/services/streaming/StreamEventParser.ts +0 -181
  82. package/src/services/streaming/ThrottledRenderer.ts +0 -139
  83. package/src/services/streaming/TranscriptBuffer.ts +0 -574
  84. package/src/services/streaming/eventStatusMap.ts +0 -52
  85. package/src/services/streaming/index.ts +0 -46
  86. package/src/services/streaming/renderFormatting.ts +0 -79
  87. package/src/services/streaming/types.ts +0 -234
  88. package/src/skills/SkillLoader.ts +0 -126
  89. package/src/skills/SkillRegistry.ts +0 -366
  90. package/src/skills/index.ts +0 -48
  91. package/src/skills/types.ts +0 -146
  92. package/src/slash-commands/billing.ts +0 -70
  93. package/src/slash-commands/build.ts +0 -413
  94. package/src/slash-commands/builtinCommands.ts +0 -2733
  95. package/src/slash-commands/clone.ts +0 -242
  96. package/src/slash-commands/council.ts +0 -125
  97. package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
  98. package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
  99. package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
  100. package/src/slash-commands/custom/index.ts +0 -7
  101. package/src/slash-commands/debate.ts +0 -254
  102. package/src/slash-commands/gmail.ts +0 -105
  103. package/src/slash-commands/index.ts +0 -388
  104. package/src/slash-commands/mcpCommand.ts +0 -205
  105. package/src/slash-commands/types.ts +0 -201
  106. package/src/store/index.ts +0 -76
  107. package/src/store/selectors.ts +0 -246
  108. package/src/store/slices/appSlice.ts +0 -205
  109. package/src/store/slices/commandSlice.ts +0 -115
  110. package/src/store/slices/configSlice.ts +0 -46
  111. package/src/store/slices/focusSlice.ts +0 -64
  112. package/src/store/slices/index.ts +0 -9
  113. package/src/store/slices/sessionSlice.ts +0 -424
  114. package/src/store/streaming-buffer.ts +0 -425
  115. package/src/store/test.ts +0 -296
  116. package/src/store/types.ts +0 -274
  117. package/src/store/vanilla.ts +0 -186
  118. package/src/tools/builtin/bash.ts +0 -236
  119. package/src/tools/builtin/council.ts +0 -105
  120. package/src/tools/builtin/edit.ts +0 -213
  121. package/src/tools/builtin/glob.ts +0 -136
  122. package/src/tools/builtin/grep.ts +0 -263
  123. package/src/tools/builtin/index.ts +0 -61
  124. package/src/tools/builtin/memory.ts +0 -66
  125. package/src/tools/builtin/read.ts +0 -168
  126. package/src/tools/builtin/skill.ts +0 -97
  127. package/src/tools/builtin/snapshot.ts +0 -40
  128. package/src/tools/builtin/task.ts +0 -106
  129. package/src/tools/builtin/write.ts +0 -134
  130. package/src/tools/createTool.ts +0 -221
  131. package/src/tools/execution/ExecutionPipeline.ts +0 -263
  132. package/src/tools/execution/index.ts +0 -40
  133. package/src/tools/execution/stages/CacheStage.ts +0 -131
  134. package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
  135. package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
  136. package/src/tools/execution/stages/ExecutionStage.ts +0 -48
  137. package/src/tools/execution/stages/FormattingStage.ts +0 -44
  138. package/src/tools/execution/stages/HookStage.ts +0 -72
  139. package/src/tools/execution/stages/PermissionStage.ts +0 -287
  140. package/src/tools/execution/stages/PostHookStage.ts +0 -71
  141. package/src/tools/execution/stages/index.ts +0 -12
  142. package/src/tools/execution/test.ts +0 -266
  143. package/src/tools/execution/types.ts +0 -273
  144. package/src/tools/index.ts +0 -81
  145. package/src/tools/registry.ts +0 -304
  146. package/src/tools/schemas.ts +0 -109
  147. package/src/tools/test.ts +0 -220
  148. package/src/tools/types.ts +0 -175
  149. package/src/tools/validation/PermissionChecker.ts +0 -242
  150. package/src/tools/validation/SensitiveFileDetector.ts +0 -210
  151. package/src/tools/validation/index.ts +0 -11
  152. package/src/ui/App.tsx +0 -166
  153. package/src/ui/components/AegisInterface.tsx +0 -484
  154. package/src/ui/components/common/ChatSearch.tsx +0 -150
  155. package/src/ui/components/common/ErrorBoundary.tsx +0 -82
  156. package/src/ui/components/common/ExitMessage.tsx +0 -120
  157. package/src/ui/components/common/LoadingIndicator.tsx +0 -49
  158. package/src/ui/components/common/index.ts +0 -6
  159. package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
  160. package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
  161. package/src/ui/components/dialog/SetupWizard.tsx +0 -297
  162. package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
  163. package/src/ui/components/dialog/index.ts +0 -8
  164. package/src/ui/components/index.ts +0 -28
  165. package/src/ui/components/input/CommandSuggestions.tsx +0 -139
  166. package/src/ui/components/input/CustomTextInput.tsx +0 -220
  167. package/src/ui/components/input/InputArea.tsx +0 -361
  168. package/src/ui/components/input/PromptSuggestions.tsx +0 -66
  169. package/src/ui/components/input/index.ts +0 -6
  170. package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
  171. package/src/ui/components/layout/ContextBar.tsx +0 -79
  172. package/src/ui/components/layout/MessageArea.tsx +0 -96
  173. package/src/ui/components/layout/MessageList.tsx +0 -647
  174. package/src/ui/components/layout/MessageSeparator.tsx +0 -26
  175. package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
  176. package/src/ui/components/layout/index.ts +0 -7
  177. package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
  178. package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
  179. package/src/ui/components/markdown/index.ts +0 -8
  180. package/src/ui/components/markdown/parser.ts +0 -336
  181. package/src/ui/components/markdown/types.ts +0 -66
  182. package/src/ui/focus/FocusManager.ts +0 -137
  183. package/src/ui/focus/index.ts +0 -13
  184. package/src/ui/focus/types.ts +0 -54
  185. package/src/ui/focus/useFocus.ts +0 -75
  186. package/src/ui/hooks/index.ts +0 -11
  187. package/src/ui/hooks/useAgent.ts +0 -284
  188. package/src/ui/hooks/useCommandHistory.ts +0 -87
  189. package/src/ui/hooks/useCommandProcessor.ts +0 -443
  190. package/src/ui/hooks/useConfirmation.ts +0 -99
  191. package/src/ui/hooks/useCtrlCHandler.ts +0 -100
  192. package/src/ui/hooks/useInputBuffer.ts +0 -122
  193. package/src/ui/hooks/useTerminalSize.ts +0 -68
  194. package/src/ui/hooks/useTerminalWidth.ts +0 -5
  195. package/src/ui/hooks/useWindowedList.ts +0 -118
  196. package/src/ui/render-debugger.ts +0 -621
  197. package/src/ui/test.ts +0 -189
  198. package/src/ui/themes/ThemeManager.ts +0 -332
  199. package/src/ui/themes/aegisTheme.ts +0 -87
  200. package/src/ui/themes/darkTheme.ts +0 -87
  201. package/src/ui/themes/defaultTheme.ts +0 -85
  202. package/src/ui/themes/index.ts +0 -10
  203. package/src/ui/themes/lightTheme.ts +0 -89
  204. package/src/ui/themes/popularThemes.ts +0 -187
  205. package/src/ui/themes/types.ts +0 -130
  206. package/src/utils/clipboard.ts +0 -48
  207. package/src/utils/debug.ts +0 -43
  208. package/src/utils/environment.ts +0 -68
  209. package/src/utils/index.ts +0 -10
@@ -1,462 +0,0 @@
1
- /**
2
- * DiscussionRoom — Multi-model debate & discussion orchestrator
3
- *
4
- * Runs N AI models in a structured debate/discussion format.
5
- * Each model responds round-robin, seeing all previous responses.
6
- *
7
- * Design:
8
- * - Creates one IChatService per model (shares existing infra)
9
- * - Runs configurable rounds with optional moderator
10
- * - Each model gets role-specific system prompt + full transcript
11
- * - Results streamed via callback or returned as structured data
12
- */
13
-
14
- import type { AgentConfig, IChatService, Message, ChatResponse } from '../types.js';
15
- import { createChatService } from '../../services/ChatService.js';
16
- import { agentMemoryBus } from '../../memory/AgentMemoryBus.js';
17
- import { agentDebug } from '../../utils/debug.js';
18
-
19
- // ── Types ────────────────────────────────────────────────────────────────────────
20
-
21
- export type DiscussionFormat = 'debate' | 'discussion' | 'qa' | 'panel';
22
-
23
- // ── Event system ───────────────────────────────────────────────────────────
24
-
25
- export type DiscussionEventType =
26
- | 'model:start' // Model starts generating a response
27
- | 'model:chunk' // Streaming token from a model
28
- | 'model:complete' // Model finished its response
29
- | 'model:error' // Model failed
30
- | 'round:start' // New round begins
31
- | 'discussion:complete' // All rounds done
32
- | 'summary:ready'; // Summary synthesized
33
-
34
- export interface DiscussionEvent {
35
- type: DiscussionEventType;
36
- model?: string;
37
- round?: number;
38
- content?: string;
39
- metadata?: Record<string, unknown>;
40
- timestamp: number;
41
- }
42
-
43
- export type DiscussionEventHandler = (event: DiscussionEvent) => void;
44
-
45
- // ── Model config ───────────────────────────────────────────────────────────
46
-
47
- export interface DebateModelConfig {
48
- /** Display name (e.g. "GPT-4o", "DeepSeek") */
49
- name: string;
50
- /** LLM config passed to createChatService */
51
- config: AgentConfig;
52
- /** Optional role description for system prompt */
53
- role?: string;
54
- /** Optional override color (ANSI 24-bit) */
55
- color?: string;
56
- }
57
-
58
- export interface DiscussionConfig {
59
- topic: string;
60
- models: DebateModelConfig[];
61
- /** Number of rounds (default 2) */
62
- rounds?: number;
63
- /** Format style (default 'debate') */
64
- format?: DiscussionFormat;
65
- /** Max tokens per response (default 500) */
66
- maxTokensPerResponse?: number;
67
- /** Optional moderator model index or name (pauses debate for mid-point synthesis) */
68
- moderator?: number | string;
69
- /** Timeout per model call in ms (default 60000) */
70
- timeout?: number;
71
- }
72
-
73
- export interface DebateRound {
74
- round: number;
75
- speaker: string;
76
- role: string;
77
- content: string;
78
- metadata?: {
79
- tokensUsed?: number;
80
- durationMs?: number;
81
- };
82
- }
83
-
84
- export interface DiscussionResult {
85
- topic: string;
86
- format: DiscussionFormat;
87
- rounds: DebateRound[];
88
- summary: string;
89
- metadata: {
90
- modelsUsed: number;
91
- totalRounds: number;
92
- totalDurationMs: number;
93
- totalTokens: number;
94
- };
95
- }
96
-
97
- // ── Colors ───────────────────────────────────────────────────────────────────────
98
-
99
- const COLORS = [
100
- '\x1b[38;2;0;229;192m', // teal
101
- '\x1b[38;2;124;111;212m', // purple
102
- '\x1b[38;2;244;114;182m', // pink
103
- '\x1b[38;2;249;115;22m', // orange
104
- '\x1b[38;2;34;197;94m', // green
105
- '\x1b[38;2;56;189;248m', // sky
106
- '\x1b[38;2;250;204;21m', // yellow
107
- '\x1b[38;2;239;68;68m', // red
108
- ];
109
-
110
- // ── DiscussionRoom ───────────────────────────────────────────────────────────────
111
-
112
- export class DiscussionRoom {
113
- private config: DiscussionConfig & {
114
- rounds: number;
115
- format: DiscussionFormat;
116
- maxTokensPerResponse: number;
117
- timeout: number;
118
- };
119
- private services: Map<string, IChatService> = new Map();
120
- private listeners: Map<DiscussionEventType, Set<DiscussionEventHandler>> = new Map();
121
- private anyListeners: Set<DiscussionEventHandler> = new Set();
122
-
123
- constructor(config: DiscussionConfig) {
124
- this.config = {
125
- rounds: 2,
126
- format: 'debate',
127
- maxTokensPerResponse: 500,
128
- timeout: 60000,
129
- ...config,
130
- } as typeof this.config;
131
-
132
- // Create chat services for each model
133
- for (const model of this.config.models) {
134
- const svc = createChatService({
135
- ...model.config,
136
- timeout: this.config.timeout,
137
- maxOutputTokens: this.config.maxTokensPerResponse,
138
- });
139
- this.services.set(model.name, svc);
140
- }
141
- }
142
-
143
- // ── Event system ───────────────────────────────────────────────────────────
144
-
145
- /**
146
- * Subscribe to debate events.
147
- * Returns unsubscribe function.
148
- */
149
- on(type: DiscussionEventType, handler: DiscussionEventHandler): () => void {
150
- if (!this.listeners.has(type)) this.listeners.set(type, new Set());
151
- this.listeners.get(type)!.add(handler);
152
- return () => this.listeners.get(type)?.delete(handler);
153
- }
154
-
155
- /**
156
- * Subscribe to all debate events.
157
- */
158
- onAny(handler: DiscussionEventHandler): () => void {
159
- this.anyListeners.add(handler);
160
- return () => this.anyListeners.delete(handler);
161
- }
162
-
163
- private emit(type: DiscussionEventType, data: Omit<DiscussionEvent, 'type' | 'timestamp'>): void {
164
- const event: DiscussionEvent = { type, timestamp: Date.now(), ...data };
165
- const typeListeners = this.listeners.get(type);
166
- if (typeListeners) {
167
- for (const h of typeListeners) try { h(event); } catch { /* handler error */ }
168
- }
169
- for (const h of this.anyListeners) try { h(event); } catch { /* handler error */ }
170
- }
171
-
172
- // ── Core ───────────────────────────────────────────────────────────────────
173
-
174
- /**
175
- * Run the full debate and return structured results.
176
- */
177
- async run(): Promise<DiscussionResult> {
178
- const startTime = Date.now();
179
- const allRounds: DebateRound[] = [];
180
- const format = this.config.format;
181
- const models = this.config.models;
182
-
183
- // ── System prompt templates per format ──
184
- const roleTemplate = this.buildRoleTemplate(format);
185
- const debateGuidelines = this.buildDebateGuidelines(format);
186
-
187
- // Assign colors
188
- const namedColors = new Map(
189
- models.map((m, i) => [m.name, m.color || COLORS[i % COLORS.length]])
190
- );
191
-
192
- // ── Run rounds ──
193
- for (let round = 1; round <= this.config.rounds; round++) {
194
- const roundLabel = format === 'debate' ? `Argumentation` :
195
- format === 'qa' ? `Question` : `Discussion`;
196
-
197
- this.emit('round:start', { round, content: roundLabel });
198
-
199
- for (const model of models) {
200
- this.emit('model:start', { model: model.name, round, content: '' });
201
- const durationStart = Date.now();
202
-
203
- // Build messages for this model: system + full transcript so far
204
- const messages: Message[] = [];
205
- messages.push({
206
- role: 'system',
207
- content: [
208
- roleTemplate,
209
- `\n\nYour name: ${model.name}`,
210
- model.role ? `\nRole: ${model.role}` : '',
211
- `\nTopic: ${this.config.topic}`,
212
- `\n\n${debateGuidelines}`,
213
- format === 'debate' ? `\nCurrent round: ${round}/${this.config.rounds}` : '',
214
- ].join(''),
215
- });
216
-
217
- // Inject conversation transcript
218
- if (allRounds.length > 0) {
219
- const transcript = allRounds
220
- .map(r => `[${r.speaker} (${r.role})]: ${r.content}`)
221
- .join('\n\n');
222
- messages.push({
223
- role: 'user',
224
- content: `Previous discussion:\n\n${transcript}\n\n---\n\n${
225
- format === 'debate'
226
- ? `Round ${round}/${this.config.rounds} — Present your arguments. Be specific and persuasive.`
227
- : format === 'qa'
228
- ? `Answer the question from your perspective.`
229
- : `Continue the discussion. Build on or challenge previous points.`
230
- }`,
231
- });
232
- } else {
233
- messages.push({
234
- role: 'user',
235
- content: format === 'debate'
236
- ? `Round 1/${this.config.rounds} — Opening statement. Present your position on: "${this.config.topic}"`
237
- : format === 'qa'
238
- ? `Question: "${this.config.topic}" — Provide your answer and reasoning.`
239
- : `Opening thoughts on: "${this.config.topic}" — Share your initial perspective.`,
240
- });
241
- }
242
-
243
- // Call the model
244
- let response: ChatResponse;
245
- try {
246
- response = await this.services.get(model.name)!.chat(messages);
247
- } catch (err) {
248
- const errMsg = err instanceof Error ? err.message : String(err);
249
- agentDebug.error(`[DiscussionRoom] ${model.name} failed: ${errMsg}`);
250
-
251
- this.emit('model:error', {
252
- model: model.name,
253
- round,
254
- content: errMsg,
255
- });
256
-
257
- // Publish error to agent memory bus
258
- agentMemoryBus.publish({
259
- channel: 'error',
260
- sourceAgent: model.name,
261
- sessionId: `debate-${format}-${this.config.topic.slice(0, 30)}`,
262
- content: `Failed to respond: ${errMsg}`,
263
- importance: 0.9,
264
- tags: ['debate', 'error'],
265
- }).catch(() => {});
266
-
267
- allRounds.push({
268
- round,
269
- speaker: model.name,
270
- role: model.role || 'participant',
271
- content: `[Failed to respond: ${errMsg}]`,
272
- metadata: { durationMs: Date.now() - durationStart },
273
- });
274
- continue;
275
- }
276
-
277
- const roundEntry: DebateRound = {
278
- round,
279
- speaker: model.name,
280
- role: model.role || 'participant',
281
- content: response.content,
282
- metadata: {
283
- tokensUsed: response.usage?.totalTokens,
284
- durationMs: Date.now() - durationStart,
285
- },
286
- };
287
-
288
- allRounds.push(roundEntry);
289
-
290
- this.emit('model:complete', {
291
- model: model.name,
292
- round,
293
- content: response.content,
294
- metadata: {
295
- tokensUsed: response.usage?.totalTokens,
296
- durationMs: Date.now() - durationStart,
297
- },
298
- });
299
-
300
- // Publish to agent memory bus so other components can observe
301
- agentMemoryBus.publish({
302
- channel: 'fact',
303
- sourceAgent: model.name,
304
- sessionId: `debate-${format}-${this.config.topic.slice(0, 30)}`,
305
- content: `[Debate Round ${round}] ${response.content.slice(0, 300)}`,
306
- importance: 0.5,
307
- tags: ['debate', `round-${round}`, format],
308
- metadata: { round, topic: this.config.topic },
309
- }).catch(() => {});
310
- }
311
- }
312
-
313
- // ── Synthesize summary ──
314
- const summary = this.synthesize(allRounds);
315
-
316
- this.emit('summary:ready', { content: summary });
317
-
318
- const totalTokens = allRounds.reduce(
319
- (sum, r) => sum + (r.metadata?.tokensUsed || 0), 0
320
- );
321
-
322
- const result: DiscussionResult = {
323
- topic: this.config.topic,
324
- format,
325
- rounds: allRounds,
326
- summary,
327
- metadata: {
328
- modelsUsed: models.length,
329
- totalRounds: this.config.rounds,
330
- totalDurationMs: Date.now() - startTime,
331
- totalTokens,
332
- },
333
- };
334
-
335
- this.emit('discussion:complete', { content: '', metadata: result as unknown as Record<string, unknown> });
336
-
337
- return result;
338
- }
339
-
340
- /**
341
- * Format debate results as a markdown string (for slash command output).
342
- */
343
- formatAsMarkdown(result: DiscussionResult): string {
344
- const lines: string[] = [];
345
- const formatIcon = result.format === 'debate' ? '⚖' :
346
- result.format === 'qa' ? '❓' :
347
- result.format === 'panel' ? '🎙' : '💬';
348
- const formatLabel = result.format.charAt(0).toUpperCase() + result.format.slice(1);
349
-
350
- lines.push(`## ${formatIcon} ${formatLabel}: ${result.topic}`);
351
- lines.push('');
352
-
353
- // Unique speakers with their displayed colors
354
- const speakers = [...new Set(result.rounds.map(r => r.speaker))];
355
- lines.push(`*Participants: ${speakers.join(', ')} · ${result.metadata.totalRounds} rounds*`);
356
- lines.push('');
357
-
358
- for (const round of result.rounds) {
359
- const color = this.config.models.find(m => m.name === round.speaker)?.color || COLORS[0];
360
- const r = round.round;
361
- lines.push(`### ${color}${round.speaker}${'\x1b[0m'} · ${round.role} _(Round ${r})_`);
362
- lines.push('');
363
- lines.push(round.content);
364
- lines.push('');
365
- }
366
-
367
- lines.push('---');
368
- lines.push('### Summary');
369
- lines.push('');
370
- lines.push(result.summary);
371
- lines.push('');
372
- lines.push(`*${result.metadata.modelsUsed} models · ${result.metadata.totalRounds} rounds · ${(result.metadata.totalDurationMs / 1000).toFixed(1)}s · ${result.metadata.totalTokens.toLocaleString()} tokens*`);
373
-
374
- return lines.join('\n');
375
- }
376
-
377
- // ── Private ─────────────────────────────────────────────────────────────────────
378
-
379
- private buildRoleTemplate(format: DiscussionFormat): string {
380
- switch (format) {
381
- case 'debate':
382
- return 'You are participating in a structured debate. Present your position clearly and persuasively. Address counter-arguments when appropriate. Be concise but thorough.';
383
- case 'discussion':
384
- return 'You are participating in a collaborative discussion. Share your perspective, ask questions, and build on others\' ideas. Be constructive and insightful.';
385
- case 'qa':
386
- return 'You are answering questions as an expert in your field. Provide accurate, well-reasoned answers with specific details and examples when possible.';
387
- case 'panel':
388
- return 'You are a panelist in an expert discussion. Offer your professional perspective, reference relevant experience, and engage with other panelists\' viewpoints.';
389
- default:
390
- return 'You are participating in a discussion. Share your thoughts clearly.';
391
- }
392
- }
393
-
394
- private buildDebateGuidelines(format: DiscussionFormat): string {
395
- switch (format) {
396
- case 'debate':
397
- return `Guidelines:
398
- - Be concise (max 3 paragraphs per round)
399
- - Support claims with reasoning or evidence
400
- - Address the strongest points made by other participants
401
- - Stay on topic — do not introduce unrelated arguments
402
- - Conclude each round with a clear takeaway`;
403
- case 'discussion':
404
- return `Guidelines:
405
- - Be concise (max 3 paragraphs per turn)
406
- - Build on or respectfully challenge previous points
407
- - Ask clarifying questions when needed
408
- - Keep the discussion productive and focused`;
409
- case 'qa':
410
- return `Guidelines:
411
- - Be concise (max 2 paragraphs per answer)
412
- - Provide specific, accurate information
413
- - Acknowledge uncertainty when applicable
414
- - Reference sources or reasoning where relevant`;
415
- case 'panel':
416
- return `Guidelines:
417
- - Be concise (max 3 paragraphs per turn)
418
- - Share real experiences and specific examples
419
- - Engage with other panelists' points
420
- - Keep the discussion accessible to the audience`;
421
- default:
422
- return 'Be concise and stay on topic.';
423
- }
424
- }
425
-
426
- /**
427
- * Synthesize all rounds into a summary using the last model or built-in logic.
428
- */
429
- private synthesize(allRounds: DebateRound[]): string {
430
- if (allRounds.length === 0) return 'No discussion took place.';
431
-
432
- // Extract key topics from all responses
433
- const topics = new Set<string>();
434
- const allText = allRounds.map(r => r.content).join(' ');
435
-
436
- // Simple keyword extraction for summary
437
- const sentences = allText.split(/[.!?]+/).filter(s => s.trim().length > 20);
438
-
439
- // Build a structured summary
440
- const lines: string[] = [];
441
- lines.push(`Discussion on "${this.config.topic}" covered ${allRounds.length} contributions from ${this.config.models.length} participants.`);
442
-
443
- // Get final positions
444
- const lastWords = new Map<string, string>();
445
- for (const r of allRounds) {
446
- const sentences = r.content.split(/[.!?]+/).filter(Boolean);
447
- if (sentences.length > 0) {
448
- lastWords.set(r.speaker, sentences[sentences.length - 1].trim());
449
- }
450
- }
451
-
452
- if (lastWords.size > 0) {
453
- lines.push('');
454
- lines.push('**Closing positions:**');
455
- for (const [speaker, closing] of lastWords) {
456
- lines.push(`- ${speaker}: ${closing.slice(0, 150)}`);
457
- }
458
- }
459
-
460
- return lines.join('\n');
461
- }
462
- }