重建会话记录逻辑
This commit is contained in:
+21
-15
@@ -15,6 +15,7 @@ import { type SessionRecord } from "../sessions/metadataStore.js";
|
||||
import { toActorKey, toProjectKey } from "../utils/fileStore.js";
|
||||
import {
|
||||
buildPromptWithLearningContext,
|
||||
extractLatestFrontendTurn,
|
||||
generateSessionTitle,
|
||||
shouldGenerateSessionTitle,
|
||||
} from "./chatSession.js";
|
||||
@@ -205,6 +206,26 @@ export const buildChatRouter = (
|
||||
messages: parsed.data.messages,
|
||||
branchGroups: parsed.data.branch_groups,
|
||||
});
|
||||
const latestTurn = extractLatestFrontendTurn(parsed.data.messages);
|
||||
if (latestTurn) {
|
||||
void learningOrchestrator.onTurnCompleted({
|
||||
...latestTurn,
|
||||
requestContext: {
|
||||
actorKey,
|
||||
clientSessionId: nextRecord.sessionId,
|
||||
projectId,
|
||||
projectKey,
|
||||
traceId: req.header("x-trace-id") ?? `save-${nextRecord.sessionId}`,
|
||||
userId,
|
||||
},
|
||||
sessionId: nextRecord.sessionId,
|
||||
}).catch((error) => {
|
||||
logger.warn(
|
||||
{ err: error, sessionId: nextRecord.sessionId },
|
||||
"post-save learning failed",
|
||||
);
|
||||
});
|
||||
}
|
||||
res.json({
|
||||
id: nextRecord.sessionId,
|
||||
title: nextRecord.title ?? "新对话",
|
||||
@@ -635,21 +656,6 @@ export const buildChatRouter = (
|
||||
);
|
||||
}
|
||||
}
|
||||
if (assistantText) {
|
||||
void learningOrchestrator.onTurnCompleted({
|
||||
assistantMessage: assistantText,
|
||||
model: parsed.data.model,
|
||||
requestContext,
|
||||
sessionId: clientSessionId,
|
||||
toolCallCount: streamResult.toolCallCount,
|
||||
userMessage: parsed.data.message,
|
||||
}).catch((error) => {
|
||||
logger.warn(
|
||||
{ err: error, sessionId: clientSessionId },
|
||||
"post-turn learning failed",
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sessionBridge.finalizeRequest(clientSessionId);
|
||||
|
||||
@@ -254,6 +254,46 @@ const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
const isSyntheticAssistantError = (content: string) =>
|
||||
/^⚠️\s*\*\*(请求已中断|错误[::]?)/.test(content);
|
||||
|
||||
export const extractLatestFrontendTurn = (messages: unknown[] | undefined) => {
|
||||
if (!Array.isArray(messages) || messages.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
||||
const assistant = messages[index];
|
||||
if (!isObjectRecord(assistant) || assistant.role !== "assistant") {
|
||||
continue;
|
||||
}
|
||||
const assistantMessage =
|
||||
typeof assistant.content === "string"
|
||||
? assistant.content.replace(/\s+/g, " ").trim()
|
||||
: "";
|
||||
if (!assistantMessage || isSyntheticAssistantError(assistantMessage)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const user = messages
|
||||
.slice(0, index)
|
||||
.reverse()
|
||||
.find((message) => isObjectRecord(message) && message.role === "user");
|
||||
if (!isObjectRecord(user) || typeof user.content !== "string") {
|
||||
continue;
|
||||
}
|
||||
const userMessage = user.content.replace(/\s+/g, " ").trim();
|
||||
if (!userMessage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return {
|
||||
assistantMessage,
|
||||
toolCallCount: estimateFrontendToolCallCount(assistant),
|
||||
userMessage,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const buildRestoredConversationFromMessages = (messages: unknown[] | undefined) => {
|
||||
if (!Array.isArray(messages) || messages.length === 0) {
|
||||
return "";
|
||||
@@ -299,4 +339,16 @@ const buildRestoredConversationFromMessages = (messages: unknown[] | undefined)
|
||||
"以下为当前前端对话线程中最近的历史对话,请延续其中已确认的目标、约束、结论与引用结果。",
|
||||
trimmedConversation,
|
||||
].join("\n");
|
||||
};
|
||||
};
|
||||
|
||||
const estimateFrontendToolCallCount = (assistant: Record<string, unknown>) => {
|
||||
const progress = Array.isArray(assistant.progress) ? assistant.progress : [];
|
||||
const artifacts = Array.isArray(assistant.artifacts) ? assistant.artifacts : [];
|
||||
const toolProgressCount = progress.filter(
|
||||
(item) =>
|
||||
isObjectRecord(item) &&
|
||||
(item.phase === "tool" ||
|
||||
(typeof item.id === "string" && item.id.startsWith("tool-"))),
|
||||
).length;
|
||||
return Math.max(toolProgressCount, artifacts.length);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user