import { json } from '@sveltejs/kit'; import { spawn } from 'child_process'; import type { RequestEvent } from '@sveltejs/kit'; export async function POST({ request }: RequestEvent) { try { const { messages, config } = await request.json(); const lastMsg = messages?.[messages.length - 1]?.content || ''; const modelFlag = config?.model ? ['-m', config.model] : []; const providerFlag = config?.provider ? ['--provider', config.provider] : []; const tempFlag = config?.temperature ? ['--temperature', String(config.temperature)] : []; const maxTokensFlag = config?.maxTokens ? ['--max-tokens', String(config.maxTokens)] : []; const hermes = spawn('hermes', [ 'chat', '-q', lastMsg, ...modelFlag, ...providerFlag, ...tempFlag, ...maxTokensFlag, '-Q', '--source', 'hermes-chat-v2' ], { timeout: 120000, env: { ...process.env } }); const stream = new ReadableStream({ async start(controller) { const decoder = new TextDecoder(); let buffer = ''; const processChunk = (chunk: Buffer) => { buffer += decoder.decode(chunk, { stream: true }); while (buffer.includes('\n')) { const idx = buffer.indexOf('\n'); const line = buffer.slice(0, idx); buffer = buffer.slice(idx + 1); if (line.trim()) { const payload = JSON.stringify({ choices: [{ delta: { content: line + '\n' } }] }); controller.enqueue(new TextEncoder().encode(`data: ${payload}\n\n`)); } } }; hermes.stdout?.on('data', processChunk); hermes.stderr?.on('data', (data: Buffer) => { const text = decoder.decode(data, { stream: true }); if (text.trim()) { const payload = JSON.stringify({ choices: [{ delta: { content: `*${text.trim()}* ` } }] }); controller.enqueue(new TextEncoder().encode(`data: ${payload}\n\n`)); } }); hermes.on('close', () => { if (buffer.trim()) { const payload = JSON.stringify({ choices: [{ delta: { content: buffer } }] }); controller.enqueue(new TextEncoder().encode(`data: ${payload}\n\n`)); } controller.enqueue(new TextEncoder().encode('data: [DONE]\n\n')); controller.close(); }); hermes.on('error', (err) => { controller.enqueue( new TextEncoder().encode( `data: ${JSON.stringify({ error: err.message })}\n\n` ) ); controller.enqueue(new TextEncoder().encode('data: [DONE]\n\n')); controller.close(); }); } }); return new Response(stream, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' } }); } catch (err) { return json( { error: err instanceof Error ? err.message : 'Internal server error' }, { status: 500 } ); } }