@elizaos/plugin-openai 2.0.0-alpha.9 → 2.0.11-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/auto-enable.ts +17 -0
  4. package/package.json +70 -17
  5. package/dist/browser/index.browser.js +0 -3
  6. package/dist/browser/index.browser.js.map +0 -24
  7. package/dist/browser/index.d.ts +0 -2
  8. package/dist/build.d.ts +0 -13
  9. package/dist/build.d.ts.map +0 -1
  10. package/dist/cjs/index.d.ts +0 -2
  11. package/dist/cjs/index.node.cjs +0 -1315
  12. package/dist/cjs/index.node.js.map +0 -24
  13. package/dist/generated/specs/specs.d.ts +0 -55
  14. package/dist/generated/specs/specs.d.ts.map +0 -1
  15. package/dist/index.browser.d.ts +0 -3
  16. package/dist/index.browser.d.ts.map +0 -1
  17. package/dist/index.d.ts +0 -4
  18. package/dist/index.d.ts.map +0 -1
  19. package/dist/index.node.d.ts +0 -3
  20. package/dist/index.node.d.ts.map +0 -1
  21. package/dist/init.d.ts +0 -4
  22. package/dist/init.d.ts.map +0 -1
  23. package/dist/models/audio.d.ts +0 -9
  24. package/dist/models/audio.d.ts.map +0 -1
  25. package/dist/models/embedding.d.ts +0 -3
  26. package/dist/models/embedding.d.ts.map +0 -1
  27. package/dist/models/image.d.ts +0 -5
  28. package/dist/models/image.d.ts.map +0 -1
  29. package/dist/models/index.d.ts +0 -8
  30. package/dist/models/index.d.ts.map +0 -1
  31. package/dist/models/object.d.ts +0 -4
  32. package/dist/models/object.d.ts.map +0 -1
  33. package/dist/models/research.d.ts +0 -34
  34. package/dist/models/research.d.ts.map +0 -1
  35. package/dist/models/text.d.ts +0 -28
  36. package/dist/models/text.d.ts.map +0 -1
  37. package/dist/models/tokenizer.d.ts +0 -4
  38. package/dist/models/tokenizer.d.ts.map +0 -1
  39. package/dist/node/index.d.ts +0 -2
  40. package/dist/node/index.node.js +0 -1286
  41. package/dist/node/index.node.js.map +0 -24
  42. package/dist/providers/index.d.ts +0 -2
  43. package/dist/providers/index.d.ts.map +0 -1
  44. package/dist/providers/openai.d.ts +0 -4
  45. package/dist/providers/openai.d.ts.map +0 -1
  46. package/dist/types/index.d.ts +0 -345
  47. package/dist/types/index.d.ts.map +0 -1
  48. package/dist/utils/audio.d.ts +0 -6
  49. package/dist/utils/audio.d.ts.map +0 -1
  50. package/dist/utils/config.d.ts +0 -27
  51. package/dist/utils/config.d.ts.map +0 -1
  52. package/dist/utils/events.d.ts +0 -21
  53. package/dist/utils/events.d.ts.map +0 -1
  54. package/dist/utils/index.d.ts +0 -6
  55. package/dist/utils/index.d.ts.map +0 -1
  56. package/dist/utils/json.d.ts +0 -10
  57. package/dist/utils/json.d.ts.map +0 -1
  58. package/dist/utils/tokenization.d.ts +0 -6
  59. package/dist/utils/tokenization.d.ts.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # @elizaos/plugin-openai
2
+
3
+ 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`.
4
+
5
+ ## What this plugin does
6
+
7
+ - **Text generation** — multiple tiers (nano, small, medium, large, mega), plus dedicated response-handler and action-planner slots. Supports streaming and structured JSON output.
8
+ - **Text embeddings** — `text-embedding-3-small` by default; dimension configurable.
9
+ - **Image generation** — DALL-E 3 by default (`dall-e-3`).
10
+ - **Image description** — vision model analyzes an image URL and returns `{ title, description }`.
11
+ - **Audio transcription** — speech-to-text (`gpt-5-mini-transcribe` by default); accepts `Buffer`, `Blob`, `File`, or a URL.
12
+ - **Text-to-speech** — returns an `ArrayBuffer` of audio. Six voices; mp3/wav/flac/opus/aac/pcm output.
13
+ - **Deep research** — `ModelType.RESEARCH` via the OpenAI Responses API (`o3-deep-research` by default); returns annotated, multi-source research reports.
14
+ - **Tokenizer** — encode/decode using js-tiktoken (browser-safe, no network calls).
15
+
16
+ Works with any OpenAI-compatible endpoint: OpenAI, Cerebras, EvoLink, OpenRouter, local servers, etc.
17
+
18
+ ## Enabling the plugin
19
+
20
+ Add `@elizaos/plugin-openai` to your character's plugin list:
21
+
22
+ ```json
23
+ {
24
+ "plugins": ["@elizaos/plugin-openai"]
25
+ }
26
+ ```
27
+
28
+ The plugin auto-enables when `OPENAI_API_KEY`, `CEREBRAS_API_KEY`, or `EVOLINK_API_KEY` is present in the environment.
29
+
30
+ ## Required configuration
31
+
32
+ ```
33
+ OPENAI_API_KEY=sk-...
34
+ ```
35
+
36
+ That is the only required setting. All other settings are optional overrides.
37
+
38
+ ## Full configuration reference
39
+
40
+ Set these as environment variables or in your character's `settings` object.
41
+
42
+ ### API endpoint
43
+
44
+ | Variable | Default | Description |
45
+ |---|---|---|
46
+ | `OPENAI_BASE_URL` | `https://api.openai.com/v1` | Override for compatible endpoints |
47
+ | `ELIZA_PROVIDER` | — | Set to `cerebras` or `evolink` to force a compatible-provider mode |
48
+ | `EVOLINK_API_KEY` | — | Auth for EvoLink's OpenAI-compatible endpoint |
49
+ | `EVOLINK_BASE_URL` | `https://direct.evolink.ai/v1` | EvoLink endpoint used when `EVOLINK_API_KEY` enables the plugin |
50
+ | `EVOLINK_MODEL` | `gpt-5.2` | Text model used by EvoLink mode |
51
+
52
+ ### Text generation models
53
+
54
+ | Variable | Default | Description |
55
+ |---|---|---|
56
+ | `OPENAI_SMALL_MODEL` / `SMALL_MODEL` | `gpt-5.4-mini` | Fast, cost-effective responses |
57
+ | `OPENAI_NANO_MODEL` / `NANO_MODEL` | falls back to small | Fastest tier |
58
+ | `OPENAI_MEDIUM_MODEL` / `MEDIUM_MODEL` | falls back to small | Mid-tier |
59
+ | `OPENAI_LARGE_MODEL` / `LARGE_MODEL` | `gpt-5` | Complex reasoning |
60
+ | `OPENAI_MEGA_MODEL` / `MEGA_MODEL` | falls back to large | Highest tier |
61
+ | `OPENAI_RESPONSE_HANDLER_MODEL` | falls back to small | Response-handler slot |
62
+ | `OPENAI_ACTION_PLANNER_MODEL` | falls back to medium | Action-planner slot |
63
+ | `OPENAI_REASONING_EFFORT` | — | `minimal`/`low`/`medium`/`high` for o-series models |
64
+
65
+ ### Embeddings
66
+
67
+ | Variable | Default | Description |
68
+ |---|---|---|
69
+ | `OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model |
70
+ | `OPENAI_EMBEDDING_URL` | `OPENAI_BASE_URL` | Separate endpoint for embeddings |
71
+ | `OPENAI_EMBEDDING_API_KEY` | `OPENAI_API_KEY` | Separate key for embeddings |
72
+ | `OPENAI_EMBEDDING_DIMENSIONS` | `1536` | Vector dimensions (must match model) |
73
+
74
+ ### Image generation and description
75
+
76
+ | Variable | Default | Description |
77
+ |---|---|---|
78
+ | `OPENAI_IMAGE_MODEL` | `dall-e-3` | Image generation model |
79
+ | `OPENAI_IMAGE_DESCRIPTION_MODEL` | `gpt-5-mini` | Vision/description model |
80
+ | `OPENAI_IMAGE_DESCRIPTION_BASE_URL` | `OPENAI_BASE_URL` | Separate endpoint for vision |
81
+ | `OPENAI_IMAGE_DESCRIPTION_API_KEY` | `OPENAI_API_KEY` | Separate key for vision |
82
+ | `OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS` | `8192` | Max tokens in description response |
83
+
84
+ ### Audio
85
+
86
+ | Variable | Default | Description |
87
+ |---|---|---|
88
+ | `OPENAI_TRANSCRIPTION_MODEL` | `gpt-5-mini-transcribe` | Speech-to-text model |
89
+ | `OPENAI_TTS_MODEL` | `tts-1` | Text-to-speech model |
90
+ | `OPENAI_TTS_VOICE` | `nova` | Voice: alloy, echo, fable, onyx, nova, shimmer |
91
+ | `OPENAI_TTS_INSTRUCTIONS` | — | Style instructions for TTS |
92
+
93
+ ### Deep research
94
+
95
+ | Variable | Default | Description |
96
+ |---|---|---|
97
+ | `OPENAI_RESEARCH_MODEL` | `o3-deep-research` | Research model (o3 or o4-mini variants) |
98
+ | `OPENAI_RESEARCH_TIMEOUT` | `3600000` (1 hr) | Request timeout in milliseconds |
99
+
100
+ ### Browser and proxy
101
+
102
+ | Variable | Default | Description |
103
+ |---|---|---|
104
+ | `OPENAI_BROWSER_BASE_URL` | — | Proxy URL for browser builds (keeps key server-side) |
105
+ | `OPENAI_BROWSER_EMBEDDING_URL` | — | Proxy URL for browser embedding requests |
106
+ | `OPENAI_ALLOW_BROWSER_API_KEY` | `false` | Send auth header in browser builds (opt-in) |
107
+
108
+ ### Other
109
+
110
+ | Variable | Default | Description |
111
+ |---|---|---|
112
+ | `OPENAI_EXPERIMENTAL_TELEMETRY` | `false` | Enable AI SDK experimental telemetry |
113
+
114
+ ## Usage examples
115
+
116
+ ```ts
117
+ import { ModelType } from "@elizaos/core";
118
+
119
+ // Text generation
120
+ const reply = await runtime.useModel(ModelType.TEXT_LARGE, {
121
+ prompt: "Explain quantum entanglement in plain English.",
122
+ });
123
+
124
+ // Streaming text
125
+ const result = await runtime.useModel(ModelType.TEXT_LARGE, {
126
+ prompt: "Count from 1 to 10.",
127
+ stream: true,
128
+ onStreamChunk: (chunk) => process.stdout.write(chunk),
129
+ });
130
+
131
+ // Structured JSON output
132
+ const data = await runtime.useModel(ModelType.TEXT_LARGE, {
133
+ prompt: "Return a JSON object with name and age fields.",
134
+ responseSchema: {
135
+ type: "object",
136
+ properties: { name: { type: "string" }, age: { type: "number" } },
137
+ required: ["name", "age"],
138
+ },
139
+ });
140
+
141
+ // Embedding
142
+ const vector = await runtime.useModel(ModelType.TEXT_EMBEDDING, {
143
+ text: "text to embed",
144
+ });
145
+
146
+ // Image generation
147
+ const images = await runtime.useModel(ModelType.IMAGE, {
148
+ prompt: "A sunset over mountains",
149
+ count: 1,
150
+ size: "1024x1024",
151
+ });
152
+
153
+ // Image description
154
+ const { title, description } = await runtime.useModel(
155
+ ModelType.IMAGE_DESCRIPTION,
156
+ "https://example.com/photo.jpg"
157
+ );
158
+
159
+ // Audio transcription (Buffer, Blob, File, or URL string all accepted)
160
+ const transcript = await runtime.useModel(ModelType.TRANSCRIPTION, audioBuffer);
161
+
162
+ // Text-to-speech
163
+ const audio = await runtime.useModel(ModelType.TEXT_TO_SPEECH, {
164
+ text: "Hello, world.",
165
+ voice: "nova",
166
+ format: "mp3",
167
+ });
168
+
169
+ // Deep research (may take minutes)
170
+ const report = await runtime.useModel(ModelType.RESEARCH, {
171
+ input: "What are the latest advances in fusion energy?",
172
+ tools: [{ type: "web_search_preview" }],
173
+ });
174
+ console.log(report.text, report.annotations);
175
+ ```
176
+
177
+ ## Browser proxy setup
178
+
179
+ 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:
180
+
181
+ ```ts
182
+ // Minimal Express proxy
183
+ import express from "express";
184
+ const app = express();
185
+ app.use(express.json());
186
+
187
+ app.all("/openai/*", async (req, res) => {
188
+ const url = `https://api.openai.com/v1/${req.params[0]}`;
189
+ const r = await fetch(url, {
190
+ method: req.method,
191
+ headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, "Content-Type": "application/json" },
192
+ body: req.method !== "GET" ? JSON.stringify(req.body) : undefined,
193
+ });
194
+ res.status(r.status).send(await r.text());
195
+ });
196
+
197
+ app.listen(3000);
198
+ ```
199
+
200
+ Then set `OPENAI_BROWSER_BASE_URL=http://localhost:3000/openai`.
201
+
202
+ ## Cerebras compatibility
203
+
204
+ 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.
205
+
206
+ ## EvoLink compatibility
207
+
208
+ 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.
209
+
210
+ ## Prompt caching
211
+
212
+ Pass `providerOptions.openai.promptCacheKey` and `promptCacheRetention` on any `GenerateTextParams` call to enable OpenAI prompt caching:
213
+
214
+ ```ts
215
+ await runtime.useModel(ModelType.TEXT_LARGE, {
216
+ prompt: "...",
217
+ providerOptions: {
218
+ openai: { promptCacheKey: "my-key", promptCacheRetention: "24h" },
219
+ },
220
+ });
221
+ ```
package/auto-enable.ts ADDED
@@ -0,0 +1,17 @@
1
+ // Auto-enable check for @elizaos/plugin-openai.
2
+ //
3
+ // Plugin manifest entry-point — referenced by package.json's
4
+ // `elizaos.plugin.autoEnableModule`. Keep this module light: env reads only,
5
+ // no service init, no transitive imports of the full plugin runtime. The
6
+ // auto-enable engine loads dozens of these per boot.
7
+ import type { PluginAutoEnableContext } from "@elizaos/core";
8
+
9
+ const ENV_KEYS = ["OPENAI_API_KEY", "CEREBRAS_API_KEY", "EVOLINK_API_KEY"] as const;
10
+
11
+ /** Enable when an OpenAI-compatible API key is present in the environment. */
12
+ export function shouldEnable(ctx: PluginAutoEnableContext): boolean {
13
+ return ENV_KEYS.some((k) => {
14
+ const v = ctx.env[k];
15
+ return typeof v === "string" && v.trim() !== "";
16
+ });
17
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@elizaos/plugin-openai",
3
- "version": "2.0.0-alpha.9",
3
+ "version": "2.0.11-beta.7",
4
4
  "type": "module",
5
- "main": "dist/cjs/index.node.cjs",
5
+ "main": "dist/node/index.node.js",
6
6
  "module": "dist/node/index.node.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "browser": "dist/browser/index.browser.js",
@@ -23,44 +23,65 @@
23
23
  "node": {
24
24
  "types": "./dist/node/index.d.ts",
25
25
  "import": "./dist/node/index.node.js",
26
- "require": "./dist/cjs/index.node.cjs",
27
26
  "default": "./dist/node/index.node.js"
28
27
  },
29
28
  "default": "./dist/node/index.node.js"
29
+ },
30
+ "./*.css": "./dist/*.css",
31
+ "./*": {
32
+ "types": "./dist/*.d.ts",
33
+ "import": "./dist/*.js",
34
+ "default": "./dist/*.js"
30
35
  }
31
36
  },
32
37
  "files": [
33
38
  "dist",
34
- "rust"
39
+ "rust",
40
+ "auto-enable.ts"
35
41
  ],
42
+ "elizaos": {
43
+ "plugin": {
44
+ "autoEnableModule": "./auto-enable.ts",
45
+ "capabilities": [
46
+ "text-large",
47
+ "text-small",
48
+ "tool-use",
49
+ "embedding",
50
+ "text-to-speech",
51
+ "image-description"
52
+ ]
53
+ }
54
+ },
36
55
  "dependencies": {
37
56
  "@ai-sdk/openai": "^3.0.9",
38
- "@elizaos/core": "alpha",
39
57
  "ai": "^6.0.30",
40
- "js-tiktoken": "^1.0.21",
41
- "undici": "^7.16.0"
58
+ "js-tiktoken": "^1.0.21"
42
59
  },
43
60
  "devDependencies": {
44
- "@biomejs/biome": "^2.3.11",
61
+ "@biomejs/biome": "^2.4.14",
62
+ "@elizaos/core": "2.0.11-beta.7",
45
63
  "@types/bun": "^1.3.8",
46
64
  "@types/json-schema": "^7.0.15",
47
65
  "@types/node": "^25.0.3",
48
- "typescript": "^5.9.3"
66
+ "typescript": "^6.0.3",
67
+ "uuid": "^14.0.0",
68
+ "vitest": "^4.0.0"
49
69
  },
50
70
  "peerDependencies": {
51
- "zod": "^4.3.6"
71
+ "@elizaos/core": "2.0.11-beta.7",
72
+ "zod": "^4.4.3"
52
73
  },
53
74
  "scripts": {
54
75
  "build:ts": "bun run build.ts",
55
76
  "dev": "bun --hot build.ts",
56
77
  "lint": "bunx @biomejs/biome check --write --unsafe .",
57
78
  "lint:check": "bunx @biomejs/biome check .",
58
- "clean": "rm -rf dist .turbo node_modules",
79
+ "clean": "rm -rf dist .turbo",
59
80
  "format": "bunx @biomejs/biome format --write .",
60
81
  "format:check": "bunx @biomejs/biome format .",
61
- "typecheck": "tsc --noEmit",
62
- "test": "vitest run __tests__/ --passWithNoTests",
63
- "test:ts": "vitest run __tests__/ --passWithNoTests",
82
+ "typecheck": "tsgo --noEmit",
83
+ "test": "vitest run --config ./vitest.config.ts",
84
+ "test:ts": "vitest run --config ./vitest.config.ts",
64
85
  "build": "bun run build.ts"
65
86
  },
66
87
  "publishConfig": {
@@ -82,6 +103,26 @@
82
103
  "default": "https://api.openai.com/v1",
83
104
  "sensitive": false
84
105
  },
106
+ "EVOLINK_API_KEY": {
107
+ "type": "string",
108
+ "description": "API key used to authenticate requests to EvoLink's OpenAI-compatible API.",
109
+ "required": false,
110
+ "sensitive": true
111
+ },
112
+ "EVOLINK_BASE_URL": {
113
+ "type": "string",
114
+ "description": "Base URL for EvoLink's OpenAI-compatible API.",
115
+ "required": false,
116
+ "default": "https://direct.evolink.ai/v1",
117
+ "sensitive": false
118
+ },
119
+ "EVOLINK_MODEL": {
120
+ "type": "string",
121
+ "description": "Identifier of the EvoLink chat model to use when EVOLINK_API_KEY enables this plugin.",
122
+ "required": false,
123
+ "default": "gpt-5.2",
124
+ "sensitive": false
125
+ },
85
126
  "OPENAI_SMALL_MODEL": {
86
127
  "type": "string",
87
128
  "description": "Identifier of the small language model to be used (overrides SMALL_MODEL).",
@@ -92,7 +133,7 @@
92
133
  "type": "string",
93
134
  "description": "Fallback identifier for the small language model if OPENAI_SMALL_MODEL is not set.",
94
135
  "required": false,
95
- "default": "gpt-5-mini",
136
+ "default": "gpt-5.4-mini",
96
137
  "sensitive": false
97
138
  },
98
139
  "OPENAI_LARGE_MODEL": {
@@ -134,6 +175,18 @@
134
175
  "default": 1536,
135
176
  "sensitive": false
136
177
  },
178
+ "OPENAI_IMAGE_DESCRIPTION_API_KEY": {
179
+ "type": "string",
180
+ "description": "Optional API key for image-description requests. Falls back to the general OpenAI API key when unset.",
181
+ "required": false,
182
+ "sensitive": true
183
+ },
184
+ "OPENAI_IMAGE_DESCRIPTION_BASE_URL": {
185
+ "type": "string",
186
+ "description": "Optional OpenAI-compatible base URL for image-description requests. Useful when text models use a non-vision-compatible endpoint.",
187
+ "required": false,
188
+ "sensitive": false
189
+ },
137
190
  "OPENAI_IMAGE_DESCRIPTION_MODEL": {
138
191
  "type": "string",
139
192
  "description": "Identifier of the model used for describing images.",
@@ -189,8 +242,8 @@
189
242
  }
190
243
  }
191
244
  },
192
- "gitHead": "646c632924826e2b75c2304a75ee56959fe4a460",
193
- "milady": {
245
+ "gitHead": "cdbc876f793d96073d7eb0d09715a031ce0cd32e",
246
+ "eliza": {
194
247
  "platforms": [
195
248
  "browser",
196
249
  "node"
@@ -1,3 +0,0 @@
1
- import{logger as l,ModelType as I}from"@elizaos/core";import{logger as _}from"@elizaos/core";import{logger as z}from"@elizaos/core";function xo(o){if(typeof process>"u"||!process.env)return;let n=process.env[o];return n===void 0?void 0:String(n)}function s(o,n,c){let r=o.getSetting(n);if(r!==void 0&&r!==null)return String(r);return xo(n)??c}function K(o,n,c){let r=s(o,n);if(r===void 0)return c;let f=Number.parseInt(r,10);if(!Number.isFinite(f))throw Error(`Setting '${n}' must be a valid integer, got: ${r}`);return f}function v(o,n,c){let r=s(o,n);if(r===void 0)return c;let f=r.toLowerCase();return f==="true"||f==="1"||f==="yes"}function E(){return typeof globalThis<"u"&&typeof globalThis.document<"u"}function g(o){return E()&&!!s(o,"OPENAI_BROWSER_BASE_URL")}function J(o){return s(o,"OPENAI_API_KEY")}function Ko(o){let n=s(o,"OPENAI_EMBEDDING_API_KEY");if(n)return z.debug("[OpenAI] Using specific embedding API key"),n;return z.debug("[OpenAI] Falling back to general API key for embeddings"),J(o)}function R(o,n=!1){if(E()&&!v(o,"OPENAI_ALLOW_BROWSER_API_KEY",!1))return{};let c=n?Ko(o):J(o);return c?{Authorization:`Bearer ${c}`}:{}}function O(o){let n=s(o,"OPENAI_BROWSER_BASE_URL"),c=E()&&n?n:s(o,"OPENAI_BASE_URL")??"https://api.openai.com/v1";return z.debug(`[OpenAI] Base URL: ${c}`),c}function u(o){let n=E()?s(o,"OPENAI_BROWSER_EMBEDDING_URL")??s(o,"OPENAI_BROWSER_BASE_URL"):s(o,"OPENAI_EMBEDDING_URL");if(n)return z.debug(`[OpenAI] Using embedding base URL: ${n}`),n;return z.debug("[OpenAI] Falling back to general base URL for embeddings"),O(o)}function F(o){return s(o,"OPENAI_SMALL_MODEL")??s(o,"SMALL_MODEL")??"gpt-5-mini"}function d(o){return s(o,"OPENAI_LARGE_MODEL")??s(o,"LARGE_MODEL")??"gpt-5"}function m(o){return s(o,"OPENAI_EMBEDDING_MODEL")??"text-embedding-3-small"}function oo(o){return s(o,"OPENAI_IMAGE_DESCRIPTION_MODEL")??"gpt-5-mini"}function no(o){return s(o,"OPENAI_TRANSCRIPTION_MODEL")??"gpt-5-mini-transcribe"}function co(o){return s(o,"OPENAI_TTS_MODEL")??"tts-1"}function ro(o){return s(o,"OPENAI_TTS_VOICE")??"nova"}function fo(o){return s(o,"OPENAI_TTS_INSTRUCTIONS")??""}function To(o){return s(o,"OPENAI_IMAGE_MODEL")??"dall-e-3"}function io(o){return v(o,"OPENAI_EXPERIMENTAL_TELEMETRY",!1)}function ko(o){return K(o,"OPENAI_EMBEDDING_DIMENSIONS",1536)}function Ao(o){return K(o,"OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS",8192)}function to(o){return s(o,"OPENAI_RESEARCH_MODEL")??"o3-deep-research"}function Po(o){return K(o,"OPENAI_RESEARCH_TIMEOUT",3600000)}globalThis.AI_SDK_LOG_WARNINGS??=!1;function Io(o,n){Wo(n)}async function Wo(o){if(E()){_.debug("[OpenAI] Skipping API validation in browser environment");return}if(!J(o)){_.warn("[OpenAI] OPENAI_API_KEY is not configured. OpenAI functionality will fail until a valid API key is provided.");return}try{let c=O(o),r=await fetch(`${c}/models`,{headers:R(o)});if(!r.ok){_.warn(`[OpenAI] API key validation failed: ${r.status} ${r.statusText}. Please verify your OPENAI_API_KEY is correct.`);return}}catch(c){let r=c instanceof Error?c.message:String(c);_.warn(`[OpenAI] API validation error: ${r}. OpenAI functionality may be limited.`)}}import{logger as U}from"@elizaos/core";import{logger as Xo}from"@elizaos/core";var S={WAV:{HEADER:[82,73,70,70],IDENTIFIER:[87,65,86,69]},MP3_ID3:[73,68,51],OGG:[79,103,103,83],FLAC:[102,76,97,67],FTYP:[102,116,121,112],WEBM_EBML:[26,69,223,163]},Co=12;function j(o,n,c){for(let r=0;r<c.length;r++){let f=c[r];if(f===void 0||o[n+r]!==f)return!1}return!0}function W(o){if(o.length<Co)return"application/octet-stream";if(j(o,0,S.WAV.HEADER)&&j(o,8,S.WAV.IDENTIFIER))return"audio/wav";let n=o[0],c=o[1];if(j(o,0,S.MP3_ID3)||n===255&&c!==void 0&&(c&224)===224)return"audio/mpeg";if(j(o,0,S.OGG))return"audio/ogg";if(j(o,0,S.FLAC))return"audio/flac";if(j(o,4,S.FTYP))return"audio/mp4";if(j(o,0,S.WEBM_EBML))return"audio/webm";return Xo.warn("Could not detect audio format from buffer, using generic binary type"),"application/octet-stream"}function Ho(o){switch(o){case"audio/wav":return"wav";case"audio/mpeg":return"mp3";case"audio/ogg":return"ogg";case"audio/flac":return"flac";case"audio/mp4":return"m4a";case"audio/webm":return"webm";case"application/octet-stream":return"bin"}}function po(o){return`recording.${Ho(o)}`}function wo(o){return o instanceof Blob||o instanceof File}function X(o){return Buffer.isBuffer(o)}function Vo(o){return typeof o==="object"&&o!==null&&"audio"in o&&(wo(o.audio)||X(o.audio))}function Qo(o){return typeof o==="object"&&o!==null&&"audioUrl"in o&&typeof o.audioUrl==="string"}async function so(o){let n=await fetch(o);if(!n.ok)throw Error(`Failed to fetch audio from URL: ${n.status}`);return n.blob()}async function C(o,n){let c=no(o),r,f={};if(typeof n==="string")U.debug(`[OpenAI] Fetching audio from URL: ${n}`),r=await so(n);else if(wo(n))r=n;else if(X(n)){let P=W(n);U.debug(`[OpenAI] Auto-detected audio MIME type: ${P}`),r=new Blob([new Uint8Array(n)],{type:P})}else if(Vo(n)){if(f=n,n.model)c=n.model;if(X(n.audio)){let P=n.mimeType??W(n.audio);U.debug(`[OpenAI] Using MIME type: ${P}`),r=new Blob([new Uint8Array(n.audio)],{type:P})}else r=n.audio}else if(Qo(n))U.debug(`[OpenAI] Fetching audio from URL: ${n.audioUrl}`),r=await so(n.audioUrl),f={prompt:n.prompt};else throw Error("TRANSCRIPTION expects Blob, File, Buffer, URL string, or TranscriptionParams object");U.debug(`[OpenAI] Using TRANSCRIPTION model: ${c}`);let T=r.type||"audio/webm",A=r.name||po(T.startsWith("audio/")?T:"audio/webm"),k=new FormData;if(k.append("file",r,A),k.append("model",c),f.language)k.append("language",f.language);if(f.responseFormat)k.append("response_format",f.responseFormat);if(f.prompt)k.append("prompt",f.prompt);if(f.temperature!==void 0)k.append("temperature",String(f.temperature));if(f.timestampGranularities)for(let P of f.timestampGranularities)k.append("timestamp_granularities[]",P);let t=O(o),i=await fetch(`${t}/audio/transcriptions`,{method:"POST",headers:R(o),body:k});if(!i.ok){let P=await i.text().catch(()=>"Unknown error");throw Error(`OpenAI transcription failed: ${i.status} ${i.statusText} - ${P}`)}return(await i.json()).text}async function H(o,n){let c,r,f="mp3",T,A;if(typeof n==="string")c=n,r=void 0;else{if(c=n.text,r=n.voice,"format"in n&&n.format)f=n.format;if("model"in n&&n.model)T=n.model;if("instructions"in n&&n.instructions)A=n.instructions}if(T=T??co(o),r=r??ro(o),A=A??fo(o),U.debug(`[OpenAI] Using TEXT_TO_SPEECH model: ${T}`),!c||c.trim().length===0)throw Error("TEXT_TO_SPEECH requires non-empty text");if(c.length>4096)throw Error("TEXT_TO_SPEECH text exceeds 4096 character limit");let k=["alloy","echo","fable","onyx","nova","shimmer"];if(r&&!k.includes(r))throw Error(`Invalid voice: ${r}. Must be one of: ${k.join(", ")}`);let t=O(o),i={model:T,voice:r,input:c,response_format:f};if(A&&A.length>0)i.instructions=A;let p=await fetch(`${t}/audio/speech`,{method:"POST",headers:{...R(o),"Content-Type":"application/json",...f==="mp3"?{Accept:"audio/mpeg"}:{}},body:JSON.stringify(i)});if(!p.ok){let P=await p.text().catch(()=>"Unknown error");throw Error(`OpenAI TTS failed: ${p.status} ${p.statusText} - ${P}`)}return p.arrayBuffer()}import{logger as x,ModelType as Go,VECTOR_DIMS as qo}from"@elizaos/core";import{EventType as Do}from"@elizaos/core";var Oo=200;function Zo(o){if(o.length<=Oo)return o;return`${o.slice(0,Oo)}…`}function Yo(o){if("promptTokens"in o){let n="promptTokensDetails"in o?o.promptTokensDetails:void 0,c=o.cachedPromptTokens??n?.cachedTokens;return{promptTokens:o.promptTokens??0,completionTokens:o.completionTokens??0,totalTokens:o.totalTokens??(o.promptTokens??0)+(o.completionTokens??0),cachedPromptTokens:c}}if("inputTokens"in o||"outputTokens"in o){let n=o.inputTokens??0,c=o.outputTokens??0,r=o.totalTokens??n+c;return{promptTokens:n,completionTokens:c,totalTokens:r,cachedPromptTokens:o.cachedInputTokens}}return{promptTokens:0,completionTokens:0,totalTokens:0}}function $(o,n,c,r){let f=Yo(r),T={runtime:o,source:"openai",provider:"openai",type:n,prompt:Zo(c),tokens:{prompt:f.promptTokens,completion:f.completionTokens,total:f.totalTokens,...f.cachedPromptTokens!==void 0?{cached:f.cachedPromptTokens}:{}}};o.emitEvent(Do.MODEL_USED,T)}var ho=8000;function Mo(o){let n=Object.values(qo);if(!n.includes(o))throw Error(`Invalid embedding dimension: ${o}. Must be one of: ${n.join(", ")}`);return o}function eo(o){if(o===null)return null;if(typeof o==="string")return o;if(typeof o==="object"&&typeof o.text==="string")return o.text;throw Error("Invalid embedding params: expected string, { text: string }, or null")}async function V(o,n){let c=m(o),r=Mo(ko(o)),f=eo(n);if(f===null){x.debug("[OpenAI] Creating test embedding for initialization");let y=Array(r).fill(0);return y[0]=0.1,y}let T=f.trim();if(T.length===0)throw Error("Cannot generate embedding for empty text");let A=ho*4;if(T.length>A)x.warn(`[OpenAI] Embedding input too long (~${Math.ceil(T.length/4)} tokens), truncating to ~${ho} tokens`),T=T.slice(0,A);let t=`${u(o)}/embeddings`;x.debug(`[OpenAI] Generating embedding with model: ${c}`);let i=await fetch(t,{method:"POST",headers:{...R(o,!0),"Content-Type":"application/json"},body:JSON.stringify({model:c,input:T})});if(!i.ok){let y=await i.text().catch(()=>"Unknown error");throw Error(`OpenAI embedding API error: ${i.status} ${i.statusText} - ${y}`)}let p=await i.json(),P=p?.data?.[0];if(!P||!P.embedding)throw Error("OpenAI API returned invalid embedding response structure");let w=P.embedding;if(w.length!==r)throw Error(`Embedding dimension mismatch: got ${w.length}, expected ${r}. Check OPENAI_EMBEDDING_DIMENSIONS setting.`);if(p.usage)$(o,Go.TEXT_EMBEDDING,T,{promptTokens:p.usage.prompt_tokens,completionTokens:0,totalTokens:p.usage.total_tokens});return x.debug(`[OpenAI] Generated embedding with ${w.length} dimensions`),w}import{logger as lo,ModelType as Bo}from"@elizaos/core";var Ro="Please analyze this image and provide a title and detailed description.";async function Q(o,n){let c=To(o),r=n.count??1,f=n.size??"1024x1024",T=n;if(lo.debug(`[OpenAI] Using IMAGE model: ${c}`),!n.prompt||n.prompt.trim().length===0)throw Error("IMAGE generation requires a non-empty prompt");if(r<1||r>10)throw Error("IMAGE count must be between 1 and 10");let A=O(o),k={model:c,prompt:n.prompt,n:r,size:f};if(T.quality)k.quality=T.quality;if(T.style)k.style=T.style;let t=await fetch(`${A}/images/generations`,{method:"POST",headers:{...R(o),"Content-Type":"application/json"},body:JSON.stringify(k)});if(!t.ok){let p=await t.text().catch(()=>"Unknown error");throw Error(`OpenAI image generation failed: ${t.status} ${t.statusText} - ${p}`)}let i=await t.json();if(!i.data||i.data.length===0)throw Error("OpenAI API returned no images");return i.data.map((p)=>({url:p.url,revisedPrompt:p.revised_prompt}))}function ao(o){return o.match(/title[:\s]+(.+?)(?:\n|$)/i)?.[1]?.trim()??"Image Analysis"}function vo(o){return o.replace(/title[:\s]+(.+?)(?:\n|$)/i,"").trim()}async function D(o,n){let c=oo(o),r=Ao(o);lo.debug(`[OpenAI] Using IMAGE_DESCRIPTION model: ${c}`);let f,T;if(typeof n==="string")f=n,T=Ro;else f=n.imageUrl,T=n.prompt??Ro;if(!f||f.trim().length===0)throw Error("IMAGE_DESCRIPTION requires a valid image URL");let A=O(o),k={model:c,messages:[{role:"user",content:[{type:"text",text:T},{type:"image_url",image_url:{url:f}}]}],max_tokens:r},t=await fetch(`${A}/chat/completions`,{method:"POST",headers:{...R(o),"Content-Type":"application/json"},body:JSON.stringify(k)});if(!t.ok){let w=await t.text().catch(()=>"Unknown error");throw Error(`OpenAI image description failed: ${t.status} ${t.statusText} - ${w}`)}let i=await t.json();if(i.usage)$(o,Bo.IMAGE_DESCRIPTION,typeof n==="string"?n:n.prompt??"",{promptTokens:i.usage.prompt_tokens,completionTokens:i.usage.completion_tokens,totalTokens:i.usage.total_tokens});let P=i.choices?.[0]?.message?.content;if(!P)throw Error("OpenAI API returned empty image description");return{title:ao(P),description:vo(P)}}import{logger as bo,ModelType as No}from"@elizaos/core";import{generateObject as on}from"ai";import{createOpenAI as yo}from"@ai-sdk/openai";var go="sk-proxy";function L(o){let n=O(o),c=J(o);if(!c&&g(o))return yo({apiKey:go,baseURL:n});if(!c)throw Error("OPENAI_API_KEY is required. Set it in your environment variables or runtime settings.");return yo({apiKey:c,baseURL:n})}import{logger as Jo}from"@elizaos/core";import{JSONParseError as uo}from"ai";var mo={MARKDOWN_JSON:/```json\n|\n```|```/g,WHITESPACE:/^\s+|\s+$/g};function $o(){return async({text:o,error:n})=>{if(!(n instanceof uo))return null;try{let c=o.replace(mo.MARKDOWN_JSON,"");return JSON.parse(c),Jo.debug("[JSON Repair] Successfully repaired JSON by removing markdown wrappers"),c}catch{return Jo.warn("[JSON Repair] Unable to repair JSON text"),null}}}async function So(o,n,c,r){let f=L(o),T=r(o);if(bo.debug(`[OpenAI] Using ${c} model: ${T}`),!n.prompt||n.prompt.trim().length===0)throw Error("Object generation requires a non-empty prompt");if(n.schema)bo.debug("[OpenAI] Schema provided but using no-schema mode. Structure is determined by prompt instructions.");let A=f.chat(T),{object:k,usage:t}=await on({model:A,output:"no-schema",prompt:n.prompt,experimental_repairText:$o()});if(t)$(o,c,n.prompt,t);if(typeof k!=="object"||k===null)throw Error(`Object generation returned ${typeof k}, expected object`);return k}async function Z(o,n){return So(o,n,No.OBJECT_SMALL,F)}async function Y(o,n){return So(o,n,No.OBJECT_LARGE,d)}import{logger as b}from"@elizaos/core";function nn(o){switch(o.type){case"web_search_preview":return{type:"web_search_preview"};case"file_search":return{type:"file_search",vector_store_ids:o.vectorStoreIds};case"code_interpreter":return{type:"code_interpreter",container:o.container??{type:"auto"}};case"mcp":return{type:"mcp",server_label:o.serverLabel,server_url:o.serverUrl,require_approval:o.requireApproval??"never"};default:throw Error(`Unknown research tool type: ${o.type}`)}}function cn(o){switch(o.type){case"web_search_call":return{id:o.id??"",type:"web_search_call",status:o.status??"completed",action:{type:o.action?.type??"search",query:o.action?.query,url:o.action?.url}};case"file_search_call":return{id:o.id??"",type:"file_search_call",status:o.status??"completed",query:o.query??"",results:o.results?.map((n)=>({fileId:n.file_id,fileName:n.file_name,score:n.score}))};case"code_interpreter_call":return{id:o.id??"",type:"code_interpreter_call",status:o.status??"completed",code:o.code??"",output:o.output};case"mcp_tool_call":return{id:o.id??"",type:"mcp_tool_call",status:o.status??"completed",serverLabel:o.server_label??"",toolName:o.tool_name??"",arguments:o.arguments??{},result:o.result};case"message":return{type:"message",content:o.content?.map((n)=>({type:"output_text",text:n.text,annotations:n.annotations?.map((c)=>({url:c.url,title:c.title,startIndex:c.start_index,endIndex:c.end_index}))??[]}))??[]};default:return null}}function rn(o){if(o.output_text){let r=[];if(o.output){for(let f of o.output)if(f.type==="message"&&f.content){for(let T of f.content)if(T.annotations)for(let A of T.annotations)r.push({url:A.url,title:A.title,startIndex:A.start_index,endIndex:A.end_index})}}return{text:o.output_text,annotations:r}}let n="",c=[];if(o.output){for(let r of o.output)if(r.type==="message"&&r.content){for(let f of r.content)if(n+=f.text,f.annotations)for(let T of f.annotations)c.push({url:T.url,title:T.title,startIndex:T.start_index,endIndex:T.end_index})}}return{text:n,annotations:c}}async function G(o,n){let c=J(o);if(!c)throw Error("OPENAI_API_KEY is required for deep research. Set it in your environment variables or runtime settings.");let r=O(o),f=n.model??to(o),T=Po(o);b.debug(`[OpenAI] Starting deep research with model: ${f}`),b.debug(`[OpenAI] Research input: ${n.input.substring(0,100)}...`);let A=n.tools?.filter((N)=>N.type==="web_search_preview"||N.type==="file_search"||N.type==="mcp");if(!A||A.length===0)b.debug("[OpenAI] No data source tools specified, defaulting to web_search_preview"),n.tools=[{type:"web_search_preview"},...n.tools??[]];let k={model:f,input:n.input};if(n.instructions)k.instructions=n.instructions;if(n.background!==void 0)k.background=n.background;if(n.tools&&n.tools.length>0)k.tools=n.tools.map(nn);if(n.maxToolCalls!==void 0)k.max_tool_calls=n.maxToolCalls;if(n.reasoningSummary)k.reasoning={summary:n.reasoningSummary};b.debug(`[OpenAI] Research request body: ${JSON.stringify(k,null,2)}`);let t=await fetch(`${r}/responses`,{method:"POST",headers:{Authorization:`Bearer ${c}`,"Content-Type":"application/json"},body:JSON.stringify(k),signal:AbortSignal.timeout(T)});if(!t.ok){let N=await t.text();throw b.error(`[OpenAI] Research request failed: ${t.status} ${N}`),Error(`Deep research request failed: ${t.status} ${t.statusText}`)}let i=await t.json();if(i.error)throw b.error(`[OpenAI] Research API error: ${i.error.message}`),Error(`Deep research error: ${i.error.message}`);b.debug(`[OpenAI] Research response received. Status: ${i.status??"completed"}`);let{text:p,annotations:P}=rn(i),w=[];if(i.output)for(let N of i.output){let a=cn(N);if(a)w.push(a)}let y={id:i.id,text:p,annotations:P,outputItems:w,status:i.status};return b.info(`[OpenAI] Research completed. Text length: ${p.length}, Annotations: ${P.length}, Output items: ${w.length}`),y}import{logger as fn,ModelType as jo}from"@elizaos/core";import{generateText as Tn,streamText as kn}from"ai";function An(o){if(!o)return;let n=o.inputTokens??0,c=o.outputTokens??0,r=o;return{promptTokens:n,completionTokens:c,totalTokens:n+c,cachedPromptTokens:r.cachedInputTokens}}function tn(o){let n=o;return{promptCacheKey:n.providerOptions?.openai?.promptCacheKey,promptCacheRetention:n.providerOptions?.openai?.promptCacheRetention}}async function Eo(o,n,c,r){let f=L(o),T=r(o);fn.debug(`[OpenAI] Using ${c} model: ${T}`);let A=tn(n),k=o.character.system??void 0,i={model:f.chat(T),prompt:n.prompt,system:k,maxOutputTokens:n.maxTokens??8192,experimental_telemetry:{isEnabled:io(o)},...A.promptCacheKey||A.promptCacheRetention?{providerOptions:{openai:{...A.promptCacheKey?{promptCacheKey:A.promptCacheKey}:{},...A.promptCacheRetention?{promptCacheRetention:A.promptCacheRetention}:{}}}}:{}};if(n.stream){let w=kn(i);return{textStream:w.textStream,text:Promise.resolve(w.text),usage:Promise.resolve(w.usage).then(An),finishReason:Promise.resolve(w.finishReason).then((y)=>y)}}let{text:p,usage:P}=await Tn(i);if(P)$(o,c,n.prompt,P);return p}async function q(o,n){return Eo(o,n,jo.TEXT_SMALL,F)}async function M(o,n){return Eo(o,n,jo.TEXT_LARGE,d)}import{ModelType as _o}from"@elizaos/core";import{ModelType as Pn}from"@elizaos/core";import{encodingForModel as In,getEncoding as pn}from"js-tiktoken";function Fo(o){let c=o.toLowerCase().includes("4o")?"o200k_base":"cl100k_base";try{return In(o)}catch{return pn(c)}}function Uo(o,n){if(n===Pn.TEXT_SMALL)return F(o);return d(o)}function zo(o,n,c){let r=Uo(o,n);return Fo(r).encode(c)}function Lo(o,n,c){let r=Uo(o,n);return Fo(r).decode(c)}async function e(o,n){if(!n.prompt)throw Error("Tokenization requires a non-empty prompt");let c=n.modelType??_o.TEXT_LARGE;return zo(o,c,n.prompt)}async function B(o,n){if(!n.tokens||!Array.isArray(n.tokens))throw Error("Detokenization requires a valid tokens array");if(n.tokens.length===0)return"";for(let r=0;r<n.tokens.length;r++){let f=n.tokens[r];if(typeof f!=="number"||!Number.isFinite(f))throw Error(`Invalid token at index ${r}: expected number`)}let c=n.modelType??_o.TEXT_LARGE;return Lo(o,c,n.tokens)}function sn(){if(typeof process>"u")return{};return process.env}var h=sn(),wn={name:"openai",description:"OpenAI API integration for text, image, audio, and embedding models",config:{OPENAI_API_KEY:h.OPENAI_API_KEY??null,OPENAI_BASE_URL:h.OPENAI_BASE_URL??null,OPENAI_SMALL_MODEL:h.OPENAI_SMALL_MODEL??null,OPENAI_LARGE_MODEL:h.OPENAI_LARGE_MODEL??null,SMALL_MODEL:h.SMALL_MODEL??null,LARGE_MODEL:h.LARGE_MODEL??null,OPENAI_EMBEDDING_MODEL:h.OPENAI_EMBEDDING_MODEL??null,OPENAI_EMBEDDING_API_KEY:h.OPENAI_EMBEDDING_API_KEY??null,OPENAI_EMBEDDING_URL:h.OPENAI_EMBEDDING_URL??null,OPENAI_EMBEDDING_DIMENSIONS:h.OPENAI_EMBEDDING_DIMENSIONS??null,OPENAI_IMAGE_DESCRIPTION_MODEL:h.OPENAI_IMAGE_DESCRIPTION_MODEL??null,OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS:h.OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS??null,OPENAI_EXPERIMENTAL_TELEMETRY:h.OPENAI_EXPERIMENTAL_TELEMETRY??null,OPENAI_RESEARCH_MODEL:h.OPENAI_RESEARCH_MODEL??null,OPENAI_RESEARCH_TIMEOUT:h.OPENAI_RESEARCH_TIMEOUT??null},async init(o,n){Io(o,n)},models:{[I.TEXT_EMBEDDING]:async(o,n)=>{return V(o,n)},[I.TEXT_TOKENIZER_ENCODE]:async(o,n)=>{return e(o,n)},[I.TEXT_TOKENIZER_DECODE]:async(o,n)=>{return B(o,n)},[I.TEXT_SMALL]:async(o,n)=>{return q(o,n)},[I.TEXT_LARGE]:async(o,n)=>{return M(o,n)},[I.IMAGE]:async(o,n)=>{return Q(o,n)},[I.IMAGE_DESCRIPTION]:async(o,n)=>{return D(o,n)},[I.TRANSCRIPTION]:async(o,n)=>{return C(o,n)},[I.TEXT_TO_SPEECH]:async(o,n)=>{return H(o,n)},[I.OBJECT_SMALL]:async(o,n)=>{return Z(o,n)},[I.OBJECT_LARGE]:async(o,n)=>{return Y(o,n)},[I.RESEARCH]:async(o,n)=>{return G(o,n)}},tests:[{name:"openai_plugin_tests",tests:[{name:"openai_test_api_connectivity",fn:async(o)=>{let n=O(o),c=await fetch(`${n}/models`,{headers:R(o)});if(!c.ok)throw Error(`API connectivity test failed: ${c.status} ${c.statusText}`);let r=await c.json();l.info(`[OpenAI Test] API connected. ${r.data?.length??0} models available.`)}},{name:"openai_test_text_embedding",fn:async(o)=>{let n=await o.useModel(I.TEXT_EMBEDDING,{text:"Hello, world!"});if(!Array.isArray(n)||n.length===0)throw Error("Embedding should return a non-empty array");l.info(`[OpenAI Test] Generated embedding with ${n.length} dimensions`)}},{name:"openai_test_text_small",fn:async(o)=>{let n=await o.useModel(I.TEXT_SMALL,{prompt:"Say hello in exactly 5 words."});if(typeof n!=="string"||n.length===0)throw Error("TEXT_SMALL should return non-empty string");l.info(`[OpenAI Test] TEXT_SMALL generated: "${n.substring(0,50)}..."`)}},{name:"openai_test_text_large",fn:async(o)=>{let n=await o.useModel(I.TEXT_LARGE,{prompt:"Explain quantum computing in 2 sentences."});if(typeof n!=="string"||n.length===0)throw Error("TEXT_LARGE should return non-empty string");l.info(`[OpenAI Test] TEXT_LARGE generated: "${n.substring(0,50)}..."`)}},{name:"openai_test_tokenizer_roundtrip",fn:async(o)=>{let c=await o.useModel(I.TEXT_TOKENIZER_ENCODE,{prompt:"Hello, tokenizer test!",modelType:I.TEXT_SMALL});if(!Array.isArray(c)||c.length===0)throw Error("Tokenization should return non-empty token array");let r=await o.useModel(I.TEXT_TOKENIZER_DECODE,{tokens:c,modelType:I.TEXT_SMALL});if(r!=="Hello, tokenizer test!")throw Error(`Tokenizer roundtrip failed: expected "Hello, tokenizer test!", got "${r}"`);l.info(`[OpenAI Test] Tokenizer roundtrip successful (${c.length} tokens)`)}},{name:"openai_test_streaming",fn:async(o)=>{let n=[],c=await o.useModel(I.TEXT_LARGE,{prompt:"Count from 1 to 5, one number per line.",stream:!0,onStreamChunk:(r)=>{n.push(r)}});if(typeof c!=="string"||c.length===0)throw Error("Streaming should return non-empty result");if(n.length===0)throw Error("No streaming chunks received");l.info(`[OpenAI Test] Streaming test: ${n.length} chunks received`)}},{name:"openai_test_image_description",fn:async(o)=>{let c=await o.useModel(I.IMAGE_DESCRIPTION,"https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Camponotus_flavomarginatus_ant.jpg/440px-Camponotus_flavomarginatus_ant.jpg");if(!c||typeof c!=="object"||!("title"in c)||!("description"in c))throw Error("Image description should return { title, description }");l.info(`[OpenAI Test] Image described: "${c.title}"`)}},{name:"openai_test_transcription",fn:async(o)=>{let r=await(await fetch("https://upload.wikimedia.org/wikipedia/commons/2/25/En-Open_Source.ogg")).arrayBuffer(),f=Buffer.from(new Uint8Array(r)),T=await o.useModel(I.TRANSCRIPTION,f);if(typeof T!=="string")throw Error("Transcription should return a string");l.info(`[OpenAI Test] Transcription: "${T.substring(0,50)}..."`)}},{name:"openai_test_text_to_speech",fn:async(o)=>{let n=await o.useModel(I.TEXT_TO_SPEECH,{text:"Hello, this is a text-to-speech test."});if(!(n instanceof ArrayBuffer)||n.byteLength===0)throw Error("TTS should return non-empty ArrayBuffer");l.info(`[OpenAI Test] TTS generated ${n.byteLength} bytes of audio`)}},{name:"openai_test_object_generation",fn:async(o)=>{let n=await o.useModel(I.OBJECT_SMALL,{prompt:"Return a JSON object with exactly these fields: name (string), age (number), active (boolean)"});if(!n||typeof n!=="object")throw Error("Object generation should return an object");l.info(`[OpenAI Test] Object generated: ${JSON.stringify(n).substring(0,100)}`)}},{name:"openai_test_research",fn:async(o)=>{let n=await o.useModel(I.RESEARCH,{input:"What is the current date and time?",tools:[{type:"web_search_preview"}],maxToolCalls:3});if(!n||typeof n!=="object"||!("text"in n))throw Error("Research should return an object with text property");if(typeof n.text!=="string"||n.text.length===0)throw Error("Research result text should be a non-empty string");l.info(`[OpenAI Test] Research completed. Text length: ${n.text.length}, Annotations: ${n.annotations?.length??0}`)}}]}]},On=wn;export{wn as openaiPlugin,On as default};
2
-
3
- //# debugId=01A431D38E4333C464756E2164756E21