Wire mic through Whisper-compatible transcriptions on LLM_BASE_URL. Photos upload to MinIO and reach the vision model as base64 image_url parts.
93 lines
2.6 KiB
TypeScript
93 lines
2.6 KiB
TypeScript
import { apiError, apiJson } from "@/lib/api-handler";
|
|
import { resolveApiAuth } from "@/lib/api-auth";
|
|
import { getAssistantPreferences, resolveAssistantSystemPrompt } from "@/lib/assistant-preference";
|
|
import { isLlmConfigured } from "@/lib/llm";
|
|
import { clientChatInputSchema } from "@/modules/agent/messages";
|
|
import { encodeSseEvent } from "@/modules/agent/server/progress";
|
|
import { runAgentChat } from "@/modules/agent/server/run";
|
|
|
|
export async function POST(request: Request) {
|
|
const auth = await resolveApiAuth(request);
|
|
if (!auth?.userId) {
|
|
return apiError("Unauthorized", 401);
|
|
}
|
|
|
|
const assistant = await getAssistantPreferences(auth.userId);
|
|
if (!assistant.enabled) {
|
|
return apiError("Assistant not enabled", 403);
|
|
}
|
|
|
|
const systemPrompt = resolveAssistantSystemPrompt(assistant.systemPrompt);
|
|
|
|
let body: unknown;
|
|
try {
|
|
body = await request.json();
|
|
} catch {
|
|
return apiError("Invalid JSON body", 400);
|
|
}
|
|
|
|
const parsed = clientChatInputSchema.safeParse(body);
|
|
if (!parsed.success) {
|
|
return apiError(parsed.error.issues[0]?.message ?? "Validation error", 400);
|
|
}
|
|
|
|
if (parsed.data.stream) {
|
|
const stream = new ReadableStream<Uint8Array>({
|
|
async start(controller) {
|
|
const encoder = new TextEncoder();
|
|
const send = (event: Parameters<typeof encodeSseEvent>[0]) => {
|
|
controller.enqueue(encoder.encode(encodeSseEvent(event)));
|
|
};
|
|
|
|
try {
|
|
const result = await runAgentChat({
|
|
messages: parsed.data.messages,
|
|
request,
|
|
systemPrompt,
|
|
onProgress: send,
|
|
});
|
|
|
|
send({
|
|
type: "done",
|
|
message: {
|
|
role: "assistant",
|
|
content: result.message.content,
|
|
},
|
|
toolCalls: result.toolCalls,
|
|
});
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : "Agent request failed";
|
|
send({ type: "error", message });
|
|
} finally {
|
|
controller.close();
|
|
}
|
|
},
|
|
});
|
|
|
|
return new Response(stream, {
|
|
headers: {
|
|
"Content-Type": "text/event-stream; charset=utf-8",
|
|
"Cache-Control": "no-cache, no-transform",
|
|
Connection: "keep-alive",
|
|
},
|
|
});
|
|
}
|
|
|
|
try {
|
|
const result = await runAgentChat({
|
|
messages: parsed.data.messages,
|
|
request,
|
|
systemPrompt,
|
|
});
|
|
|
|
return apiJson({
|
|
...result,
|
|
configured: isLlmConfigured(),
|
|
provider: isLlmConfigured() ? "openai" : "mock",
|
|
});
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : "Agent request failed";
|
|
return apiError(message, 502);
|
|
}
|
|
}
|