gadget/docs/archive/tools/chat/summarize.ts

167 lines
4.6 KiB
TypeScript

// 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<string> {
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();