Crux
API ReferenceAdapters

@use-crux/openai

OpenAI SDK adapter, factory pattern with native generation options plus dense embedding helpers.

Peer dependency: openai

import {
  createOpenAI,
  embedding,
  openaiProviderRuntime,
  openAITranscript,
  toMessages,
  fromMessages,
} from "@use-crux/openai";
import { createGenerateObjectFn, createGenerateTextFn } from "@use-crux/openai";

For media workflows, start with Media and multimodal, then use Streaming generated media for streamImage() and streamSpeech(). For text usage and provider comparison, see the Execution guide.

Request capacity and counting

The adapter exposes adapter.capacity(model) and the standalone openAIModelCapacity(model) helper. Capacity lookup is synchronous and never calls the provider.

import { openAIModelCapacity } from "@use-crux/openai";

const profile = openAIModelCapacity("gpt-4o-mini");
Known model-id prefixContext windowDefault output reserve
gpt-5400,000128,000
gpt-4.11,047,57632,768
gpt-4o128,00016,384
gpt-4-turbo128,0004,096
gpt-48,1924,096
gpt-3.5-turbo16,3854,096
o1, o3, o4200,000100,000

Prefix matching includes dated aliases. Unknown identifiers use a conservative 16,384-token window with a 4,096-token reserve. Known profiles report countingConfidence: "estimated"; the fallback reports "conservative".

The adapter does not call a token-count endpoint. Crux estimates the complete request and applies the margin reported by request inspection. Use inputBudget when you need a smaller product limit or earlier optimization.

createOpenAI(client)

Create an adapter bound to an OpenAI client.

createOpenAI() is openaiProviderRuntime.create. The package-owned openAITranscript owns message conversion plus assistant text/tool-call extraction; response metadata normalization, stream deltas, and settings/schema mapping stay in this package too. Crux still owns prompt resolution, tool loops, safety, validation retry, memory capture, and observability.

OpenAI Chat content support maps image parts to image_url, wav/mp3 file parts with data sources to input_audio, and supported file data/provider-file sources to OpenAI file parts. Unsupported model/content combinations throw after prompt resolution and before the client or custom transport runs. Assistant/user media returned in provider content arrays decodes back into canonical ContentPart[]. Chat Completions tool messages remain text-only; when a tool returns media, Crux sends the correlated text tool result followed by native media in a user content part on the same next turn.

The package also exports native generateImage(), streamImage(), transcribe(), generateSpeech(), and streamSpeech() operations. Translation is selected through the transcription task union; requested timing/detail must match the selected endpoint. Returned image/audio assets are usable immediately and are never persisted implicitly. Typed extra records expose endpoint-specific controls. These operations also accept portable canonical Safety options: image and speech expose guardrails/safety, while transcription additionally exposes one-shot output-text constraints. Provider-native raw values remain unguarded; see the content-primitive matrix.

FieldTypeDescription
clientOpenAIThe OpenAI client instance

Returns:

MethodDescription
.generate(prompt, options)Execute a prompt via chat.completions.parse (structured) or .create (text)
.stream(prompt, options)Stream a prompt execution
.generateImage(options)Generate or edit completed images through the native Images API
.transcribe(options)Transcribe or translate audio with requested native detail
.generateSpeech(options)Generate one completed native speech asset
.streamImage(options)Stream genuine Images API preview/final events
.streamSpeech(options)Stream genuine Speech API response-body bytes
.prepare(prompt, options)Prepare a sans-I/O call handle with OpenAI params
.retrievalModel(config)Bind OpenAI generation to core retrieval recipe steps
.reranker(config)Create a judge-backed core Reranker
import { createOpenAI } from "@use-crux/openai";
import OpenAI from "openai";

const adapter = createOpenAI(
  new OpenAI({ apiKey: process.env.OPENAI_API_KEY }),
);

const result = await adapter.generate(editDraft, {
  model: "gpt-4o",
  input: { instruction: "Fix the intro" },
});
result.text;
result.usage;
result.finalStep;

Media uses the same call and message list:

import { prompt } from "@use-crux/core";

const describeChart = prompt({ id: "describe-chart" });

await adapter.generate(describeChart, {
  model: "gpt-4o",
  messages: [
    {
      role: "user",
      content: [
        { type: "text", text: "Describe this chart." },
        {
          type: "image",
          source: new URL("https://example.com/chart.png"),
          providerOptions: { openai: { detail: "high" } },
        },
      ],
    },
  ],
});

adapter.generate(prompt, options)

FieldTypeDescription
promptPromptThe prompt to execute
options.modelstringModel name
options.inputobjectInput values
options.toolsRecord<string, unknown>?Additional Crux tools to merge at call time
options.toolMiddlewareToolMiddleware | readonly ToolMiddleware[]?Tool execution hooks, including Crux resumable approvals through result.messages.
options.toolApprovalToolApprovalMap?Call-site approval policy; exact tool names beat '*'.
options.toolsContextRecord<string, unknown>?Required for composed tools that declare contextSchema; values are Zod-validated before the tool loop starts.
options.runtimeContextunknown?Shared per-run context visible to tool execute, middleware, and function-form toolApproval policies.
options.transport(params, info) => Promise<ChatCompletion>BYO wire call. Crux still owns tools, approvals, validation retry, routing, and timeouts.
options.extra.toolsChatCompletionTool[]?OpenAI-native tools that bypass Crux tool conversion
options.extra.tool_choicestring?OpenAI-native tool selection
options.extra.parallel_tool_callsboolean?Allow parallel tool calls

Returns: normalized Crux generate result with:

  • result.text: extracted assistant text
  • result.usage: accumulated usage when every provider-call step reported usage
  • result.cost: provider-reported cost when available
  • result.finalStep: final provider-call text, usage, finish reason, response id, and actual model id
  • result.raw: raw OpenAI SDK response
  • result._meta: retained trace metadata for observability plumbing

When the prompt has an output schema, the provider-parsed value remains available on result.raw.choices[0].message.parsed.

adapter.stream(prompt, options)

Stream a prompt execution.

FieldTypeDescription
promptPromptThe prompt to execute
options.modelstringModel name
options.inputobjectInput values
options.toolsRecord<string, unknown>?Additional Crux tools to merge at call time
options.toolMiddlewareToolMiddleware | readonly ToolMiddleware[]?Tool execution hooks, including Crux resumable approvals through result.messages.
options.toolApprovalToolApprovalMap?Call-site approval policy; exact tool names beat '*'.
options.toolsContextRecord<string, unknown>?Required for composed tools that declare contextSchema; values are Zod-validated before the tool loop starts.
options.runtimeContextunknown?Shared per-run context visible to tool execute, middleware, and function-form toolApproval policies.
options.extra.toolsChatCompletionTool[]?OpenAI-native tools that bypass Crux tool conversion
options.extra.tool_choicestring?OpenAI-native tool selection
options.extra.parallel_tool_callsboolean?Allow parallel tool calls

Returns: StreamResult<TOutput, TPartial>:

  • result.textStream: published, Safety-final text deltas
  • result.fullStream: every published logical event in canonical order
  • result.partialOutputStream: canonical partial z.input for a structured prompt
  • result.completion: promise resolving to the canonical completion envelope (text, optional object, optional usage, optional cost, steps, finalStep, messages, and pending approvals)
  • result.cancel(reason?): abort the whole logical operation, including the active provider attempt

There is deliberately no raw on a managed stream: a provider stream resolves before terminal Safety and describes only one attempt, so exposing it would bypass guardrail holds, structured occurrence gating, commit gates, and validation retry.

Media operations

Completed and streaming image, transcription, and speech behavior is documented separately in OpenAI media operations. That page owns native endpoints, typed extra controls, model gates, terminal raw types, and stream framing.

toParams(resolved, options) / fromResponse(response)

toParams() converts a ResolvedPrompt plus { model, settings?, extra? } into OpenAI chat-completion params. ResolvedPrompt does not include a model, so options.model is required. fromResponse() normalizes an OpenAI response into Crux AdapterResponse facts.

These codecs are translation-only. Use managed generate()/stream() when Crux should run tools, approvals, validation retry, memory capture, safety, and observability.

adapter.prepare(prompt, options)

Prepare a headless OpenAI call. Crux resolves the prompt and returns public OpenAI params without making the SDK call. Feed a raw OpenAI response back with finish(response), or use step(response) when tools, validation retry, or approval suspension may need another provider turn.

generate(prompt, { ...options, transport }) is the BYO-wire mode where Crux keeps owning the loop and invokes your callback for each OpenAI request. stream() with transport is intentionally unsupported and rejects with CruxTransportStreamUnsupportedError.

adapter.retrievalModel(config)

Create a core RetrievalModel from the adapter instance.

const retrievalModel = adapter.retrievalModel({ model: "gpt-4o-mini" });

Use it as a recipe-level model or step-level model.

adapter.reranker(config)

Create a core Reranker for rerank({ engine }).

const engine = adapter.reranker({
  model: "gpt-4o-mini",
  topN: 12,
});

OpenAI's direct SDK adapter does not expose a native rerank endpoint. adapter.reranker() uses Crux's judgeReranker() over the configured OpenAI model, so each rerank call spends generation tokens.

toMessages(sdkMessages)

Convert OpenAI ChatCompletionMessageParam[] to canonical Message[].

FieldTypeDescription
sdkMessagesChatCompletionMessageParam[]OpenAI SDK messages

Returns: Message[]

fromMessages(messages)

Convert canonical Message[] to OpenAI ChatCompletionMessageParam[].

FieldTypeDescription
messagesMessage[]Canonical messages

Returns: ChatCompletionMessageParam[]

Assistant tool calls become OpenAI tool_calls; tool results become tool role messages with tool_call_id. For rich tool output, that correlated tool message keeps the safe text projection and a following user message carries the native media parts.

openAITranscript is the lower-level NativeTranscriptCodec used by createOpenAI(). The public toMessages() and fromMessages() wrappers delegate to it.

createGenerateObjectFn(client)

Create a provider-native GenerateObjectFn bound only to a client. Every call must supply a non-empty OpenAI model id.

FieldTypeDescription
clientOpenAIOpenAI client instance

Returns: GenerateObjectFn

const generateObject = createGenerateObjectFn(client);
const { object } = await generateObject({
  model: "gpt-4.1-mini",
  messages,
  schema,
});

This helper uses the same native chat profile and media codec as createOpenAI(). It accepts exactly one of prompt or canonical messages, uses OpenAI's structured parse surface, and returns { object }. It does not run Crux prompt resolution, validation retry, safety, tools, memory capture, or instrumentation.

createGenerateTextFn(client, model)

Create a GenerateTextFn bound to a client and model.

FieldTypeDescription
clientOpenAIOpenAI client instance
modelstringModel name

Returns: GenerateTextFn

This helper is also generated from the native chat profile, so text helper calls and adapter calls share request construction and response extraction.

embedding(client, config)

Create a dense Crux embedding backed by client.embeddings.create().

import OpenAI from "openai";
import { embedding } from "@use-crux/openai";

const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const docsEmbedding = embedding(client, {
  name: "docs-embedding",
  model: "text-embedding-3-small",
});

Known OpenAI embedding models infer their default dimensions automatically. For custom model IDs, pass dimensions explicitly. The hosted OpenAI embedding surface is text-only. The helper declares modalities: ['text']; media input throws EmbeddingModalityError before an OpenAI client call.

FieldTypeDescription
clientOpenAIOpenAI client instance
config.namestringStable embedding identifier
config.modelstringOpenAI embedding model
config.dimensionsnumber?Explicit vector dimensionality. Required for unknown/custom model IDs.
config.versionstring?Extra vector-semantic revision for cache invalidation.
config.maxInputTokensnumber?Per-input token ceiling. Defaults to 8192.
config.batch.maxSizenumber?Top-level Crux batch size. Defaults to 100.
config.batch.concurrencynumber?Top-level Crux batch concurrency. Defaults to 1.
config.userstring?Optional OpenAI end-user identifier

The helper fingerprint always includes the model, then appends version when supplied; resolved dimensions participate through the core embedding fingerprint. A user version never replaces model identity, so either change invalidates cached vectors.

Types

import type {
  OpenAIChatRequest,
  OpenAIEmbeddingConfig,
  OpenAIExtra,
} from "@use-crux/openai";

On this page