From ce6a09b891a079bc2cbb5c546f390537b6240732 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 11 Dec 2025 16:12:14 +0900 Subject: [PATCH] feat(background-notification): add completion notification hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 GENERATED WITH ASSISTANCE OF [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode) --- src/hooks/background-notification/index.ts | 103 +++++++++++++++++++++ src/hooks/background-notification/types.ts | 5 + 2 files changed, 108 insertions(+) create mode 100644 src/hooks/background-notification/index.ts create mode 100644 src/hooks/background-notification/types.ts diff --git a/src/hooks/background-notification/index.ts b/src/hooks/background-notification/index.ts new file mode 100644 index 0000000..479e2d3 --- /dev/null +++ b/src/hooks/background-notification/index.ts @@ -0,0 +1,103 @@ +import type { BackgroundManager, BackgroundTask } from "../../features/background-agent" + +interface Event { + type: string + properties?: Record +} + +interface EventInput { + event: Event +} + +interface ChatMessageInput { + sessionID: string + [key: string]: unknown +} + +interface ChatMessageOutput { + parts: Array<{ type: string; text: string }> + [key: string]: unknown +} + +function formatDuration(start: Date, end?: Date): string { + const duration = (end ?? new Date()).getTime() - start.getTime() + const seconds = Math.floor(duration / 1000) + const minutes = Math.floor(seconds / 60) + const hours = Math.floor(minutes / 60) + + if (hours > 0) { + return `${hours}h ${minutes % 60}m ${seconds % 60}s` + } else if (minutes > 0) { + return `${minutes}m ${seconds % 60}s` + } else { + return `${seconds}s` + } +} + +function formatNotifications(tasks: BackgroundTask[]): string { + if (tasks.length === 0) { + return "" + } + + if (tasks.length > 1) { + let message = `✅ **Background Tasks Complete (${tasks.length})**\n\n` + + for (const task of tasks) { + const duration = formatDuration(task.startedAt, task.completedAt) + const toolCalls = task.progress?.toolCalls ?? 0 + + message += `• **${task.id}** - ${task.description}\n` + message += ` Duration: ${duration} | Tool calls: ${toolCalls}\n\n` + } + + message += `Use \`background_result\` tool to retrieve results.` + + return message + } + + const task = tasks[0] + const duration = formatDuration(task.startedAt, task.completedAt) + const toolCalls = task.progress?.toolCalls ?? 0 + + return `✅ **Background Task Complete** + +**Task ID:** ${task.id} +**Description:** ${task.description} +**Duration:** ${duration} +**Tool calls:** ${toolCalls} + +The background task has finished. Use \`background_result\` tool with task ID \`${task.id}\` to retrieve the full result.` +} + +export function createBackgroundNotificationHook(manager: BackgroundManager) { + const eventHandler = async ({ event }: EventInput) => { + manager.handleEvent(event) + } + + const chatMessageHandler = async ( + input: ChatMessageInput, + output: ChatMessageOutput + ) => { + const notifications = manager.getPendingNotifications(input.sessionID) + + if (notifications.length === 0) { + return + } + + const message = formatNotifications(notifications) + + output.parts.unshift({ + type: "text", + text: message, + }) + + manager.clearNotifications(input.sessionID) + } + + return { + event: eventHandler, + "chat.message": chatMessageHandler, + } +} + +export type { BackgroundNotificationHookConfig } from "./types" diff --git a/src/hooks/background-notification/types.ts b/src/hooks/background-notification/types.ts new file mode 100644 index 0000000..00c2e8e --- /dev/null +++ b/src/hooks/background-notification/types.ts @@ -0,0 +1,5 @@ +import type { BackgroundTask } from "../../features/background-agent" + +export interface BackgroundNotificationHookConfig { + formatNotification?: (tasks: BackgroundTask[]) => string +}