diff --git a/apps/web/src/app/agents/[id]/chat/[chatId]/page.tsx b/apps/web/src/app/agents/[id]/chat/[chatId]/page.tsx index 5c290bc..f10585e 100644 --- a/apps/web/src/app/agents/[id]/chat/[chatId]/page.tsx +++ b/apps/web/src/app/agents/[id]/chat/[chatId]/page.tsx @@ -227,6 +227,7 @@ export default function PublicAgentChatPage(): React.ReactElement { const [hasMoreMessages, setHasMoreMessages] = useState(false); const [isLoadingMore, setIsLoadingMore] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(true); + const [viewMode, setViewMode] = useState<'chat' | 'debug'>('chat'); // Track first item index for prepending (Virtuoso pattern) const [firstItemIndex, setFirstItemIndex] = useState(10000); @@ -643,32 +644,80 @@ export default function PublicAgentChatPage(): React.ReactElement { {/* Main Chat Area */}
{/* Chat Header */} -
-
+
+
+
+ +
+

{agent.name}

+

+ {PROVIDER_DISPLAY_NAMES[agent.provider]} • {agent.modelId} +

+
+
+ +
+ {/* View Mode Tabs */} +
+ -
-

{agent.name}

-

- {PROVIDER_DISPLAY_NAMES[agent.provider]} • {agent.modelId} -

-
-
- {/* Messages */} -
- {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 },