openai
js/ai/model/openai.ts
fino:ai/model/openai — OpenAI provider adapter for the shared Model interface.
OpenAI API reference: https://platform.openai.com/docs/api-reference
openai() returns a provider-neutral Model backed by OpenAI chat
completions and embeddings. openaiProvider() returns a discovery-capable
provider that calls GET /models on an OpenAI-compatible base URL and can
construct models from discovered ids. Both paths translate Fino message parts
into OpenAI content blocks, map streamed chunks into StreamEvent values,
normalize usage and stop reasons, and expose native JSON Schema
response-format support through model capabilities.
Defaults and limits
apiKey defaults to OPENAI_API_KEY, baseUrl defaults to the public
OpenAI API, and model defaults to gpt-4o. The adapter uses
text-embedding-3-small for embed() and returns embeddings in input order
even when the provider response is unordered. Provider HTTP failures throw
ModelError with the response status and body.
Pass a custom client for tests, proxies, or runtimes that need their own
HTTP transport. This adapter does not retry; retry and fallback policy belong
to fino:ai/agent.
import { agent } from 'fino:ai/agent';
import { openaiProvider } from 'fino:ai/model/openai';
const [info] = await openaiProvider().listModels();
const bot = agent({
model: await info.create({ temperature: 0.2 }),
instructions: 'Answer with one concise paragraph.',
});
const result = await bot.generate('Explain durable agent sessions.');
console.log(result.text);
Functions
function openaiProvider(opts: ProviderOptions = {}): ModelProvider
Create an OpenAI-compatible model provider.
listModels() calls GET /models on baseUrl, which defaults to the
public OpenAI /v1 API base URL. OpenAI-compatible gateways (vLLM, Ollama,
LiteLLM, and similar) can override baseUrl and keep the same discovery
shape. Each returned ModelInfo carries the raw listing entry in
metadata and a create() shortcut that builds the model with the
provider's credentials and defaults; createModel(id, opts) does the same
for an id you already know. Options passed to create()/createModel()
override the provider-level defaults per model.
Throws immediately if no API key is given and OPENAI_API_KEY is unset.
listModels() throws ModelListingUnsupportedError when the endpoint
responds 404 (a compatible gateway without a listing route) and ModelError
for any other non-2xx response.
import { openaiProvider } from 'fino:ai/model/openai';
const provider = openaiProvider({
baseUrl: 'http://localhost:8000/v1',
apiKey: 'sk-local',
});
const models = await provider.listModels();
console.log(models.map((m) => m.id));
const model = await provider.createModel(models[0].id, { temperature: 0 });
const result = await model.generate({
messages: [{ role: 'user', content: 'Summarize the release notes.' }],
});
console.log(result.text);
function openai(opts: ProviderOptions = {}): Model
Create an OpenAI-backed Model.
model defaults to gpt-4o and apiKey defaults to OPENAI_API_KEY;
construction throws if neither the option nor the environment variable
provides a key. Sampling options (maxTokens, temperature, topP,
seed) become model-level defaults that individual generate() and
stream() requests may override, and providerOptions.openai entries are
merged verbatim into every request body for provider-specific knobs.
generate() and stream() call POST /chat/completions; embed() calls
POST /embeddings with text-embedding-3-small and returns one
Float32Array per input, in input order. Non-2xx responses throw
ModelError carrying the status and response body. Override client in
tests or custom runtimes that provide their own HTTP transport.
import { openai } from 'fino:ai/model/openai';
const model = openai({ model: 'gpt-4o-mini', temperature: 0.3 });
const result = await model.generate({
system: 'You are a terse changelog writer.',
messages: [{ role: 'user', content: 'Describe the 2.1 release.' }],
});
console.log(result.text, result.usage);
const stream = model.stream({
messages: [{ role: 'user', content: 'Draft the announcement post.' }],
});
for await (const event of stream) {
if (event.type === 'text_delta') console.log(event.text);
}