Set "stream": true. The response is Content-Type: text/event-stream: lines of data: {chat.completion.chunk} separated by blank lines.
: keepalive
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","model":"arlo","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","model":"arlo","choices":[{"index":0,"delta":{"content":"Hel"},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","model":"arlo","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","model":"arlo","choices":[],"usage":{"prompt_tokens":120,"completion_tokens":12,"total_tokens":132}}
data: [DONE]- The first chunk has
delta.role. Text arrives indelta.content. - A chunk with
finish_reasonends the answer. Withstream_options.include_usagea final chunk with emptychoicesandusagefollows. - The stream ends with
data: [DONE]. - Comment lines (such as
: keepalive) may appear at any time. Ignore lines that do not start withdata:.
If the model is asleep
Artemii's models run on machines that switch off when idle. A streamed request simply stays open while the machine starts, for up to 8 minutes, and the answer follows with no retry needed. A non-streamed request waits up to the gateway's limit and then answers 503 model_starting with Retry-After.
Errors after the stream began
The HTTP status is already 200, so a failure arrives as a data line, followed by [DONE]:
data: {"error":{"message":"...","type":"server_error","code":"upstream_error"}}
data: [DONE]The SDK throws an ArtemiiError for this. If you parse by hand, check for error on every chunk.
Examples
curl
curl -N https://mayfair-ai.crelloo.workers.dev/v1/chat/completions \
-H "Authorization: Bearer $ARTEMII_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"arlo","stream":true,"messages":[{"role":"user","content":"Hello"}]}'JavaScript with the SDK
import { createClient } from './artemii.js';
const ai = createClient({ baseUrl: 'https://mayfair-ai.crelloo.workers.dev', apiKey: process.env.ARTEMII_KEY });
for await (const part of ai.chat({ model: 'arlo', stream: true, messages: [{ role: 'user', content: 'Tell me a story' }] })) {
process.stdout.write(part.choices[0]?.delta?.content ?? '');
}
// or collect the whole text and render each piece as it arrives
const text = await ai.chatText({ model: 'arlo', messages: [{ role: 'user', content: 'Hello' }] }, (piece) => process.stdout.write(piece));
console.log('\n' + text.length + ' characters');JavaScript with plain fetch
// Plain fetch, Node 18+ or any runtime with streams. No SDK needed.
const res = await fetch('https://mayfair-ai.crelloo.workers.dev/v1/chat/completions', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.ARTEMII_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'arlo', stream: true, stream_options: { include_usage: true }, messages: [{ role: 'user', content: 'Hello' }] }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const decoder = new TextDecoder();
let buffer = '';
for await (const chunk of res.body) {
buffer += decoder.decode(chunk, { stream: true });
let end;
while ((end = buffer.indexOf('\n\n')) >= 0) {
const event = buffer.slice(0, end);
buffer = buffer.slice(end + 2);
for (const line of event.split('\n')) {
if (!line.startsWith('data:')) continue; // ": keepalive" comment lines
const data = line.slice(5).trim();
if (data === '[DONE]') continue;
const part = JSON.parse(data);
if (part.error) throw new Error(part.error.message); // a failure after the stream began
process.stdout.write(part.choices[0]?.delta?.content ?? '');
}
}
}
console.log();Python
import os
from openai import OpenAI
client = OpenAI(base_url="https://mayfair-ai.crelloo.workers.dev/v1", api_key=os.environ["ARTEMII_KEY"])
stream = client.chat.completions.create(model="arlo", stream=True, messages=[{"role": "user", "content": "Hello"}])
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="")
print()Stopping early
Close the connection (abort the request). With the SDK pass signal to chat(). The gateway counts what was produced.