@elizaos/plugin-openai 1.5.16 → 1.5.18

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.
@@ -18,19 +18,18 @@ var __toESM = (mod, isNodeMode, target) => {
18
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
 
20
20
  // src/index.ts
21
- import { createOpenAI } from "@ai-sdk/openai";
22
- import { EventType, logger, ModelType, VECTOR_DIMS } from "@elizaos/core";
23
- import {
24
- generateObject,
25
- generateText,
26
- JSONParseError
27
- } from "ai";
28
- import { encodingForModel } from "js-tiktoken";
21
+ import { logger as logger10, ModelType as ModelType7 } from "@elizaos/core";
22
+
23
+ // src/init.ts
24
+ import { logger as logger2 } from "@elizaos/core";
25
+
26
+ // src/utils/config.ts
27
+ import { logger } from "@elizaos/core";
29
28
  function getSetting(runtime, key, defaultValue) {
30
29
  return runtime.getSetting(key) ?? process.env[key] ?? defaultValue;
31
30
  }
32
31
  function isBrowser() {
33
- return typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
32
+ return typeof globalThis !== "undefined" && "document" in globalThis && typeof globalThis.document !== "undefined";
34
33
  }
35
34
  function isProxyMode(runtime) {
36
35
  return isBrowser() && !!getSetting(runtime, "OPENAI_BROWSER_BASE_URL");
@@ -69,13 +68,13 @@ function getEmbeddingApiKey(runtime) {
69
68
  return getApiKey(runtime);
70
69
  }
71
70
  function getSmallModel(runtime) {
72
- return getSetting(runtime, "OPENAI_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", "gpt-5-nano");
71
+ return getSetting(runtime, "OPENAI_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", "gpt-4o-mini");
73
72
  }
74
73
  function getLargeModel(runtime) {
75
- return getSetting(runtime, "OPENAI_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", "gpt-5-mini");
74
+ return getSetting(runtime, "OPENAI_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", "gpt-4o");
76
75
  }
77
76
  function getImageDescriptionModel(runtime) {
78
- return getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_MODEL", "gpt-5-nano") ?? "gpt-5-nano";
77
+ return getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_MODEL", "gpt-5-nano");
79
78
  }
80
79
  function getExperimentalTelemetry(runtime) {
81
80
  const setting = getSetting(runtime, "OPENAI_EXPERIMENTAL_TELEMETRY", "false");
@@ -84,121 +83,347 @@ function getExperimentalTelemetry(runtime) {
84
83
  logger.debug(`[OpenAI] Experimental telemetry in function: "${setting}" (type: ${typeof setting}, normalized: "${normalizedSetting}", result: ${result})`);
85
84
  return result;
86
85
  }
86
+
87
+ // src/init.ts
88
+ function initializeOpenAI(_config, runtime) {
89
+ (async () => {
90
+ try {
91
+ if (!getApiKey(runtime) && !isBrowser()) {
92
+ logger2.warn("OPENAI_API_KEY is not set in environment - OpenAI functionality will be limited");
93
+ return;
94
+ }
95
+ try {
96
+ const baseURL = getBaseURL(runtime);
97
+ const response = await fetch(`${baseURL}/models`, {
98
+ headers: getAuthHeader(runtime)
99
+ });
100
+ if (!response.ok) {
101
+ logger2.warn(`OpenAI API key validation failed: ${response.statusText}`);
102
+ logger2.warn("OpenAI functionality will be limited until a valid API key is provided");
103
+ } else {
104
+ logger2.log("OpenAI API key validated successfully");
105
+ }
106
+ } catch (fetchError) {
107
+ const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
108
+ logger2.warn(`Error validating OpenAI API key: ${message}`);
109
+ logger2.warn("OpenAI functionality will be limited until a valid API key is provided");
110
+ }
111
+ } catch (error) {
112
+ const message = error?.errors?.map((e) => e.message).join(", ") || (error instanceof Error ? error.message : String(error));
113
+ logger2.warn(`OpenAI plugin configuration issue: ${message} - You need to configure the OPENAI_API_KEY in your environment variables`);
114
+ }
115
+ })();
116
+ }
117
+
118
+ // src/models/text.ts
119
+ import { logger as logger3, ModelType } from "@elizaos/core";
120
+ import { generateText } from "ai";
121
+
122
+ // src/providers/openai.ts
123
+ import { createOpenAI } from "@ai-sdk/openai";
87
124
  function createOpenAIClient(runtime) {
88
125
  const baseURL = getBaseURL(runtime);
89
126
  const apiKey = getApiKey(runtime) ?? (isProxyMode(runtime) ? "sk-proxy" : undefined);
90
127
  return createOpenAI({ apiKey: apiKey ?? "", baseURL });
91
128
  }
92
- async function tokenizeText(model, prompt) {
93
- const modelName = model === ModelType.TEXT_SMALL ? process.env.OPENAI_SMALL_MODEL ?? process.env.SMALL_MODEL ?? "gpt-5-nano" : process.env.LARGE_MODEL ?? "gpt-5-mini";
94
- const tokens = encodingForModel(modelName).encode(prompt);
95
- return tokens;
96
- }
97
- async function detokenizeText(model, tokens) {
98
- const modelName = model === ModelType.TEXT_SMALL ? process.env.OPENAI_SMALL_MODEL ?? process.env.SMALL_MODEL ?? "gpt-5-nano" : process.env.OPENAI_LARGE_MODEL ?? process.env.LARGE_MODEL ?? "gpt-5-mini";
99
- return encodingForModel(modelName).decode(tokens);
129
+
130
+ // src/utils/events.ts
131
+ import { EventType } from "@elizaos/core";
132
+ function emitModelUsageEvent(runtime, type, prompt, usage) {
133
+ const promptTokens = ("promptTokens" in usage ? usage.promptTokens : undefined) ?? ("inputTokens" in usage ? usage.inputTokens : undefined) ?? 0;
134
+ const completionTokens = ("completionTokens" in usage ? usage.completionTokens : undefined) ?? ("outputTokens" in usage ? usage.outputTokens : undefined) ?? 0;
135
+ const totalTokens = ("totalTokens" in usage ? usage.totalTokens : undefined) ?? promptTokens + completionTokens;
136
+ runtime.emitEvent(EventType.MODEL_USED, {
137
+ provider: "openai",
138
+ type,
139
+ prompt,
140
+ tokens: {
141
+ prompt: promptTokens,
142
+ completion: completionTokens,
143
+ total: totalTokens
144
+ }
145
+ });
100
146
  }
101
- async function generateObjectByModelType(runtime, params, modelType, getModelFn) {
147
+
148
+ // src/models/text.ts
149
+ async function generateTextByModelType(runtime, params, modelType, getModelFn) {
102
150
  const openai = createOpenAIClient(runtime);
103
151
  const modelName = getModelFn(runtime);
104
- logger.log(`[OpenAI] Using ${modelType} model: ${modelName}`);
105
- const temperature = params.temperature ?? 0;
106
- const schemaPresent = !!params.schema;
107
- if (schemaPresent) {
108
- logger.info(`Using ${modelType} without schema validation (schema provided but output=no-schema)`);
152
+ const experimentalTelemetry = getExperimentalTelemetry(runtime);
153
+ logger3.log(`[OpenAI] Using ${modelType} model: ${modelName}`);
154
+ logger3.log(params.prompt);
155
+ const {
156
+ prompt,
157
+ stopSequences = [],
158
+ maxTokens = 8192,
159
+ temperature = 0.7,
160
+ frequencyPenalty = 0.7,
161
+ presencePenalty = 0.7
162
+ } = params;
163
+ const { text: openaiResponse, usage } = await generateText({
164
+ model: openai.languageModel(modelName),
165
+ prompt,
166
+ system: runtime.character.system ?? undefined,
167
+ temperature,
168
+ maxOutputTokens: maxTokens,
169
+ frequencyPenalty,
170
+ presencePenalty,
171
+ stopSequences,
172
+ experimental_telemetry: {
173
+ isEnabled: experimentalTelemetry
174
+ }
175
+ });
176
+ if (usage) {
177
+ emitModelUsageEvent(runtime, modelType, prompt, usage);
178
+ }
179
+ return openaiResponse;
180
+ }
181
+ async function handleTextSmall(runtime, params) {
182
+ return generateTextByModelType(runtime, params, ModelType.TEXT_SMALL, getSmallModel);
183
+ }
184
+ async function handleTextLarge(runtime, params) {
185
+ return generateTextByModelType(runtime, params, ModelType.TEXT_LARGE, getLargeModel);
186
+ }
187
+ // src/models/embedding.ts
188
+ import { logger as logger4, ModelType as ModelType2, VECTOR_DIMS } from "@elizaos/core";
189
+ async function handleTextEmbedding(runtime, params) {
190
+ const embeddingModelName = getSetting(runtime, "OPENAI_EMBEDDING_MODEL", "text-embedding-3-small");
191
+ const embeddingDimension = Number.parseInt(getSetting(runtime, "OPENAI_EMBEDDING_DIMENSIONS", "1536") || "1536", 10);
192
+ if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {
193
+ const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(", ")}`;
194
+ logger4.error(errorMsg);
195
+ throw new Error(errorMsg);
196
+ }
197
+ if (params === null) {
198
+ logger4.debug("Creating test embedding for initialization");
199
+ const testVector = Array(embeddingDimension).fill(0);
200
+ testVector[0] = 0.1;
201
+ return testVector;
202
+ }
203
+ let text;
204
+ if (typeof params === "string") {
205
+ text = params;
206
+ } else if (typeof params === "object" && params.text) {
207
+ text = params.text;
208
+ } else {
209
+ const errorMsg = "Invalid input format for embedding";
210
+ logger4.warn(errorMsg);
211
+ const fallbackVector = Array(embeddingDimension).fill(0);
212
+ fallbackVector[0] = 0.2;
213
+ return fallbackVector;
214
+ }
215
+ if (!text.trim()) {
216
+ const errorMsg = "Empty text for embedding";
217
+ logger4.warn(errorMsg);
218
+ const fallbackVector = Array(embeddingDimension).fill(0);
219
+ fallbackVector[0] = 0.3;
220
+ return fallbackVector;
109
221
  }
222
+ const embeddingBaseURL = getEmbeddingBaseURL(runtime);
110
223
  try {
111
- const { object, usage } = await generateObject({
112
- model: openai.languageModel(modelName),
113
- output: "no-schema",
114
- prompt: params.prompt,
115
- temperature,
116
- experimental_repairText: getJsonRepairFunction()
224
+ const response = await fetch(`${embeddingBaseURL}/embeddings`, {
225
+ method: "POST",
226
+ headers: {
227
+ ...getAuthHeader(runtime, true),
228
+ "Content-Type": "application/json"
229
+ },
230
+ body: JSON.stringify({
231
+ model: embeddingModelName,
232
+ input: text
233
+ })
117
234
  });
118
- if (usage) {
119
- emitModelUsageEvent(runtime, modelType, params.prompt, usage);
235
+ if (!response.ok) {
236
+ logger4.error(`OpenAI API error: ${response.status} - ${response.statusText}`);
237
+ throw new Error(`OpenAI API error: ${response.status} - ${response.statusText}`);
120
238
  }
121
- return object;
122
- } catch (error) {
123
- if (error instanceof JSONParseError) {
124
- logger.error(`[generateObject] Failed to parse JSON: ${error.message}`);
125
- const repairFunction = getJsonRepairFunction();
126
- const repairedJsonString = await repairFunction({
127
- text: error.text,
128
- error
129
- });
130
- if (repairedJsonString) {
131
- try {
132
- const repairedObject = JSON.parse(repairedJsonString);
133
- logger.info("[generateObject] Successfully repaired JSON.");
134
- return repairedObject;
135
- } catch (repairParseError) {
136
- const message = repairParseError instanceof Error ? repairParseError.message : String(repairParseError);
137
- logger.error(`[generateObject] Failed to parse repaired JSON: ${message}`);
138
- throw repairParseError;
139
- }
140
- } else {
141
- logger.error("[generateObject] JSON repair failed.");
142
- throw error;
143
- }
144
- } else {
145
- const message = error instanceof Error ? error.message : String(error);
146
- logger.error(`[generateObject] Unknown error: ${message}`);
147
- throw error;
239
+ const data = await response.json();
240
+ if (!data?.data?.[0]?.embedding) {
241
+ logger4.error("API returned invalid structure");
242
+ throw new Error("API returned invalid structure");
243
+ }
244
+ const embedding = data.data[0].embedding;
245
+ if (!Array.isArray(embedding) || embedding.length !== embeddingDimension) {
246
+ const errorMsg = `Embedding length ${embedding?.length ?? 0} does not match configured dimension ${embeddingDimension}`;
247
+ logger4.error(errorMsg);
248
+ const fallbackVector = Array(embeddingDimension).fill(0);
249
+ fallbackVector[0] = 0.4;
250
+ return fallbackVector;
148
251
  }
252
+ if (data.usage) {
253
+ const usage = {
254
+ inputTokens: data.usage.prompt_tokens,
255
+ outputTokens: 0,
256
+ totalTokens: data.usage.total_tokens
257
+ };
258
+ emitModelUsageEvent(runtime, ModelType2.TEXT_EMBEDDING, text, usage);
259
+ }
260
+ logger4.log(`Got valid embedding with length ${embedding.length}`);
261
+ return embedding;
262
+ } catch (error) {
263
+ const message = error instanceof Error ? error.message : String(error);
264
+ logger4.error(`Error generating embedding: ${message}`);
265
+ throw error instanceof Error ? error : new Error(message);
149
266
  }
150
267
  }
151
- function getJsonRepairFunction() {
152
- return async ({ text, error }) => {
153
- try {
154
- if (error instanceof JSONParseError) {
155
- const cleanedText = text.replace(/```json\n|\n```|```/g, "");
156
- JSON.parse(cleanedText);
157
- return cleanedText;
158
- }
159
- return null;
160
- } catch (jsonError) {
161
- const message = jsonError instanceof Error ? jsonError.message : String(jsonError);
162
- logger.warn(`Failed to repair JSON text: ${message}`);
163
- return null;
268
+ // src/models/image.ts
269
+ import { logger as logger5, ModelType as ModelType3 } from "@elizaos/core";
270
+ async function handleImageGeneration(runtime, params) {
271
+ const n = params.n || 1;
272
+ const size = params.size || "1024x1024";
273
+ const prompt = params.prompt;
274
+ const modelName = getSetting(runtime, "OPENAI_IMAGE_MODEL", "gpt-image-1");
275
+ logger5.log(`[OpenAI] Using IMAGE model: ${modelName}`);
276
+ const baseURL = getBaseURL(runtime);
277
+ try {
278
+ const response = await fetch(`${baseURL}/images/generations`, {
279
+ method: "POST",
280
+ headers: {
281
+ ...getAuthHeader(runtime),
282
+ "Content-Type": "application/json"
283
+ },
284
+ body: JSON.stringify({
285
+ model: modelName,
286
+ prompt,
287
+ n,
288
+ size
289
+ })
290
+ });
291
+ if (!response.ok) {
292
+ throw new Error(`Failed to generate image: ${response.statusText}`);
164
293
  }
165
- };
294
+ const data = await response.json();
295
+ const typedData = data;
296
+ return typedData;
297
+ } catch (error) {
298
+ const message = error instanceof Error ? error.message : String(error);
299
+ throw error;
300
+ }
166
301
  }
167
- function emitModelUsageEvent(runtime, type, prompt, usage) {
168
- runtime.emitEvent(EventType.MODEL_USED, {
169
- provider: "openai",
170
- type,
171
- prompt,
172
- tokens: {
173
- prompt: usage.inputTokens,
174
- completion: usage.outputTokens,
175
- total: usage.totalTokens
302
+ async function handleImageDescription(runtime, params) {
303
+ let imageUrl;
304
+ let promptText;
305
+ const modelName = getImageDescriptionModel(runtime);
306
+ logger5.log(`[OpenAI] Using IMAGE_DESCRIPTION model: ${modelName}`);
307
+ const maxTokens = Number.parseInt(getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS", "8192") || "8192", 10);
308
+ const DEFAULT_PROMPT = "Please analyze this image and provide a title and detailed description.";
309
+ if (typeof params === "string") {
310
+ imageUrl = params;
311
+ promptText = DEFAULT_PROMPT;
312
+ } else {
313
+ imageUrl = params.imageUrl;
314
+ promptText = params.prompt || DEFAULT_PROMPT;
315
+ }
316
+ const messages = [
317
+ {
318
+ role: "user",
319
+ content: [
320
+ { type: "text", text: promptText },
321
+ { type: "image_url", image_url: { url: imageUrl } }
322
+ ]
176
323
  }
177
- });
324
+ ];
325
+ const baseURL = getBaseURL(runtime);
326
+ try {
327
+ const requestBody = {
328
+ model: modelName,
329
+ messages,
330
+ max_tokens: maxTokens
331
+ };
332
+ const response = await fetch(`${baseURL}/chat/completions`, {
333
+ method: "POST",
334
+ headers: {
335
+ "Content-Type": "application/json",
336
+ ...getAuthHeader(runtime)
337
+ },
338
+ body: JSON.stringify(requestBody)
339
+ });
340
+ if (!response.ok) {
341
+ throw new Error(`OpenAI API error: ${response.status}`);
342
+ }
343
+ const result = await response.json();
344
+ const typedResult = result;
345
+ const content = typedResult.choices?.[0]?.message?.content;
346
+ if (typedResult.usage) {
347
+ emitModelUsageEvent(runtime, ModelType3.IMAGE_DESCRIPTION, typeof params === "string" ? params : params.prompt || "", {
348
+ inputTokens: typedResult.usage.prompt_tokens,
349
+ outputTokens: typedResult.usage.completion_tokens,
350
+ totalTokens: typedResult.usage.total_tokens
351
+ });
352
+ }
353
+ if (!content) {
354
+ return {
355
+ title: "Failed to analyze image",
356
+ description: "No response from API"
357
+ };
358
+ }
359
+ const isCustomPrompt = typeof params === "object" && Boolean(params.prompt) && params.prompt !== DEFAULT_PROMPT;
360
+ if (isCustomPrompt) {
361
+ return content;
362
+ }
363
+ const titleMatch = content.match(/title[:\s]+(.+?)(?:\n|$)/i);
364
+ const title = titleMatch?.[1]?.trim();
365
+ if (!title) {
366
+ logger5.warn("Could not extract title from image description response");
367
+ }
368
+ const finalTitle = title || "Image Analysis";
369
+ const description = content.replace(/title[:\s]+(.+?)(?:\n|$)/i, "").trim();
370
+ const processedResult = { title: finalTitle, description };
371
+ return processedResult;
372
+ } catch (error) {
373
+ const message = error instanceof Error ? error.message : String(error);
374
+ logger5.error(`Error analyzing image: ${message}`);
375
+ return {
376
+ title: "Failed to analyze image",
377
+ description: `Error: ${message}`
378
+ };
379
+ }
380
+ }
381
+ // src/models/audio.ts
382
+ import { logger as logger7 } from "@elizaos/core";
383
+
384
+ // src/utils/audio.ts
385
+ import { logger as logger6 } from "@elizaos/core";
386
+ var MAGIC_BYTES = {
387
+ WAV: {
388
+ HEADER: [82, 73, 70, 70],
389
+ IDENTIFIER: [87, 65, 86, 69]
390
+ },
391
+ MP3_ID3: [73, 68, 51],
392
+ OGG: [79, 103, 103, 83],
393
+ FLAC: [102, 76, 97, 67],
394
+ FTYP: [102, 116, 121, 112],
395
+ WEBM_EBML: [26, 69, 223, 163]
396
+ };
397
+ function matchBytes(buffer, offset, bytes) {
398
+ for (let i = 0;i < bytes.length; i++) {
399
+ if (buffer[offset + i] !== bytes[i])
400
+ return false;
401
+ }
402
+ return true;
178
403
  }
179
404
  function detectAudioMimeType(buffer) {
180
405
  if (buffer.length < 12) {
181
406
  return "application/octet-stream";
182
407
  }
183
- if (buffer[0] === 82 && buffer[1] === 73 && buffer[2] === 70 && buffer[3] === 70 && buffer[8] === 87 && buffer[9] === 65 && buffer[10] === 86 && buffer[11] === 69) {
408
+ if (matchBytes(buffer, 0, MAGIC_BYTES.WAV.HEADER) && matchBytes(buffer, 8, MAGIC_BYTES.WAV.IDENTIFIER)) {
184
409
  return "audio/wav";
185
410
  }
186
- if (buffer[0] === 73 && buffer[1] === 68 && buffer[2] === 51 || buffer[0] === 255 && (buffer[1] & 224) === 224) {
411
+ if (matchBytes(buffer, 0, MAGIC_BYTES.MP3_ID3) || buffer[0] === 255 && (buffer[1] & 224) === 224) {
187
412
  return "audio/mpeg";
188
413
  }
189
- if (buffer[0] === 79 && buffer[1] === 103 && buffer[2] === 103 && buffer[3] === 83) {
414
+ if (matchBytes(buffer, 0, MAGIC_BYTES.OGG)) {
190
415
  return "audio/ogg";
191
416
  }
192
- if (buffer[0] === 102 && buffer[1] === 76 && buffer[2] === 97 && buffer[3] === 67) {
417
+ if (matchBytes(buffer, 0, MAGIC_BYTES.FLAC)) {
193
418
  return "audio/flac";
194
419
  }
195
- if (buffer[4] === 102 && buffer[5] === 116 && buffer[6] === 121 && buffer[7] === 112) {
420
+ if (matchBytes(buffer, 4, MAGIC_BYTES.FTYP)) {
196
421
  return "audio/mp4";
197
422
  }
198
- if (buffer[0] === 26 && buffer[1] === 69 && buffer[2] === 223 && buffer[3] === 163) {
423
+ if (matchBytes(buffer, 0, MAGIC_BYTES.WEBM_EBML)) {
199
424
  return "audio/webm";
200
425
  }
201
- logger.warn("Could not detect audio format from buffer, using generic binary type");
426
+ logger6.warn("Could not detect audio format from buffer, using generic binary type");
202
427
  return "application/octet-stream";
203
428
  }
204
429
  async function webStreamToNodeStream(webStream) {
@@ -224,10 +449,12 @@ async function webStreamToNodeStream(webStream) {
224
449
  });
225
450
  } catch (error) {
226
451
  const message = error instanceof Error ? error.message : String(error);
227
- logger.error(`Failed to load node:stream module: ${message}`);
452
+ logger6.error(`Failed to load node:stream module: ${message}`);
228
453
  throw new Error(`Cannot convert stream: node:stream module unavailable. This feature requires a Node.js environment.`);
229
454
  }
230
455
  }
456
+
457
+ // src/models/audio.ts
231
458
  async function fetchTextToSpeech(runtime, options) {
232
459
  const defaultModel = getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
233
460
  const defaultVoice = getSetting(runtime, "OPENAI_TTS_VOICE", "nova");
@@ -269,6 +496,191 @@ async function fetchTextToSpeech(runtime, options) {
269
496
  throw new Error(`Failed to fetch speech from OpenAI TTS: ${message}`);
270
497
  }
271
498
  }
499
+ async function handleTranscription(runtime, input) {
500
+ let modelName = getSetting(runtime, "OPENAI_TRANSCRIPTION_MODEL", "gpt-4o-mini-transcribe");
501
+ logger7.log(`[OpenAI] Using TRANSCRIPTION model: ${modelName}`);
502
+ const baseURL = getBaseURL(runtime);
503
+ let blob;
504
+ let extraParams = null;
505
+ if (input instanceof Blob || input instanceof File) {
506
+ blob = input;
507
+ } else if (Buffer.isBuffer(input)) {
508
+ const detectedMimeType = detectAudioMimeType(input);
509
+ logger7.debug(`Auto-detected audio MIME type: ${detectedMimeType}`);
510
+ const uint8Array = new Uint8Array(input);
511
+ blob = new Blob([uint8Array], { type: detectedMimeType });
512
+ } else if (typeof input === "object" && input !== null && input.audio != null) {
513
+ const params = input;
514
+ if (!(params.audio instanceof Blob) && !(params.audio instanceof File) && !Buffer.isBuffer(params.audio)) {
515
+ throw new Error("TRANSCRIPTION param 'audio' must be a Blob/File/Buffer.");
516
+ }
517
+ if (Buffer.isBuffer(params.audio)) {
518
+ let mimeType = params.mimeType;
519
+ if (!mimeType) {
520
+ mimeType = detectAudioMimeType(params.audio);
521
+ logger7.debug(`Auto-detected audio MIME type: ${mimeType}`);
522
+ } else {
523
+ logger7.debug(`Using provided MIME type: ${mimeType}`);
524
+ }
525
+ const uint8Array = new Uint8Array(params.audio);
526
+ blob = new Blob([uint8Array], { type: mimeType });
527
+ } else {
528
+ blob = params.audio;
529
+ }
530
+ extraParams = params;
531
+ if (typeof params.model === "string" && params.model) {
532
+ modelName = params.model;
533
+ }
534
+ } else {
535
+ throw new Error("TRANSCRIPTION expects a Blob/File/Buffer or an object { audio: Blob/File/Buffer, mimeType?, language?, response_format?, timestampGranularities?, prompt?, temperature?, model? }");
536
+ }
537
+ const mime = blob.type || "audio/webm";
538
+ const filename = blob.name || (mime.includes("mp3") || mime.includes("mpeg") ? "recording.mp3" : mime.includes("ogg") ? "recording.ogg" : mime.includes("wav") ? "recording.wav" : mime.includes("webm") ? "recording.webm" : "recording.bin");
539
+ const formData = new FormData;
540
+ formData.append("file", blob, filename);
541
+ formData.append("model", String(modelName));
542
+ if (extraParams) {
543
+ if (typeof extraParams.language === "string") {
544
+ formData.append("language", String(extraParams.language));
545
+ }
546
+ if (typeof extraParams.response_format === "string") {
547
+ formData.append("response_format", String(extraParams.response_format));
548
+ }
549
+ if (typeof extraParams.prompt === "string") {
550
+ formData.append("prompt", String(extraParams.prompt));
551
+ }
552
+ if (typeof extraParams.temperature === "number") {
553
+ formData.append("temperature", String(extraParams.temperature));
554
+ }
555
+ if (Array.isArray(extraParams.timestampGranularities)) {
556
+ for (const g of extraParams.timestampGranularities) {
557
+ formData.append("timestamp_granularities[]", String(g));
558
+ }
559
+ }
560
+ }
561
+ try {
562
+ const response = await fetch(`${baseURL}/audio/transcriptions`, {
563
+ method: "POST",
564
+ headers: {
565
+ ...getAuthHeader(runtime)
566
+ },
567
+ body: formData
568
+ });
569
+ if (!response.ok) {
570
+ throw new Error(`Failed to transcribe audio: ${response.status} ${response.statusText}`);
571
+ }
572
+ const data = await response.json();
573
+ return data.text || "";
574
+ } catch (error) {
575
+ const message = error instanceof Error ? error.message : String(error);
576
+ logger7.error(`TRANSCRIPTION error: ${message}`);
577
+ throw error;
578
+ }
579
+ }
580
+ async function handleTextToSpeech(runtime, input) {
581
+ const options = typeof input === "string" ? { text: input } : input;
582
+ const resolvedModel = options.model || getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
583
+ logger7.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${resolvedModel}`);
584
+ try {
585
+ const speechStream = await fetchTextToSpeech(runtime, options);
586
+ return speechStream;
587
+ } catch (error) {
588
+ const message = error instanceof Error ? error.message : String(error);
589
+ logger7.error(`Error in TEXT_TO_SPEECH: ${message}`);
590
+ throw error;
591
+ }
592
+ }
593
+ // src/models/object.ts
594
+ import { logger as logger9, ModelType as ModelType4 } from "@elizaos/core";
595
+ import { generateObject } from "ai";
596
+
597
+ // src/utils/json.ts
598
+ import { logger as logger8 } from "@elizaos/core";
599
+ import { JSONParseError } from "ai";
600
+ function getJsonRepairFunction() {
601
+ return async ({ text, error }) => {
602
+ try {
603
+ if (error instanceof JSONParseError) {
604
+ const cleanedText = text.replace(/```json\n|\n```|```/g, "");
605
+ JSON.parse(cleanedText);
606
+ return cleanedText;
607
+ }
608
+ return null;
609
+ } catch (jsonError) {
610
+ const message = jsonError instanceof Error ? jsonError.message : String(jsonError);
611
+ logger8.warn(`Failed to repair JSON text: ${message}`);
612
+ return null;
613
+ }
614
+ };
615
+ }
616
+
617
+ // src/models/object.ts
618
+ async function generateObjectByModelType(runtime, params, modelType, getModelFn) {
619
+ const openai = createOpenAIClient(runtime);
620
+ const modelName = getModelFn(runtime);
621
+ logger9.log(`[OpenAI] Using ${modelType} model: ${modelName}`);
622
+ const temperature = params.temperature ?? 0;
623
+ const schemaPresent = !!params.schema;
624
+ if (schemaPresent) {
625
+ logger9.warn(`Schema provided but ignored: OpenAI object generation currently uses output=no-schema. The schema parameter has no effect.`);
626
+ }
627
+ try {
628
+ const { object, usage } = await generateObject({
629
+ model: openai.languageModel(modelName),
630
+ output: "no-schema",
631
+ prompt: params.prompt,
632
+ temperature,
633
+ experimental_repairText: getJsonRepairFunction()
634
+ });
635
+ if (usage) {
636
+ emitModelUsageEvent(runtime, modelType, params.prompt, usage);
637
+ }
638
+ return object;
639
+ } catch (error) {
640
+ const message = error instanceof Error ? error.message : String(error);
641
+ logger9.error(`[generateObject] Error: ${message}`);
642
+ throw error;
643
+ }
644
+ }
645
+ async function handleObjectSmall(runtime, params) {
646
+ return generateObjectByModelType(runtime, params, ModelType4.OBJECT_SMALL, getSmallModel);
647
+ }
648
+ async function handleObjectLarge(runtime, params) {
649
+ return generateObjectByModelType(runtime, params, ModelType4.OBJECT_LARGE, getLargeModel);
650
+ }
651
+ // src/models/tokenizer.ts
652
+ import { ModelType as ModelType6 } from "@elizaos/core";
653
+
654
+ // src/utils/tokenization.ts
655
+ import { ModelType as ModelType5 } from "@elizaos/core";
656
+ import { encodingForModel, getEncoding } from "js-tiktoken";
657
+ function resolveTokenizerEncoding(modelName) {
658
+ const normalized = modelName.toLowerCase();
659
+ const fallbackEncoding = normalized.includes("4o") ? "o200k_base" : "cl100k_base";
660
+ try {
661
+ return encodingForModel(modelName);
662
+ } catch (error) {
663
+ return getEncoding(fallbackEncoding);
664
+ }
665
+ }
666
+ async function tokenizeText(runtime, model, prompt) {
667
+ const modelName = model === ModelType5.TEXT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
668
+ const tokens = resolveTokenizerEncoding(modelName).encode(prompt);
669
+ return tokens;
670
+ }
671
+ async function detokenizeText(runtime, model, tokens) {
672
+ const modelName = model === ModelType5.TEXT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
673
+ return resolveTokenizerEncoding(modelName).decode(tokens);
674
+ }
675
+
676
+ // src/models/tokenizer.ts
677
+ async function handleTokenizerEncode(runtime, { prompt, modelType = ModelType6.TEXT_LARGE }) {
678
+ return await tokenizeText(runtime, modelType, prompt);
679
+ }
680
+ async function handleTokenizerDecode(runtime, { tokens, modelType = ModelType6.TEXT_LARGE }) {
681
+ return await detokenizeText(runtime, modelType, tokens);
682
+ }
683
+ // src/index.ts
272
684
  var openaiPlugin = {
273
685
  name: "openai",
274
686
  description: "OpenAI plugin",
@@ -288,383 +700,41 @@ var openaiPlugin = {
288
700
  OPENAI_EXPERIMENTAL_TELEMETRY: process.env.OPENAI_EXPERIMENTAL_TELEMETRY
289
701
  },
290
702
  async init(_config, runtime) {
291
- new Promise(async (resolve) => {
292
- resolve();
293
- try {
294
- if (!getApiKey(runtime) && !isBrowser()) {
295
- logger.warn("OPENAI_API_KEY is not set in environment - OpenAI functionality will be limited");
296
- return;
297
- }
298
- try {
299
- const baseURL = getBaseURL(runtime);
300
- const response = await fetch(`${baseURL}/models`, {
301
- headers: { ...getAuthHeader(runtime) }
302
- });
303
- if (!response.ok) {
304
- logger.warn(`OpenAI API key validation failed: ${response.statusText}`);
305
- logger.warn("OpenAI functionality will be limited until a valid API key is provided");
306
- } else {
307
- logger.log("OpenAI API key validated successfully");
308
- }
309
- } catch (fetchError) {
310
- const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
311
- logger.warn(`Error validating OpenAI API key: ${message}`);
312
- logger.warn("OpenAI functionality will be limited until a valid API key is provided");
313
- }
314
- } catch (error) {
315
- const message = error?.errors?.map((e) => e.message).join(", ") || (error instanceof Error ? error.message : String(error));
316
- logger.warn(`OpenAI plugin configuration issue: ${message} - You need to configure the OPENAI_API_KEY in your environment variables`);
317
- }
318
- });
703
+ initializeOpenAI(_config, runtime);
319
704
  },
320
705
  models: {
321
- [ModelType.TEXT_EMBEDDING]: async (runtime, params) => {
322
- const embeddingModelName = getSetting(runtime, "OPENAI_EMBEDDING_MODEL", "text-embedding-3-small");
323
- const embeddingDimension = Number.parseInt(getSetting(runtime, "OPENAI_EMBEDDING_DIMENSIONS", "1536") || "1536", 10);
324
- if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {
325
- const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(", ")}`;
326
- logger.error(errorMsg);
327
- throw new Error(errorMsg);
328
- }
329
- if (params === null) {
330
- logger.debug("Creating test embedding for initialization");
331
- const testVector = Array(embeddingDimension).fill(0);
332
- testVector[0] = 0.1;
333
- return testVector;
334
- }
335
- let text;
336
- if (typeof params === "string") {
337
- text = params;
338
- } else if (typeof params === "object" && params.text) {
339
- text = params.text;
340
- } else {
341
- logger.warn("Invalid input format for embedding");
342
- const fallbackVector = Array(embeddingDimension).fill(0);
343
- fallbackVector[0] = 0.2;
344
- return fallbackVector;
345
- }
346
- if (!text.trim()) {
347
- logger.warn("Empty text for embedding");
348
- const emptyVector = Array(embeddingDimension).fill(0);
349
- emptyVector[0] = 0.3;
350
- return emptyVector;
351
- }
352
- const embeddingBaseURL = getEmbeddingBaseURL(runtime);
353
- try {
354
- const response = await fetch(`${embeddingBaseURL}/embeddings`, {
355
- method: "POST",
356
- headers: {
357
- ...getAuthHeader(runtime, true),
358
- "Content-Type": "application/json"
359
- },
360
- body: JSON.stringify({
361
- model: embeddingModelName,
362
- input: text
363
- })
364
- });
365
- if (!response.ok) {
366
- logger.error(`OpenAI API error: ${response.status} - ${response.statusText}`);
367
- const errorVector = Array(embeddingDimension).fill(0);
368
- errorVector[0] = 0.4;
369
- return errorVector;
370
- }
371
- const data = await response.json();
372
- if (!data?.data?.[0]?.embedding) {
373
- logger.error("API returned invalid structure");
374
- const errorVector = Array(embeddingDimension).fill(0);
375
- errorVector[0] = 0.5;
376
- return errorVector;
377
- }
378
- const embedding = data.data[0].embedding;
379
- if (data.usage) {
380
- const usage = {
381
- inputTokens: data.usage.prompt_tokens,
382
- outputTokens: 0,
383
- totalTokens: data.usage.total_tokens
384
- };
385
- emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage);
386
- }
387
- logger.log(`Got valid embedding with length ${embedding.length}`);
388
- return embedding;
389
- } catch (error) {
390
- const message = error instanceof Error ? error.message : String(error);
391
- logger.error(`Error generating embedding: ${message}`);
392
- const errorVector = Array(embeddingDimension).fill(0);
393
- errorVector[0] = 0.6;
394
- return errorVector;
395
- }
706
+ [ModelType7.TEXT_EMBEDDING]: async (runtime, params) => {
707
+ return handleTextEmbedding(runtime, params);
396
708
  },
397
- [ModelType.TEXT_TOKENIZER_ENCODE]: async (_runtime, { prompt, modelType = ModelType.TEXT_LARGE }) => {
398
- return await tokenizeText(modelType ?? ModelType.TEXT_LARGE, prompt);
709
+ [ModelType7.TEXT_TOKENIZER_ENCODE]: async (runtime, params) => {
710
+ return handleTokenizerEncode(runtime, params);
399
711
  },
400
- [ModelType.TEXT_TOKENIZER_DECODE]: async (_runtime, { tokens, modelType = ModelType.TEXT_LARGE }) => {
401
- return await detokenizeText(modelType ?? ModelType.TEXT_LARGE, tokens);
712
+ [ModelType7.TEXT_TOKENIZER_DECODE]: async (runtime, params) => {
713
+ return handleTokenizerDecode(runtime, params);
402
714
  },
403
- [ModelType.TEXT_SMALL]: async (runtime, {
404
- prompt,
405
- stopSequences = [],
406
- maxTokens = 8192,
407
- temperature = 0.7,
408
- frequencyPenalty = 0.7,
409
- presencePenalty = 0.7
410
- }) => {
411
- const openai = createOpenAIClient(runtime);
412
- const modelName = getSmallModel(runtime);
413
- const experimentalTelemetry = getExperimentalTelemetry(runtime);
414
- logger.log(`[OpenAI] Using TEXT_SMALL model: ${modelName}`);
415
- logger.log(prompt);
416
- const { text: openaiResponse, usage } = await generateText({
417
- model: openai.languageModel(modelName),
418
- prompt,
419
- system: runtime.character.system ?? undefined,
420
- temperature,
421
- maxOutputTokens: maxTokens,
422
- frequencyPenalty,
423
- presencePenalty,
424
- stopSequences,
425
- experimental_telemetry: {
426
- isEnabled: experimentalTelemetry
427
- }
428
- });
429
- if (usage) {
430
- emitModelUsageEvent(runtime, ModelType.TEXT_SMALL, prompt, usage);
431
- }
432
- return openaiResponse;
715
+ [ModelType7.TEXT_SMALL]: async (runtime, params) => {
716
+ return handleTextSmall(runtime, params);
433
717
  },
434
- [ModelType.TEXT_LARGE]: async (runtime, {
435
- prompt,
436
- stopSequences = [],
437
- maxTokens = 8192,
438
- temperature = 0.7,
439
- frequencyPenalty = 0.7,
440
- presencePenalty = 0.7
441
- }) => {
442
- const openai = createOpenAIClient(runtime);
443
- const modelName = getLargeModel(runtime);
444
- const experimentalTelemetry = getExperimentalTelemetry(runtime);
445
- logger.log(`[OpenAI] Using TEXT_LARGE model: ${modelName}`);
446
- logger.log(prompt);
447
- const { text: openaiResponse, usage } = await generateText({
448
- model: openai.languageModel(modelName),
449
- prompt,
450
- system: runtime.character.system ?? undefined,
451
- temperature,
452
- maxOutputTokens: maxTokens,
453
- frequencyPenalty,
454
- presencePenalty,
455
- stopSequences,
456
- experimental_telemetry: {
457
- isEnabled: experimentalTelemetry
458
- }
459
- });
460
- if (usage) {
461
- emitModelUsageEvent(runtime, ModelType.TEXT_LARGE, prompt, usage);
462
- }
463
- return openaiResponse;
718
+ [ModelType7.TEXT_LARGE]: async (runtime, params) => {
719
+ return handleTextLarge(runtime, params);
464
720
  },
465
- [ModelType.IMAGE]: async (runtime, params) => {
466
- const n = params.n || 1;
467
- const size = params.size || "1024x1024";
468
- const prompt = params.prompt;
469
- const modelName = "gpt-image-1";
470
- logger.log(`[OpenAI] Using IMAGE model: ${modelName}`);
471
- const baseURL = getBaseURL(runtime);
472
- try {
473
- const response = await fetch(`${baseURL}/images/generations`, {
474
- method: "POST",
475
- headers: {
476
- ...getAuthHeader(runtime),
477
- "Content-Type": "application/json"
478
- },
479
- body: JSON.stringify({
480
- model: modelName,
481
- prompt,
482
- n,
483
- size
484
- })
485
- });
486
- if (!response.ok) {
487
- throw new Error(`Failed to generate image: ${response.statusText}`);
488
- }
489
- const data = await response.json();
490
- const typedData = data;
491
- return typedData.data;
492
- } catch (error) {
493
- const message = error instanceof Error ? error.message : String(error);
494
- throw error;
495
- }
721
+ [ModelType7.IMAGE]: async (runtime, params) => {
722
+ return handleImageGeneration(runtime, params);
496
723
  },
497
- [ModelType.IMAGE_DESCRIPTION]: async (runtime, params) => {
498
- let imageUrl;
499
- let promptText;
500
- const modelName = getImageDescriptionModel(runtime);
501
- logger.log(`[OpenAI] Using IMAGE_DESCRIPTION model: ${modelName}`);
502
- const maxTokens = Number.parseInt(getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS", "8192") || "8192", 10);
503
- if (typeof params === "string") {
504
- imageUrl = params;
505
- promptText = "Please analyze this image and provide a title and detailed description.";
506
- } else {
507
- imageUrl = params.imageUrl;
508
- promptText = params.prompt || "Please analyze this image and provide a title and detailed description.";
509
- }
510
- const messages = [
511
- {
512
- role: "user",
513
- content: [
514
- { type: "text", text: promptText },
515
- { type: "image_url", image_url: { url: imageUrl } }
516
- ]
517
- }
518
- ];
519
- const baseURL = getBaseURL(runtime);
520
- try {
521
- const requestBody = {
522
- model: modelName,
523
- messages,
524
- max_tokens: maxTokens
525
- };
526
- const response = await fetch(`${baseURL}/chat/completions`, {
527
- method: "POST",
528
- headers: {
529
- "Content-Type": "application/json",
530
- ...getAuthHeader(runtime)
531
- },
532
- body: JSON.stringify(requestBody)
533
- });
534
- if (!response.ok) {
535
- throw new Error(`OpenAI API error: ${response.status}`);
536
- }
537
- const result = await response.json();
538
- const typedResult = result;
539
- const content = typedResult.choices?.[0]?.message?.content;
540
- if (typedResult.usage) {
541
- emitModelUsageEvent(runtime, ModelType.IMAGE_DESCRIPTION, typeof params === "string" ? params : params.prompt || "", {
542
- inputTokens: typedResult.usage.prompt_tokens,
543
- outputTokens: typedResult.usage.completion_tokens,
544
- totalTokens: typedResult.usage.total_tokens
545
- });
546
- }
547
- if (!content) {
548
- return {
549
- title: "Failed to analyze image",
550
- description: "No response from API"
551
- };
552
- }
553
- const isCustomPrompt = typeof params === "object" && params.prompt && params.prompt !== "Please analyze this image and provide a title and detailed description.";
554
- if (isCustomPrompt) {
555
- return content;
556
- }
557
- const titleMatch = content.match(/title[:\s]+(.+?)(?:\n|$)/i);
558
- const title = titleMatch?.[1]?.trim() || "Image Analysis";
559
- const description = content.replace(/title[:\s]+(.+?)(?:\n|$)/i, "").trim();
560
- const processedResult = { title, description };
561
- return processedResult;
562
- } catch (error) {
563
- const message = error instanceof Error ? error.message : String(error);
564
- logger.error(`Error analyzing image: ${message}`);
565
- return {
566
- title: "Failed to analyze image",
567
- description: `Error: ${message}`
568
- };
569
- }
724
+ [ModelType7.IMAGE_DESCRIPTION]: async (runtime, params) => {
725
+ return handleImageDescription(runtime, params);
570
726
  },
571
- [ModelType.TRANSCRIPTION]: async (runtime, input) => {
572
- let modelName = getSetting(runtime, "OPENAI_TRANSCRIPTION_MODEL", "gpt-4o-mini-transcribe");
573
- logger.log(`[OpenAI] Using TRANSCRIPTION model: ${modelName}`);
574
- const baseURL = getBaseURL(runtime);
575
- let blob;
576
- let extraParams = null;
577
- if (input instanceof Blob || input instanceof File) {
578
- blob = input;
579
- } else if (Buffer.isBuffer(input)) {
580
- const detectedMimeType = detectAudioMimeType(input);
581
- logger.debug(`Auto-detected audio MIME type: ${detectedMimeType}`);
582
- blob = new Blob([input], { type: detectedMimeType });
583
- } else if (typeof input === "object" && input !== null && input.audio != null) {
584
- const params = input;
585
- if (!(params.audio instanceof Blob) && !(params.audio instanceof File) && !Buffer.isBuffer(params.audio)) {
586
- throw new Error("TRANSCRIPTION param 'audio' must be a Blob/File/Buffer.");
587
- }
588
- if (Buffer.isBuffer(params.audio)) {
589
- let mimeType = params.mimeType;
590
- if (!mimeType) {
591
- mimeType = detectAudioMimeType(params.audio);
592
- logger.debug(`Auto-detected audio MIME type: ${mimeType}`);
593
- } else {
594
- logger.debug(`Using provided MIME type: ${mimeType}`);
595
- }
596
- blob = new Blob([params.audio], { type: mimeType });
597
- } else {
598
- blob = params.audio;
599
- }
600
- extraParams = params;
601
- if (typeof params.model === "string" && params.model) {
602
- modelName = params.model;
603
- }
604
- } else {
605
- throw new Error("TRANSCRIPTION expects a Blob/File/Buffer or an object { audio: Blob/File/Buffer, mimeType?, language?, response_format?, timestampGranularities?, prompt?, temperature?, model? }");
606
- }
607
- const mime = blob.type || "audio/webm";
608
- const filename = blob.name || (mime.includes("mp3") || mime.includes("mpeg") ? "recording.mp3" : mime.includes("ogg") ? "recording.ogg" : mime.includes("wav") ? "recording.wav" : mime.includes("webm") ? "recording.webm" : "recording.bin");
609
- const formData = new FormData;
610
- formData.append("file", blob, filename);
611
- formData.append("model", String(modelName));
612
- if (extraParams) {
613
- if (typeof extraParams.language === "string") {
614
- formData.append("language", String(extraParams.language));
615
- }
616
- if (typeof extraParams.response_format === "string") {
617
- formData.append("response_format", String(extraParams.response_format));
618
- }
619
- if (typeof extraParams.prompt === "string") {
620
- formData.append("prompt", String(extraParams.prompt));
621
- }
622
- if (typeof extraParams.temperature === "number") {
623
- formData.append("temperature", String(extraParams.temperature));
624
- }
625
- if (Array.isArray(extraParams.timestampGranularities)) {
626
- for (const g of extraParams.timestampGranularities) {
627
- formData.append("timestamp_granularities[]", String(g));
628
- }
629
- }
630
- }
631
- try {
632
- const response = await fetch(`${baseURL}/audio/transcriptions`, {
633
- method: "POST",
634
- headers: {
635
- ...getAuthHeader(runtime)
636
- },
637
- body: formData
638
- });
639
- if (!response.ok) {
640
- throw new Error(`Failed to transcribe audio: ${response.status} ${response.statusText}`);
641
- }
642
- const data = await response.json();
643
- return data.text || "";
644
- } catch (error) {
645
- const message = error instanceof Error ? error.message : String(error);
646
- logger.error(`TRANSCRIPTION error: ${message}`);
647
- throw error;
648
- }
727
+ [ModelType7.TRANSCRIPTION]: async (runtime, input) => {
728
+ return handleTranscription(runtime, input);
649
729
  },
650
- [ModelType.TEXT_TO_SPEECH]: async (runtime, input) => {
651
- const options = typeof input === "string" ? { text: input } : input;
652
- const resolvedModel = options.model || getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
653
- logger.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${resolvedModel}`);
654
- try {
655
- const speechStream = await fetchTextToSpeech(runtime, options);
656
- return speechStream;
657
- } catch (error) {
658
- const message = error instanceof Error ? error.message : String(error);
659
- logger.error(`Error in TEXT_TO_SPEECH: ${message}`);
660
- throw error;
661
- }
730
+ [ModelType7.TEXT_TO_SPEECH]: async (runtime, input) => {
731
+ return handleTextToSpeech(runtime, input);
662
732
  },
663
- [ModelType.OBJECT_SMALL]: async (runtime, params) => {
664
- return generateObjectByModelType(runtime, params, ModelType.OBJECT_SMALL, getSmallModel);
733
+ [ModelType7.OBJECT_SMALL]: async (runtime, params) => {
734
+ return handleObjectSmall(runtime, params);
665
735
  },
666
- [ModelType.OBJECT_LARGE]: async (runtime, params) => {
667
- return generateObjectByModelType(runtime, params, ModelType.OBJECT_LARGE, getLargeModel);
736
+ [ModelType7.OBJECT_LARGE]: async (runtime, params) => {
737
+ return handleObjectLarge(runtime, params);
668
738
  }
669
739
  },
670
740
  tests: [
@@ -676,12 +746,10 @@ var openaiPlugin = {
676
746
  fn: async (runtime) => {
677
747
  const baseURL = getBaseURL(runtime);
678
748
  const response = await fetch(`${baseURL}/models`, {
679
- headers: {
680
- Authorization: `Bearer ${getApiKey(runtime)}`
681
- }
749
+ headers: getAuthHeader(runtime)
682
750
  });
683
751
  const data = await response.json();
684
- logger.log({ data: data?.data?.length ?? "N/A" }, "Models Available");
752
+ logger10.log({ data: data?.data?.length ?? "N/A" }, "Models Available");
685
753
  if (!response.ok) {
686
754
  throw new Error(`Failed to validate OpenAI API key: ${response.statusText}`);
687
755
  }
@@ -691,13 +759,13 @@ var openaiPlugin = {
691
759
  name: "openai_test_text_embedding",
692
760
  fn: async (runtime) => {
693
761
  try {
694
- const embedding = await runtime.useModel(ModelType.TEXT_EMBEDDING, {
762
+ const embedding = await runtime.useModel(ModelType7.TEXT_EMBEDDING, {
695
763
  text: "Hello, world!"
696
764
  });
697
- logger.log({ embedding }, "embedding");
765
+ logger10.log({ embedding }, "embedding");
698
766
  } catch (error) {
699
767
  const message = error instanceof Error ? error.message : String(error);
700
- logger.error(`Error in test_text_embedding: ${message}`);
768
+ logger10.error(`Error in test_text_embedding: ${message}`);
701
769
  throw error;
702
770
  }
703
771
  }
@@ -706,16 +774,16 @@ var openaiPlugin = {
706
774
  name: "openai_test_text_large",
707
775
  fn: async (runtime) => {
708
776
  try {
709
- const text = await runtime.useModel(ModelType.TEXT_LARGE, {
777
+ const text = await runtime.useModel(ModelType7.TEXT_LARGE, {
710
778
  prompt: "What is the nature of reality in 10 words?"
711
779
  });
712
780
  if (text.length === 0) {
713
781
  throw new Error("Failed to generate text");
714
782
  }
715
- logger.log({ text }, "generated with test_text_large");
783
+ logger10.log({ text }, "generated with test_text_large");
716
784
  } catch (error) {
717
785
  const message = error instanceof Error ? error.message : String(error);
718
- logger.error(`Error in test_text_large: ${message}`);
786
+ logger10.error(`Error in test_text_large: ${message}`);
719
787
  throw error;
720
788
  }
721
789
  }
@@ -724,16 +792,16 @@ var openaiPlugin = {
724
792
  name: "openai_test_text_small",
725
793
  fn: async (runtime) => {
726
794
  try {
727
- const text = await runtime.useModel(ModelType.TEXT_SMALL, {
795
+ const text = await runtime.useModel(ModelType7.TEXT_SMALL, {
728
796
  prompt: "What is the nature of reality in 10 words?"
729
797
  });
730
798
  if (text.length === 0) {
731
799
  throw new Error("Failed to generate text");
732
800
  }
733
- logger.log({ text }, "generated with test_text_small");
801
+ logger10.log({ text }, "generated with test_text_small");
734
802
  } catch (error) {
735
803
  const message = error instanceof Error ? error.message : String(error);
736
- logger.error(`Error in test_text_small: ${message}`);
804
+ logger10.error(`Error in test_text_small: ${message}`);
737
805
  throw error;
738
806
  }
739
807
  }
@@ -741,17 +809,17 @@ var openaiPlugin = {
741
809
  {
742
810
  name: "openai_test_image_generation",
743
811
  fn: async (runtime) => {
744
- logger.log("openai_test_image_generation");
812
+ logger10.log("openai_test_image_generation");
745
813
  try {
746
- const image = await runtime.useModel(ModelType.IMAGE, {
814
+ const image = await runtime.useModel(ModelType7.IMAGE, {
747
815
  prompt: "A beautiful sunset over a calm ocean",
748
816
  n: 1,
749
817
  size: "1024x1024"
750
818
  });
751
- logger.log({ image }, "generated with test_image_generation");
819
+ logger10.log({ image }, "generated with test_image_generation");
752
820
  } catch (error) {
753
821
  const message = error instanceof Error ? error.message : String(error);
754
- logger.error(`Error in test_image_generation: ${message}`);
822
+ logger10.error(`Error in test_image_generation: ${message}`);
755
823
  throw error;
756
824
  }
757
825
  }
@@ -760,36 +828,36 @@ var openaiPlugin = {
760
828
  name: "image-description",
761
829
  fn: async (runtime) => {
762
830
  try {
763
- logger.log("openai_test_image_description");
831
+ logger10.log("openai_test_image_description");
764
832
  try {
765
- const result = await runtime.useModel(ModelType.IMAGE_DESCRIPTION, "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg/537px-Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg");
833
+ const result = await runtime.useModel(ModelType7.IMAGE_DESCRIPTION, "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg/537px-Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg");
766
834
  if (result && typeof result === "object" && "title" in result && "description" in result) {
767
- logger.log({ result }, "Image description");
835
+ logger10.log({ result }, "Image description");
768
836
  } else {
769
- logger.error("Invalid image description result format:", result);
837
+ logger10.error("Invalid image description result format:", result);
770
838
  }
771
839
  } catch (e) {
772
840
  const message = e instanceof Error ? e.message : String(e);
773
- logger.error(`Error in image description test: ${message}`);
841
+ logger10.error(`Error in image description test: ${message}`);
774
842
  }
775
843
  } catch (e) {
776
844
  const message = e instanceof Error ? e.message : String(e);
777
- logger.error(`Error in openai_test_image_description: ${message}`);
845
+ logger10.error(`Error in openai_test_image_description: ${message}`);
778
846
  }
779
847
  }
780
848
  },
781
849
  {
782
850
  name: "openai_test_transcription",
783
851
  fn: async (runtime) => {
784
- logger.log("openai_test_transcription");
852
+ logger10.log("openai_test_transcription");
785
853
  try {
786
854
  const response = await fetch("https://upload.wikimedia.org/wikipedia/en/4/40/Chris_Benoit_Voice_Message.ogg");
787
855
  const arrayBuffer = await response.arrayBuffer();
788
- const transcription = await runtime.useModel(ModelType.TRANSCRIPTION, Buffer.from(new Uint8Array(arrayBuffer)));
789
- logger.log({ transcription }, "generated with test_transcription");
856
+ const transcription = await runtime.useModel(ModelType7.TRANSCRIPTION, Buffer.from(new Uint8Array(arrayBuffer)));
857
+ logger10.log({ transcription }, "generated with test_transcription");
790
858
  } catch (error) {
791
859
  const message = error instanceof Error ? error.message : String(error);
792
- logger.error(`Error in test_transcription: ${message}`);
860
+ logger10.error(`Error in test_transcription: ${message}`);
793
861
  throw error;
794
862
  }
795
863
  }
@@ -798,39 +866,41 @@ var openaiPlugin = {
798
866
  name: "openai_test_text_tokenizer_encode",
799
867
  fn: async (runtime) => {
800
868
  const prompt = "Hello tokenizer encode!";
801
- const tokens = await runtime.useModel(ModelType.TEXT_TOKENIZER_ENCODE, { prompt });
869
+ const tokens = await runtime.useModel(ModelType7.TEXT_TOKENIZER_ENCODE, { prompt });
802
870
  if (!Array.isArray(tokens) || tokens.length === 0) {
803
871
  throw new Error("Failed to tokenize text: expected non-empty array of tokens");
804
872
  }
805
- logger.log({ tokens }, "Tokenized output");
873
+ logger10.log({ tokens }, "Tokenized output");
806
874
  }
807
875
  },
808
876
  {
809
877
  name: "openai_test_text_tokenizer_decode",
810
878
  fn: async (runtime) => {
811
879
  const prompt = "Hello tokenizer decode!";
812
- const tokens = await runtime.useModel(ModelType.TEXT_TOKENIZER_ENCODE, { prompt });
813
- const decodedText = await runtime.useModel(ModelType.TEXT_TOKENIZER_DECODE, { tokens });
880
+ const tokens = await runtime.useModel(ModelType7.TEXT_TOKENIZER_ENCODE, { prompt });
881
+ const decodedText = await runtime.useModel(ModelType7.TEXT_TOKENIZER_DECODE, {
882
+ tokens
883
+ });
814
884
  if (decodedText !== prompt) {
815
885
  throw new Error(`Decoded text does not match original. Expected "${prompt}", got "${decodedText}"`);
816
886
  }
817
- logger.log({ decodedText }, "Decoded text");
887
+ logger10.log({ decodedText }, "Decoded text");
818
888
  }
819
889
  },
820
890
  {
821
891
  name: "openai_test_text_to_speech",
822
892
  fn: async (runtime) => {
823
893
  try {
824
- const response = await fetchTextToSpeech(runtime, {
894
+ const response = await runtime.useModel(ModelType7.TEXT_TO_SPEECH, {
825
895
  text: "Hello, this is a test for text-to-speech."
826
896
  });
827
897
  if (!response) {
828
898
  throw new Error("Failed to generate speech");
829
899
  }
830
- logger.log("Generated speech successfully");
900
+ logger10.log("Generated speech successfully");
831
901
  } catch (error) {
832
902
  const message = error instanceof Error ? error.message : String(error);
833
- logger.error(`Error in openai_test_text_to_speech: ${message}`);
903
+ logger10.error(`Error in openai_test_text_to_speech: ${message}`);
834
904
  throw error;
835
905
  }
836
906
  }
@@ -845,4 +915,4 @@ export {
845
915
  src_default as default
846
916
  };
847
917
 
848
- //# debugId=05D284FD8B26700A64756E2164756E21
918
+ //# debugId=967FB48261E5AE3064756E2164756E21