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
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.
pip install openai2. 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.
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.
export KILN_API_KEY="sk-bk-..."
python chat.pyStreaming chat CLI. Type 'exit' to quit.
> Say hello in five words.
Hello there, nice meeting you!
> exitCheck 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