openai://¶
OpenAI's hosted chat-completions and embeddings API. The canonical
client-side LLM component — sends a single user message (plus an
optional system prompt) to POST /v1/chat/completions or
POST /v1/embeddings and writes the model's text or embedding vector
back onto the exchange body. Reach for this when you want OpenAI itself,
or when you want to talk to a third-party OpenAI-compatible server
(local proxies, OpenAI-style gateways, LM Studio, etc.) — set
baseURL to override the endpoint.
For a list of supported provider-specific schemes built on the same shape (Mistral, Fireworks, Groq, Together, xAI, vLLM, DeepInfra, Hugging Face, etc.), see the providers guide.
URI shape¶
openai://chat?model=<id>&apiKey=<key>&temperature=<float>&maxTokens=<int>&baseURL=<url>
openai://embeddings?model=<id>&apiKey=<key>&baseURL=<url>
The path token (chat or embeddings) is required — openai:// with
no operation is rejected.
Parameters¶
| Param | Type | Default | Used by | Description |
|---|---|---|---|---|
| path | enum | required | both | chat (chat completions) or embeddings (vector embeddings). |
model |
string | gpt-4o |
both | OpenAI model id. Common chat ids: gpt-4o, gpt-4o-mini, gpt-4-turbo, o3. Common embedding ids: text-embedding-3-small, text-embedding-3-large. |
apiKey |
string | (from constructor) | both | OpenAI API key. Sent as Authorization: Bearer <key>. Can also be supplied to openai.NewWithAPIKey at component-registration time. |
baseURL |
string | https://api.openai.com/v1 |
both | Base URL for the API. Override to point at a proxy or compatible server. |
temperature |
float | 0.7 |
chat | Sampling temperature (0.0 = deterministic, ~1.0 = creative). Sent only when non-zero. Reasoning models (o-series, GPT-5) reject non-default values; Helix omits the field entirely on those models. |
maxTokens |
int | 4096 |
chat | Hard cap on completion tokens. Sent as max_tokens on standard models, max_completion_tokens on reasoning models. |
developerMessage |
string | (unset) | chat | OpenAI's developer-role message (sits between system and user; instructions the user shouldn't override). Per-request override via HelixLLMDeveloperMessage header. |
storeFullResponse |
boolean | false |
chat | When true, the full upstream JSON response body is set on the openai.response header (as a string). Useful for downstream auditing / replay. |
dimensions |
int | (unset) | embeddings | Request a reduced embedding dimensionality (text-embedding-3-* only — earlier models ignore). Sent as the OpenAI dimensions field. |
encodingFormat |
enum | float |
embeddings | Wire encoding of the embedding vector. float returns []float64; base64 returns a base64-encoded string body and saves bandwidth. |
Plus the shared LLM-provider params from pkg/component/llmutil
(seed, topP, topK, stop, responseFormat, reasoningEffort,
verbosity — see the LLM providers guide).
No consumer; openai:// is producer-only. See openai-server
if you want to receive OpenAI-format requests from external clients.
Headers¶
The producer reads one optional header from the exchange before the request goes out:
| Header | Used when | Effect |
|---|---|---|
systemPrompt |
chat operation | Prepended as a role: system message. |
After a successful call, the producer sets these headers on the exchange:
| Header | Operation | Description |
|---|---|---|
openai.model |
both | The model id used for the call. |
openai.id |
chat | OpenAI completion id (chatcmpl-...). |
openai.finishReason |
chat | stop, length, content_filter, etc. |
openai.response |
chat | (Only when storeFullResponse=true.) The raw upstream JSON response body, as a string. |
openai.usage.promptTokens |
both | Tokens billed for the prompt. |
openai.usage.completionTokens |
chat | Tokens billed for the completion. |
openai.usage.totalTokens |
both | Sum of prompt + completion (chat); same as promptTokens (embeddings). |
openai.embedding.count |
embeddings | Number of embeddings returned (1 for single-string input, N for batch). |
openai.embedding.dimensions |
embeddings | Echoed back when the URI dimensions= param is set. |
openai.embedding.encoding |
embeddings | Echoed back when encodingFormat=base64 (omitted when default float). |
These plug straight into the cost/tokens reporting stack — see the
observability guide.
Examples¶
Single chat call with a system prompt set upstream:
- id: chat
from: direct://summarize
steps:
- setHeader:
name: systemPrompt
starlang: |
%sl 2.0
output text/plain
---
"You are a terse summariser. Reply in one sentence."
- to: openai://chat?model=gpt-4o&apiKey=${OPENAI_API_KEY}
Embeddings — body in, vector out:
- id: embed
from: direct://embed
steps:
- to: openai://embeddings?model=text-embedding-3-small&apiKey=${OPENAI_API_KEY}
Batch embeddings — []string body in, list of vectors out:
- id: embed-batch
from: direct://embed-batch
steps:
- to: openai://embeddings?model=text-embedding-3-small&apiKey=${OPENAI_API_KEY}
# The body is set upstream to []string{"doc1", "doc2", "doc3"} —
# output body is a []any of three vectors; openai.embedding.count = 3.
Reduced-dimension embeddings (text-embedding-3-* only):
Bandwidth-saving embeddings via encodingFormat=base64:
- to: openai://embeddings?model=text-embedding-3-small&encodingFormat=base64&apiKey=${OPENAI_API_KEY}
Strict policy message via the new developer role:
- to: openai://chat?model=gpt-4o&developerMessage=Always%20respond%20in%20JSON.&apiKey=${OPENAI_API_KEY}
Audit-trail flow — capture the raw OpenAI response for replay/replay:
- to: openai://chat?model=gpt-4o&storeFullResponse=true&apiKey=${OPENAI_API_KEY}
- to: file:audit?fileName=${date:now:yyyyMMdd-HHmmss}.json&body=${header.openai.response}
Point at a third-party OpenAI-compatible endpoint (e.g. an internal proxy):
Behavior notes¶
- HTTP only. This component does not stream — it reads the full JSON
response (capped at 100 MB) and replaces the exchange body with the
assistant message text (or the first embedding vector). For
token-by-token streaming through routes, use the
agentcomponent or a multimodal route step. - Single-turn. The component sends exactly one user turn per call. Multi-turn conversation is the responsibility of the caller — use memory on the agent layer if you need history.
- 120s default timeout on the underlying
http.Client. - No automatic retries. A non-200 response is surfaced as an error;
wrap in a
resilienceprocessor if you need backoff. - Vision is supported directly at the URI seam — see
Multimodal input below. Function calling is
not yet at the URI seam — use the
agentcomponent for that. - The OpenAI model catalogue lists every chat and embedding id that this component will accept.
Multimodal input¶
openai://chat accepts vision input alongside text. The component
detects the input shape from the exchange body and Helix-only headers
listed below, then serialises into OpenAI's image_url content-block
format. Use a vision-capable model (gpt-4o, gpt-4o-mini,
gpt-4-turbo, etc.) — text-only models will reject the request.
Input shapes accepted¶
| Body | Headers | What gets sent |
|---|---|---|
string or []byte (non-image bytes) |
— | Plain text, single message. Wire shape: "content": "..." (back-compat with existing routes). |
[]byte whose first bytes match an image magic header (PNG, JPEG, GIF, WEBP, BMP, TIFF) |
HelixLLMSystemPrompt for the prompt |
Multimodal: "content": [{"type":"image_url","image_url":{"url":"data:image/png;base64,…"}}]. |
*exchange.MultipartContent |
— | Pass-through — caller has structured the input. Each ContentPart becomes a content block in order. |
| Any text body | HelixLLMImages set to an array of URLs OR []ContentPart |
Mixed message: text block first, then one image_url block per image. |
Multimodal headers¶
| Header | Type | Purpose |
|---|---|---|
HelixLLMSystemPrompt |
string | System message. systemPrompt (legacy) still works. |
HelixLLMImages |
[]string (URLs) / []ContentPart / []map[string]any |
Additional images to send alongside the body text. Each entry may be a URL, a {mime_type, data} pair (base64-string data is decoded automatically), or a full ContentPart. |
HelixLLMImageDetail |
"auto" / "high" / "low" |
Propagated to image_url.detail — OpenAI's token-budget knob for image inputs. |
Examples¶
Caption a PNG from disk¶
- id: caption-image
from: file:///inbox?include=.*\.png$
steps:
- set-header:
name: HelixLLMSystemPrompt
constant: "Describe this image in one paragraph."
- to: openai://chat?model=gpt-4o&apiKey=${env:OPENAI_API_KEY}&imageDetail=high
Mixed text + image (URL)¶
- set-body: "Is this medication safe with metformin?"
- set-header:
name: HelixLLMImages
starlang: |
[ "https://internal.example.com/pills/r4291.jpg" ]
- to: openai://chat?model=gpt-4o&apiKey=${env:OPENAI_API_KEY}
Per-page PDF→markdown via direct VLM¶
# Upstream step rendered a PDF page to PNG bytes on the body.
- set-header:
name: HelixLLMSystemPrompt
constant: |
Convert this page to clean Markdown.
Preserve every dosage, route, and frequency verbatim.
Render tables as Markdown tables.
- to: openai://chat?model=gpt-4o&apiKey=${env:OPENAI_API_KEY}&maxTokens=4096&imageDetail=high
GPT-5 / o-series reasoning models¶
The openai:// component auto-detects reasoning-family models by
prefix (o1*, o3*, o4*, gpt-5*) and adapts the wire shape:
| Behaviour | Reasoning model | Legacy model |
|---|---|---|
| Token cap field | max_completion_tokens (auto-renamed) |
max_tokens |
temperature |
omitted from the wire — OpenAI's default 1 applies | sent as set |
reasoning_effort |
sent when set | n/a (OpenAI 400s if sent) |
verbosity |
sent when set (GPT-5+) | n/a |
You no longer need to manually set temperature=1 for reasoning models — Helix omits the field, OpenAI uses its default. Same behaviour across openai://, vlm://?provider=openai, and agent:// with an OpenAI provider.
URI knobs (all OpenAI-shape only — Anthropic / Ollama / Vertex ignore):
| Param | Type | Values |
|---|---|---|
reasoningEffort |
enum | minimal / low / medium / high / xhigh |
verbosity |
enum | low / medium / high |
Per-request overrides via headers:
- HelixLLMReasoningEffort
- HelixLLMVerbosity
# GPT-5 reasoning call — Helix sends max_completion_tokens and omits temperature.
- to: openai://chat
params:
model: gpt-5
apiKey: ${env:OPENAI_API_KEY}
# temperature: not needed — Helix auto-omits for reasoning models
maxTokens: 16384 # → max_completion_tokens on the wire
reasoningEffort: high # minimal | low | medium | high | xhigh
verbosity: medium
seed: 42
responseFormat: json_object
Not yet supported: the Responses API (/v1/responses). For
gpt-5-pro / gpt-5.2-pro that may require it, use the
agent layer or wait for the Responses-API round.
Source¶
pkg/component/openai/openai.gopkg/component/openai/openai_test.go
See also¶
openai-server— the inverse: expose Helix agents under an OpenAI-compatible REST API.anthropic,vertex,bedrock— alternative non-OpenAI clients.mistral,fireworks,groq,together,xai,vllm,deepinfra,huggingface,azure— OpenAI-compatible providers sharing this same request/response shape viapkg/component/llmutil.- providers guide — comparison and selection criteria.