feat: auto-notify user on paired task completion with @mention
- done → ✅ 작업 완료 - escalated → ⚠️ 자동 해결 불가 - arbiter_escalated → ⚠️ 중재자: 사람 개입 필요 - stopped → no notification (user initiated)
This commit is contained in:
@@ -48,7 +48,11 @@ vi.mock('./platform-prompts.js', () => ({
|
|||||||
vi.mock('./db.js', () => ({
|
vi.mock('./db.js', () => ({
|
||||||
createServiceHandoff: vi.fn(),
|
createServiceHandoff: vi.fn(),
|
||||||
getAllTasks: vi.fn(() => []),
|
getAllTasks: vi.fn(() => []),
|
||||||
|
getLastHumanMessageSender: vi.fn(() => null),
|
||||||
getLatestOpenPairedTaskForChat: vi.fn(() => undefined),
|
getLatestOpenPairedTaskForChat: vi.fn(() => undefined),
|
||||||
|
getLatestTurnNumber: vi.fn(() => 0),
|
||||||
|
getPairedTaskById: vi.fn(() => undefined),
|
||||||
|
insertPairedTurnOutput: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('./service-routing.js', () => ({
|
vi.mock('./service-routing.js', () => ({
|
||||||
|
|||||||
@@ -131,7 +131,8 @@ export async function runAgentForGroup(
|
|||||||
group.agentType,
|
group.agentType,
|
||||||
);
|
);
|
||||||
// Arbiter always starts fresh — never resume a previous session
|
// Arbiter always starts fresh — never resume a previous session
|
||||||
const sessionId = activeRole === 'arbiter' ? undefined : sessions[sessionFolder];
|
const sessionId =
|
||||||
|
activeRole === 'arbiter' ? undefined : sessions[sessionFolder];
|
||||||
const memoryBriefing = sessionId
|
const memoryBriefing = sessionId
|
||||||
? undefined
|
? undefined
|
||||||
: await buildRoomMemoryBriefing({
|
: await buildRoomMemoryBriefing({
|
||||||
@@ -1047,6 +1048,29 @@ export async function runAgentForGroup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify user when paired task reaches a terminal state that requires attention.
|
||||||
|
if (pairedExecutionContext) {
|
||||||
|
const finishedTask = getPairedTaskById(pairedExecutionContext.task.id);
|
||||||
|
if (finishedTask?.status === 'completed' && finishedTask.completion_reason) {
|
||||||
|
const sender = getLastHumanMessageSender(chatJid);
|
||||||
|
const mention = sender ? `<@${sender}>` : '';
|
||||||
|
const notifications: Record<string, string> = {
|
||||||
|
done: `${mention} ✅ 작업 완료.`,
|
||||||
|
escalated: `${mention} ⚠️ 자동 해결 불가 — 확인이 필요합니다.`,
|
||||||
|
arbiter_escalated: `${mention} ⚠️ 중재자 판단: 사람 개입이 필요합니다.`,
|
||||||
|
};
|
||||||
|
const message = notifications[finishedTask.completion_reason];
|
||||||
|
if (message) {
|
||||||
|
await args.onOutput?.({
|
||||||
|
status: 'success',
|
||||||
|
result: message,
|
||||||
|
output: { visibility: 'public', text: message },
|
||||||
|
phase: 'final',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// After owner/reviewer completes, enqueue the next turn so
|
// After owner/reviewer completes, enqueue the next turn so
|
||||||
// the message loop picks it up without waiting for a new message.
|
// the message loop picks it up without waiting for a new message.
|
||||||
// Skip if owner produced no output — likely interrupted by /stop.
|
// Skip if owner produced no output — likely interrupted by /stop.
|
||||||
|
|||||||
Reference in New Issue
Block a user