diff --git a/server.js b/server.js index 1b85be1..b4cd8ab 100644 --- a/server.js +++ b/server.js @@ -40,13 +40,36 @@ app.post('/api/chat', (req, res) => { const env = { ...process.env, CLAUDE_CONFIG_DIR: configDir }; - const proc = spawn(CLAUDE_BIN, ['-p', text, '--model', modelId, '--output-format', 'text'], { + const proc = spawn(CLAUDE_BIN, ['-p', text, '--model', modelId, '--output-format', 'stream-json', '--verbose'], { env, stdio: ['ignore', 'pipe', 'pipe'], }); + let buf = ''; proc.stdout.on('data', (chunk) => { - res.write(`data: ${JSON.stringify({ text: chunk.toString() })}\n\n`); + buf += chunk.toString(); + const lines = buf.split('\n'); + buf = lines.pop(); // keep incomplete line + for (const line of lines) { + if (!line.trim()) continue; + try { + const obj = JSON.parse(line); + // streaming delta + if (obj.type === 'content_block_delta' && obj.delta?.type === 'text_delta') { + res.write(`data: ${JSON.stringify({ text: obj.delta.text })}\n\n`); + } + // fallback: full assistant message + else if (obj.type === 'assistant' && obj.message?.content) { + for (const block of obj.message.content) { + if (block.type === 'text') res.write(`data: ${JSON.stringify({ text: block.text })}\n\n`); + } + } + // error in result + else if (obj.type === 'result' && obj.is_error) { + res.write(`data: ${JSON.stringify({ error: obj.result || 'unknown error' })}\n\n`); + } + } catch (e) {} + } }); let stderrBuf = '';