import type { Context } from "hono"; import { stream } from "hono/streaming"; import { runAgentTurn } from "../agent/runner"; import { agentOptions } from "../agent-options"; interface ChatMessage { role: string; content: string; } interface ChatCompletionRequest { messages?: ChatMessage[]; stream?: boolean; } function extractLastUserMessage(messages: ChatMessage[]): string | null { for (let i = messages.length - 1; i >= 0; i--) { if (messages[i].role === "user" && messages[i].content) { return messages[i].content; } } return null; } export async function handleChatCompletions(c: Context) { const body = await c.req.json(); if ( !body.messages || !Array.isArray(body.messages) || body.messages.length === 0 ) { return c.json( { error: "messages array is required and must not be empty" }, 400, ); } const userMessage = extractLastUserMessage(body.messages); if (!userMessage) { return c.json({ error: "No user message found in messages array" }, 400); } const opts = await agentOptions(); const result = await runAgentTurn("conversation", { ...opts, customMessage: userMessage, }); const runId = `run_${crypto.randomUUID()}`; const created = Math.floor(Date.now() / 1000); const content = result.success ? result.summary || "Agent completed with no summary." : `Error: ${result.error || "Agent failed"}`; if (body.stream) { return stream(c, async (s) => { c.header("Content-Type", "text/event-stream"); c.header("Cache-Control", "no-cache"); c.header("Connection", "keep-alive"); const chunk = JSON.stringify({ id: runId, object: "chat.completion.chunk", created, model: "clarkling", choices: [ { index: 0, delta: { role: "assistant", content }, finish_reason: "stop", }, ], }); await s.write(`data: ${chunk}\n\n`); await s.write("data: [DONE]\n\n"); }); } return c.json({ id: runId, object: "chat.completion", created, model: "clarkling", choices: [ { index: 0, message: { role: "assistant", content }, finish_reason: "stop", }, ], usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }, }); }