// src/tools/chat/summarize.ts // Copyright (C) 2025 DTP Technologies, LLC // All Rights Reserved import type { ToolDefinition } from "../../lib/ai-client.js"; import type { IUser } from "../../models/user.js"; import { DtpTool, type ToolArguments, type ToolContext, } from "../../lib/tool.js"; import { ChatHistory } from "../../models/chat-history.js"; import { ChatSession, ChatSessionMode } from "../../models/chat-session.js"; import AiService from "../../services/ai.js"; export class ChatSummarizeTool extends DtpTool { get name(): string { return "ChatSummarizeTool"; } get slug(): string { return "chat-summarize"; } get metadata() { return { name: this.definition.function.name || "chat_summarize", category: "chat", tags: ["summarize", "session", "overview", "recap"], modes: [ ChatSessionMode.Plan, ChatSessionMode.Build, ChatSessionMode.Test, ChatSessionMode.Ship, ChatSessionMode.Develop, ], }; } public definition: ToolDefinition = { type: "function", function: { name: "chat_summarize", description: "Summarize the conversation in the current or specified session. Returns a concise summary of the key topics, decisions, and outcomes discussed.", parameters: { type: "object", properties: { session_id: { type: "string", description: "Optional: Session ID to summarize. If omitted, summarizes the current session.", }, max_length: { type: "number", description: "Optional: Maximum length of summary in words (default: 100).", }, }, required: [], }, }, }; public async execute( context: ToolContext, args: ToolArguments, ): Promise { const { session_id, max_length = 100 } = args; const user = context.session.user as IUser; const userId = user._id.toHexString(); const currentSessionId = context.session._id.toHexString(); const targetSessionId = (session_id as string | undefined) || currentSessionId; if (!targetSessionId) { return this.error( "MISSING_SESSION", "No session ID provided and no current session context.", ); } try { const session = await ChatSession.findOne({ _id: targetSessionId, user: userId, }); if (!session) { return this.error( "NOT_FOUND", `Session not found: ${targetSessionId}`, { recoveryHint: "Verify the session ID exists and belongs to the current user.", }, ); } const history = await ChatHistory.find({ session: targetSessionId, status: "success", }) .sort({ createdAt: 1 }) .lean(); if (history.length === 0) { return this.success( { summary: "", turnCount: 0 }, "No conversation history found in this session.", ); } const conversationText = history .map((turn) => { let text = `User: ${turn.prompt}\n`; if (turn.response?.message) { text += `Assistant: ${turn.response.message}`; } return text; }) .join("\n\n---\n\n"); const summaryPrompt = `Summarize the following conversation in approximately ${max_length} words or less. Focus on the main topics discussed, any decisions made, and key outcomes. Be concise and factual. Conversation: ${conversationText}`; this.log.debug("Generating summary", { sessionId: targetSessionId, turnCount: history.length, maxLength: max_length, }); const utilityClient = await AiService.getUtilityClient(userId); const utilityModel = await AiService.getUtilityModel(userId); const response = await utilityClient.chat( [{ role: "user", content: summaryPrompt }], [], utilityModel, ); const summary = response.content.trim(); return this.success({ summary }, summary); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.log.error("Failed to summarize session", { sessionId: targetSessionId, error: errorMessage, }); return this.error( "OPERATION_FAILED", `Failed to generate summary: ${errorMessage}`, { recoveryHint: "Try again with a smaller max_length, or proceed without a summary.", }, ); } } } export default new ChatSummarizeTool();