优化会话标题生成逻辑,增加消息限制与格式处理

This commit is contained in:
2026-05-20 17:51:59 +08:00
parent f24e8109a0
commit 4870e8a577
+32 -11
View File
@@ -4,7 +4,10 @@ import { type OpencodeRuntimeAdapter } from "../runtime/opencode.js";
import { collectTextContent } from "./chatStream.js"; import { collectTextContent } from "./chatStream.js";
const TITLE_PROMPT_TIMEOUT_MS = 2500; const TITLE_PROMPT_TIMEOUT_MS = 5000;
const TITLE_CONTEXT_MESSAGE_LIMIT = 40;
const TITLE_CONTEXT_CHAR_LIMIT = 2400;
const TITLE_CONTEXT_MESSAGE_CHAR_LIMIT = 240;
const buildSessionTitle = (message: string) => { const buildSessionTitle = (message: string) => {
const normalized = message.replace(/\s+/g, " ").trim(); const normalized = message.replace(/\s+/g, " ").trim();
@@ -18,7 +21,7 @@ const buildTitleConversationContext = async (
runtime: OpencodeRuntimeAdapter, runtime: OpencodeRuntimeAdapter,
sessionId: string, sessionId: string,
) => { ) => {
const messages = await runtime.messages(sessionId, 12); const messages = await runtime.messages(sessionId, TITLE_CONTEXT_MESSAGE_LIMIT);
const recentMessages = messages const recentMessages = messages
.filter( .filter(
(message) => (message) =>
@@ -26,19 +29,35 @@ const buildTitleConversationContext = async (
) )
.map((message) => ({ .map((message) => ({
role: message.info.role, role: message.info.role,
content: collectTextContent(message.parts).replace(/\s+/g, " ").trim(), content: collectTextContent(message.parts)
.replace(/\s+/g, " ")
.trim()
.slice(0, TITLE_CONTEXT_MESSAGE_CHAR_LIMIT),
})) }))
.filter((message) => message.content.length > 0) .filter((message) => message.content.length > 0);
.slice(-6);
if (recentMessages.length === 0) { if (recentMessages.length === 0) {
return ""; return "";
} }
return recentMessages const formattedMessages = recentMessages.map(
.map((message) => `${message.role === "user" ? "用户" : "助手"}${message.content}`) (message) => `${message.role === "user" ? "用户" : "助手"}${message.content}`,
.join("\n") );
.slice(0, 2400); const fullConversation = formattedMessages.join("\n");
if (fullConversation.length <= TITLE_CONTEXT_CHAR_LIMIT) {
return fullConversation;
}
const headCount = Math.min(4, formattedMessages.length);
const tailCount = Math.min(8, Math.max(0, formattedMessages.length - headCount));
const middleOmitted = formattedMessages.length > headCount + tailCount;
const summary = [
...formattedMessages.slice(0, headCount),
...(middleOmitted ? ["……(中间省略若干轮对话)"] : []),
...formattedMessages.slice(-tailCount),
].join("\n");
return summary.slice(0, TITLE_CONTEXT_CHAR_LIMIT);
}; };
const normalizeGeneratedTitle = (rawTitle: string, fallback: string) => { const normalizeGeneratedTitle = (rawTitle: string, fallback: string) => {
@@ -75,15 +94,17 @@ export const generateSessionTitle = async (
titleSession.id, titleSession.id,
[ [
"你是会话标题生成器。", "你是会话标题生成器。",
"请根据用户问题生成一个 8-16 字中文标题。", "请根据下面整段多轮对话生成一个 8-16 字中文标题。",
"要求:简洁、可读、避免标点、不要引号、不要解释。", "要求:简洁、可读、避免标点、不要引号、不要解释。",
"请优先概括最近这轮对话的核心任务或结论。", "先理解完整对话,再概括核心任务或结论。",
"不要直接照抄用户任一条消息原文。",
"只输出标题本身。", "只输出标题本身。",
"", "",
conversation, conversation,
].join("\n"), ].join("\n"),
) )
.then(async () => { .then(async () => {
await runtime.waitForSessionIdle(titleSession.id, TITLE_PROMPT_TIMEOUT_MS);
const messages = await runtime.messages(titleSession.id, 20); const messages = await runtime.messages(titleSession.id, 20);
const assistantMessage = [...messages] const assistantMessage = [...messages]
.reverse() .reverse()