import type { BackgroundTask } from "../../features/background-agent" import { consumeNewMessages } from "../../shared/session-cursor" import type { BackgroundOutputClient, BackgroundOutputMessagesResult } from "./clients" import { extractMessages, getErrorMessage } from "./session-messages" import { formatDuration } from "./time-format" function getTimeString(value: unknown): string { return typeof value === "string" ? value : "" } export async function formatTaskResult(task: BackgroundTask, client: BackgroundOutputClient): Promise { if (!task.sessionID) { return `Error: Task has no sessionID` } const messagesResult: BackgroundOutputMessagesResult = await client.session.messages({ path: { id: task.sessionID }, }) const errorMessage = getErrorMessage(messagesResult) if (errorMessage) { return `Error fetching messages: ${errorMessage}` } const messages = extractMessages(messagesResult) if (!Array.isArray(messages) || messages.length === 0) { return `Task Result Task ID: ${task.id} Description: ${task.description} Duration: ${formatDuration(task.startedAt ?? new Date(), task.completedAt)} Session ID: ${task.sessionID} --- (No messages found)` } const relevantMessages = messages.filter((m) => m.info?.role === "assistant" || m.info?.role === "tool") if (relevantMessages.length === 0) { return `Task Result Task ID: ${task.id} Description: ${task.description} Duration: ${formatDuration(task.startedAt ?? new Date(), task.completedAt)} Session ID: ${task.sessionID} --- (No assistant or tool response found)` } const sortedMessages = [...relevantMessages].sort((a, b) => { const timeA = getTimeString(a.info?.time) const timeB = getTimeString(b.info?.time) return timeA.localeCompare(timeB) }) const newMessages = consumeNewMessages(task.sessionID, sortedMessages) if (newMessages.length === 0) { const duration = formatDuration(task.startedAt ?? new Date(), task.completedAt) return `Task Result Task ID: ${task.id} Description: ${task.description} Duration: ${duration} Session ID: ${task.sessionID} --- (No new output since last check)` } const extractedContent: string[] = [] for (const message of newMessages) { for (const part of message.parts ?? []) { if ((part.type === "text" || part.type === "reasoning") && part.text) { extractedContent.push(part.text) continue } if (part.type === "tool_result") { const toolResult = part as { content?: string | Array<{ type: string; text?: string }> } if (typeof toolResult.content === "string" && toolResult.content) { extractedContent.push(toolResult.content) continue } if (Array.isArray(toolResult.content)) { for (const block of toolResult.content) { if ((block.type === "text" || block.type === "reasoning") && block.text) { extractedContent.push(block.text) } } } } } } const textContent = extractedContent.filter((text) => text.length > 0).join("\n\n") const duration = formatDuration(task.startedAt ?? new Date(), task.completedAt) return `Task Result Task ID: ${task.id} Description: ${task.description} Duration: ${duration} Session ID: ${task.sessionID} --- ${textContent || "(No text output)"}` }