Skip to Content

Chat

POST /api/chat runs the conversational resume agent (resumate-chat-v2) and streams the reply as SSE. It returns incremental text and, when the agent produces a full revised resume, a resume_update event.

Request

{ "mode": "optimize", "messages": [ { "role": "user", "content": "Make my summary punchier and quantify impact." } ], "currentResume": { "basics": { "name": "Ada Lovelace" }, "work": [] }, "config": { "provider": "openai", "model": "gpt-4o-mini" } }
FieldTypeRequiredNotes
messagesChatMessage[]Non-empty array; each { role, content }. rolesystem · user · assistant · ai
modestringcreate · optimize · analyze · translate · interview · general (default general)
currentResumeobjectThe resume the agent should reason about / edit
configobjectLLM overrides (provider, model, etc.); resolved server-side
contextobjectArbitrary extra context

A 400 is returned if messages is missing or empty.

The agent reads the latest user message as the active instruction; earlier messages are history. mode steers behaviour (e.g. optimize vs analyze) but the message content drives the result.

Response stream

The stream interleaves these event types (see SSE events for the full list):

typeMeaning
run_startedRun created; runId is now valid
message_chunkIncremental assistant text in content — concatenate in order
resume_updateA complete revised resume in data (and payload.resume)
run_completedAgent finished successfully
doneTerminal frame — stop reading
errorSomething failed; error holds the message
data: {"type":"run_started","runId":"clx..."} data: {"type":"message_chunk","content":"Here's a tighter summary…","runId":"clx..."} data: {"type":"resume_update","data":{"basics":{...},"work":[...]},"runId":"clx..."} data: {"type":"run_completed","runId":"clx..."} data: {"type":"done","runId":"clx..."}

Consuming it

const res = await fetch('http://localhost:3112/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ mode: 'optimize', messages: [{ role: 'user', content: 'Tighten my summary.' }], currentResume, }), }) const reader = res.body!.getReader() const decoder = new TextDecoder() let buffer = '' let text = '' for (;;) { const { value, done } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const frames = buffer.split('\n\n') buffer = frames.pop() ?? '' for (const frame of frames) { const dataLine = frame.split('\n').find((l) => l.startsWith('data: ')) if (!dataLine) continue const ev = JSON.parse(dataLine.slice(6)) switch (ev.type) { case 'message_chunk': text += ev.content; break case 'resume_update': onResume(ev.data); break case 'error': throw new Error(ev.error) case 'done': return text } } }

resume_update may arrive before the final message_chunk — the agent emits the revised resume as soon as it can extract a complete document from its output. Treat the events as a stream, not a fixed order.

Last updated on