Streaming an answer
POST /api/v1/ask streams. The response is a sequence of lines, each one a complete JSON object
carrying a type. Read it line by line and act on the types you care about.
curl -N -X POST https://api.bighugger.com/v1/ask \
-H 'authorization: Bearer $BIGHUGGER_API_KEY' \
-H 'content-type: application/json' \
-d '{"question": "which small models run well on an iPhone?"}'
-N matters: without it curl buffers, and you get the whole answer at the end rather than as it
is written.
Event types
type | Fields | When |
|---|---|---|
thread | id, title | First. The thread this question opened. |
status | stage | The run moved to a new stage: planning, searching, then reading. |
plan | queries | The searches the question was turned into. |
sources | hits[] — each with id, title, url, kind | What retrieval found, before the answer is written. |
tool | name, input | The agent started a tool call. |
tool_done | error | That call finished; error is a boolean. |
text | delta | A fragment of the answer. Concatenate these in order. |
done | thread_id, workbook_url, sources | Last on a successful run. |
error | error, message | The run failed. See Errors. |
Reading the stream
Two rules make a client that keeps working:
Concatenate text deltas, in order. They are fragments, not sentences. A delta may split a
word.
Skip types you do not recognise. New event types are added over time and are not a breaking
change. A client that throws on an unknown type will break on a release that adds one; a client
that ignores it will not.
A minimal reader:
const res = await fetch("https://api.bighugger.com/v1/ask", {
method: "POST",
headers: {
authorization: `Bearer ${process.env.BIGHUGGER_API_KEY}`,
"content-type": "application/json",
},
body: JSON.stringify({ question: "which small models run well on an iPhone?" }),
});
let answer = "";
for await (const line of lines(res.body)) {
const event = JSON.parse(line);
switch (event.type) {
case "text": answer += event.delta; break;
case "sources": console.log(`${event.hits.length} sources`); break;
case "done": console.log(answer); break;
case "error": throw new Error(`${event.error}: ${event.message}`);
// Anything else is ignored on purpose.
}
}
Endings
A run ends with exactly one of done or error. A stream that stops without either was cut in
transit — treat it as a failure and retry, remembering that a retried question is billed again.
The whole run is billed once when it finishes, however many stages it passed through.