feat: new chat working stateless. Added citation logic.

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2025-12-20 23:15:49 -08:00
parent 24f438a39e
commit 947087452f
10 changed files with 441 additions and 160 deletions

View file

@ -1,74 +0,0 @@
import type { UIMessage } from "ai";
export const maxDuration = 30;
export async function POST(req: Request) {
try {
const body = await req.json();
const {
messages,
chat_id,
search_space_id,
}: {
messages: UIMessage[];
chat_id?: number;
search_space_id?: number;
} = body;
// Get auth token from headers
const authHeader = req.headers.get("authorization");
if (!authHeader) {
return new Response("Unauthorized", { status: 401 });
}
// Get the last user message
const lastUserMessage = messages.filter((m) => m.role === "user").pop();
if (!lastUserMessage) {
return new Response("No user message found", { status: 400 });
}
// Extract text content from the message
const userQuery =
typeof lastUserMessage.content === "string"
? lastUserMessage.content
: lastUserMessage.content
.filter((c: any) => c.type === "text")
.map((c: any) => c.text)
.join(" ");
// Call the DeepAgent backend
const backendUrl = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
const response = await fetch(`${backendUrl}/api/v1/new_chat`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: authHeader,
},
body: JSON.stringify({
chat_id: chat_id || 0,
user_query: userQuery,
search_space_id: search_space_id || 0,
}),
});
if (!response.ok) {
return new Response(`Backend error: ${response.statusText}`, {
status: response.status,
});
}
// The backend returns SSE stream with Vercel AI SDK Data Stream Protocol
// We need to forward this stream to the client
return new Response(response.body, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
},
});
} catch (error) {
console.error("Error in deep-agent-chat route:", error);
return new Response("Internal Server Error", { status: 500 });
}
}

View file

@ -1,17 +1,44 @@
"use client";
import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
import { AssistantRuntimeProvider, useLocalRuntime } from "@assistant-ui/react";
import { useParams } from "next/navigation";
import { useMemo } from "react";
import { Thread } from "@/components/assistant-ui/thread";
import { createNewChatAdapter } from "@/lib/chat/new-chat-transport";
export default function NewChatPage() {
// Using the official assistant-ui pattern - useChatRuntime with NO parameters
// It defaults to /api/chat endpoint
const runtime = useChatRuntime();
const params = useParams();
// Extract search_space_id and chat_id from URL params
const searchSpaceId = useMemo(() => {
const id = params.search_space_id;
const parsed = typeof id === "string" ? Number.parseInt(id, 10) : 0;
return Number.isNaN(parsed) ? 0 : parsed;
}, [params.search_space_id]);
const chatId = useMemo(() => {
const id = params.chat_id;
let parsed = 0;
if (Array.isArray(id) && id.length > 0) {
parsed = Number.parseInt(id[0], 10);
} else if (typeof id === "string") {
parsed = Number.parseInt(id, 10);
}
return Number.isNaN(parsed) ? 0 : parsed;
}, [params.chat_id]);
// Create the adapter with the extracted params
const adapter = useMemo(
() => createNewChatAdapter({ searchSpaceId, chatId }),
[searchSpaceId, chatId]
);
// Use LocalRuntime with our custom adapter
const runtime = useLocalRuntime(adapter);
return (
<AssistantRuntimeProvider runtime={runtime}>
<div className="h-full">
<div className="h-[calc(100vh-64px)] max-h-[calc(100vh-64px)] overflow-hidden">
<Thread />
</div>
</AssistantRuntimeProvider>