Skip to content

Chat completions

POST /v1/chat/completions takes a conversation and returns the assistant’s next message. The request and response shapes are OpenAI’s; this page covers what siema_ai does with each field.

from openai import OpenAI
import os
client = OpenAI(base_url="https://api.siema-ai.pl/v1", api_key=os.environ["SIEMA_API_KEY"])
r = client.chat.completions.create(
model="polish-pro",
messages=[
{"role": "system", "content": "Jesteś asystentem działu obsługi klienta sklepu z elektroniką."},
{"role": "user", "content": "Klient pyta, czy może zwrócić otwarte słuchawki po 10 dniach. Odpowiedz uprzejmie."},
],
max_tokens=300,
temperature=0.3,
)
print(r.choices[0].message.content)
print(r.usage) # prompt_tokens, completion_tokens, total_tokens

Set your HTTP client’s own timeout to 180 seconds or more — the gateway’s own budget for a cold start (see Streaming). A shorter client timeout can abandon the request before the model has answered; you’re still charged the estimated input tokens for it, and if your SDK retries on timeout (twice by default), that cost repeats on every retry.

Field What siema_ai does
model Required. An alias from GET /v1/models. An alias that doesn’t exist returns 404 model_not_found. An alias that exists but doesn’t have the chat capability (for example embed) returns 400 invalid_request with param: "model".
messages Required, a non-empty array. Roles system, user, assistant, tool. content is a string, an array of content parts, or null — an assistant message that carries only tool_calls has null content.
stream false returns one JSON object; true returns server-sent events. See Streaming.
stream_options.include_usage When true, the final stream chunk carries usage. The gateway always fetches usage from the model server for billing; this flag only controls whether you see it.
max_tokens, max_completion_tokens Either name works and both mean the same thing: an upper bound on generated tokens, an integer of at least 1 (anything else is 400 invalid_request). A value above the model’s max_output_tokens is clamped silently to that ceiling. Omit the field, or send JSON null, and the model’s ceiling is used. This null-is-absent handling is specific to these two fields: a null model or messages is 400 invalid_request, and every other field’s null is forwarded as sent. Whichever name you send, the value forwarded upstream is always max_tokens.
n, best_of Forwarded unmodified, with no limit applied by siema_ai. The model server may return more than one choice; the output tokens of every choice returned are billed, not just the first.
temperature, top_p, stop, user Forwarded to the model unchanged.
Anything else Forwarded unchanged: tools, tool_choice, response_format, seed, logprobs, presence_penalty, frequency_penalty, and so on. If the model server rejects a field, you get its error back, typically as 400 invalid_request.
Value Meaning
stop The model finished or hit one of your stop sequences.
length Generation hit max_tokens. If you asked for more than max_output_tokens, this is the clamped ceiling, not your number. Ask for a shorter answer or continue the conversation.
tool_calls The model wants to call a tool; see message.tool_calls.
content_filter The model server stopped generation. Rare with open models.

tools and tool_choice pass straight through to the model server unchanged. Whether a given alias actually returns tool_calls in practice isn’t something we promise or have verified for every alias — test tool calling with the alias you plan to use before relying on it in production. If the model server doesn’t support the fields you send, you get its error back as 400 invalid_request.

Image content parts are forwarded to the model server unmodified and unvalidated by the gateway. Only a model whose capabilities include vision understands an image_url part — and no V1 alias has vision today (check GET /v1/models before you build against this). Send images the same way once a vision-capable alias is available:

r = client.chat.completions.create(
model="<a future alias with vision in its capabilities>",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Co jest na tym paragonie? Wypisz pozycje i sumę."},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ..."}},
],
}],
)

Send an image part to an alias without vision and the model server that receives it can’t understand the part; it rejects the request and the gateway surfaces that as 400 invalid_request. Image bytes are forwarded to the model server and, like all prompt content, are never stored.

  • A short system message in Polish (Odpowiadaj po polsku.) is a simple way to keep the reply language consistent across all three chat aliases.
  • Bielik handles formal register well; say formalnie or bezpośrednio when it matters.
  • For structured output, ask for JSON and pass response_format: {"type": "json_object"}; validate the result, as with any model.

Cost in micro-PLN is ceil(prompt_tokens × input_price / 1 000 000) + ceil(completion_tokens × output_price / 1 000 000), each term rounded up separately, at the price in force when the request started. For example, on polish-pro’s current placeholder prices, 2 000 prompt tokens and 500 completion tokens cost 3 000 + 1 500 = 4 500 micro-PLN.

The usage object in the response is what you’re billed for when the model server reports it. When it doesn’t — for instance a stream that breaks before reaching a final usage chunk — siema_ai estimates the tokens instead and marks the request estimated in the console; see Streaming. See Billing for the full picture.