aegiscode 3.1.10 → 3.4.2
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/bin/aegis.js +165 -0
- package/package.json +18 -86
- package/LICENSE +0 -21
- package/README.md +0 -394
- package/dist/main.js +0 -2171
- package/gui/run-gui.cjs +0 -13
- package/src/agent/Agent.ts +0 -903
- package/src/agent/SimpleAgent.ts +0 -48
- package/src/agent/index.ts +0 -54
- package/src/agent/orchestrator/AppBuilder.ts +0 -443
- package/src/agent/orchestrator/CouncilAgent.ts +0 -310
- package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
- package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
- package/src/agent/orchestrator/index.ts +0 -38
- package/src/agent/orchestrator/utils.ts +0 -397
- package/src/agent/pricing.ts +0 -115
- package/src/agent/router.ts +0 -74
- package/src/agent/routerStats.ts +0 -121
- package/src/agent/types.ts +0 -318
- package/src/auth/login.ts +0 -383
- package/src/cli/config.ts +0 -189
- package/src/cli/index.ts +0 -17
- package/src/cli/middleware.ts +0 -119
- package/src/cli/types.ts +0 -75
- package/src/config/ConfigManager.ts +0 -587
- package/src/config/index.ts +0 -7
- package/src/config/types.ts +0 -584
- package/src/context/CompactionService.ts +0 -300
- package/src/context/ContextManager.ts +0 -450
- package/src/context/FileAnalyzer.ts +0 -267
- package/src/context/TokenCounter.ts +0 -265
- package/src/context/index.ts +0 -27
- package/src/context/storage/CacheStore.ts +0 -176
- package/src/context/storage/JSONLStore.ts +0 -201
- package/src/context/storage/MemoryStore.ts +0 -205
- package/src/context/storage/PersistentStore.ts +0 -327
- package/src/context/storage/index.ts +0 -9
- package/src/context/storage/pathUtils.ts +0 -114
- package/src/context/test.ts +0 -309
- package/src/context/types.ts +0 -268
- package/src/hooks/HookExecutor.ts +0 -434
- package/src/hooks/HookManager.ts +0 -596
- package/src/hooks/HookService.ts +0 -269
- package/src/hooks/Matcher.ts +0 -157
- package/src/hooks/index.ts +0 -63
- package/src/hooks/types.ts +0 -424
- package/src/main.tsx +0 -596
- package/src/mcp/HealthMonitor.ts +0 -150
- package/src/mcp/McpClient.ts +0 -491
- package/src/mcp/McpRegistry.ts +0 -321
- package/src/mcp/createMcpTool.ts +0 -251
- package/src/mcp/index.ts +0 -15
- package/src/mcp/server.ts +0 -334
- package/src/mcp/test-server.ts +0 -88
- package/src/mcp/test.ts +0 -372
- package/src/mcp/types.ts +0 -247
- package/src/memory/AgentMemoryBus.ts +0 -432
- package/src/memory/CloudSync.ts +0 -99
- package/src/memory/DriveSync.ts +0 -106
- package/src/memory/SharedMemory.ts +0 -951
- package/src/memory/index.ts +0 -14
- package/src/memory/machineFingerprint.ts +0 -40
- package/src/orchestrator/SubAgentMetadata.ts +0 -136
- package/src/prompts/builder.ts +0 -213
- package/src/prompts/default.ts +0 -144
- package/src/prompts/index.ts +0 -16
- package/src/prompts/plan.ts +0 -64
- package/src/prompts/test.ts +0 -78
- package/src/services/AnthropicChatService.ts +0 -341
- package/src/services/ChatService.ts +0 -347
- package/src/services/ClaudeCliChatService.ts +0 -256
- package/src/services/CloudSync.ts +0 -168
- package/src/services/CostLedger.ts +0 -211
- package/src/services/Heartbeat.ts +0 -135
- package/src/services/LearningCollector.ts +0 -291
- package/src/services/OllamaInstaller.ts +0 -342
- package/src/services/VersionChecker.ts +0 -445
- package/src/services/index.ts +0 -57
- package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
- package/src/services/streaming/RenderingProfile.ts +0 -90
- package/src/services/streaming/StreamEventParser.ts +0 -181
- package/src/services/streaming/ThrottledRenderer.ts +0 -139
- package/src/services/streaming/TranscriptBuffer.ts +0 -574
- package/src/services/streaming/eventStatusMap.ts +0 -52
- package/src/services/streaming/index.ts +0 -46
- package/src/services/streaming/renderFormatting.ts +0 -79
- package/src/services/streaming/types.ts +0 -234
- package/src/skills/SkillLoader.ts +0 -126
- package/src/skills/SkillRegistry.ts +0 -366
- package/src/skills/index.ts +0 -48
- package/src/skills/types.ts +0 -146
- package/src/slash-commands/billing.ts +0 -70
- package/src/slash-commands/build.ts +0 -413
- package/src/slash-commands/builtinCommands.ts +0 -2733
- package/src/slash-commands/clone.ts +0 -242
- package/src/slash-commands/council.ts +0 -125
- package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
- package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
- package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
- package/src/slash-commands/custom/index.ts +0 -7
- package/src/slash-commands/debate.ts +0 -254
- package/src/slash-commands/gmail.ts +0 -105
- package/src/slash-commands/index.ts +0 -388
- package/src/slash-commands/mcpCommand.ts +0 -205
- package/src/slash-commands/types.ts +0 -201
- package/src/store/index.ts +0 -76
- package/src/store/selectors.ts +0 -246
- package/src/store/slices/appSlice.ts +0 -205
- package/src/store/slices/commandSlice.ts +0 -115
- package/src/store/slices/configSlice.ts +0 -46
- package/src/store/slices/focusSlice.ts +0 -64
- package/src/store/slices/index.ts +0 -9
- package/src/store/slices/sessionSlice.ts +0 -424
- package/src/store/streaming-buffer.ts +0 -425
- package/src/store/test.ts +0 -296
- package/src/store/types.ts +0 -274
- package/src/store/vanilla.ts +0 -186
- package/src/tools/builtin/bash.ts +0 -236
- package/src/tools/builtin/council.ts +0 -105
- package/src/tools/builtin/edit.ts +0 -213
- package/src/tools/builtin/glob.ts +0 -136
- package/src/tools/builtin/grep.ts +0 -263
- package/src/tools/builtin/index.ts +0 -61
- package/src/tools/builtin/memory.ts +0 -66
- package/src/tools/builtin/read.ts +0 -168
- package/src/tools/builtin/skill.ts +0 -97
- package/src/tools/builtin/snapshot.ts +0 -40
- package/src/tools/builtin/task.ts +0 -106
- package/src/tools/builtin/write.ts +0 -134
- package/src/tools/createTool.ts +0 -221
- package/src/tools/execution/ExecutionPipeline.ts +0 -263
- package/src/tools/execution/index.ts +0 -40
- package/src/tools/execution/stages/CacheStage.ts +0 -131
- package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
- package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
- package/src/tools/execution/stages/ExecutionStage.ts +0 -48
- package/src/tools/execution/stages/FormattingStage.ts +0 -44
- package/src/tools/execution/stages/HookStage.ts +0 -72
- package/src/tools/execution/stages/PermissionStage.ts +0 -287
- package/src/tools/execution/stages/PostHookStage.ts +0 -71
- package/src/tools/execution/stages/index.ts +0 -12
- package/src/tools/execution/test.ts +0 -266
- package/src/tools/execution/types.ts +0 -273
- package/src/tools/index.ts +0 -81
- package/src/tools/registry.ts +0 -304
- package/src/tools/schemas.ts +0 -109
- package/src/tools/test.ts +0 -220
- package/src/tools/types.ts +0 -175
- package/src/tools/validation/PermissionChecker.ts +0 -242
- package/src/tools/validation/SensitiveFileDetector.ts +0 -210
- package/src/tools/validation/index.ts +0 -11
- package/src/ui/App.tsx +0 -166
- package/src/ui/components/AegisInterface.tsx +0 -484
- package/src/ui/components/common/ChatSearch.tsx +0 -150
- package/src/ui/components/common/ErrorBoundary.tsx +0 -82
- package/src/ui/components/common/ExitMessage.tsx +0 -120
- package/src/ui/components/common/LoadingIndicator.tsx +0 -49
- package/src/ui/components/common/index.ts +0 -6
- package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
- package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
- package/src/ui/components/dialog/SetupWizard.tsx +0 -297
- package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
- package/src/ui/components/dialog/index.ts +0 -8
- package/src/ui/components/index.ts +0 -28
- package/src/ui/components/input/CommandSuggestions.tsx +0 -139
- package/src/ui/components/input/CustomTextInput.tsx +0 -220
- package/src/ui/components/input/InputArea.tsx +0 -361
- package/src/ui/components/input/PromptSuggestions.tsx +0 -66
- package/src/ui/components/input/index.ts +0 -6
- package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
- package/src/ui/components/layout/ContextBar.tsx +0 -79
- package/src/ui/components/layout/MessageArea.tsx +0 -96
- package/src/ui/components/layout/MessageList.tsx +0 -647
- package/src/ui/components/layout/MessageSeparator.tsx +0 -26
- package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
- package/src/ui/components/layout/index.ts +0 -7
- package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
- package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
- package/src/ui/components/markdown/index.ts +0 -8
- package/src/ui/components/markdown/parser.ts +0 -336
- package/src/ui/components/markdown/types.ts +0 -66
- package/src/ui/focus/FocusManager.ts +0 -137
- package/src/ui/focus/index.ts +0 -13
- package/src/ui/focus/types.ts +0 -54
- package/src/ui/focus/useFocus.ts +0 -75
- package/src/ui/hooks/index.ts +0 -11
- package/src/ui/hooks/useAgent.ts +0 -284
- package/src/ui/hooks/useCommandHistory.ts +0 -87
- package/src/ui/hooks/useCommandProcessor.ts +0 -443
- package/src/ui/hooks/useConfirmation.ts +0 -99
- package/src/ui/hooks/useCtrlCHandler.ts +0 -100
- package/src/ui/hooks/useInputBuffer.ts +0 -122
- package/src/ui/hooks/useTerminalSize.ts +0 -68
- package/src/ui/hooks/useTerminalWidth.ts +0 -5
- package/src/ui/hooks/useWindowedList.ts +0 -118
- package/src/ui/render-debugger.ts +0 -621
- package/src/ui/test.ts +0 -189
- package/src/ui/themes/ThemeManager.ts +0 -332
- package/src/ui/themes/aegisTheme.ts +0 -87
- package/src/ui/themes/darkTheme.ts +0 -87
- package/src/ui/themes/defaultTheme.ts +0 -85
- package/src/ui/themes/index.ts +0 -10
- package/src/ui/themes/lightTheme.ts +0 -89
- package/src/ui/themes/popularThemes.ts +0 -187
- package/src/ui/themes/types.ts +0 -130
- package/src/utils/clipboard.ts +0 -48
- package/src/utils/debug.ts +0 -43
- package/src/utils/environment.ts +0 -68
- 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
|
-
}
|