426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
230 lines
10 KiB
Markdown
230 lines
10 KiB
Markdown
# @elizaos/plugin-openai
|
|
|
|
OpenAI model-provider plugin for [elizaOS](https://github.com/elizaos/eliza). Adds text generation, embeddings, image generation, image description, audio transcription, text-to-speech, and deep research to any Eliza agent by registering handlers for the standard `ModelType.*` slots on the `AgentRuntime`.
|
|
|
|
## What this plugin does
|
|
|
|
- **Text generation** — multiple tiers (nano, small, medium, large, mega), plus dedicated response-handler and action-planner slots. Supports streaming and structured JSON output.
|
|
- **Text embeddings** — `text-embedding-3-small` by default; dimension configurable.
|
|
- **Image generation** — DALL-E 3 by default (`dall-e-3`).
|
|
- **Image description** — vision model analyzes an image URL and returns `{ title, description }`.
|
|
- **Audio transcription** — speech-to-text (`gpt-5-mini-transcribe` by default); accepts `Buffer`, `Blob`, `File`, or a URL.
|
|
- **Text-to-speech** — returns an `ArrayBuffer` of audio. Six voices; mp3/wav/flac/opus/aac/pcm output.
|
|
- **Deep research** — `ModelType.RESEARCH` via the OpenAI Responses API (`o3-deep-research` by default); returns annotated, multi-source research reports.
|
|
- **Tokenizer** — encode/decode using js-tiktoken (browser-safe, no network calls).
|
|
|
|
Works with any OpenAI-compatible endpoint: OpenAI, Cerebras, EvoLink, OpenRouter, local servers, etc.
|
|
|
|
## Enabling the plugin
|
|
|
|
Add `@elizaos/plugin-openai` to your character's plugin list:
|
|
|
|
```json
|
|
{
|
|
"plugins": ["@elizaos/plugin-openai"]
|
|
}
|
|
```
|
|
|
|
The plugin auto-enables when `OPENAI_API_KEY`, `CEREBRAS_API_KEY`, or `EVOLINK_API_KEY` is present in the environment.
|
|
|
|
## Required configuration
|
|
|
|
```
|
|
OPENAI_API_KEY=sk-...
|
|
```
|
|
|
|
That is the only required setting. All other settings are optional overrides.
|
|
|
|
## Full configuration reference
|
|
|
|
Set these as environment variables or in your character's `settings` object.
|
|
|
|
### API endpoint
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_BASE_URL` | `https://api.openai.com/v1` | Override for compatible endpoints |
|
|
| `ELIZA_PROVIDER` | — | Set to `cerebras` or `evolink` to force a compatible-provider mode |
|
|
| `EVOLINK_API_KEY` | — | Auth for EvoLink's OpenAI-compatible endpoint |
|
|
| `EVOLINK_BASE_URL` | `https://direct.evolink.ai/v1` | EvoLink endpoint used when `EVOLINK_API_KEY` enables the plugin |
|
|
| `EVOLINK_MODEL` | `gpt-5.2` | Text model used by EvoLink mode |
|
|
|
|
### Text generation models
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_SMALL_MODEL` / `SMALL_MODEL` | `gpt-5.4-mini` | Fast, cost-effective responses |
|
|
| `OPENAI_NANO_MODEL` / `NANO_MODEL` | falls back to small | Fastest tier |
|
|
| `OPENAI_MEDIUM_MODEL` / `MEDIUM_MODEL` | falls back to small | Mid-tier |
|
|
| `OPENAI_LARGE_MODEL` / `LARGE_MODEL` | `gpt-5` | Complex reasoning |
|
|
| `OPENAI_MEGA_MODEL` / `MEGA_MODEL` | falls back to large | Highest tier |
|
|
| `OPENAI_RESPONSE_HANDLER_MODEL` | falls back to small | Response-handler slot |
|
|
| `OPENAI_ACTION_PLANNER_MODEL` | falls back to medium | Action-planner slot |
|
|
| `OPENAI_REASONING_EFFORT` | — | `minimal`/`low`/`medium`/`high` for o-series models |
|
|
|
|
### Embeddings
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model |
|
|
| `OPENAI_EMBEDDING_URL` | `OPENAI_BASE_URL` | Separate endpoint for embeddings |
|
|
| `OPENAI_EMBEDDING_API_KEY` | `OPENAI_API_KEY` | Separate key for embeddings |
|
|
| `OPENAI_EMBEDDING_DIMENSIONS` | `1536` | Vector dimensions (must match model) |
|
|
|
|
### Image generation and description
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_IMAGE_MODEL` | `dall-e-3` | Image generation model |
|
|
| `OPENAI_IMAGE_DESCRIPTION_MODEL` | `gpt-5-mini` | Vision/description model |
|
|
| `OPENAI_IMAGE_DESCRIPTION_BASE_URL` | `OPENAI_BASE_URL` | Separate endpoint for vision |
|
|
| `OPENAI_IMAGE_DESCRIPTION_API_KEY` | `OPENAI_API_KEY` | Separate key for vision |
|
|
| `OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS` | `8192` | Max tokens in description response |
|
|
|
|
### Audio
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_TRANSCRIPTION_MODEL` | `gpt-5-mini-transcribe` | Speech-to-text model |
|
|
| `OPENAI_TTS_MODEL` | `tts-1` | Text-to-speech model |
|
|
| `OPENAI_TTS_VOICE` | `nova` | Voice: alloy, echo, fable, onyx, nova, shimmer |
|
|
| `OPENAI_TTS_INSTRUCTIONS` | — | Style instructions for TTS |
|
|
|
|
### Deep research
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_RESEARCH_MODEL` | `o3-deep-research` | Research model (o3 or o4-mini variants) |
|
|
| `OPENAI_RESEARCH_TIMEOUT` | `3600000` (1 hr) | Request timeout in milliseconds |
|
|
|
|
### Browser and proxy
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_BROWSER_BASE_URL` | — | Proxy URL for browser builds (keeps key server-side) |
|
|
| `OPENAI_BROWSER_EMBEDDING_URL` | — | Proxy URL for browser embedding requests |
|
|
| `OPENAI_ALLOW_BROWSER_API_KEY` | `false` | Send auth header in browser builds (opt-in) |
|
|
|
|
### Other
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `OPENAI_EXPERIMENTAL_TELEMETRY` | `false` | Enable AI SDK experimental telemetry |
|
|
|
|
## Usage examples
|
|
|
|
```ts
|
|
import { ModelType } from "@elizaos/core";
|
|
|
|
// Text generation
|
|
const reply = await runtime.useModel(ModelType.TEXT_LARGE, {
|
|
prompt: "Explain quantum entanglement in plain English.",
|
|
});
|
|
|
|
// Streaming text
|
|
const result = await runtime.useModel(ModelType.TEXT_LARGE, {
|
|
prompt: "Count from 1 to 10.",
|
|
stream: true,
|
|
onStreamChunk: (chunk) => process.stdout.write(chunk),
|
|
});
|
|
|
|
// Structured JSON output
|
|
const data = await runtime.useModel(ModelType.TEXT_LARGE, {
|
|
prompt: "Return a JSON object with name and age fields.",
|
|
responseSchema: {
|
|
type: "object",
|
|
properties: { name: { type: "string" }, age: { type: "number" } },
|
|
required: ["name", "age"],
|
|
},
|
|
});
|
|
|
|
// Embedding
|
|
const vector = await runtime.useModel(ModelType.TEXT_EMBEDDING, {
|
|
text: "text to embed",
|
|
});
|
|
|
|
// Image generation
|
|
const images = await runtime.useModel(ModelType.IMAGE, {
|
|
prompt: "A sunset over mountains",
|
|
count: 1,
|
|
size: "1024x1024",
|
|
});
|
|
|
|
// Image description
|
|
const { title, description } = await runtime.useModel(
|
|
ModelType.IMAGE_DESCRIPTION,
|
|
"https://example.com/photo.jpg"
|
|
);
|
|
|
|
// Audio transcription (Buffer, Blob, File, or URL string all accepted)
|
|
const transcript = await runtime.useModel(ModelType.TRANSCRIPTION, audioBuffer);
|
|
|
|
// Text-to-speech
|
|
const audio = await runtime.useModel(ModelType.TEXT_TO_SPEECH, {
|
|
text: "Hello, world.",
|
|
voice: "nova",
|
|
format: "mp3",
|
|
});
|
|
|
|
// Deep research (may take minutes)
|
|
const report = await runtime.useModel(ModelType.RESEARCH, {
|
|
input: "What are the latest advances in fusion energy?",
|
|
tools: [{ type: "web_search_preview" }],
|
|
});
|
|
console.log(report.text, report.annotations);
|
|
```
|
|
|
|
## Browser proxy setup
|
|
|
|
In browser builds this plugin does not send `Authorization` headers by default, to avoid exposing API keys in frontend bundles. Point `OPENAI_BROWSER_BASE_URL` at a server-side proxy that injects the key:
|
|
|
|
```ts
|
|
// Minimal Express proxy
|
|
import express from "express";
|
|
const app = express();
|
|
app.use(express.json());
|
|
|
|
app.all("/openai/*", async (req, res) => {
|
|
const url = `https://api.openai.com/v1/${req.params[0]}`;
|
|
const r = await fetch(url, {
|
|
method: req.method,
|
|
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, "Content-Type": "application/json" },
|
|
body: req.method !== "GET" ? JSON.stringify(req.body) : undefined,
|
|
});
|
|
res.status(r.status).send(await r.text());
|
|
});
|
|
|
|
app.listen(3000);
|
|
```
|
|
|
|
Then set `OPENAI_BROWSER_BASE_URL=http://localhost:3000/openai`.
|
|
|
|
## Cerebras compatibility
|
|
|
|
Point `OPENAI_BASE_URL` at a Cerebras endpoint or set `ELIZA_PROVIDER=cerebras` and the plugin automatically adapts: structured output uses `json_object` mode, `reasoning_effort` defaults to `"low"` for reasoning-capable models (to prevent empty responses), and `CEREBRAS_API_KEY` is accepted as an alias for `OPENAI_API_KEY`. Embeddings fall back to a deterministic local hash when no explicit embedding URL is set, since Cerebras does not provide an embeddings endpoint.
|
|
|
|
## EvoLink compatibility
|
|
|
|
Set `EVOLINK_API_KEY` to use EvoLink through its OpenAI-compatible endpoint. The plugin defaults to `https://direct.evolink.ai/v1` and `gpt-5.2`; set `EVOLINK_BASE_URL` or `EVOLINK_MODEL` to override either value.
|
|
|
|
## Prompt caching
|
|
|
|
Pass `providerOptions.openai.promptCacheKey` and `promptCacheRetention` on any `GenerateTextParams` call to enable OpenAI prompt caching:
|
|
|
|
```ts
|
|
await runtime.useModel(ModelType.TEXT_LARGE, {
|
|
prompt: "...",
|
|
providerOptions: {
|
|
openai: { promptCacheKey: "my-key", promptCacheRetention: "24h" },
|
|
},
|
|
});
|
|
```
|
|
|
|
## Free-form record/map tool arguments degrade under strict schema
|
|
|
|
A tool parameter that declares a free-form record/map — `additionalProperties: true` or a value schema (e.g. a contact `customFields: { type: "object", additionalProperties: { type: "string" } }`) — **cannot round-trip today**. The plugin's single schema choke point forces `additionalProperties: false` on every object before it reaches the wire, because strict-grammar backends (Cerebras / Eliza Cloud) reject open maps with a hard 400 and provider strictness is proxy-blind (an agent pointed at `api.elizacloud.ai` with `OPENAI_API_KEY` looks like plain OpenAI but may still route to strict Cerebras — see #11123 / #11156). With the object closed, the model can emit no arbitrary keys, so the map arg arrives **empty**.
|
|
|
|
This is a known limitation, not a silent one: the declared intent is folded into the property `description`, and when a tool's parameters contain such a record the plugin emits **one structured `logger.warn` per tool** (`[OpenAI] Tool "…" declares N free-form record/map argument(s) …`) listing each offending path so the degradation is observable in logs. The warning is scoped to **tool parameters only** — `response_format` is intentionally excluded.
|
|
|
|
Making these args actually emittable requires a product decision tracked in [#12150](https://github.com/elizaOS/eliza/issues/12150): option **A** (preserve open records for known non-strict providers, which first needs a reliable strictness signal) or option **B** (a two-sided transform that rewrites records into a strict-safe key/value shape and reverse-maps returned tool-call arguments). This plugin currently ships option **C** (accept the limitation, but make it observable + documented) as the safe stopgap.
|