- {messages.length === 0 && !streamingContent ? (
+ {/* Debug JSON View */}
+ {viewMode === 'debug' && (
+
+
+
+ Raw Messages Array ({messages.length} messages)
+
+
+ Messages are ordered by createdAt. Each message includes role, content, and tool
+ call data.
+
+
+
+ {JSON.stringify(messages, null, 2)}
+
+
+ )}
+
+ {/* Chat View */}
+ {viewMode === 'chat' && (
+ <>
+ {/* Messages */}
+
+ {messages.length === 0 && !streamingContent ? (
@@ -897,6 +946,8 @@ export default function PublicAgentChatPage(): React.ReactElement {
Press Enter to send, Shift+Enter for new line
+ >
+ )}
diff --git a/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts b/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts
index b14b313..936165e 100644
--- a/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts
+++ b/apps/web/src/app/api/agents/[id]/conversation/[conversationId]/route.ts
@@ -269,6 +269,12 @@ export async function POST(request: NextRequest, context: RouteContext): Promise
// Accumulate tool calls with their input args
const toolCallsMap: Map
=
new Map();
+ // Collect tool results to save AFTER assistant message (for correct chronological order)
+ const pendingToolResults: Array<{
+ toolCallId: string;
+ toolName: string;
+ output: unknown;
+ }> = [];
let inputTokens = 0;
let outputTokens = 0;
@@ -312,7 +318,7 @@ export async function POST(request: NextRequest, context: RouteContext): Promise
}
}
- // Send tool results
+ // Send tool results via SSE but don't save yet (save after assistant message for correct order)
if (toolResults && toolResults.length > 0) {
for (const tr of toolResults) {
sendEvent('tool_result', {
@@ -320,16 +326,11 @@ export async function POST(request: NextRequest, context: RouteContext): Promise
output: tr.output,
});
- // Save tool message to database
- await prisma.message.create({
- data: {
- conversationId: conversation.id,
- role: 'TOOL',
- content: JSON.stringify(tr.output),
- toolCallId: tr.toolCallId,
- toolName: tr.toolName,
- toolResult: tr.output as object,
- },
+ // Collect tool results to save after assistant message
+ pendingToolResults.push({
+ toolCallId: tr.toolCallId,
+ toolName: tr.toolName,
+ output: tr.output,
});
}
}
@@ -360,7 +361,7 @@ export async function POST(request: NextRequest, context: RouteContext): Promise
outputTokens = finalUsage.outputTokens ?? outputTokens;
}
- // Save assistant message
+ // Save assistant message FIRST (so it has earlier createdAt than tool results)
const assistantMessage = await prisma.message.create({
data: {
conversationId: conversation.id,
@@ -376,6 +377,20 @@ export async function POST(request: NextRequest, context: RouteContext): Promise
},
});
+ // Now save TOOL messages (after assistant, for correct chronological order)
+ for (const tr of pendingToolResults) {
+ await prisma.message.create({
+ data: {
+ conversationId: conversation.id,
+ role: 'TOOL',
+ content: JSON.stringify(tr.output),
+ toolCallId: tr.toolCallId,
+ toolName: tr.toolName,
+ toolResult: tr.output as object,
+ },
+ });
+ }
+
// Update conversation timestamp
await prisma.conversation.update({
where: { id: conversation.id },