Skip to content

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):

- to: openai://embeddings?model=text-embedding-3-large&dimensions=256&apiKey=${OPENAI_API_KEY}

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):

- to: openai://chat?model=gpt-4o&baseURL=https://gateway.internal/v1&apiKey=${PROXY_KEY}

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 agent component 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 resilience processor 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 agent component 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.go
  • pkg/component/openai/openai_test.go

See also