From 09020cfa0326cc7675b73098632787ac03376f8e Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Sat, 8 Aug 2026 23:29:47 +0800 Subject: [PATCH] feat: update session handling to include title generation and error logging improvements --- packages/drizzle-pkg/db.sqlite | Bin 1970176 -> 1990656 bytes server/api/agent/chat/index.post.ts | 35 ++++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite index 249438323183a470c8a0fb14037e1e3df5639307..e457305ddc764b4f074a677639e48d0916fdd1c8 100644 GIT binary patch delta 16413 zcmdsdd3;mXov&6~y0&cA0LF$Jvjm#}mW^$ekV!&2S!q}Uoj9?DErX0LgC!eGLa$^j zFW?ohkHN+Z;DyCYVq)2n7drEKeVz7A(!Tc1>r6W{4bi=lJ~J)JG$keL{LVR&d__z! zq0>LcaId6u&hMufh1Ps{UwZ11LW8j=uXwkpA|c<9ldd%;9M0UEzxS2N3PZ6jB`f`iK2KkiwRi6> zQN@w0gNM_T_9kZ*tUqGjIbZ&qe{_TSz}nRG;=GjNOha+u4iSlYeZC<**{m(xn|UZ@ zySPG|wLU%9uy+00>?DId;m7J<&Xe!aB%{#ZsyENjq-(yf*`e8@c~6}-u%COB_`RFFUm@>Z?3sJL-khlvk%oO`;3p&wKDYHAJyNL?m->5 z;bS-bc!hrKq8~fy#}4|joqlX1ALVmytL<}cGrwEU!AYNxE|M_W%!|w#W{&z#>VHxH zP~D|Iq0U$DP_I)*tEDPl^%GT}>a^;xDoyp2YMDwM`uouT8)^@24z+}4g+3p;Ds)!J z?T}xGOoUttsR+pn*%p!#5~ch~`GNAs%4^CxrCIrX%(KhWnn_tPs94d&V(HadoAqgu;pP4bBp-}Gt9IwR#=u~p(0r- zn~D`>Qk8v`Htbn77o|v6PuWBoDy9zNSD7?KOcqopRf@@ixLGDuh{;GD=Vx`PTtpYl z>@ulLL>F8qm5RxNL_sE%h{=NLBwzW+I4q{Yf+CZADW(e&BFPux;ey0SCiy&wOe|uO z&w|KALbli-lYAOPC#p0^?$~3V2y@St+hkwbL$`)~8p$z5k`n1U36sV=!>nK;)E}$= zS$zXIwn|-~-lKj}y;RMpK2-gqYE*SWRiQGfcB(e0SXD^qe*n)8hqi{6hUSEB4NVD+ z4wZ#?Lf#Fz9&#?k5|SPAQb=OReC3x)m+~jd0cE4|P32zYbIR4qIf_pezg7H5aZPbb zaYXU@6N>LB;uSOGx8=W)|E;`7UL!Zl|3?0le7QVa_Mfs}$;N?mPsk3+UXeW^iX5ce%cQx|?dWDkSOTXh(xhpg(X7x!gnu0V&*3-1yTYr&3&QtE*M&bBzBHV{ zx>zC!=-&f5iEE4U)7KYeA5KgyOpz*SJ$>K1)nrZf(bSZ6>3a{QCK*h+1d07MU09eJ zYpOH$+?=pFDL2_PXKiv~R(f%2-d=N7QJz#KuFBN>VbsfysQ+nR3WNKIBHBzFE*}ET5CMa6-wokRfgicB15|I zur4qEfGI~R6W8Qsf!5Zg==90!Ql(N+%@KnkE4`qwC_5obnqHR;B zIO0De4rpAO*TVlX{N=D8hds@-sqYNV%=oo>nRUsYh-8UX^O{txRw^Y*S+i8m-u_&nzr38S;&{Mk`rbDm3-GhAr;yYWHZPOxpJT7k?a(w%t5Xz8-(S zvXPWHt&4Y)v3A`xR*>!_V?7lg??t_Ql?_JQoSSbdEYQPP@$oE-BUF{cP_E%Cc%0AA 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 RNaomW+Fr>rrSik}e*ol)Vaxyk 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 {