diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite index 2494383..e457305 100644 Binary files a/packages/drizzle-pkg/db.sqlite and b/packages/drizzle-pkg/db.sqlite differ diff --git a/server/api/agent/chat/index.post.ts b/server/api/agent/chat/index.post.ts index b52cb75..91df98f 100644 --- a/server/api/agent/chat/index.post.ts +++ b/server/api/agent/chat/index.post.ts @@ -4,7 +4,7 @@ import { getCurrentUser, getConfigGlobal, getConfigUser } from "#server/utils/co import { createOpenAI } from "@ai-sdk/openai"; import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { type LanguageModel, type ModelMessage, streamText, stepCountIs } from "ai"; -import { getSessionByIdAndUser, getMessagesBySession, getMaxSortOrder, saveMessage, truncateMessagesAfter, deleteMessage, getMessageById, updateMessageContent, updateMessageParts, touchSession, countAssistantMessages } from "#server/service/agent/session"; +import { getSessionByIdAndUser, getMessagesBySession, getMaxSortOrder, saveMessage, truncateMessagesAfter, deleteMessage, getMessageById, updateMessageContent, updateMessageParts, touchSession, countAssistantMessages, updateSession } from "#server/service/agent/session"; import { getAgentToolsForChat, getAgentToolsBySlugs, executeAgentTool } from "#server/service/agent-tool"; import { getTempTokenFromCookie } from "#server/service/agent/temp-token"; import { checkRateLimit, incrementRateLimit } from "#server/service/agent/rate-limit"; @@ -493,6 +493,7 @@ export default defineEventHandler(async (event) => { } }, onFinish: async ({ finishReason, usage, steps, text: assistantText }) => { + try { if (serverAbortController.signal.aborted) { logger.info("[%s] [AGENT-CHAT] onFinish skipped due to abort", event.context.requestId ?? "-"); unregisterAbortController(sessionId); @@ -616,16 +617,36 @@ export default defineEventHandler(async (event) => { if (!user) { incrementRateLimit(sessionId, ip); const rateLimit = checkRateLimit(sessionId, ip); - setResponseHeaders(event, { - "X-RateLimit-Session-Remaining": String(rateLimit.sessionRemaining), - "X-RateLimit-Ip-Remaining": String(rateLimit.ipRemaining), - }); + try { + setResponseHeaders(event, { + "X-RateLimit-Session-Remaining": String(rateLimit.sessionRemaining), + "X-RateLimit-Ip-Remaining": String(rateLimit.ipRemaining), + }); + } catch {} } - if (shouldGenerateTitle && titleModelId && assistantText.trim().length > 0) { - generateSessionTitle(sessionId, content.trim(), assistantText, titleModelId, user?.id ?? null).catch((e) => { logger.error("[AGENT-CHAT] title gen failed: %s", e?.message ?? e); }); + if (shouldGenerateTitle && assistantText.trim().length > 0) { + if (!user) { + const excerpt = assistantText + .replace(/[#*`_~>\-!\[\]()]/g, "") + .trim() + .replace(/\s+/g, " ") + .slice(0, 20); + logger.info("[%s] [AGENT-TITLE] excerpt attempt: shouldGenerateTitle=%s excerptLen=%d", event.context.requestId ?? "-", shouldGenerateTitle, excerpt.length); + if (excerpt) { + await updateSession(sessionId, { title: excerpt }); + logger.info("[%s] [AGENT-TITLE] sessionId=%s title=%s (excerpt)", event.context.requestId ?? "-", sessionId, excerpt); + } + } else if (titleModelId) { + generateSessionTitle(sessionId, content.trim(), assistantText, titleModelId, user.id).catch((e) => { logger.error("[AGENT-CHAT] title gen failed: %s", e?.message ?? e); }); + } + } else { + logger.debug("[%s] [AGENT-TITLE] skipped: shouldGenerateTitle=%s assistantTextLen=%d", event.context.requestId ?? "-", shouldGenerateTitle, assistantText.trim().length); } unregisterAbortController(sessionId); + } catch (e) { + logger.error("[%s] [AGENT-CHAT] onFinish error: %s", event.context.requestId ?? "-", e?.message ?? e); + } }, onAbort: async () => { try {