@jungjaehoon/mama-os 0.9.2 ā 0.9.3
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/README.md +41 -7
- package/dist/api/graph-api.js +1 -1
- package/dist/api/graph-api.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +60 -15
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +16 -4
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js.map +1 -1
- package/dist/gateways/slack.d.ts.map +1 -1
- package/dist/gateways/slack.js +0 -10
- package/dist/gateways/slack.js.map +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts +3 -1
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +21 -12
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/background-task-manager.d.ts +2 -2
- package/dist/multi-agent/background-task-manager.js +2 -2
- package/dist/multi-agent/council-engine.d.ts +60 -0
- package/dist/multi-agent/council-engine.d.ts.map +1 -0
- package/dist/multi-agent/council-engine.js +284 -0
- package/dist/multi-agent/council-engine.js.map +1 -0
- package/dist/multi-agent/multi-agent-base.d.ts +17 -9
- package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-base.js +109 -30
- package/dist/multi-agent/multi-agent-base.js.map +1 -1
- package/dist/multi-agent/multi-agent-discord.d.ts +3 -35
- package/dist/multi-agent/multi-agent-discord.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-discord.js +57 -300
- package/dist/multi-agent/multi-agent-discord.js.map +1 -1
- package/dist/multi-agent/multi-agent-slack.d.ts +0 -25
- package/dist/multi-agent/multi-agent-slack.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-slack.js +95 -234
- package/dist/multi-agent/multi-agent-slack.js.map +1 -1
- package/dist/multi-agent/shared-context.d.ts.map +1 -1
- package/dist/multi-agent/shared-context.js +4 -4
- package/dist/multi-agent/shared-context.js.map +1 -1
- package/dist/multi-agent/system-reminder.d.ts +1 -1
- package/dist/multi-agent/system-reminder.js +1 -1
- package/dist/multi-agent/types.d.ts +11 -15
- package/dist/multi-agent/types.d.ts.map +1 -1
- package/dist/multi-agent/types.js +1 -3
- package/dist/multi-agent/types.js.map +1 -1
- package/dist/multi-agent/ultrawork-state.d.ts +57 -0
- package/dist/multi-agent/ultrawork-state.d.ts.map +1 -0
- package/dist/multi-agent/ultrawork-state.js +191 -0
- package/dist/multi-agent/ultrawork-state.js.map +1 -0
- package/dist/multi-agent/ultrawork.d.ts +37 -19
- package/dist/multi-agent/ultrawork.d.ts.map +1 -1
- package/dist/multi-agent/ultrawork.js +587 -41
- package/dist/multi-agent/ultrawork.js.map +1 -1
- package/dist/multi-agent/workflow-engine.d.ts.map +1 -1
- package/dist/multi-agent/workflow-engine.js +39 -14
- package/dist/multi-agent/workflow-engine.js.map +1 -1
- package/dist/multi-agent/workflow-types.d.ts +69 -0
- package/dist/multi-agent/workflow-types.d.ts.map +1 -1
- package/dist/onboarding/complete-autonomous-prompt.d.ts +1 -1
- package/dist/onboarding/complete-autonomous-prompt.d.ts.map +1 -1
- package/dist/onboarding/complete-autonomous-prompt.js +27 -10
- package/dist/onboarding/complete-autonomous-prompt.js.map +1 -1
- package/dist/onboarding/phase-7-integrations.d.ts.map +1 -1
- package/dist/onboarding/phase-7-integrations.js +23 -3
- package/dist/onboarding/phase-7-integrations.js.map +1 -1
- package/dist/onboarding/phase-9-finalization.d.ts.map +1 -1
- package/dist/onboarding/phase-9-finalization.js +33 -0
- package/dist/onboarding/phase-9-finalization.js.map +1 -1
- package/package.json +1 -1
- package/templates/personas/architect.md +70 -0
- package/templates/personas/conductor.md +302 -0
- package/templates/personas/developer.md +20 -7
- package/templates/personas/pm.md +49 -33
- package/templates/personas/reviewer.md +18 -5
- package/dist/multi-agent/pr-review-poller.d.ts +0 -197
- package/dist/multi-agent/pr-review-poller.d.ts.map +0 -1
- package/dist/multi-agent/pr-review-poller.js +0 -972
- package/dist/multi-agent/pr-review-poller.js.map +0 -1
- package/templates/personas/sisyphus-builtin-en.md +0 -161
- package/templates/personas/sisyphus.md +0 -218
|
@@ -45,7 +45,6 @@ const message_splitter_js_1 = require("../gateways/message-splitter.js");
|
|
|
45
45
|
const delegation_format_validator_js_1 = require("./delegation-format-validator.js");
|
|
46
46
|
const channel_history_js_1 = require("../gateways/channel-history.js");
|
|
47
47
|
const prompt_enhancer_js_1 = require("../agent/prompt-enhancer.js");
|
|
48
|
-
const pr_review_poller_js_1 = require("./pr-review-poller.js");
|
|
49
48
|
const child_process_1 = require("child_process");
|
|
50
49
|
const util_1 = require("util");
|
|
51
50
|
const debugLogger = __importStar(require("@jungjaehoon/mama-core/debug-logger"));
|
|
@@ -97,16 +96,8 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
97
96
|
historyInjected = new Set();
|
|
98
97
|
/** Cleanup interval handle for periodic tasks */
|
|
99
98
|
cleanupInterval = null;
|
|
100
|
-
/** PR poller summaries per channel for LEAD wake-up */
|
|
101
|
-
prPollerSummaries = new Map();
|
|
102
|
-
/** Tracks channels where APPROVE+commit was processed (prevents congratulation loops) */
|
|
103
|
-
approveProcessedChannels = new Map();
|
|
104
|
-
/** APPROVE cooldown period -- blocks agent-to-agent routing after commit (30 seconds) */
|
|
105
|
-
static APPROVE_COOLDOWN_MS = 30 * 1000;
|
|
106
99
|
/** Cleanup interval period (1 minute) */
|
|
107
100
|
static CLEANUP_INTERVAL_MS = 60_000;
|
|
108
|
-
/** PR review chain override (allows LEAD ā DEV ā REVIEWER ā LEAD) */
|
|
109
|
-
static PR_REVIEW_MAX_CHAIN = 6;
|
|
110
101
|
constructor(config, processOptions = {}, runtimeOptions = {}) {
|
|
111
102
|
super(config, processOptions, runtimeOptions);
|
|
112
103
|
this.multiBotManager = new multi_bot_manager_js_1.MultiBotManager(config);
|
|
@@ -115,7 +106,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
115
106
|
this.cleanupInterval = setInterval(() => {
|
|
116
107
|
this.messageQueue.clearExpired();
|
|
117
108
|
this.cleanupProcessedMentions();
|
|
118
|
-
this.cleanupApproveChannels();
|
|
119
109
|
}, MultiAgentDiscordHandler.CLEANUP_INTERVAL_MS);
|
|
120
110
|
// Setup idle event listeners for all agents (F7)
|
|
121
111
|
this.setupIdleListeners();
|
|
@@ -193,15 +183,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
193
183
|
if (this.processedMentions.has(dedupKey))
|
|
194
184
|
return;
|
|
195
185
|
this.processedMentions.set(dedupKey, Date.now());
|
|
196
|
-
// Block agent-to-LEAD mentions during post-APPROVE cooldown
|
|
197
|
-
// Only blocks mentions targeting the default (LEAD) agent -- not other agents like DEV
|
|
198
|
-
const approveCooldown = this.approveProcessedChannels.get(message.channel.id);
|
|
199
|
-
if (message.author.bot &&
|
|
200
|
-
approveCooldown &&
|
|
201
|
-
Date.now() - approveCooldown < MultiAgentDiscordHandler.APPROVE_COOLDOWN_MS &&
|
|
202
|
-
agentId === this.config.default_agent) {
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
186
|
const cleanContent = message.content.replace(/<@!?\d+>/g, '').trim();
|
|
206
187
|
if (!cleanContent)
|
|
207
188
|
return;
|
|
@@ -213,7 +194,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
213
194
|
// Chain depth check for mention_delegation
|
|
214
195
|
if (isFromAgent && senderAgentId && senderAgentId !== 'main') {
|
|
215
196
|
const chainState = this.orchestrator.getChainState(message.channel.id);
|
|
216
|
-
const maxDepth = this.getEffectiveMaxMentionDepth(
|
|
197
|
+
const maxDepth = this.getEffectiveMaxMentionDepth();
|
|
217
198
|
if (chainState.blocked) {
|
|
218
199
|
logger.info(`[MultiAgent] Mention chain blocked in channel ${message.channel.id}, ignoring`);
|
|
219
200
|
return;
|
|
@@ -300,7 +281,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
300
281
|
if (this.config.mention_delegation) {
|
|
301
282
|
const botUserIdMap = this.multiBotManager.getBotUserIdMap();
|
|
302
283
|
// Include LEAD (default agent) which uses the main bot token
|
|
303
|
-
// Without this, @
|
|
284
|
+
// Without this, @Conductor in other agents' personas won't resolve to <@userId>
|
|
304
285
|
const defaultAgentId = this.config.default_agent;
|
|
305
286
|
if (defaultAgentId && !botUserIdMap.has(defaultAgentId)) {
|
|
306
287
|
const mainBotUserId = this.multiBotManager.getMainBotUserId();
|
|
@@ -311,16 +292,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
311
292
|
this.processManager.setBotUserIdMap(botUserIdMap);
|
|
312
293
|
this.processManager.setMentionDelegation(true);
|
|
313
294
|
logger.info(`[MultiAgent] Mention delegation enabled with ${botUserIdMap.size} bot IDs`);
|
|
314
|
-
if (this.isPrReviewPollingEnabled()) {
|
|
315
|
-
// PR Review Poller: target LEAD directly.
|
|
316
|
-
// LEAD analyzes ā delegates to DevBot ā DevBot fixes ā Reviewer reviews after.
|
|
317
|
-
const orchestratorId = defaultAgentId || 'sisyphus';
|
|
318
|
-
const orchestratorUserId = botUserIdMap.get(orchestratorId);
|
|
319
|
-
if (orchestratorUserId) {
|
|
320
|
-
this.prReviewPoller.setTargetAgentUserId(orchestratorUserId);
|
|
321
|
-
logger.info(`[MultiAgent] PR Poller target: ${orchestratorId} (LEAD)`);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
295
|
}
|
|
325
296
|
}
|
|
326
297
|
/**
|
|
@@ -354,109 +325,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
354
325
|
}
|
|
355
326
|
}
|
|
356
327
|
}, 'discord');
|
|
357
|
-
if (this.isPrReviewPollingEnabled()) {
|
|
358
|
-
// Capture compact batch summaries so LEAD receives actionable context.
|
|
359
|
-
this.prReviewPoller.setMessageSender(async () => { });
|
|
360
|
-
this.prReviewPoller.setOnBatchItem(async (channelId, summary, item) => {
|
|
361
|
-
const bucket = this.prPollerSummaries.get(channelId) ?? [];
|
|
362
|
-
const compact = this.compactPrReviewBatchSummary(summary);
|
|
363
|
-
if (!compact || bucket.some((candidate) => candidate.id === item.id)) {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
const merged = {
|
|
367
|
-
...item,
|
|
368
|
-
summary: compact,
|
|
369
|
-
};
|
|
370
|
-
// Keep bounded for prompt size and avoid repeats within one poll batch.
|
|
371
|
-
this.prPollerSummaries.set(channelId, [...bucket, merged].slice(-12));
|
|
372
|
-
});
|
|
373
|
-
// After poll cycle: post count to channel and wake up PR workflow agents.
|
|
374
|
-
this.prReviewPoller.setOnBatchComplete(async (channelId, digest) => {
|
|
375
|
-
const items = (digest?.items && digest.items.length > 0
|
|
376
|
-
? digest.items
|
|
377
|
-
: this.prPollerSummaries.get(channelId)) ?? [];
|
|
378
|
-
if (items.length === 0) {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
const actionItems = digest?.newItems ?? items.filter((item) => !item.isReminder);
|
|
382
|
-
const reminderItems = digest?.reminderItems ?? items.filter((item) => item.isReminder);
|
|
383
|
-
const allActionable = actionItems.length > 0;
|
|
384
|
-
const count = items.length;
|
|
385
|
-
if (!allActionable) {
|
|
386
|
-
this.prPollerSummaries.delete(channelId);
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
const compactItems = items.map((item, idx) => `- ${idx + 1}. [${item.severity}] ${item.summary}`);
|
|
390
|
-
const summaryLines = compactItems.join('\n');
|
|
391
|
-
const sessions = this.prReviewPoller.getSessionDetails();
|
|
392
|
-
const session = sessions.find((s) => s.channelId === channelId);
|
|
393
|
-
if (!session) {
|
|
394
|
-
// Clean up stale summary to prevent memory leak
|
|
395
|
-
this.prPollerSummaries.delete(channelId);
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
const prLabel = `${session.owner}/${session.repo}#${session.prNumber}`;
|
|
399
|
-
const promptSummary = `\n${summaryLines}`;
|
|
400
|
-
const reminderSummary = reminderItems.length > 0 ? `\nš Reminders only: ${reminderItems.length} item(s).` : '';
|
|
401
|
-
this.prPollerSummaries.delete(channelId);
|
|
402
|
-
// Post summary to channel (visible to humans)
|
|
403
|
-
const channel = await client.channels.fetch(channelId);
|
|
404
|
-
if (channel && 'send' in channel) {
|
|
405
|
-
const content = `š PR ${prLabel} ā ${count} new review item(s)\n\n${promptSummary}${reminderSummary}`;
|
|
406
|
-
const chunks = (0, message_splitter_js_1.splitForDiscord)(content);
|
|
407
|
-
for (const chunk of chunks) {
|
|
408
|
-
await channel.send({
|
|
409
|
-
content: chunk,
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
// Wake up LEAD with compact PR summary + workspace path.
|
|
414
|
-
this.orchestrator.resetChain(channelId);
|
|
415
|
-
const defaultAgentId = this.config.default_agent || 'sisyphus';
|
|
416
|
-
const workspace = `\`${session.workspaceDir}\``;
|
|
417
|
-
const workflowPrompt = `š PR Review follow-up (${count} new item(s))`;
|
|
418
|
-
const taskContext = `Target: ${prLabel}\nWorkspace: ${workspace}\n`;
|
|
419
|
-
const itemsContext = `Items:\n${summaryLines}`;
|
|
420
|
-
const basePrompt = `${workflowPrompt}\n${taskContext}${itemsContext}${reminderSummary}`;
|
|
421
|
-
this.messageQueue.enqueue(defaultAgentId, {
|
|
422
|
-
prompt: `${basePrompt}\n\nClassify severity, implement fixable items, and coordinate with Dev/Reviewer.`,
|
|
423
|
-
channelId,
|
|
424
|
-
source: 'discord',
|
|
425
|
-
enqueuedAt: Date.now(),
|
|
426
|
-
context: { channelId, userId: 'pr-poller' },
|
|
427
|
-
});
|
|
428
|
-
logger.info(`[MultiAgent] PR Poller -> LEAD wake-up (${count} items)`);
|
|
429
|
-
this.tryDrainNow(defaultAgentId, 'discord', channelId).catch(() => { });
|
|
430
|
-
// Wake implementation/review agents in parallel so review loop can proceed autonomously.
|
|
431
|
-
const helperAgents = this.resolvePrReviewAssistants(defaultAgentId);
|
|
432
|
-
for (const helperAgentId of helperAgents) {
|
|
433
|
-
const helperPrompt = helperAgentId === 'developer'
|
|
434
|
-
? `${basePrompt}\n\nImplement available fixes in the workspace and request Reviewer verification when changes are made.`
|
|
435
|
-
: `${basePrompt}\n\nInspect the comments for correctness issues and provide reviewer guidance.`;
|
|
436
|
-
this.messageQueue.enqueue(helperAgentId, {
|
|
437
|
-
prompt: helperPrompt,
|
|
438
|
-
channelId,
|
|
439
|
-
source: 'discord',
|
|
440
|
-
enqueuedAt: Date.now(),
|
|
441
|
-
context: { channelId, userId: 'pr-poller' },
|
|
442
|
-
});
|
|
443
|
-
logger.info(`[MultiAgent] PR Poller -> ${helperAgentId} wake-up (${count} items)`);
|
|
444
|
-
this.tryDrainNow(helperAgentId, 'discord', channelId).catch(() => { });
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
logger.info('[MultiAgent] PR Review Poller message sender configured for Discord');
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Keep PR poller summaries short and remove duplicates.
|
|
452
|
-
*/
|
|
453
|
-
compactPrReviewBatchSummary(summary) {
|
|
454
|
-
const compact = summary.replace(/[\r\n]+/g, ' ').trim();
|
|
455
|
-
const max = 230;
|
|
456
|
-
if (!compact) {
|
|
457
|
-
return '';
|
|
458
|
-
}
|
|
459
|
-
return compact.length > max ? `${compact.slice(0, max)}ā¦` : compact;
|
|
460
328
|
}
|
|
461
329
|
/**
|
|
462
330
|
* Set main bot token (to avoid duplicate logins in MultiBotManager)
|
|
@@ -472,10 +340,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
472
340
|
this.orchestrator.updateConfig(config);
|
|
473
341
|
this.processManager.updateConfig(config);
|
|
474
342
|
this.multiBotManager.updateConfig(config);
|
|
475
|
-
if (!this.isPrReviewPollingEnabled()) {
|
|
476
|
-
this.prReviewPoller.stopAll();
|
|
477
|
-
this.prPollerSummaries.clear();
|
|
478
|
-
}
|
|
479
343
|
}
|
|
480
344
|
/**
|
|
481
345
|
* Handle a Discord message with multi-agent logic
|
|
@@ -490,14 +354,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
490
354
|
}
|
|
491
355
|
// Build message context
|
|
492
356
|
const context = this.buildMessageContext(message, cleanContent);
|
|
493
|
-
this.updateChainOverrideForChannel(context.channelId);
|
|
494
357
|
// Record human message to shared context
|
|
495
358
|
if (!context.isBot) {
|
|
496
359
|
this.sharedContext.recordHumanMessage(context.channelId, message.author.username, cleanContent, message.id);
|
|
497
|
-
if (this.isPrReviewPollingEnabled()) {
|
|
498
|
-
// Auto-detect PR URLs in user messages and start polling
|
|
499
|
-
this.detectAndPollPRUrls(cleanContent, context.channelId, message);
|
|
500
|
-
}
|
|
501
360
|
}
|
|
502
361
|
// Select responding agents
|
|
503
362
|
const selection = this.orchestrator.selectRespondingAgents(context);
|
|
@@ -532,10 +391,6 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
532
391
|
if (responses.length === 0) {
|
|
533
392
|
return null;
|
|
534
393
|
}
|
|
535
|
-
// Auto-detect PR URLs in agent responses and start polling
|
|
536
|
-
for (const resp of responses) {
|
|
537
|
-
this.detectAndPollPRUrls(resp.rawContent, context.channelId, message);
|
|
538
|
-
}
|
|
539
394
|
return {
|
|
540
395
|
selectedAgents: selection.selectedAgents,
|
|
541
396
|
reason: selection.reason,
|
|
@@ -808,15 +663,21 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
808
663
|
}
|
|
809
664
|
let msg = '';
|
|
810
665
|
const modelTag = event.agentModel ? ` [${event.agentModel}]` : '';
|
|
666
|
+
const progress = event.totalSteps && event.completedSteps !== undefined
|
|
667
|
+
? ` [${event.completedSteps}/${event.totalSteps}]`
|
|
668
|
+
: '';
|
|
811
669
|
if (event.type === 'step-started') {
|
|
812
|
-
msg = ` ${event.agentDisplayName}${modelTag} ģģ...`;
|
|
670
|
+
msg = ` ${event.agentDisplayName}${modelTag}${progress} ģģ...`;
|
|
813
671
|
}
|
|
814
672
|
else if (event.type === 'step-completed') {
|
|
815
673
|
const sec = event.duration_ms ? Math.round(event.duration_ms / 1000) : 0;
|
|
816
|
-
|
|
674
|
+
const pct = event.totalSteps && event.completedSteps !== undefined
|
|
675
|
+
? ` (${Math.round((event.completedSteps / event.totalSteps) * 100)}%)`
|
|
676
|
+
: '';
|
|
677
|
+
msg = `${event.agentDisplayName}${modelTag} (${sec}s)${pct} ģė£`;
|
|
817
678
|
}
|
|
818
679
|
else if (event.type === 'step-failed') {
|
|
819
|
-
msg = `${event.agentDisplayName}${modelTag} ā ģ¤ķØ: ${event.error?.substring(0, 100)}`;
|
|
680
|
+
msg = `${event.agentDisplayName}${modelTag}${progress} ā ģ¤ķØ: ${event.error?.substring(0, 100)}`;
|
|
820
681
|
}
|
|
821
682
|
if (msg) {
|
|
822
683
|
this.sendChannelNotification(context.channelId, msg).catch(() => { });
|
|
@@ -836,6 +697,38 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
836
697
|
duration: totalDuration,
|
|
837
698
|
};
|
|
838
699
|
}
|
|
700
|
+
// Check for council plan (after workflow, before tool calls)
|
|
701
|
+
const councilResult = await this.tryExecuteCouncil(result.response, context.channelId, 'discord', (event) => {
|
|
702
|
+
if (!this.discordClient)
|
|
703
|
+
return;
|
|
704
|
+
let msg = '';
|
|
705
|
+
if (event.type === 'council-round-started') {
|
|
706
|
+
msg = `š£ļø ${event.agentDisplayName} Round ${event.round} ģģ...`;
|
|
707
|
+
}
|
|
708
|
+
else if (event.type === 'council-round-completed') {
|
|
709
|
+
const sec = event.duration_ms ? Math.round(event.duration_ms / 1000) : 0;
|
|
710
|
+
msg = `š£ļø ${event.agentDisplayName} Round ${event.round} (${sec}s) ģė£`;
|
|
711
|
+
}
|
|
712
|
+
else if (event.type === 'council-round-failed') {
|
|
713
|
+
msg = `š£ļø ${event.agentDisplayName} Round ${event.round} ā ģ¤ķØ: ${event.error?.substring(0, 100)}`;
|
|
714
|
+
}
|
|
715
|
+
if (msg) {
|
|
716
|
+
this.sendChannelNotification(context.channelId, msg).catch(() => { });
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
if (councilResult) {
|
|
720
|
+
const display = councilResult.directMessage
|
|
721
|
+
? `${councilResult.directMessage}\n\n${councilResult.result}`
|
|
722
|
+
: councilResult.result;
|
|
723
|
+
const formattedResponse = this.formatAgentResponse(agent, display);
|
|
724
|
+
return {
|
|
725
|
+
agentId,
|
|
726
|
+
agent,
|
|
727
|
+
content: formattedResponse,
|
|
728
|
+
rawContent: display,
|
|
729
|
+
duration: Date.now() - workflowStart + (result.duration_ms ?? 0),
|
|
730
|
+
};
|
|
731
|
+
}
|
|
839
732
|
const cleanedResponse = await this.executeAgentToolCalls(agentId, result.response);
|
|
840
733
|
// Detect API error responses ā skip mention resolution and delegation to prevent error loops
|
|
841
734
|
const isErrorResponse = /API Error:\s*\d{3}\b/.test(cleanedResponse);
|
|
@@ -849,8 +742,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
849
742
|
let submittedCount = 0;
|
|
850
743
|
const submittedAgents = [];
|
|
851
744
|
for (const delegation of bgDelegations) {
|
|
852
|
-
if (!delegation.background)
|
|
745
|
+
if (!delegation.background) {
|
|
853
746
|
continue;
|
|
747
|
+
}
|
|
854
748
|
const check = this.delegationManager.isDelegationAllowed(delegation.fromAgentId, delegation.toAgentId);
|
|
855
749
|
if (check.allowed) {
|
|
856
750
|
this.backgroundTaskManager.submit({
|
|
@@ -975,8 +869,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
975
869
|
if (delegations.length > 0 && hasBackground) {
|
|
976
870
|
let submittedCount = 0;
|
|
977
871
|
for (const delegation of delegations) {
|
|
978
|
-
if (!delegation.background)
|
|
872
|
+
if (!delegation.background) {
|
|
979
873
|
continue;
|
|
874
|
+
}
|
|
980
875
|
const check = this.delegationManager.isDelegationAllowed(delegation.fromAgentId, delegation.toAgentId);
|
|
981
876
|
if (check.allowed) {
|
|
982
877
|
this.backgroundTaskManager.submit({
|
|
@@ -1119,7 +1014,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1119
1014
|
console.error(`[MultiAgent] Failed to send response for agent ${response.agentId}:`, err);
|
|
1120
1015
|
}
|
|
1121
1016
|
}
|
|
1122
|
-
// Post-send: Auto-review trigger for default agent (Armed
|
|
1017
|
+
// Post-send: Auto-review trigger for default agent (Armed Conductor) self-implementations
|
|
1123
1018
|
const defaultAgentId = this.config.default_agent;
|
|
1124
1019
|
if (defaultAgentId) {
|
|
1125
1020
|
const selfImplemented = responses.find((r) => r.agentId === defaultAgentId && this.detectSelfImplementation(r.rawContent));
|
|
@@ -1130,7 +1025,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1130
1025
|
return sentMessages;
|
|
1131
1026
|
}
|
|
1132
1027
|
/**
|
|
1133
|
-
* Detect if the default agent (
|
|
1028
|
+
* Detect if the default agent (Conductor) performed direct code edits.
|
|
1134
1029
|
* Checks for Claude CLI tool-use markers that indicate Edit/Write operations.
|
|
1135
1030
|
*/
|
|
1136
1031
|
detectSelfImplementation(rawContent) {
|
|
@@ -1149,7 +1044,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1149
1044
|
return editIndicators.some((pattern) => pattern.test(rawContent));
|
|
1150
1045
|
}
|
|
1151
1046
|
/**
|
|
1152
|
-
* Check git diff size after
|
|
1047
|
+
* Check git diff size after Conductor self-implementation.
|
|
1153
1048
|
* If diff exceeds thresholds, auto-trigger Reviewer for quality gate.
|
|
1154
1049
|
*
|
|
1155
1050
|
* Thresholds (PAIR mode auto-escalation):
|
|
@@ -1189,7 +1084,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1189
1084
|
}
|
|
1190
1085
|
}
|
|
1191
1086
|
if (filesChanged > MAX_FILES || totalLines > MAX_LINES) {
|
|
1192
|
-
logger.info(`[AutoReview]
|
|
1087
|
+
logger.info(`[AutoReview] Conductor self-implementation exceeded thresholds: ${filesChanged} files, ${totalLines} lines -> auto-triggering Reviewer`);
|
|
1193
1088
|
// Find reviewer agent using shared helper
|
|
1194
1089
|
const reviewerEntry = this.findReviewerAgent();
|
|
1195
1090
|
const reviewerAgentId = reviewerEntry?.[0];
|
|
@@ -1199,7 +1094,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1199
1094
|
}
|
|
1200
1095
|
}
|
|
1201
1096
|
else {
|
|
1202
|
-
logger.info(`[AutoReview]
|
|
1097
|
+
logger.info(`[AutoReview] Conductor self-implementation within thresholds: ${filesChanged} files, ${totalLines} lines -- no auto-review needed`);
|
|
1203
1098
|
}
|
|
1204
1099
|
}
|
|
1205
1100
|
catch {
|
|
@@ -1256,33 +1151,14 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1256
1151
|
}
|
|
1257
1152
|
}
|
|
1258
1153
|
logger.info(`[MultiAgent] Auto-routing mentions from ${response.agentId}: -> ${mentionedAgentIds.join(', ')}`);
|
|
1259
|
-
const defaultAgentId = this.config.default_agent;
|
|
1260
|
-
const hasApproveSignal = /\b(APPROVE[DS]?|LGTM)\b/i.test(response.rawContent) &&
|
|
1261
|
-
!/\b(not?\s+approve|don'?t\s+approve|cannot\s+approve|rejected)\b/i.test(response.rawContent);
|
|
1262
|
-
const isReviewerApproveToLead = this.isReviewerAgent(response.agentId) &&
|
|
1263
|
-
mentionedAgentIds.includes(defaultAgentId || '') &&
|
|
1264
|
-
hasApproveSignal;
|
|
1265
|
-
if (isReviewerApproveToLead) {
|
|
1266
|
-
// Dedup: skip if APPROVE already processed for this channel
|
|
1267
|
-
const lastApprove = this.approveProcessedChannels.get(originalMessage.channel.id);
|
|
1268
|
-
if (lastApprove &&
|
|
1269
|
-
Date.now() - lastApprove < MultiAgentDiscordHandler.APPROVE_COOLDOWN_MS) {
|
|
1270
|
-
logger.info(`[MultiAgent] APPROVE already processed for ${originalMessage.channel.id}, skipping`);
|
|
1271
|
-
continue;
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
1154
|
// Route to all mentioned agents in parallel
|
|
1275
|
-
await Promise.all(mentionedAgentIds.map((targetAgentId) => this.handleDelegatedMention(targetAgentId, originalMessage, response
|
|
1276
|
-
// Set APPROVE cooldown AFTER routing to LEAD (so LEAD gets the first one)
|
|
1277
|
-
if (isReviewerApproveToLead) {
|
|
1278
|
-
this.approveProcessedChannels.set(originalMessage.channel.id, Date.now());
|
|
1279
|
-
}
|
|
1155
|
+
await Promise.all(mentionedAgentIds.map((targetAgentId) => this.handleDelegatedMention(targetAgentId, originalMessage, response)));
|
|
1280
1156
|
}
|
|
1281
1157
|
}
|
|
1282
1158
|
/**
|
|
1283
1159
|
* Handle a delegated mention: process target agent response and recursively route.
|
|
1284
1160
|
*/
|
|
1285
|
-
async handleDelegatedMention(targetAgentId, originalMessage, sourceResponse
|
|
1161
|
+
async handleDelegatedMention(targetAgentId, originalMessage, sourceResponse) {
|
|
1286
1162
|
// Dedup: prevent double processing
|
|
1287
1163
|
const dedupKey = `${targetAgentId}:${sourceResponse.messageId || originalMessage.id}`;
|
|
1288
1164
|
if (this.processedMentions.has(dedupKey))
|
|
@@ -1333,16 +1209,10 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1333
1209
|
channelId,
|
|
1334
1210
|
timestamp: Date.now(),
|
|
1335
1211
|
});
|
|
1336
|
-
|
|
1212
|
+
const delegationContent = sourceResponse.rawContent
|
|
1337
1213
|
.replace(/<@!?\d+>/g, '')
|
|
1338
1214
|
.replace(/DELEGATE(?:_BG)?::[\w-]+::/g, '')
|
|
1339
1215
|
.trim();
|
|
1340
|
-
if (reviewerSignal === 'REVIEWER_APPROVED' && targetAgentId === this.config.default_agent) {
|
|
1341
|
-
delegationContent +=
|
|
1342
|
-
'\n\nš [SYSTEM] Reviewer has APPROVED the changes.\n' +
|
|
1343
|
-
'Review the changes yourself, then commit and push when you are satisfied.\n' +
|
|
1344
|
-
'Use your judgement on the commit message and which files to include.';
|
|
1345
|
-
}
|
|
1346
1216
|
try {
|
|
1347
1217
|
const response = await this.processAgentResponse(targetAgentId, {
|
|
1348
1218
|
channelId,
|
|
@@ -1455,7 +1325,7 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1455
1325
|
}
|
|
1456
1326
|
/**
|
|
1457
1327
|
* Resolve @Name mentions in LLM response text to <@userId> Discord format.
|
|
1458
|
-
* LLMs generate plain text like "@LEAD", "@
|
|
1328
|
+
* LLMs generate plain text like "@LEAD", "@Conductor", "@DevBot" which won't
|
|
1459
1329
|
* trigger Discord mentions or routeResponseMentions detection.
|
|
1460
1330
|
*/
|
|
1461
1331
|
resolveResponseMentions(text) {
|
|
@@ -1503,122 +1373,9 @@ class MultiAgentDiscordHandler extends multi_agent_base_js_1.MultiAgentHandlerBa
|
|
|
1503
1373
|
}
|
|
1504
1374
|
return resolved;
|
|
1505
1375
|
}
|
|
1506
|
-
|
|
1507
|
-
const now = Date.now();
|
|
1508
|
-
for (const [channelId, ts] of this.approveProcessedChannels) {
|
|
1509
|
-
if (now - ts > MultiAgentDiscordHandler.APPROVE_COOLDOWN_MS) {
|
|
1510
|
-
this.approveProcessedChannels.delete(channelId);
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
/**
|
|
1515
|
-
* Detect PR URLs in text and auto-start polling.
|
|
1516
|
-
* Sends a notification to the channel when polling starts.
|
|
1517
|
-
*/
|
|
1518
|
-
detectAndPollPRUrls(text, channelId, message) {
|
|
1519
|
-
if (!this.isPrReviewPollingEnabled())
|
|
1520
|
-
return;
|
|
1521
|
-
const prUrls = pr_review_poller_js_1.PRReviewPoller.extractPRUrls(text);
|
|
1522
|
-
if (prUrls.length === 0)
|
|
1523
|
-
return;
|
|
1524
|
-
for (const prUrl of prUrls) {
|
|
1525
|
-
this.prReviewPoller
|
|
1526
|
-
.startPolling(prUrl, channelId)
|
|
1527
|
-
.then((started) => {
|
|
1528
|
-
const parsed = this.prReviewPoller.parsePRUrl(prUrl);
|
|
1529
|
-
const key = parsed ? `${parsed.owner}/${parsed.repo}#${parsed.prNumber}` : prUrl;
|
|
1530
|
-
if (started) {
|
|
1531
|
-
this.updateChainOverrideForChannel(channelId);
|
|
1532
|
-
if ('send' in message.channel) {
|
|
1533
|
-
message.channel
|
|
1534
|
-
.send({
|
|
1535
|
-
content: `š **PR Review Poller Started** -- ${key}\nDetecting new review comments every 60 seconds.`,
|
|
1536
|
-
})
|
|
1537
|
-
.catch((err) => {
|
|
1538
|
-
console.warn(`[MultiAgent] Failed to send PR polling start message to Discord channel ${channelId}:`, err?.message || err);
|
|
1539
|
-
});
|
|
1540
|
-
}
|
|
1541
|
-
logger.info(`[MultiAgent] PR Poller started for ${key} in Discord channel ${channelId}`);
|
|
1542
|
-
}
|
|
1543
|
-
else {
|
|
1544
|
-
if ('send' in message.channel) {
|
|
1545
|
-
message.channel
|
|
1546
|
-
.send({
|
|
1547
|
-
content: `ā¹ļø PR Review Poller is already active for ${key}.`,
|
|
1548
|
-
})
|
|
1549
|
-
.catch((err) => {
|
|
1550
|
-
console.warn(`[MultiAgent] Failed to send PR polling already-running message to Discord channel ${channelId}:`, err?.message || err);
|
|
1551
|
-
});
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
|
-
})
|
|
1555
|
-
.catch((err) => {
|
|
1556
|
-
console.error(`[MultiAgent] Failed to start PR polling:`, err);
|
|
1557
|
-
if ('send' in message.channel) {
|
|
1558
|
-
message.channel
|
|
1559
|
-
.send({
|
|
1560
|
-
content: `ā ļø Failed to start PR Review Poller for ${prUrl}: ${String(err)}`,
|
|
1561
|
-
})
|
|
1562
|
-
.catch((sendErr) => {
|
|
1563
|
-
console.warn(`[MultiAgent] Failed to send PR polling error message to Discord channel ${channelId}:`, sendErr?.message || sendErr);
|
|
1564
|
-
});
|
|
1565
|
-
}
|
|
1566
|
-
});
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
/**
|
|
1570
|
-
* Resolve helper agents for PR review workflow in addition to default lead.
|
|
1571
|
-
*/
|
|
1572
|
-
resolvePrReviewAssistants(defaultAgentId) {
|
|
1573
|
-
const candidateIds = ['developer', 'reviewer', 'dev', 'lead'];
|
|
1574
|
-
const helperAgents = [];
|
|
1575
|
-
for (const id of candidateIds) {
|
|
1576
|
-
const cfg = this.config.agents[id];
|
|
1577
|
-
if (!cfg || id === defaultAgentId) {
|
|
1578
|
-
continue;
|
|
1579
|
-
}
|
|
1580
|
-
if (cfg.enabled === false) {
|
|
1581
|
-
continue;
|
|
1582
|
-
}
|
|
1583
|
-
helperAgents.push(id);
|
|
1584
|
-
}
|
|
1585
|
-
return [...new Set(helperAgents)];
|
|
1586
|
-
}
|
|
1587
|
-
/**
|
|
1588
|
-
* Update chain/mention depth overrides when PR review polling is active.
|
|
1589
|
-
*/
|
|
1590
|
-
updateChainOverrideForChannel(channelId) {
|
|
1591
|
-
if (this.isPrReviewActive(channelId)) {
|
|
1592
|
-
this.orchestrator.setChannelChainLimit(channelId, MultiAgentDiscordHandler.PR_REVIEW_MAX_CHAIN);
|
|
1593
|
-
}
|
|
1594
|
-
else {
|
|
1595
|
-
this.orchestrator.clearChannelChainLimit(channelId);
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
getEffectiveMaxMentionDepth(channelId) {
|
|
1599
|
-
if (this.isPrReviewActive(channelId)) {
|
|
1600
|
-
return MultiAgentDiscordHandler.PR_REVIEW_MAX_CHAIN;
|
|
1601
|
-
}
|
|
1376
|
+
getEffectiveMaxMentionDepth() {
|
|
1602
1377
|
return this.config.max_mention_depth ?? 3;
|
|
1603
1378
|
}
|
|
1604
|
-
isPrReviewActive(channelId) {
|
|
1605
|
-
if (!this.isPrReviewPollingEnabled()) {
|
|
1606
|
-
return false;
|
|
1607
|
-
}
|
|
1608
|
-
return this.prReviewPoller
|
|
1609
|
-
.getSessionDetails()
|
|
1610
|
-
.some((session) => session.channelId === channelId);
|
|
1611
|
-
}
|
|
1612
|
-
isPrReviewPollingEnabled() {
|
|
1613
|
-
return this.config.pr_review_poller?.enabled === true;
|
|
1614
|
-
}
|
|
1615
|
-
/**
|
|
1616
|
-
* Check if an agent ID is the reviewer agent
|
|
1617
|
-
*/
|
|
1618
|
-
isReviewerAgent(agentId) {
|
|
1619
|
-
return (agentId.toLowerCase().includes('review') ||
|
|
1620
|
-
this.config.agents[agentId]?.name?.toLowerCase().includes('review') === true);
|
|
1621
|
-
}
|
|
1622
1379
|
/**
|
|
1623
1380
|
* Find the reviewer agent entry from config
|
|
1624
1381
|
*/
|