Skip to content
View as Markdown

Streaming chat CLI quickstart

Goal

Build a terminal chat client that prints Kiln's reply as it streams in, one token at a time, instead of waiting for the whole response.

Outcome

A runnable Python script, chat.py, that keeps a conversation history, sends each line you type as a new user turn, and streams the assistant's reply to your terminal as it is generated.

Copy this prompt for your agent

prompt
Write a Python CLI named chat.py that: reads KILN_API_KEY (required) and KILN_BASE_URL (optional, default "https://api.bricksum.com/v1") from the environment, creates an OpenAI client pointed at that base URL, keeps a `messages` list, and loops reading a line from stdin. Each line becomes a user message. Call client.chat.completions.create with model="qwen3-32b", stream=True and max_tokens=800, print chunk.choices[0].delta.content as each chunk arrives, then append the full reply as an assistant message only if it is non-empty. Exit the loop when the input is "exit".

Prerequisites

  • Python 3.10 or later and the openai package (pip install openai). The openai release this page was verified with requires 3.10; on 3.9, pip silently installs an older major version.
  • A Kiln API key from Console → API keys, exported as KILN_API_KEY.

1. Install the SDK

The official OpenAI Python client is the streaming CLI's only dependency.

bash
pip install openai

2. Write chat.py

Save the script below. It reads one line at a time, sends it as a user turn, and prints each delta as it streams instead of waiting for the finished reply.

python
import os
from openai import OpenAI

client = OpenAI(
    base_url=os.environ.get("KILN_BASE_URL", "https://api.bricksum.com/v1"),
    api_key=os.environ["KILN_API_KEY"],  # sk-bk-...
)
messages = []

print("Streaming chat CLI. Type 'exit' to quit.")
while True:
    user_input = input("> ")
    if user_input.strip().lower() == "exit":
        break
    messages.append({"role": "user", "content": user_input})

    stream = client.chat.completions.create(
        model="qwen3-32b",
        messages=messages,
        stream=True,
        max_tokens=800,
    )
    reply = ""
    for chunk in stream:
        delta = chunk.choices[0].delta.content or ""
        print(delta, end="", flush=True)
        reply += delta
    print()
    if reply:
        messages.append({"role": "assistant", "content": reply})

3. Run it

Export your key and run the script. Type a message and press Enter; the reply prints progressively. Type exit to quit.

bash
export KILN_API_KEY="sk-bk-..."
python chat.py
expected output
Streaming chat CLI. Type 'exit' to quit.
> Say hello in five words.
Hello there, nice meeting you!
> exit

Check your work

Send a message and watch the reply print word by word instead of appearing all at once. Send a follow-up (for example, "summarize that in one line") and confirm the reply refers back to the first turn — that's the messages list carrying history. If a reply comes back as an empty line, the model spent the whole max_tokens budget on reasoning before it wrote any text (finish_reason "length"): raise max_tokens above 800 in chat.py, for example to 1600, and ask again.

Next steps

  • Streaming — the SSE event format, keepalive comments and how cost is added to the final chunk
  • Tool calling, end to end — give the same client a tool it can call mid-conversation
Note
Snippets on this page were run against the Kiln API on 2026-09-21 with openai 3.16.2 (Python 3.14.7). Not verified: The automated snippet sweep cannot feed input to this interactive script; it was run by hand instead, with the same interpreter and SDK version above, on gpt-oss-120b. The script now names qwen3-32b, which it has not yet been run against.