| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- import {
- createUIMessageStream,
- createUIMessageStreamResponse,
- type UIMessage,
- } from "ai";
- import { pipeJsonRender } from "@json-render/core";
- import { getSession, dropSession } from "@/lib/agent";
- import { DEFAULT_AGENT_ID, isAgentId } from "@/lib/agents";
- // Harness turns are long: the agent boots a sandbox, edits files, and runs
- // commands before answering.
- export const maxDuration = 600;
- function lastUserText(messages: UIMessage[]): string | null {
- for (let i = messages.length - 1; i >= 0; i--) {
- const message = messages[i];
- if (message?.role !== "user") continue;
- const text = message.parts
- .filter((part) => part.type === "text")
- .map((part) => part.text)
- .join("\n")
- .trim();
- return text.length > 0 ? text : null;
- }
- return null;
- }
- export async function POST(req: Request) {
- const body = await req.json();
- const chatId: string = body.id ?? "default";
- const messages: UIMessage[] = body.messages ?? [];
- const prompt = lastUserText(messages);
- if (!prompt) {
- return new Response(
- JSON.stringify({ error: "a user message with text is required" }),
- { status: 400, headers: { "Content-Type": "application/json" } },
- );
- }
- // The agent is chosen on the first message and locked for the chat: an
- // existing session ignores `body.agent` and keeps its original agent.
- const requestedAgent = isAgentId(body.agent) ? body.agent : DEFAULT_AGENT_ID;
- // The harness session owns its own conversation history, so each turn
- // sends only the fresh user input -- not the whole transcript.
- const { session, agent } = await getSession(chatId, requestedAgent);
- const result = await agent.stream({ prompt, session });
- const stream = createUIMessageStream({
- execute: async ({ writer }) => {
- writer.merge(pipeJsonRender(result.toUIMessageStream()));
- },
- });
- return createUIMessageStreamResponse({ stream });
- }
- export async function DELETE(req: Request) {
- const { searchParams } = new URL(req.url);
- const chatId = searchParams.get("id") ?? "default";
- dropSession(chatId);
- return new Response(null, { status: 204 });
- }
|