feat(ai): persist raw tool execution results in postgres to enable fine-tuning dataset extraction

This commit is contained in:
2026-05-16 11:59:46 -07:00
parent dfd799f046
commit f0d7548fe1
2 changed files with 38 additions and 6 deletions

View File

@@ -77,15 +77,23 @@ export default function SessionViewer() {
session_id: sessionId,
title: thread.title,
created_at: thread.createdAt,
messages: messages.map((m) => ({
messages: messages.map((m: any) => ({
role: m.role,
content:
m.content || (m.textSegments ? m.textSegments.join("\n\n") : ""),
tool_calls: m.toolCalls
? m.toolCalls.map((tc) => ({
? m.toolCalls.map((tc: any) => {
const rawResult = m._rawToolResults?.find(
(tr: any) =>
tr.name === tc.name &&
JSON.stringify(tr.args) === JSON.stringify(tc.args),
)?.result;
return {
name: tc.name,
arguments: tc.args,
}))
result: rawResult,
};
})
: undefined,
})),
};

View File

@@ -723,14 +723,38 @@ export async function POST(request: Request) {
// segmentation it shows during streaming. Older messages
// (pre-this-fix) won't have textSegments and fall back to
// single-bubble content rendering.
const finalMsg: ChatMessage & { textSegments?: string[] } = {
const finalMsg: ChatMessage & {
textSegments?: string[];
_rawToolResults?: Array<{ name: string; args: any; result: string }>;
} = {
role: "assistant",
content: assistantText,
toolCalls: assistantToolCalls.length ? assistantToolCalls : undefined,
textSegments: assistantTextSegments.length
? assistantTextSegments
: undefined,
_rawToolResults: assistantToolCalls.length ? [] : undefined,
};
// Option 1 implemented: Save the raw tool results directly into the database row
// alongside the assistant message so it can be extracted later for fine-tuning.
if (finalMsg._rawToolResults) {
// We slice out the tool messages from the internal messages array we just built
// during the loop and attach them to the final row payload.
const toolResults = messages.filter((m) => m.role === "tool");
finalMsg._rawToolResults = assistantToolCalls.map((tc) => {
const tr = toolResults.find((m) => m.toolCallId === tc.id);
return {
name: tc.name,
args: tc.args,
result:
typeof tr?.content === "string"
? tr.content
: JSON.stringify(tr?.content || ""),
};
});
}
await query(
`INSERT INTO fs_chat_messages (thread_id, user_id, data) VALUES ($1, $2, $3)`,
[thread_id, email, JSON.stringify(finalMsg)],