OpenAI SDK compatibility
The official openai packages for Python and JavaScript, and any client that
speaks the OpenAI HTTP API, work with two configuration changes:
client = OpenAI(base_url="https://api.siema-ai.pl/v1", api_key=os.environ["SIEMA_API_KEY"])Nothing else in your code needs to change for chat completions or streaming,
beyond setting model to a siema_ai alias. Embeddings need the same, plus one
more thing: embed is a different model from whatever you used before, so its
vectors aren’t compatible with ones you already stored (dimensions and
semantics differ — OpenAI’s text-embedding-3-small, for example, returns
1536-dimensional vectors, embed returns 1024). Recompute anything you’ve
already embedded after switching.
Supported endpoints
Section titled “Supported endpoints”| Endpoint | Status |
|---|---|
POST /v1/chat/completions |
Supported, streaming and non-streaming |
POST /v1/embeddings |
Supported |
GET /v1/models, GET /v1/models/{id} |
Supported, with siema_ai extensions |
POST /v1/completions (legacy) |
Not offered |
/v1/responses, /v1/files, /v1/images/*, /v1/audio/*, /v1/fine_tuning/*, /v1/batches, /v1/assistants |
Not offered |
Calling an endpoint we do not offer, or a supported endpoint with the wrong
HTTP method, returns 404 with error.code = "unsupported_endpoint" (calling
one without an API key returns 401 first).
What the gateway changes
Section titled “What the gateway changes”| Field | Behaviour |
|---|---|
model |
Must be a siema_ai alias. Rewritten to the upstream model name internally; responses echo your alias. |
max_tokens, max_completion_tokens |
Both are clamped to the model’s max_output_tokens and sent upstream as max_tokens. Omit either and the clamped ceiling is sent for you. |
stream_options.include_usage |
Usage is always requested from the model server for billing; you receive the usage chunk only if you asked for it. |
max_tokens, max_completion_tokens sent as JSON null |
Treated as absent, not forwarded as a literal null — the model’s ceiling is used. Every other field’s null is forwarded exactly as sent, with two exceptions: a null model or messages is 400 invalid_request rather than being forwarded, and a null stream_options on a streaming request is replaced with {"include_usage": true}. |
OpenAI-Organization, OpenAI-Project and other client headers |
Not forwarded upstream; your API key alone identifies the organisation. |
| Everything else | Forwarded unmodified. |
Differences you may notice
Section titled “Differences you may notice”- Exhausted balance is HTTP 402, not 429. See Errors.
- Error responses carry
request_id, andX-Request-Idis always generated by siema_ai — a client-sent value is ignored, not echoed. - Model objects carry
capabilities,context_length,max_output_tokensandpricing. Clients that validate model objects strictly against OpenAI’s schema should ignore unknown fields (the official SDKs do). - No
X-RateLimit-*response headers;Retry-Afteris sent on 429. nis forwarded with no limit applied; the model server may return more than one choice, and the output tokens of every choice returned are billed.- A mid-stream failure ends the connection with no in-band error event and no
data: [DONE]; see Streaming for detection. - Embeddings
encoding_format: base64works — the official Python SDK requests it by default and decodes it for you; other clients may too. Bothfloatandbase64work. toolsandtool_choiceare forwarded to the model server unchanged, but tool calling isn’t guaranteed for every alias in V1; test with the alias you plan to use before relying on it. See Chat completions.- Model names such as
gpt-4oreturn404 model_not_found. Map them topolish-prooradvancedin your configuration.
Other clients
Section titled “Other clients”Anything with an “OpenAI-compatible base URL” setting works: LangChain
(ChatOpenAI(base_url=...)), LlamaIndex, Vercel AI SDK (createOpenAI({ baseURL })),
LiteLLM (openai/polish-pro with api_base), Open WebUI, Continue, and most
IDE assistants. Set the model name to an alias and the key to your sk-siema- key.
Two client-specific notes, as guidance rather than a promise:
- LlamaIndex’s
OpenAIclass validates the model name against OpenAI’s own list and rejects an alias it doesn’t recognise; useOpenAILikeinstead. - LangChain’s
OpenAIEmbeddingssends pre-tokenized integer arrays by default, which siema_ai’s embeddings endpoint rejects with400 invalid_request(it only accepts strings). Passcheck_embedding_ctx_length=Falseto send plain strings instead.