Models
Failure Tempest 1All modelsStatus
Research
OverviewAPI fusionEvaluation
Developers
DocumentationConsoleChangelog
Company
PricingEnterpriseAboutSecurityContact
Account
Sign inCreate account
Docs/Streaming
Documentation

Watch it think.

Set stream to true. The working arrives as reasoning_content deltas, the answer as content deltas, and the last chunk carries usage and cost.

Wire format

Streaming uses server-sent events exactly like OpenAI Chat Completions: a series of data: {...} lines with chat.completion.chunk objects, ending with data: [DONE].

  • choices[0].delta.reasoning_content — the pipeline's working, in full: the brief, every draft as it lands (headed ━━ Draft A · verify lens · …), and the audit. Billed as reasoning tokens (usage.completion_tokens_details.reasoning_tokens).
  • choices[0].delta.content — the answer itself.
  • The final chunk carries usage (with cost in USD) and a tempest object.

Passing stream_options: {"include_usage": true} is harmless; the final usage chunk is sent either way.

curl

curl -N https://api.failure.fail/v1/chat/completions \
  -H "Authorization: Bearer $FAILURE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "failure-tempest-1",
    "stream": true,
    "messages": [{"role": "user", "content": "Why does TCP need a three-way handshake?"}]
  }'

Python

import os
from openai import OpenAI

client = OpenAI(base_url="https://api.failure.fail/v1", api_key=os.environ["FAILURE_API_KEY"])

stream = client.chat.completions.create(
    model="failure-tempest-1",
    messages=[{"role": "user", "content": "Why does TCP need a three-way handshake?"}],
    stream=True,
    stream_options={"include_usage": True},
)

answer, working = [], []
final = None
for chunk in stream:
    if chunk.choices:
        delta = chunk.choices[0].delta
        r = getattr(delta, "reasoning_content", None)  # extra field, not in the SDK types
        if r:
            working.append(r)
        if delta.content:
            answer.append(delta.content)
            print(delta.content, end="", flush=True)
    if chunk.usage:
        final = chunk

print()
u = final.usage
print("prompt", u.prompt_tokens, "completion", u.completion_tokens)
print("cached", u.prompt_tokens_details.cached_tokens if u.prompt_tokens_details else 0)
extra = final.model_extra or {}
print("cost", getattr(u, "cost", None), "tempest", extra.get("tempest"))

TypeScript

import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.failure.fail/v1", apiKey: process.env.FAILURE_API_KEY });

const stream = await client.chat.completions.create({
  model: "failure-tempest-1",
  messages: [{ role: "user", content: "Why does TCP need a three-way handshake?" }],
  stream: true,
  stream_options: { include_usage: true },
});

let answer = "";
for await (const chunk of stream) {
  const delta: any = chunk.choices[0]?.delta ?? {};
  if (delta.reasoning_content) process.stderr.write(delta.reasoning_content);
  if (delta.content) {
    answer += delta.content;
    process.stdout.write(delta.content);
  }
  if (chunk.usage) {
    const u: any = chunk.usage;
    console.log("\nusage", u.prompt_tokens, u.completion_tokens, u.prompt_tokens_details?.cached_tokens, "cost", u.cost);
    console.log("tempest", (chunk as any).tempest);
  }
}

The final chunk

{
  "id": "chatcmpl-...",
  "object": "chat.completion.chunk",
  "model": "failure-tempest-1",
  "choices": [],
  "usage": {
    "prompt_tokens": 18,
    "completion_tokens": 412,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 318 },
    "cost": 0.01245
  },
  "tempest": {
    "task": "...",
    "difficulty": "...",
    "stage": "...",
    "cache": "...",
    "billed_usd": 0.01245
  }
}

Illustrative values. The fields are the contract; the numbers are not measurements.

Showing the working

A fused answer on a hard prompt waits for drafts. Show the reasoning_content stream in a collapsible panel so users can see progress, and render content as the answer. Do not feed reasoning_content back into later turns — send only the answer as the assistant message.

Errors mid-stream

Errors before the stream opens arrive as normal HTTP errors (see errors). If the connection drops mid-stream, treat the partial answer as incomplete and retry the whole request.