@elizaos/plugin-openai 1.5.13 → 1.5.14

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.
@@ -1,3 +1,3 @@
1
- import{createOpenAI as M}from"@ai-sdk/openai";import{EventType as c,logger as X,ModelType as _,VECTOR_DIMS as V}from"@elizaos/core";import{generateObject as T,generateText as A,JSONParseError as x}from"ai";import{encodingForModel as S}from"js-tiktoken";function J(Q,G,W){return Q.getSetting(G)??process.env[G]??W}function O(){return typeof globalThis<"u"&&typeof globalThis.document<"u"}function y(Q){return O()&&!!J(Q,"OPENAI_BROWSER_BASE_URL")}function K(Q,G=!1){if(O())return{};let W=G?l(Q):D(Q);return W?{Authorization:`Bearer ${W}`}:{}}function v(Q){let G=J(Q,"OPENAI_BROWSER_BASE_URL"),W=O()&&G?G:J(Q,"OPENAI_BASE_URL","https://api.openai.com/v1");return X.debug(`[OpenAI] Default base URL: ${W}`),W}function d(Q){let G=O()?J(Q,"OPENAI_BROWSER_EMBEDDING_URL")||J(Q,"OPENAI_BROWSER_BASE_URL"):J(Q,"OPENAI_EMBEDDING_URL");if(G)return X.debug(`[OpenAI] Using specific embedding base URL: ${G}`),G;return X.debug("[OpenAI] Falling back to general base URL for embeddings."),v(Q)}function D(Q){return J(Q,"OPENAI_API_KEY")}function l(Q){let G=J(Q,"OPENAI_EMBEDDING_API_KEY");if(G)return X.debug("[OpenAI] Using specific embedding API key (present)"),G;return X.debug("[OpenAI] Falling back to general API key for embeddings."),D(Q)}function E(Q){return J(Q,"OPENAI_SMALL_MODEL")??J(Q,"SMALL_MODEL","gpt-5-nano")}function L(Q){return J(Q,"OPENAI_LARGE_MODEL")??J(Q,"LARGE_MODEL","gpt-5-mini")}function p(Q){return J(Q,"OPENAI_IMAGE_DESCRIPTION_MODEL","gpt-5-nano")??"gpt-5-nano"}function k(Q){let G=J(Q,"OPENAI_EXPERIMENTAL_TELEMETRY","false"),W=String(G).toLowerCase(),Y=W==="true";return X.debug(`[OpenAI] Experimental telemetry in function: "${G}" (type: ${typeof G}, normalized: "${W}", result: ${Y})`),Y}function P(Q){let G=v(Q),W=D(Q)??(y(Q)?"sk-proxy":void 0);return M({apiKey:W??"",baseURL:G})}async function u(Q,G){let W=Q===_.TEXT_SMALL?process.env.OPENAI_SMALL_MODEL??process.env.SMALL_MODEL??"gpt-5-nano":process.env.LARGE_MODEL??"gpt-5-mini";return S(W).encode(G)}async function s(Q,G){let W=Q===_.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";return S(W).decode(G)}async function B(Q,G,W,Y){let C=P(Q),I=Y(Q);X.log(`[OpenAI] Using ${W} model: ${I}`);let Z=G.temperature??0;if(!!G.schema)X.info(`Using ${W} without schema validation (schema provided but output=no-schema)`);try{let{object:F,usage:$}=await T({model:C.languageModel(I),output:"no-schema",prompt:G.prompt,temperature:Z,experimental_repairText:U()});if($)j(Q,W,G.prompt,$);return F}catch(F){if(F instanceof x){X.error(`[generateObject] Failed to parse JSON: ${F.message}`);let q=await U()({text:F.text,error:F});if(q)try{let H=JSON.parse(q);return X.info("[generateObject] Successfully repaired JSON."),H}catch(H){let N=H instanceof Error?H.message:String(H);throw X.error(`[generateObject] Failed to parse repaired JSON: ${N}`),H}else throw X.error("[generateObject] JSON repair failed."),F}else{let $=F instanceof Error?F.message:String(F);throw X.error(`[generateObject] Unknown error: ${$}`),F}}}function U(){return async({text:Q,error:G})=>{try{if(G instanceof x){let W=Q.replace(/```json\n|\n```|```/g,"");return JSON.parse(W),W}return null}catch(W){let Y=W instanceof Error?W.message:String(W);return X.warn(`Failed to repair JSON text: ${Y}`),null}}}function j(Q,G,W,Y){Q.emitEvent(c.MODEL_USED,{provider:"openai",type:G,prompt:W,tokens:{prompt:Y.inputTokens,completion:Y.outputTokens,total:Y.totalTokens}})}async function R(Q,G){let W=J(Q,"OPENAI_TTS_MODEL","gpt-4o-mini-tts"),Y=J(Q,"OPENAI_TTS_VOICE","nova"),C=J(Q,"OPENAI_TTS_INSTRUCTIONS",""),I=v(Q);try{let Z=await fetch(`${I}/audio/speech`,{method:"POST",headers:{...K(Q),"Content-Type":"application/json"},body:JSON.stringify({model:W,voice:Y,input:G,...C&&{instructions:C}})});if(!Z.ok){let z=await Z.text();throw Error(`OpenAI TTS error ${Z.status}: ${z}`)}return Z.body}catch(Z){let z=Z instanceof Error?Z.message:String(Z);throw Error(`Failed to fetch speech from OpenAI TTS: ${z}`)}}var g={name:"openai",description:"OpenAI plugin",config:{OPENAI_API_KEY:process.env.OPENAI_API_KEY,OPENAI_BASE_URL:process.env.OPENAI_BASE_URL,OPENAI_SMALL_MODEL:process.env.OPENAI_SMALL_MODEL,OPENAI_LARGE_MODEL:process.env.OPENAI_LARGE_MODEL,SMALL_MODEL:process.env.SMALL_MODEL,LARGE_MODEL:process.env.LARGE_MODEL,OPENAI_EMBEDDING_MODEL:process.env.OPENAI_EMBEDDING_MODEL,OPENAI_EMBEDDING_API_KEY:process.env.OPENAI_EMBEDDING_API_KEY,OPENAI_EMBEDDING_URL:process.env.OPENAI_EMBEDDING_URL,OPENAI_EMBEDDING_DIMENSIONS:process.env.OPENAI_EMBEDDING_DIMENSIONS,OPENAI_IMAGE_DESCRIPTION_MODEL:process.env.OPENAI_IMAGE_DESCRIPTION_MODEL,OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS:process.env.OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS,OPENAI_EXPERIMENTAL_TELEMETRY:process.env.OPENAI_EXPERIMENTAL_TELEMETRY},async init(Q,G){new Promise(async(W)=>{W();try{if(!D(G)&&!O()){X.warn("OPENAI_API_KEY is not set in environment - OpenAI functionality will be limited");return}try{let Y=v(G),C=await fetch(`${Y}/models`,{headers:{...K(G)}});if(!C.ok)X.warn(`OpenAI API key validation failed: ${C.statusText}`),X.warn("OpenAI functionality will be limited until a valid API key is provided");else X.log("OpenAI API key validated successfully")}catch(Y){let C=Y instanceof Error?Y.message:String(Y);X.warn(`Error validating OpenAI API key: ${C}`),X.warn("OpenAI functionality will be limited until a valid API key is provided")}}catch(Y){let C=Y?.errors?.map((I)=>I.message).join(", ")||(Y instanceof Error?Y.message:String(Y));X.warn(`OpenAI plugin configuration issue: ${C} - You need to configure the OPENAI_API_KEY in your environment variables`)}})},models:{[_.TEXT_EMBEDDING]:async(Q,G)=>{let W=J(Q,"OPENAI_EMBEDDING_MODEL","text-embedding-3-small"),Y=Number.parseInt(J(Q,"OPENAI_EMBEDDING_DIMENSIONS","1536")||"1536",10);if(!Object.values(V).includes(Y)){let Z=`Invalid embedding dimension: ${Y}. Must be one of: ${Object.values(V).join(", ")}`;throw X.error(Z),Error(Z)}if(G===null){X.debug("Creating test embedding for initialization");let Z=Array(Y).fill(0);return Z[0]=0.1,Z}let C;if(typeof G==="string")C=G;else if(typeof G==="object"&&G.text)C=G.text;else{X.warn("Invalid input format for embedding");let Z=Array(Y).fill(0);return Z[0]=0.2,Z}if(!C.trim()){X.warn("Empty text for embedding");let Z=Array(Y).fill(0);return Z[0]=0.3,Z}let I=d(Q);try{let Z=await fetch(`${I}/embeddings`,{method:"POST",headers:{...K(Q,!0),"Content-Type":"application/json"},body:JSON.stringify({model:W,input:C})}),F=await Z.clone().text();if(!Z.ok){X.error(`OpenAI API error: ${Z.status} - ${Z.statusText}`);let H=Array(Y).fill(0);return H[0]=0.4,H}let $=await Z.json();if(!$?.data?.[0]?.embedding){X.error("API returned invalid structure");let H=Array(Y).fill(0);return H[0]=0.5,H}let q=$.data[0].embedding;if($.usage){let H={inputTokens:$.usage.prompt_tokens,outputTokens:0,totalTokens:$.usage.total_tokens};j(Q,_.TEXT_EMBEDDING,C,H)}return X.log(`Got valid embedding with length ${q.length}`),q}catch(Z){let z=Z instanceof Error?Z.message:String(Z);X.error(`Error generating embedding: ${z}`);let F=Array(Y).fill(0);return F[0]=0.6,F}},[_.TEXT_TOKENIZER_ENCODE]:async(Q,{prompt:G,modelType:W=_.TEXT_LARGE})=>{return await u(W??_.TEXT_LARGE,G)},[_.TEXT_TOKENIZER_DECODE]:async(Q,{tokens:G,modelType:W=_.TEXT_LARGE})=>{return await s(W??_.TEXT_LARGE,G)},[_.TEXT_SMALL]:async(Q,{prompt:G,stopSequences:W=[],maxTokens:Y=8192,temperature:C=0.7,frequencyPenalty:I=0.7,presencePenalty:Z=0.7})=>{let z=P(Q),F=E(Q),$=k(Q);X.log(`[OpenAI] Using TEXT_SMALL model: ${F}`),X.log(G);let{text:q,usage:H}=await A({model:z.languageModel(F),prompt:G,system:Q.character.system??void 0,temperature:C,maxOutputTokens:Y,frequencyPenalty:I,presencePenalty:Z,stopSequences:W,experimental_telemetry:{isEnabled:$}});if(H)j(Q,_.TEXT_SMALL,G,H);return q},[_.TEXT_LARGE]:async(Q,{prompt:G,stopSequences:W=[],maxTokens:Y=8192,temperature:C=0.7,frequencyPenalty:I=0.7,presencePenalty:Z=0.7})=>{let z=P(Q),F=L(Q),$=k(Q);X.log(`[OpenAI] Using TEXT_LARGE model: ${F}`),X.log(G);let{text:q,usage:H}=await A({model:z.languageModel(F),prompt:G,system:Q.character.system??void 0,temperature:C,maxOutputTokens:Y,frequencyPenalty:I,presencePenalty:Z,stopSequences:W,experimental_telemetry:{isEnabled:$}});if(H)j(Q,_.TEXT_LARGE,G,H);return q},[_.IMAGE]:async(Q,G)=>{let W=G.n||1,Y=G.size||"1024x1024",C=G.prompt,I="gpt-image-1";X.log("[OpenAI] Using IMAGE model: gpt-image-1");let Z=v(Q);try{let z=await fetch(`${Z}/images/generations`,{method:"POST",headers:{...K(Q),"Content-Type":"application/json"},body:JSON.stringify({model:"gpt-image-1",prompt:C,n:W,size:Y})}),$=await z.clone().text();if(!z.ok)throw Error(`Failed to generate image: ${z.statusText}`);return(await z.json()).data}catch(z){let F=z instanceof Error?z.message:String(z);throw z}},[_.IMAGE_DESCRIPTION]:async(Q,G)=>{let W,Y,C=p(Q);X.log(`[OpenAI] Using IMAGE_DESCRIPTION model: ${C}`);let I=Number.parseInt(J(Q,"OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS","8192")||"8192",10);if(typeof G==="string")W=G,Y="Please analyze this image and provide a title and detailed description.";else W=G.imageUrl,Y=G.prompt||"Please analyze this image and provide a title and detailed description.";let Z=[{role:"user",content:[{type:"text",text:Y},{type:"image_url",image_url:{url:W}}]}],z=v(Q);try{let F={model:C,messages:Z,max_tokens:I},$=await fetch(`${z}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",...K(Q)},body:JSON.stringify(F)}),H=await $.clone().text();if(!$.ok)throw Error(`OpenAI API error: ${$.status}`);let w=await $.json(),h=w.choices?.[0]?.message?.content;if(w.usage)j(Q,_.IMAGE_DESCRIPTION,typeof G==="string"?G:G.prompt||"",{inputTokens:w.usage.prompt_tokens,outputTokens:w.usage.completion_tokens,totalTokens:w.usage.total_tokens});if(!h)return{title:"Failed to analyze image",description:"No response from API"};if(typeof G==="object"&&G.prompt&&G.prompt!=="Please analyze this image and provide a title and detailed description.")return h;let b=h.match(/title[:\s]+(.+?)(?:\n|$)/i)?.[1]?.trim()||"Image Analysis",f=h.replace(/title[:\s]+(.+?)(?:\n|$)/i,"").trim();return{title:b,description:f}}catch(F){let $=F instanceof Error?F.message:String(F);return X.error(`Error analyzing image: ${$}`),{title:"Failed to analyze image",description:`Error: ${$}`}}},[_.TRANSCRIPTION]:async(Q,G)=>{X.debug({size:G?.length??0},"audioBuffer received");let W=J(Q,"OPENAI_TRANSCRIPTION_MODEL","gpt-4o-mini-transcribe");X.log(`[OpenAI] Using TRANSCRIPTION model: ${W}`);let Y=v(Q);if(!G||G.length===0)throw Error("Audio buffer is empty or invalid for transcription");let C=new FormData,I=G.buffer,Z=G.byteOffset||0,z=Z+(G.byteLength||0),F=I.slice(Z,z);C.append("file",new Blob([F],{type:"audio/mpeg"}),"recording.mp3"),C.append("model",W);try{let $=await fetch(`${Y}/audio/transcriptions`,{method:"POST",headers:{...K(Q)},body:C}),H=await $.clone().text();if(X.log({response:$},"response"),!$.ok)throw Error(`Failed to transcribe audio: ${$.statusText}`);return(await $.json()).text}catch($){let q=$ instanceof Error?$.message:String($);throw $}},[_.TEXT_TO_SPEECH]:async(Q,G)=>{let W=J(Q,"OPENAI_TTS_MODEL","gpt-4o-mini-tts");X.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${W}`);try{return await R(Q,G)}catch(Y){let C=Y instanceof Error?Y.message:String(Y);throw Y}},[_.OBJECT_SMALL]:async(Q,G)=>{return B(Q,G,_.OBJECT_SMALL,E)},[_.OBJECT_LARGE]:async(Q,G)=>{return B(Q,G,_.OBJECT_LARGE,L)}},tests:[{name:"openai_plugin_tests",tests:[{name:"openai_test_url_and_api_key_validation",fn:async(Q)=>{let G=v(Q),W=await fetch(`${G}/models`,{headers:{Authorization:`Bearer ${D(Q)}`}}),Y=await W.json();if(X.log({data:Y?.data?.length??"N/A"},"Models Available"),!W.ok)throw Error(`Failed to validate OpenAI API key: ${W.statusText}`)}},{name:"openai_test_text_embedding",fn:async(Q)=>{try{let G=await Q.useModel(_.TEXT_EMBEDDING,{text:"Hello, world!"});X.log({embedding:G},"embedding")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_text_embedding: ${W}`),G}}},{name:"openai_test_text_large",fn:async(Q)=>{try{let G=await Q.useModel(_.TEXT_LARGE,{prompt:"What is the nature of reality in 10 words?"});if(G.length===0)throw Error("Failed to generate text");X.log({text:G},"generated with test_text_large")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_text_large: ${W}`),G}}},{name:"openai_test_text_small",fn:async(Q)=>{try{let G=await Q.useModel(_.TEXT_SMALL,{prompt:"What is the nature of reality in 10 words?"});if(G.length===0)throw Error("Failed to generate text");X.log({text:G},"generated with test_text_small")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_text_small: ${W}`),G}}},{name:"openai_test_image_generation",fn:async(Q)=>{X.log("openai_test_image_generation");try{let G=await Q.useModel(_.IMAGE,{prompt:"A beautiful sunset over a calm ocean",n:1,size:"1024x1024"});X.log({image:G},"generated with test_image_generation")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_image_generation: ${W}`),G}}},{name:"image-description",fn:async(Q)=>{try{X.log("openai_test_image_description");try{let G=await Q.useModel(_.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");if(G&&typeof G==="object"&&"title"in G&&"description"in G)X.log({result:G},"Image description");else X.error("Invalid image description result format:",G)}catch(G){let W=G instanceof Error?G.message:String(G);X.error(`Error in image description test: ${W}`)}}catch(G){let W=G instanceof Error?G.message:String(G);X.error(`Error in openai_test_image_description: ${W}`)}}},{name:"openai_test_transcription",fn:async(Q)=>{X.log("openai_test_transcription");try{let W=await(await fetch("https://upload.wikimedia.org/wikipedia/en/4/40/Chris_Benoit_Voice_Message.ogg")).arrayBuffer(),Y=await Q.useModel(_.TRANSCRIPTION,Buffer.from(new Uint8Array(W)));X.log({transcription:Y},"generated with test_transcription")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_transcription: ${W}`),G}}},{name:"openai_test_text_tokenizer_encode",fn:async(Q)=>{let W=await Q.useModel(_.TEXT_TOKENIZER_ENCODE,{prompt:"Hello tokenizer encode!"});if(!Array.isArray(W)||W.length===0)throw Error("Failed to tokenize text: expected non-empty array of tokens");X.log({tokens:W},"Tokenized output")}},{name:"openai_test_text_tokenizer_decode",fn:async(Q)=>{let W=await Q.useModel(_.TEXT_TOKENIZER_ENCODE,{prompt:"Hello tokenizer decode!"}),Y=await Q.useModel(_.TEXT_TOKENIZER_DECODE,{tokens:W});if(Y!=="Hello tokenizer decode!")throw Error(`Decoded text does not match original. Expected "Hello tokenizer decode!", got "${Y}"`);X.log({decodedText:Y},"Decoded text")}},{name:"openai_test_text_to_speech",fn:async(Q)=>{try{if(!await R(Q,"Hello, this is a test for text-to-speech."))throw Error("Failed to generate speech");X.log("Generated speech successfully")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in openai_test_text_to_speech: ${W}`),G}}}]}]},a=g;export{g as openaiPlugin,a as default};
1
+ import{createOpenAI as x}from"@ai-sdk/openai";import{EventType as b,logger as X,ModelType as F,VECTOR_DIMS as N}from"@elizaos/core";import{generateObject as M,generateText as V,JSONParseError as P}from"ai";import{encodingForModel as U}from"js-tiktoken";function z(Q,G,W){return Q.getSetting(G)??process.env[G]??W}function h(){return typeof globalThis<"u"&&typeof globalThis.document<"u"}function c(Q){return h()&&!!z(Q,"OPENAI_BROWSER_BASE_URL")}function K(Q,G=!1){if(h())return{};let W=G?y(Q):O(Q);return W?{Authorization:`Bearer ${W}`}:{}}function j(Q){let G=z(Q,"OPENAI_BROWSER_BASE_URL"),W=h()&&G?G:z(Q,"OPENAI_BASE_URL","https://api.openai.com/v1");return X.debug(`[OpenAI] Default base URL: ${W}`),W}function T(Q){let G=h()?z(Q,"OPENAI_BROWSER_EMBEDDING_URL")||z(Q,"OPENAI_BROWSER_BASE_URL"):z(Q,"OPENAI_EMBEDDING_URL");if(G)return X.debug(`[OpenAI] Using specific embedding base URL: ${G}`),G;return X.debug("[OpenAI] Falling back to general base URL for embeddings."),j(Q)}function O(Q){return z(Q,"OPENAI_API_KEY")}function y(Q){let G=z(Q,"OPENAI_EMBEDDING_API_KEY");if(G)return X.debug("[OpenAI] Using specific embedding API key (present)"),G;return X.debug("[OpenAI] Falling back to general API key for embeddings."),O(Q)}function A(Q){return z(Q,"OPENAI_SMALL_MODEL")??z(Q,"SMALL_MODEL","gpt-5-nano")}function D(Q){return z(Q,"OPENAI_LARGE_MODEL")??z(Q,"LARGE_MODEL","gpt-5-mini")}function d(Q){return z(Q,"OPENAI_IMAGE_DESCRIPTION_MODEL","gpt-5-nano")??"gpt-5-nano"}function k(Q){let G=z(Q,"OPENAI_EXPERIMENTAL_TELEMETRY","false"),W=String(G).toLowerCase(),Y=W==="true";return X.debug(`[OpenAI] Experimental telemetry in function: "${G}" (type: ${typeof G}, normalized: "${W}", result: ${Y})`),Y}function B(Q){let G=j(Q),W=O(Q)??(c(Q)?"sk-proxy":void 0);return x({apiKey:W??"",baseURL:G})}async function l(Q,G){let W=Q===F.TEXT_SMALL?process.env.OPENAI_SMALL_MODEL??process.env.SMALL_MODEL??"gpt-5-nano":process.env.LARGE_MODEL??"gpt-5-mini";return U(W).encode(G)}async function u(Q,G){let W=Q===F.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";return U(W).decode(G)}async function E(Q,G,W,Y){let C=B(Q),H=Y(Q);X.log(`[OpenAI] Using ${W} model: ${H}`);let _=G.temperature??0;if(!!G.schema)X.info(`Using ${W} without schema validation (schema provided but output=no-schema)`);try{let{object:$,usage:Z}=await M({model:C.languageModel(H),output:"no-schema",prompt:G.prompt,temperature:_,experimental_repairText:L()});if(Z)v(Q,W,G.prompt,Z);return $}catch($){if($ instanceof P){X.error(`[generateObject] Failed to parse JSON: ${$.message}`);let I=await L()({text:$.text,error:$});if(I)try{let w=JSON.parse(I);return X.info("[generateObject] Successfully repaired JSON."),w}catch(w){let q=w instanceof Error?w.message:String(w);throw X.error(`[generateObject] Failed to parse repaired JSON: ${q}`),w}else throw X.error("[generateObject] JSON repair failed."),$}else{let Z=$ instanceof Error?$.message:String($);throw X.error(`[generateObject] Unknown error: ${Z}`),$}}}function L(){return async({text:Q,error:G})=>{try{if(G instanceof P){let W=Q.replace(/```json\n|\n```|```/g,"");return JSON.parse(W),W}return null}catch(W){let Y=W instanceof Error?W.message:String(W);return X.warn(`Failed to repair JSON text: ${Y}`),null}}}function v(Q,G,W,Y){Q.emitEvent(b.MODEL_USED,{provider:"openai",type:G,prompt:W,tokens:{prompt:Y.inputTokens,completion:Y.outputTokens,total:Y.totalTokens}})}async function f(Q,G){let W=z(Q,"OPENAI_TTS_MODEL","gpt-4o-mini-tts"),Y=z(Q,"OPENAI_TTS_VOICE","nova"),C=z(Q,"OPENAI_TTS_INSTRUCTIONS",""),H=j(Q),_=G.model||W,J=G.voice||Y,$=G.instructions??C,Z=G.format||"mp3";try{let I=await fetch(`${H}/audio/speech`,{method:"POST",headers:{...K(Q),"Content-Type":"application/json",...Z==="mp3"?{Accept:"audio/mpeg"}:{}},body:JSON.stringify({model:_,voice:J,input:G.text,format:Z,...$&&{instructions:$}})});if(!I.ok){let w=await I.text();throw Error(`OpenAI TTS error ${I.status}: ${w}`)}return I.body}catch(I){let w=I instanceof Error?I.message:String(I);throw Error(`Failed to fetch speech from OpenAI TTS: ${w}`)}}var p={name:"openai",description:"OpenAI plugin",config:{OPENAI_API_KEY:process.env.OPENAI_API_KEY,OPENAI_BASE_URL:process.env.OPENAI_BASE_URL,OPENAI_SMALL_MODEL:process.env.OPENAI_SMALL_MODEL,OPENAI_LARGE_MODEL:process.env.OPENAI_LARGE_MODEL,SMALL_MODEL:process.env.SMALL_MODEL,LARGE_MODEL:process.env.LARGE_MODEL,OPENAI_EMBEDDING_MODEL:process.env.OPENAI_EMBEDDING_MODEL,OPENAI_EMBEDDING_API_KEY:process.env.OPENAI_EMBEDDING_API_KEY,OPENAI_EMBEDDING_URL:process.env.OPENAI_EMBEDDING_URL,OPENAI_EMBEDDING_DIMENSIONS:process.env.OPENAI_EMBEDDING_DIMENSIONS,OPENAI_IMAGE_DESCRIPTION_MODEL:process.env.OPENAI_IMAGE_DESCRIPTION_MODEL,OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS:process.env.OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS,OPENAI_EXPERIMENTAL_TELEMETRY:process.env.OPENAI_EXPERIMENTAL_TELEMETRY},async init(Q,G){new Promise(async(W)=>{W();try{if(!O(G)&&!h()){X.warn("OPENAI_API_KEY is not set in environment - OpenAI functionality will be limited");return}try{let Y=j(G),C=await fetch(`${Y}/models`,{headers:{...K(G)}});if(!C.ok)X.warn(`OpenAI API key validation failed: ${C.statusText}`),X.warn("OpenAI functionality will be limited until a valid API key is provided");else X.log("OpenAI API key validated successfully")}catch(Y){let C=Y instanceof Error?Y.message:String(Y);X.warn(`Error validating OpenAI API key: ${C}`),X.warn("OpenAI functionality will be limited until a valid API key is provided")}}catch(Y){let C=Y?.errors?.map((H)=>H.message).join(", ")||(Y instanceof Error?Y.message:String(Y));X.warn(`OpenAI plugin configuration issue: ${C} - You need to configure the OPENAI_API_KEY in your environment variables`)}})},models:{[F.TEXT_EMBEDDING]:async(Q,G)=>{let W=z(Q,"OPENAI_EMBEDDING_MODEL","text-embedding-3-small"),Y=Number.parseInt(z(Q,"OPENAI_EMBEDDING_DIMENSIONS","1536")||"1536",10);if(!Object.values(N).includes(Y)){let _=`Invalid embedding dimension: ${Y}. Must be one of: ${Object.values(N).join(", ")}`;throw X.error(_),Error(_)}if(G===null){X.debug("Creating test embedding for initialization");let _=Array(Y).fill(0);return _[0]=0.1,_}let C;if(typeof G==="string")C=G;else if(typeof G==="object"&&G.text)C=G.text;else{X.warn("Invalid input format for embedding");let _=Array(Y).fill(0);return _[0]=0.2,_}if(!C.trim()){X.warn("Empty text for embedding");let _=Array(Y).fill(0);return _[0]=0.3,_}let H=T(Q);try{let _=await fetch(`${H}/embeddings`,{method:"POST",headers:{...K(Q,!0),"Content-Type":"application/json"},body:JSON.stringify({model:W,input:C})});if(!_.ok){X.error(`OpenAI API error: ${_.status} - ${_.statusText}`);let Z=Array(Y).fill(0);return Z[0]=0.4,Z}let J=await _.json();if(!J?.data?.[0]?.embedding){X.error("API returned invalid structure");let Z=Array(Y).fill(0);return Z[0]=0.5,Z}let $=J.data[0].embedding;if(J.usage){let Z={inputTokens:J.usage.prompt_tokens,outputTokens:0,totalTokens:J.usage.total_tokens};v(Q,F.TEXT_EMBEDDING,C,Z)}return X.log(`Got valid embedding with length ${$.length}`),$}catch(_){let J=_ instanceof Error?_.message:String(_);X.error(`Error generating embedding: ${J}`);let $=Array(Y).fill(0);return $[0]=0.6,$}},[F.TEXT_TOKENIZER_ENCODE]:async(Q,{prompt:G,modelType:W=F.TEXT_LARGE})=>{return await l(W??F.TEXT_LARGE,G)},[F.TEXT_TOKENIZER_DECODE]:async(Q,{tokens:G,modelType:W=F.TEXT_LARGE})=>{return await u(W??F.TEXT_LARGE,G)},[F.TEXT_SMALL]:async(Q,{prompt:G,stopSequences:W=[],maxTokens:Y=8192,temperature:C=0.7,frequencyPenalty:H=0.7,presencePenalty:_=0.7})=>{let J=B(Q),$=A(Q),Z=k(Q);X.log(`[OpenAI] Using TEXT_SMALL model: ${$}`),X.log(G);let{text:I,usage:w}=await V({model:J.languageModel($),prompt:G,system:Q.character.system??void 0,temperature:C,maxOutputTokens:Y,frequencyPenalty:H,presencePenalty:_,stopSequences:W,experimental_telemetry:{isEnabled:Z}});if(w)v(Q,F.TEXT_SMALL,G,w);return I},[F.TEXT_LARGE]:async(Q,{prompt:G,stopSequences:W=[],maxTokens:Y=8192,temperature:C=0.7,frequencyPenalty:H=0.7,presencePenalty:_=0.7})=>{let J=B(Q),$=D(Q),Z=k(Q);X.log(`[OpenAI] Using TEXT_LARGE model: ${$}`),X.log(G);let{text:I,usage:w}=await V({model:J.languageModel($),prompt:G,system:Q.character.system??void 0,temperature:C,maxOutputTokens:Y,frequencyPenalty:H,presencePenalty:_,stopSequences:W,experimental_telemetry:{isEnabled:Z}});if(w)v(Q,F.TEXT_LARGE,G,w);return I},[F.IMAGE]:async(Q,G)=>{let W=G.n||1,Y=G.size||"1024x1024",C=G.prompt,H="gpt-image-1";X.log("[OpenAI] Using IMAGE model: gpt-image-1");let _=j(Q);try{let J=await fetch(`${_}/images/generations`,{method:"POST",headers:{...K(Q),"Content-Type":"application/json"},body:JSON.stringify({model:"gpt-image-1",prompt:C,n:W,size:Y})});if(!J.ok)throw Error(`Failed to generate image: ${J.statusText}`);return(await J.json()).data}catch(J){let $=J instanceof Error?J.message:String(J);throw J}},[F.IMAGE_DESCRIPTION]:async(Q,G)=>{let W,Y,C=d(Q);X.log(`[OpenAI] Using IMAGE_DESCRIPTION model: ${C}`);let H=Number.parseInt(z(Q,"OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS","8192")||"8192",10);if(typeof G==="string")W=G,Y="Please analyze this image and provide a title and detailed description.";else W=G.imageUrl,Y=G.prompt||"Please analyze this image and provide a title and detailed description.";let _=[{role:"user",content:[{type:"text",text:Y},{type:"image_url",image_url:{url:W}}]}],J=j(Q);try{let $={model:C,messages:_,max_tokens:H},Z=await fetch(`${J}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",...K(Q)},body:JSON.stringify($)});if(!Z.ok)throw Error(`OpenAI API error: ${Z.status}`);let w=await Z.json(),q=w.choices?.[0]?.message?.content;if(w.usage)v(Q,F.IMAGE_DESCRIPTION,typeof G==="string"?G:G.prompt||"",{inputTokens:w.usage.prompt_tokens,outputTokens:w.usage.completion_tokens,totalTokens:w.usage.total_tokens});if(!q)return{title:"Failed to analyze image",description:"No response from API"};if(typeof G==="object"&&G.prompt&&G.prompt!=="Please analyze this image and provide a title and detailed description.")return q;let R=q.match(/title[:\s]+(.+?)(?:\n|$)/i)?.[1]?.trim()||"Image Analysis",S=q.replace(/title[:\s]+(.+?)(?:\n|$)/i,"").trim();return{title:R,description:S}}catch($){let Z=$ instanceof Error?$.message:String($);return X.error(`Error analyzing image: ${Z}`),{title:"Failed to analyze image",description:`Error: ${Z}`}}},[F.TRANSCRIPTION]:async(Q,G)=>{let W=z(Q,"OPENAI_TRANSCRIPTION_MODEL","gpt-4o-mini-transcribe");X.log(`[OpenAI] Using TRANSCRIPTION model: ${W}`);let Y=j(Q),C,H=null;if(G instanceof Blob||G instanceof File)C=G;else if(typeof G==="object"&&G!==null&&G.audio!=null){let Z=G;if(!(Z.audio instanceof Blob)&&!(Z.audio instanceof File))throw Error("TRANSCRIPTION param 'audio' must be a Blob/File. Wrap buffers as: new Blob([buffer], { type: 'audio/mpeg' })");if(C=Z.audio,H=Z,typeof Z.model==="string"&&Z.model)W=Z.model}else throw Error("TRANSCRIPTION expects a Blob/File or an object { audio: Blob/File, language?, response_format?, timestampGranularities?, prompt?, temperature?, model? }");let _=C.type||"audio/webm",J=C.name||(_.includes("mp3")||_.includes("mpeg")?"recording.mp3":_.includes("ogg")?"recording.ogg":_.includes("wav")?"recording.wav":_.includes("webm")?"recording.webm":"recording.bin"),$=new FormData;if($.append("file",C,J),$.append("model",String(W)),H){if(typeof H.language==="string")$.append("language",String(H.language));if(typeof H.response_format==="string")$.append("response_format",String(H.response_format));if(typeof H.prompt==="string")$.append("prompt",String(H.prompt));if(typeof H.temperature==="number")$.append("temperature",String(H.temperature));if(Array.isArray(H.timestampGranularities))for(let Z of H.timestampGranularities)$.append("timestamp_granularities[]",String(Z))}try{let Z=await fetch(`${Y}/audio/transcriptions`,{method:"POST",headers:{...K(Q)},body:$});if(!Z.ok)throw Error(`Failed to transcribe audio: ${Z.status} ${Z.statusText}`);return(await Z.json()).text||""}catch(Z){let I=Z instanceof Error?Z.message:String(Z);throw X.error(`TRANSCRIPTION error: ${I}`),Z}},[F.TEXT_TO_SPEECH]:async(Q,G)=>{let W=typeof G==="string"?{text:G}:G,Y=W.model||z(Q,"OPENAI_TTS_MODEL","gpt-4o-mini-tts");X.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${Y}`);try{return await f(Q,W)}catch(C){let H=C instanceof Error?C.message:String(C);throw X.error(`Error in TEXT_TO_SPEECH: ${H}`),C}},[F.OBJECT_SMALL]:async(Q,G)=>{return E(Q,G,F.OBJECT_SMALL,A)},[F.OBJECT_LARGE]:async(Q,G)=>{return E(Q,G,F.OBJECT_LARGE,D)}},tests:[{name:"openai_plugin_tests",tests:[{name:"openai_test_url_and_api_key_validation",fn:async(Q)=>{let G=j(Q),W=await fetch(`${G}/models`,{headers:{Authorization:`Bearer ${O(Q)}`}}),Y=await W.json();if(X.log({data:Y?.data?.length??"N/A"},"Models Available"),!W.ok)throw Error(`Failed to validate OpenAI API key: ${W.statusText}`)}},{name:"openai_test_text_embedding",fn:async(Q)=>{try{let G=await Q.useModel(F.TEXT_EMBEDDING,{text:"Hello, world!"});X.log({embedding:G},"embedding")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_text_embedding: ${W}`),G}}},{name:"openai_test_text_large",fn:async(Q)=>{try{let G=await Q.useModel(F.TEXT_LARGE,{prompt:"What is the nature of reality in 10 words?"});if(G.length===0)throw Error("Failed to generate text");X.log({text:G},"generated with test_text_large")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_text_large: ${W}`),G}}},{name:"openai_test_text_small",fn:async(Q)=>{try{let G=await Q.useModel(F.TEXT_SMALL,{prompt:"What is the nature of reality in 10 words?"});if(G.length===0)throw Error("Failed to generate text");X.log({text:G},"generated with test_text_small")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_text_small: ${W}`),G}}},{name:"openai_test_image_generation",fn:async(Q)=>{X.log("openai_test_image_generation");try{let G=await Q.useModel(F.IMAGE,{prompt:"A beautiful sunset over a calm ocean",n:1,size:"1024x1024"});X.log({image:G},"generated with test_image_generation")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_image_generation: ${W}`),G}}},{name:"image-description",fn:async(Q)=>{try{X.log("openai_test_image_description");try{let G=await Q.useModel(F.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");if(G&&typeof G==="object"&&"title"in G&&"description"in G)X.log({result:G},"Image description");else X.error("Invalid image description result format:",G)}catch(G){let W=G instanceof Error?G.message:String(G);X.error(`Error in image description test: ${W}`)}}catch(G){let W=G instanceof Error?G.message:String(G);X.error(`Error in openai_test_image_description: ${W}`)}}},{name:"openai_test_transcription",fn:async(Q)=>{X.log("openai_test_transcription");try{let W=await(await fetch("https://upload.wikimedia.org/wikipedia/en/4/40/Chris_Benoit_Voice_Message.ogg")).arrayBuffer(),Y=await Q.useModel(F.TRANSCRIPTION,Buffer.from(new Uint8Array(W)));X.log({transcription:Y},"generated with test_transcription")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in test_transcription: ${W}`),G}}},{name:"openai_test_text_tokenizer_encode",fn:async(Q)=>{let W=await Q.useModel(F.TEXT_TOKENIZER_ENCODE,{prompt:"Hello tokenizer encode!"});if(!Array.isArray(W)||W.length===0)throw Error("Failed to tokenize text: expected non-empty array of tokens");X.log({tokens:W},"Tokenized output")}},{name:"openai_test_text_tokenizer_decode",fn:async(Q)=>{let W=await Q.useModel(F.TEXT_TOKENIZER_ENCODE,{prompt:"Hello tokenizer decode!"}),Y=await Q.useModel(F.TEXT_TOKENIZER_DECODE,{tokens:W});if(Y!=="Hello tokenizer decode!")throw Error(`Decoded text does not match original. Expected "Hello tokenizer decode!", got "${Y}"`);X.log({decodedText:Y},"Decoded text")}},{name:"openai_test_text_to_speech",fn:async(Q)=>{try{if(!await f(Q,{text:"Hello, this is a test for text-to-speech."}))throw Error("Failed to generate speech");X.log("Generated speech successfully")}catch(G){let W=G instanceof Error?G.message:String(G);throw X.error(`Error in openai_test_text_to_speech: ${W}`),G}}}]}]},g=p;export{p as openaiPlugin,g as default};
2
2
 
3
- //# debugId=C6DE2BE8B57F1DEB64756E2164756E21
3
+ //# debugId=89F51A79E528892264756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "import { createOpenAI } from \"@ai-sdk/openai\";\nimport type {\n DetokenizeTextParams,\n GenerateTextParams,\n IAgentRuntime,\n ImageDescriptionParams,\n ModelTypeName,\n ObjectGenerationParams,\n Plugin,\n TextEmbeddingParams,\n TokenizeTextParams,\n} from \"@elizaos/core\";\nimport { EventType, logger, ModelType, VECTOR_DIMS } from \"@elizaos/core\";\nimport {\n generateObject,\n generateText,\n JSONParseError,\n type JSONValue,\n type LanguageModelUsage,\n} from \"ai\";\nimport { encodingForModel, type TiktokenModel } from \"js-tiktoken\";\n\n/**\n * Retrieves a configuration setting from the runtime, falling back to environment variables or a default value if not found.\n *\n * @param key - The name of the setting to retrieve.\n * @param defaultValue - The value to return if the setting is not found in the runtime or environment.\n * @returns The resolved setting value, or {@link defaultValue} if not found.\n */\nfunction getSetting(\n runtime: IAgentRuntime,\n key: string,\n defaultValue?: string,\n): string | undefined {\n return runtime.getSetting(key) ?? process.env[key] ?? defaultValue;\n}\n\nfunction isBrowser(): boolean {\n return (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).document !== \"undefined\"\n );\n}\n\n/**\n * Determines whether we're running in a browser with a server-hosted proxy configured.\n * In this mode, we do not require a real API key on the client and rely on the proxy to inject it.\n */\nfunction isProxyMode(runtime: IAgentRuntime): boolean {\n return isBrowser() && !!getSetting(runtime, \"OPENAI_BROWSER_BASE_URL\");\n}\n\nfunction getAuthHeader(\n runtime: IAgentRuntime,\n forEmbedding = false,\n): Record<string, string> {\n if (isBrowser()) return {};\n const key = forEmbedding ? getEmbeddingApiKey(runtime) : getApiKey(runtime);\n return key ? { Authorization: `Bearer ${key}` } : {};\n}\n\n/**\n * Retrieves the OpenAI API base URL from runtime settings, environment variables, or defaults, using provider-aware resolution.\n *\n * @returns The resolved base URL for OpenAI API requests.\n */\nfunction getBaseURL(runtime: IAgentRuntime): string {\n const browserURL = getSetting(runtime, \"OPENAI_BROWSER_BASE_URL\");\n const baseURL = (\n isBrowser() && browserURL\n ? browserURL\n : getSetting(runtime, \"OPENAI_BASE_URL\", \"https://api.openai.com/v1\")\n ) as string;\n logger.debug(`[OpenAI] Default base URL: ${baseURL}`);\n return baseURL;\n}\n\n/**\n * Retrieves the OpenAI API base URL for embeddings, falling back to the general base URL.\n *\n * @returns The resolved base URL for OpenAI embedding requests.\n */\nfunction getEmbeddingBaseURL(runtime: IAgentRuntime): string {\n const embeddingURL = isBrowser()\n ? getSetting(runtime, \"OPENAI_BROWSER_EMBEDDING_URL\") ||\n getSetting(runtime, \"OPENAI_BROWSER_BASE_URL\")\n : getSetting(runtime, \"OPENAI_EMBEDDING_URL\");\n if (embeddingURL) {\n logger.debug(`[OpenAI] Using specific embedding base URL: ${embeddingURL}`);\n return embeddingURL;\n }\n logger.debug(\"[OpenAI] Falling back to general base URL for embeddings.\");\n return getBaseURL(runtime);\n}\n\n/**\n * Helper function to get the API key for OpenAI\n *\n * @param runtime The runtime context\n * @returns The configured API key\n */\nfunction getApiKey(runtime: IAgentRuntime): string | undefined {\n return getSetting(runtime, \"OPENAI_API_KEY\");\n}\n\n/**\n * Helper function to get the embedding API key for OpenAI, falling back to the general API key if not set.\n *\n * @param runtime The runtime context\n * @returns The configured API key\n */\nfunction getEmbeddingApiKey(runtime: IAgentRuntime): string | undefined {\n const embeddingApiKey = getSetting(runtime, \"OPENAI_EMBEDDING_API_KEY\");\n if (embeddingApiKey) {\n logger.debug(\"[OpenAI] Using specific embedding API key (present)\");\n return embeddingApiKey;\n }\n logger.debug(\"[OpenAI] Falling back to general API key for embeddings.\");\n return getApiKey(runtime);\n}\n\n/**\n * Helper function to get the small model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured small model name\n */\nfunction getSmallModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENAI_SMALL_MODEL\") ??\n (getSetting(runtime, \"SMALL_MODEL\", \"gpt-5-nano\") as string)\n );\n}\n\n/**\n * Helper function to get the large model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured large model name\n */\nfunction getLargeModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENAI_LARGE_MODEL\") ??\n (getSetting(runtime, \"LARGE_MODEL\", \"gpt-5-mini\") as string)\n );\n}\n\n/**\n * Helper function to get the image description model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured image description model name\n */\nfunction getImageDescriptionModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENAI_IMAGE_DESCRIPTION_MODEL\", \"gpt-5-nano\") ??\n \"gpt-5-nano\"\n );\n}\n\n/**\n * Helper function to get experimental telemetry setting\n *\n * @param runtime The runtime context\n * @returns Whether experimental telemetry is enabled\n */\nfunction getExperimentalTelemetry(runtime: IAgentRuntime): boolean {\n const setting = getSetting(runtime, \"OPENAI_EXPERIMENTAL_TELEMETRY\", \"false\");\n // Convert to string and check for truthy values\n const normalizedSetting = String(setting).toLowerCase();\n const result = normalizedSetting === \"true\";\n logger.debug(\n `[OpenAI] Experimental telemetry in function: \"${setting}\" (type: ${typeof setting}, normalized: \"${normalizedSetting}\", result: ${result})`,\n );\n return result;\n}\n\n/**\n * Create an OpenAI client with proper configuration\n *\n * @param runtime The runtime context\n * @returns Configured OpenAI client\n */\nfunction createOpenAIClient(runtime: IAgentRuntime) {\n const baseURL = getBaseURL(runtime);\n // In proxy mode (browser + proxy base URL), pass a harmless placeholder key.\n // The server proxy replaces Authorization; no secrets leave the server.\n const apiKey =\n getApiKey(runtime) ?? (isProxyMode(runtime) ? \"sk-proxy\" : undefined);\n return createOpenAI({ apiKey: (apiKey ?? \"\") as string, baseURL });\n}\n\n/**\n * Asynchronously tokenizes the given text based on the specified model and prompt.\n *\n * @param {ModelTypeName} model - The type of model to use for tokenization.\n * @param {string} prompt - The text prompt to tokenize.\n * @returns {number[]} - An array of tokens representing the encoded prompt.\n */\nasync function tokenizeText(model: ModelTypeName, prompt: string) {\n const modelName =\n model === ModelType.TEXT_SMALL\n ? (process.env.OPENAI_SMALL_MODEL ??\n process.env.SMALL_MODEL ??\n \"gpt-5-nano\")\n : (process.env.LARGE_MODEL ?? \"gpt-5-mini\");\n const tokens = encodingForModel(modelName as TiktokenModel).encode(prompt);\n return tokens;\n}\n\n/**\n * Detokenize a sequence of tokens back into text using the specified model.\n *\n * @param {ModelTypeName} model - The type of model to use for detokenization.\n * @param {number[]} tokens - The sequence of tokens to detokenize.\n * @returns {string} The detokenized text.\n */\nasync function detokenizeText(model: ModelTypeName, tokens: number[]) {\n const modelName =\n model === ModelType.TEXT_SMALL\n ? (process.env.OPENAI_SMALL_MODEL ??\n process.env.SMALL_MODEL ??\n \"gpt-5-nano\")\n : (process.env.OPENAI_LARGE_MODEL ??\n process.env.LARGE_MODEL ??\n \"gpt-5-mini\");\n return encodingForModel(modelName as TiktokenModel).decode(tokens);\n}\n\n/**\n * Helper function to generate objects using specified model type\n */\nasync function generateObjectByModelType(\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n modelType: string,\n getModelFn: (runtime: IAgentRuntime) => string,\n): Promise<JSONValue> {\n const openai = createOpenAIClient(runtime);\n const modelName = getModelFn(runtime);\n logger.log(`[OpenAI] Using ${modelType} model: ${modelName}`);\n const temperature = params.temperature ?? 0;\n const schemaPresent = !!params.schema;\n\n if (schemaPresent) {\n logger.info(\n `Using ${modelType} without schema validation (schema provided but output=no-schema)`,\n );\n }\n\n try {\n const { object, usage } = await generateObject({\n model: openai.languageModel(modelName),\n output: \"no-schema\",\n prompt: params.prompt,\n temperature: temperature,\n experimental_repairText: getJsonRepairFunction(),\n });\n\n if (usage) {\n emitModelUsageEvent(\n runtime,\n modelType as ModelTypeName,\n params.prompt,\n usage,\n );\n }\n return object;\n } catch (error: unknown) {\n if (error instanceof JSONParseError) {\n logger.error(`[generateObject] Failed to parse JSON: ${error.message}`);\n\n const repairFunction = getJsonRepairFunction();\n const repairedJsonString = await repairFunction({\n text: error.text,\n error,\n });\n\n if (repairedJsonString) {\n try {\n const repairedObject = JSON.parse(repairedJsonString);\n logger.info(\"[generateObject] Successfully repaired JSON.\");\n return repairedObject;\n } catch (repairParseError: unknown) {\n const message =\n repairParseError instanceof Error\n ? repairParseError.message\n : String(repairParseError);\n logger.error(\n `[generateObject] Failed to parse repaired JSON: ${message}`,\n );\n throw repairParseError;\n }\n } else {\n logger.error(\"[generateObject] JSON repair failed.\");\n throw error;\n }\n } else {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`[generateObject] Unknown error: ${message}`);\n throw error;\n }\n }\n}\n\n/**\n * Returns a function to repair JSON text\n */\nfunction getJsonRepairFunction(): (params: {\n text: string;\n error: unknown;\n}) => Promise<string | null> {\n return async ({ text, error }: { text: string; error: unknown }) => {\n try {\n if (error instanceof JSONParseError) {\n const cleanedText = text.replace(/```json\\n|\\n```|```/g, \"\");\n JSON.parse(cleanedText);\n return cleanedText;\n }\n return null;\n } catch (jsonError: unknown) {\n const message =\n jsonError instanceof Error ? jsonError.message : String(jsonError);\n logger.warn(`Failed to repair JSON text: ${message}`);\n return null;\n }\n };\n}\n\n/**\n * Emits a model usage event\n * @param runtime The runtime context\n * @param type The model type\n * @param prompt The prompt used\n * @param usage The LLM usage data\n */\nfunction emitModelUsageEvent(\n runtime: IAgentRuntime,\n type: ModelTypeName,\n prompt: string,\n usage: LanguageModelUsage,\n) {\n runtime.emitEvent(EventType.MODEL_USED, {\n provider: \"openai\",\n type,\n prompt,\n tokens: {\n prompt: usage.inputTokens,\n completion: usage.outputTokens,\n total: usage.totalTokens,\n },\n });\n}\n\n/**\n * function for text-to-speech\n */\nasync function fetchTextToSpeech(runtime: IAgentRuntime, text: string) {\n const model = getSetting(runtime, \"OPENAI_TTS_MODEL\", \"gpt-4o-mini-tts\");\n const voice = getSetting(runtime, \"OPENAI_TTS_VOICE\", \"nova\");\n const instructions = getSetting(runtime, \"OPENAI_TTS_INSTRUCTIONS\", \"\");\n const baseURL = getBaseURL(runtime);\n\n try {\n const res = await fetch(`${baseURL}/audio/speech`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model,\n voice,\n input: text,\n ...(instructions && { instructions }),\n }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`OpenAI TTS error ${res.status}: ${err}`);\n }\n\n return res.body;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to fetch speech from OpenAI TTS: ${message}`);\n }\n}\n\n/**\n * Defines the OpenAI plugin with its name, description, and configuration options.\n * @type {Plugin}\n */\nexport const openaiPlugin: Plugin = {\n name: \"openai\",\n description: \"OpenAI plugin\",\n config: {\n OPENAI_API_KEY: process.env.OPENAI_API_KEY,\n OPENAI_BASE_URL: process.env.OPENAI_BASE_URL,\n OPENAI_SMALL_MODEL: process.env.OPENAI_SMALL_MODEL,\n OPENAI_LARGE_MODEL: process.env.OPENAI_LARGE_MODEL,\n SMALL_MODEL: process.env.SMALL_MODEL,\n LARGE_MODEL: process.env.LARGE_MODEL,\n OPENAI_EMBEDDING_MODEL: process.env.OPENAI_EMBEDDING_MODEL,\n OPENAI_EMBEDDING_API_KEY: process.env.OPENAI_EMBEDDING_API_KEY,\n OPENAI_EMBEDDING_URL: process.env.OPENAI_EMBEDDING_URL,\n OPENAI_EMBEDDING_DIMENSIONS: process.env.OPENAI_EMBEDDING_DIMENSIONS,\n OPENAI_IMAGE_DESCRIPTION_MODEL: process.env.OPENAI_IMAGE_DESCRIPTION_MODEL,\n OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS:\n process.env.OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS,\n OPENAI_EXPERIMENTAL_TELEMETRY: process.env.OPENAI_EXPERIMENTAL_TELEMETRY,\n },\n async init(_config, runtime) {\n // do check in the background\n new Promise<void>(async (resolve) => {\n resolve();\n try {\n if (!getApiKey(runtime) && !isBrowser()) {\n logger.warn(\n \"OPENAI_API_KEY is not set in environment - OpenAI functionality will be limited\",\n );\n return;\n }\n try {\n const baseURL = getBaseURL(runtime);\n const response = await fetch(`${baseURL}/models`, {\n headers: { ...getAuthHeader(runtime) },\n });\n if (!response.ok) {\n logger.warn(\n `OpenAI API key validation failed: ${response.statusText}`,\n );\n logger.warn(\n \"OpenAI functionality will be limited until a valid API key is provided\",\n );\n } else {\n logger.log(\"OpenAI API key validated successfully\");\n }\n } catch (fetchError: unknown) {\n const message =\n fetchError instanceof Error\n ? fetchError.message\n : String(fetchError);\n logger.warn(`Error validating OpenAI API key: ${message}`);\n logger.warn(\n \"OpenAI functionality will be limited until a valid API key is provided\",\n );\n }\n } catch (error: unknown) {\n const message =\n (error as { errors?: Array<{ message: string }> })?.errors\n ?.map((e) => e.message)\n .join(\", \") ||\n (error instanceof Error ? error.message : String(error));\n logger.warn(\n `OpenAI plugin configuration issue: ${message} - You need to configure the OPENAI_API_KEY in your environment variables`,\n );\n }\n });\n },\n\n models: {\n [ModelType.TEXT_EMBEDDING]: async (\n runtime: IAgentRuntime,\n params: TextEmbeddingParams | string | null,\n ): Promise<number[]> => {\n const embeddingModelName = getSetting(\n runtime,\n \"OPENAI_EMBEDDING_MODEL\",\n \"text-embedding-3-small\",\n );\n const embeddingDimension = Number.parseInt(\n getSetting(runtime, \"OPENAI_EMBEDDING_DIMENSIONS\", \"1536\") || \"1536\",\n 10,\n ) as (typeof VECTOR_DIMS)[keyof typeof VECTOR_DIMS];\n\n if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {\n const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(\", \")}`;\n logger.error(errorMsg);\n throw new Error(errorMsg);\n }\n if (params === null) {\n logger.debug(\"Creating test embedding for initialization\");\n const testVector = Array(embeddingDimension).fill(0);\n testVector[0] = 0.1;\n return testVector;\n }\n let text: string;\n if (typeof params === \"string\") {\n text = params;\n } else if (typeof params === \"object\" && params.text) {\n text = params.text;\n } else {\n logger.warn(\"Invalid input format for embedding\");\n const fallbackVector = Array(embeddingDimension).fill(0);\n fallbackVector[0] = 0.2;\n return fallbackVector;\n }\n if (!text.trim()) {\n logger.warn(\"Empty text for embedding\");\n const emptyVector = Array(embeddingDimension).fill(0);\n emptyVector[0] = 0.3;\n return emptyVector;\n }\n\n const embeddingBaseURL = getEmbeddingBaseURL(runtime);\n\n try {\n const response = await fetch(`${embeddingBaseURL}/embeddings`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime, true),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: embeddingModelName,\n input: text,\n }),\n });\n\n const responseClone = response.clone();\n const rawResponseBody = await responseClone.text();\n\n if (!response.ok) {\n logger.error(\n `OpenAI API error: ${response.status} - ${response.statusText}`,\n );\n const errorVector = Array(embeddingDimension).fill(0);\n errorVector[0] = 0.4;\n return errorVector;\n }\n\n const data = (await response.json()) as {\n data: [{ embedding: number[] }];\n usage?: { prompt_tokens: number; total_tokens: number };\n };\n\n if (!data?.data?.[0]?.embedding) {\n logger.error(\"API returned invalid structure\");\n const errorVector = Array(embeddingDimension).fill(0);\n errorVector[0] = 0.5;\n return errorVector;\n }\n\n const embedding = data.data[0].embedding;\n\n if (data.usage) {\n const usage = {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: 0,\n totalTokens: data.usage.total_tokens,\n };\n\n emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage);\n }\n\n logger.log(`Got valid embedding with length ${embedding.length}`);\n return embedding;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error generating embedding: ${message}`);\n const errorVector = Array(embeddingDimension).fill(0);\n errorVector[0] = 0.6;\n return errorVector;\n }\n },\n [ModelType.TEXT_TOKENIZER_ENCODE]: async (\n _runtime,\n { prompt, modelType = ModelType.TEXT_LARGE }: TokenizeTextParams,\n ) => {\n return await tokenizeText(modelType ?? ModelType.TEXT_LARGE, prompt);\n },\n [ModelType.TEXT_TOKENIZER_DECODE]: async (\n _runtime,\n { tokens, modelType = ModelType.TEXT_LARGE }: DetokenizeTextParams,\n ) => {\n return await detokenizeText(modelType ?? ModelType.TEXT_LARGE, tokens);\n },\n [ModelType.TEXT_SMALL]: async (\n runtime: IAgentRuntime,\n {\n prompt,\n stopSequences = [],\n maxTokens = 8192,\n temperature = 0.7,\n frequencyPenalty = 0.7,\n presencePenalty = 0.7,\n }: GenerateTextParams,\n ) => {\n const openai = createOpenAIClient(runtime);\n const modelName = getSmallModel(runtime);\n const experimentalTelemetry = getExperimentalTelemetry(runtime);\n\n logger.log(`[OpenAI] Using TEXT_SMALL model: ${modelName}`);\n logger.log(prompt);\n\n const { text: openaiResponse, usage } = await generateText({\n model: openai.languageModel(modelName),\n prompt: prompt,\n system: runtime.character.system ?? undefined,\n temperature: temperature,\n maxOutputTokens: maxTokens,\n frequencyPenalty: frequencyPenalty,\n presencePenalty: presencePenalty,\n stopSequences: stopSequences,\n experimental_telemetry: {\n isEnabled: experimentalTelemetry,\n },\n });\n\n if (usage) {\n emitModelUsageEvent(runtime, ModelType.TEXT_SMALL, prompt, usage);\n }\n\n return openaiResponse;\n },\n [ModelType.TEXT_LARGE]: async (\n runtime: IAgentRuntime,\n {\n prompt,\n stopSequences = [],\n maxTokens = 8192,\n temperature = 0.7,\n frequencyPenalty = 0.7,\n presencePenalty = 0.7,\n }: GenerateTextParams,\n ) => {\n const openai = createOpenAIClient(runtime);\n const modelName = getLargeModel(runtime);\n const experimentalTelemetry = getExperimentalTelemetry(runtime);\n\n logger.log(`[OpenAI] Using TEXT_LARGE model: ${modelName}`);\n logger.log(prompt);\n\n const { text: openaiResponse, usage } = await generateText({\n model: openai.languageModel(modelName),\n prompt: prompt,\n system: runtime.character.system ?? undefined,\n temperature: temperature,\n maxOutputTokens: maxTokens,\n frequencyPenalty: frequencyPenalty,\n presencePenalty: presencePenalty,\n stopSequences: stopSequences,\n experimental_telemetry: {\n isEnabled: experimentalTelemetry,\n },\n });\n\n if (usage) {\n emitModelUsageEvent(runtime, ModelType.TEXT_LARGE, prompt, usage);\n }\n\n return openaiResponse;\n },\n [ModelType.IMAGE]: async (\n runtime: IAgentRuntime,\n params: {\n prompt: string;\n n?: number;\n size?: string;\n },\n ) => {\n const n = params.n || 1;\n const size = params.size || \"1024x1024\";\n const prompt = params.prompt;\n const modelName = \"gpt-image-1\"; // Updated image model\n logger.log(`[OpenAI] Using IMAGE model: ${modelName}`);\n\n const baseURL = getBaseURL(runtime);\n\n try {\n const response = await fetch(`${baseURL}/images/generations`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: modelName,\n prompt: prompt,\n n: n,\n size: size,\n }),\n });\n\n const responseClone = response.clone();\n const rawResponseBody = await responseClone.text();\n\n if (!response.ok) {\n throw new Error(`Failed to generate image: ${response.statusText}`);\n }\n\n const data = await response.json();\n const typedData = data as { data: { url: string }[] };\n\n return typedData.data;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n throw error;\n }\n },\n [ModelType.IMAGE_DESCRIPTION]: async (\n runtime: IAgentRuntime,\n params: ImageDescriptionParams | string,\n ) => {\n let imageUrl: string;\n let promptText: string | undefined;\n const modelName = getImageDescriptionModel(runtime);\n logger.log(`[OpenAI] Using IMAGE_DESCRIPTION model: ${modelName}`);\n const maxTokens = Number.parseInt(\n getSetting(runtime, \"OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS\", \"8192\") ||\n \"8192\",\n 10,\n );\n\n if (typeof params === \"string\") {\n imageUrl = params;\n promptText =\n \"Please analyze this image and provide a title and detailed description.\";\n } else {\n imageUrl = params.imageUrl;\n promptText =\n params.prompt ||\n \"Please analyze this image and provide a title and detailed description.\";\n }\n\n const messages = [\n {\n role: \"user\",\n content: [\n { type: \"text\", text: promptText },\n { type: \"image_url\", image_url: { url: imageUrl } },\n ],\n },\n ];\n\n const baseURL = getBaseURL(runtime);\n\n try {\n const requestBody: Record<string, any> = {\n model: modelName,\n messages: messages,\n max_tokens: maxTokens,\n };\n\n const response = await fetch(`${baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...getAuthHeader(runtime),\n },\n body: JSON.stringify(requestBody),\n });\n\n const responseClone = response.clone();\n const rawResponseBody = await responseClone.text();\n\n if (!response.ok) {\n throw new Error(`OpenAI API error: ${response.status}`);\n }\n\n const result: unknown = await response.json();\n\n type OpenAIResponseType = {\n choices?: Array<{\n message?: { content?: string };\n finish_reason?: string;\n }>;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n };\n };\n\n const typedResult = result as OpenAIResponseType;\n const content = typedResult.choices?.[0]?.message?.content;\n\n if (typedResult.usage) {\n emitModelUsageEvent(\n runtime,\n ModelType.IMAGE_DESCRIPTION,\n typeof params === \"string\" ? params : params.prompt || \"\",\n {\n inputTokens: typedResult.usage.prompt_tokens,\n outputTokens: typedResult.usage.completion_tokens,\n totalTokens: typedResult.usage.total_tokens,\n },\n );\n }\n\n if (!content) {\n return {\n title: \"Failed to analyze image\",\n description: \"No response from API\",\n };\n }\n\n // Check if a custom prompt was provided (not the default prompt)\n const isCustomPrompt =\n typeof params === \"object\" &&\n params.prompt &&\n params.prompt !==\n \"Please analyze this image and provide a title and detailed description.\";\n\n // If custom prompt is used, return the raw content\n if (isCustomPrompt) {\n return content;\n }\n\n // Otherwise, maintain backwards compatibility with object return\n const titleMatch = content.match(/title[:\\s]+(.+?)(?:\\n|$)/i);\n const title = titleMatch?.[1]?.trim() || \"Image Analysis\";\n const description = content\n .replace(/title[:\\s]+(.+?)(?:\\n|$)/i, \"\")\n .trim();\n\n const processedResult = { title, description };\n return processedResult;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error analyzing image: ${message}`);\n return {\n title: \"Failed to analyze image\",\n description: `Error: ${message}`,\n };\n }\n },\n [ModelType.TRANSCRIPTION]: async (\n runtime: IAgentRuntime,\n audioBuffer: Buffer,\n ) => {\n logger.debug({ size: audioBuffer?.length ?? 0 }, \"audioBuffer received\");\n\n const modelName = getSetting(\n runtime,\n \"OPENAI_TRANSCRIPTION_MODEL\",\n \"gpt-4o-mini-transcribe\",\n );\n logger.log(`[OpenAI] Using TRANSCRIPTION model: ${modelName}`);\n\n const baseURL = getBaseURL(runtime);\n if (!audioBuffer || audioBuffer.length === 0) {\n throw new Error(\"Audio buffer is empty or invalid for transcription\");\n }\n\n const formData = new FormData();\n const arrayBuffer = (\n audioBuffer as unknown as {\n buffer: ArrayBuffer;\n byteOffset: number;\n byteLength: number;\n }\n ).buffer;\n const start = (audioBuffer as any).byteOffset || 0;\n const end = start + ((audioBuffer as any).byteLength || 0);\n const safeArrayBuffer = arrayBuffer.slice(start, end);\n formData.append(\n \"file\",\n new Blob([safeArrayBuffer], { type: \"audio/mpeg\" }),\n \"recording.mp3\",\n );\n formData.append(\"model\", modelName as string);\n\n try {\n const response = await fetch(`${baseURL}/audio/transcriptions`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime),\n },\n body: formData,\n });\n\n const responseClone = response.clone();\n const rawResponseBody = await responseClone.text();\n\n logger.log({ response }, \"response\");\n\n if (!response.ok) {\n throw new Error(`Failed to transcribe audio: ${response.statusText}`);\n }\n\n const data = (await response.json()) as { text: string };\n const processedText = data.text;\n\n return processedText;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n throw error;\n }\n },\n [ModelType.TEXT_TO_SPEECH]: async (\n runtime: IAgentRuntime,\n text: string,\n ) => {\n const ttsModelName = getSetting(\n runtime,\n \"OPENAI_TTS_MODEL\",\n \"gpt-4o-mini-tts\",\n );\n logger.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${ttsModelName}`);\n try {\n const speechStream = await fetchTextToSpeech(runtime, text);\n return speechStream;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n throw error;\n }\n },\n [ModelType.OBJECT_SMALL]: async (\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n ) => {\n return generateObjectByModelType(\n runtime,\n params,\n ModelType.OBJECT_SMALL,\n getSmallModel,\n );\n },\n [ModelType.OBJECT_LARGE]: async (\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n ) => {\n return generateObjectByModelType(\n runtime,\n params,\n ModelType.OBJECT_LARGE,\n getLargeModel,\n );\n },\n },\n tests: [\n {\n name: \"openai_plugin_tests\",\n tests: [\n {\n name: \"openai_test_url_and_api_key_validation\",\n fn: async (runtime: IAgentRuntime) => {\n const baseURL = getBaseURL(runtime);\n const response = await fetch(`${baseURL}/models`, {\n headers: {\n Authorization: `Bearer ${getApiKey(runtime)}`,\n },\n });\n const data = await response.json();\n logger.log(\n { data: (data as { data?: unknown[] })?.data?.length ?? \"N/A\" },\n \"Models Available\",\n );\n if (!response.ok) {\n throw new Error(\n `Failed to validate OpenAI API key: ${response.statusText}`,\n );\n }\n },\n },\n {\n name: \"openai_test_text_embedding\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const embedding = await runtime.useModel(\n ModelType.TEXT_EMBEDDING,\n {\n text: \"Hello, world!\",\n },\n );\n logger.log({ embedding }, \"embedding\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_text_embedding: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_text_large\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"What is the nature of reality in 10 words?\",\n });\n if (text.length === 0) {\n throw new Error(\"Failed to generate text\");\n }\n logger.log({ text }, \"generated with test_text_large\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_text_large: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_text_small\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_SMALL, {\n prompt: \"What is the nature of reality in 10 words?\",\n });\n if (text.length === 0) {\n throw new Error(\"Failed to generate text\");\n }\n logger.log({ text }, \"generated with test_text_small\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_text_small: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_image_generation\",\n fn: async (runtime: IAgentRuntime) => {\n logger.log(\"openai_test_image_generation\");\n try {\n const image = await runtime.useModel(ModelType.IMAGE, {\n prompt: \"A beautiful sunset over a calm ocean\",\n n: 1,\n size: \"1024x1024\",\n });\n logger.log({ image }, \"generated with test_image_generation\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_image_generation: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"image-description\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n logger.log(\"openai_test_image_description\");\n try {\n const result = await runtime.useModel(\n ModelType.IMAGE_DESCRIPTION,\n \"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\",\n );\n\n if (\n result &&\n typeof result === \"object\" &&\n \"title\" in result &&\n \"description\" in result\n ) {\n logger.log({ result }, \"Image description\");\n } else {\n logger.error(\n \"Invalid image description result format:\",\n result,\n );\n }\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.error(`Error in image description test: ${message}`);\n }\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.error(\n `Error in openai_test_image_description: ${message}`,\n );\n }\n },\n },\n {\n name: \"openai_test_transcription\",\n fn: async (runtime: IAgentRuntime) => {\n logger.log(\"openai_test_transcription\");\n try {\n const response = await fetch(\n \"https://upload.wikimedia.org/wikipedia/en/4/40/Chris_Benoit_Voice_Message.ogg\",\n );\n const arrayBuffer = await response.arrayBuffer();\n const transcription = await runtime.useModel(\n ModelType.TRANSCRIPTION,\n Buffer.from(new Uint8Array(arrayBuffer)),\n );\n logger.log(\n { transcription },\n \"generated with test_transcription\",\n );\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_transcription: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_text_tokenizer_encode\",\n fn: async (runtime: IAgentRuntime) => {\n const prompt = \"Hello tokenizer encode!\";\n const tokens = await runtime.useModel(\n ModelType.TEXT_TOKENIZER_ENCODE,\n { prompt },\n );\n if (!Array.isArray(tokens) || tokens.length === 0) {\n throw new Error(\n \"Failed to tokenize text: expected non-empty array of tokens\",\n );\n }\n logger.log({ tokens }, \"Tokenized output\");\n },\n },\n {\n name: \"openai_test_text_tokenizer_decode\",\n fn: async (runtime: IAgentRuntime) => {\n const prompt = \"Hello tokenizer decode!\";\n const tokens = await runtime.useModel(\n ModelType.TEXT_TOKENIZER_ENCODE,\n { prompt },\n );\n const decodedText = await runtime.useModel(\n ModelType.TEXT_TOKENIZER_DECODE,\n { tokens },\n );\n if (decodedText !== prompt) {\n throw new Error(\n `Decoded text does not match original. Expected \"${prompt}\", got \"${decodedText}\"`,\n );\n }\n logger.log({ decodedText }, \"Decoded text\");\n },\n },\n {\n name: \"openai_test_text_to_speech\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const text = \"Hello, this is a test for text-to-speech.\";\n const response = await fetchTextToSpeech(runtime, text);\n if (!response) {\n throw new Error(\"Failed to generate speech\");\n }\n logger.log(\"Generated speech successfully\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in openai_test_text_to_speech: ${message}`);\n throw error;\n }\n },\n },\n ],\n },\n ],\n};\nexport default openaiPlugin;\n"
5
+ "import { createOpenAI } from \"@ai-sdk/openai\";\nimport type {\n DetokenizeTextParams,\n GenerateTextParams,\n IAgentRuntime,\n ImageDescriptionParams,\n ModelTypeName,\n ObjectGenerationParams,\n Plugin,\n TextEmbeddingParams,\n TokenizeTextParams,\n} from \"@elizaos/core\";\nimport { EventType, logger, ModelType, VECTOR_DIMS } from \"@elizaos/core\";\nimport {\n generateObject,\n generateText,\n JSONParseError,\n type JSONValue,\n type LanguageModelUsage,\n} from \"ai\";\nimport { encodingForModel, type TiktokenModel } from \"js-tiktoken\";\n\nexport interface OpenAITranscriptionParams {\n audio: Blob | File;\n model?: string;\n language?: string;\n response_format?: string;\n prompt?: string;\n temperature?: number;\n timestampGranularities?: string[];\n}\n\nexport interface OpenAITextToSpeechParams {\n text: string;\n model?: string;\n voice?: string;\n format?: \"mp3\" | \"wav\" | \"flac\" | string;\n instructions?: string;\n}\n\n/**\n * Retrieves a configuration setting from the runtime, falling back to environment variables or a default value if not found.\n *\n * @param key - The name of the setting to retrieve.\n * @param defaultValue - The value to return if the setting is not found in the runtime or environment.\n * @returns The resolved setting value, or {@link defaultValue} if not found.\n */\nfunction getSetting(\n runtime: IAgentRuntime,\n key: string,\n defaultValue?: string,\n): string | undefined {\n return runtime.getSetting(key) ?? process.env[key] ?? defaultValue;\n}\n\nfunction isBrowser(): boolean {\n return (\n typeof globalThis !== \"undefined\" &&\n typeof (globalThis as any).document !== \"undefined\"\n );\n}\n\n/**\n * Determines whether we're running in a browser with a server-hosted proxy configured.\n * In this mode, we do not require a real API key on the client and rely on the proxy to inject it.\n */\nfunction isProxyMode(runtime: IAgentRuntime): boolean {\n return isBrowser() && !!getSetting(runtime, \"OPENAI_BROWSER_BASE_URL\");\n}\n\nfunction getAuthHeader(\n runtime: IAgentRuntime,\n forEmbedding = false,\n): Record<string, string> {\n if (isBrowser()) return {};\n const key = forEmbedding ? getEmbeddingApiKey(runtime) : getApiKey(runtime);\n return key ? { Authorization: `Bearer ${key}` } : {};\n}\n\n/**\n * Retrieves the OpenAI API base URL from runtime settings, environment variables, or defaults, using provider-aware resolution.\n *\n * @returns The resolved base URL for OpenAI API requests.\n */\nfunction getBaseURL(runtime: IAgentRuntime): string {\n const browserURL = getSetting(runtime, \"OPENAI_BROWSER_BASE_URL\");\n const baseURL = (\n isBrowser() && browserURL\n ? browserURL\n : getSetting(runtime, \"OPENAI_BASE_URL\", \"https://api.openai.com/v1\")\n ) as string;\n logger.debug(`[OpenAI] Default base URL: ${baseURL}`);\n return baseURL;\n}\n\n/**\n * Retrieves the OpenAI API base URL for embeddings, falling back to the general base URL.\n *\n * @returns The resolved base URL for OpenAI embedding requests.\n */\nfunction getEmbeddingBaseURL(runtime: IAgentRuntime): string {\n const embeddingURL = isBrowser()\n ? getSetting(runtime, \"OPENAI_BROWSER_EMBEDDING_URL\") ||\n getSetting(runtime, \"OPENAI_BROWSER_BASE_URL\")\n : getSetting(runtime, \"OPENAI_EMBEDDING_URL\");\n if (embeddingURL) {\n logger.debug(`[OpenAI] Using specific embedding base URL: ${embeddingURL}`);\n return embeddingURL;\n }\n logger.debug(\"[OpenAI] Falling back to general base URL for embeddings.\");\n return getBaseURL(runtime);\n}\n\n/**\n * Helper function to get the API key for OpenAI\n *\n * @param runtime The runtime context\n * @returns The configured API key\n */\nfunction getApiKey(runtime: IAgentRuntime): string | undefined {\n return getSetting(runtime, \"OPENAI_API_KEY\");\n}\n\n/**\n * Helper function to get the embedding API key for OpenAI, falling back to the general API key if not set.\n *\n * @param runtime The runtime context\n * @returns The configured API key\n */\nfunction getEmbeddingApiKey(runtime: IAgentRuntime): string | undefined {\n const embeddingApiKey = getSetting(runtime, \"OPENAI_EMBEDDING_API_KEY\");\n if (embeddingApiKey) {\n logger.debug(\"[OpenAI] Using specific embedding API key (present)\");\n return embeddingApiKey;\n }\n logger.debug(\"[OpenAI] Falling back to general API key for embeddings.\");\n return getApiKey(runtime);\n}\n\n/**\n * Helper function to get the small model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured small model name\n */\nfunction getSmallModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENAI_SMALL_MODEL\") ??\n (getSetting(runtime, \"SMALL_MODEL\", \"gpt-5-nano\") as string)\n );\n}\n\n/**\n * Helper function to get the large model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured large model name\n */\nfunction getLargeModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENAI_LARGE_MODEL\") ??\n (getSetting(runtime, \"LARGE_MODEL\", \"gpt-5-mini\") as string)\n );\n}\n\n/**\n * Helper function to get the image description model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured image description model name\n */\nfunction getImageDescriptionModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENAI_IMAGE_DESCRIPTION_MODEL\", \"gpt-5-nano\") ??\n \"gpt-5-nano\"\n );\n}\n\n/**\n * Helper function to get experimental telemetry setting\n *\n * @param runtime The runtime context\n * @returns Whether experimental telemetry is enabled\n */\nfunction getExperimentalTelemetry(runtime: IAgentRuntime): boolean {\n const setting = getSetting(runtime, \"OPENAI_EXPERIMENTAL_TELEMETRY\", \"false\");\n // Convert to string and check for truthy values\n const normalizedSetting = String(setting).toLowerCase();\n const result = normalizedSetting === \"true\";\n logger.debug(\n `[OpenAI] Experimental telemetry in function: \"${setting}\" (type: ${typeof setting}, normalized: \"${normalizedSetting}\", result: ${result})`,\n );\n return result;\n}\n\n/**\n * Create an OpenAI client with proper configuration\n *\n * @param runtime The runtime context\n * @returns Configured OpenAI client\n */\nfunction createOpenAIClient(runtime: IAgentRuntime) {\n const baseURL = getBaseURL(runtime);\n // In proxy mode (browser + proxy base URL), pass a harmless placeholder key.\n // The server proxy replaces Authorization; no secrets leave the server.\n const apiKey =\n getApiKey(runtime) ?? (isProxyMode(runtime) ? \"sk-proxy\" : undefined);\n return createOpenAI({ apiKey: (apiKey ?? \"\") as string, baseURL });\n}\n\n/**\n * Asynchronously tokenizes the given text based on the specified model and prompt.\n *\n * @param {ModelTypeName} model - The type of model to use for tokenization.\n * @param {string} prompt - The text prompt to tokenize.\n * @returns {number[]} - An array of tokens representing the encoded prompt.\n */\nasync function tokenizeText(model: ModelTypeName, prompt: string) {\n const modelName =\n model === ModelType.TEXT_SMALL\n ? (process.env.OPENAI_SMALL_MODEL ??\n process.env.SMALL_MODEL ??\n \"gpt-5-nano\")\n : (process.env.LARGE_MODEL ?? \"gpt-5-mini\");\n const tokens = encodingForModel(modelName as TiktokenModel).encode(prompt);\n return tokens;\n}\n\n/**\n * Detokenize a sequence of tokens back into text using the specified model.\n *\n * @param {ModelTypeName} model - The type of model to use for detokenization.\n * @param {number[]} tokens - The sequence of tokens to detokenize.\n * @returns {string} The detokenized text.\n */\nasync function detokenizeText(model: ModelTypeName, tokens: number[]) {\n const modelName =\n model === ModelType.TEXT_SMALL\n ? (process.env.OPENAI_SMALL_MODEL ??\n process.env.SMALL_MODEL ??\n \"gpt-5-nano\")\n : (process.env.OPENAI_LARGE_MODEL ??\n process.env.LARGE_MODEL ??\n \"gpt-5-mini\");\n return encodingForModel(modelName as TiktokenModel).decode(tokens);\n}\n\n/**\n * Helper function to generate objects using specified model type\n */\nasync function generateObjectByModelType(\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n modelType: string,\n getModelFn: (runtime: IAgentRuntime) => string,\n): Promise<JSONValue> {\n const openai = createOpenAIClient(runtime);\n const modelName = getModelFn(runtime);\n logger.log(`[OpenAI] Using ${modelType} model: ${modelName}`);\n const temperature = params.temperature ?? 0;\n const schemaPresent = !!params.schema;\n\n if (schemaPresent) {\n logger.info(\n `Using ${modelType} without schema validation (schema provided but output=no-schema)`,\n );\n }\n\n try {\n const { object, usage } = await generateObject({\n model: openai.languageModel(modelName),\n output: \"no-schema\",\n prompt: params.prompt,\n temperature: temperature,\n experimental_repairText: getJsonRepairFunction(),\n });\n\n if (usage) {\n emitModelUsageEvent(\n runtime,\n modelType as ModelTypeName,\n params.prompt,\n usage,\n );\n }\n return object;\n } catch (error: unknown) {\n if (error instanceof JSONParseError) {\n logger.error(`[generateObject] Failed to parse JSON: ${error.message}`);\n\n const repairFunction = getJsonRepairFunction();\n const repairedJsonString = await repairFunction({\n text: error.text,\n error,\n });\n\n if (repairedJsonString) {\n try {\n const repairedObject = JSON.parse(repairedJsonString);\n logger.info(\"[generateObject] Successfully repaired JSON.\");\n return repairedObject;\n } catch (repairParseError: unknown) {\n const message =\n repairParseError instanceof Error\n ? repairParseError.message\n : String(repairParseError);\n logger.error(\n `[generateObject] Failed to parse repaired JSON: ${message}`,\n );\n throw repairParseError;\n }\n } else {\n logger.error(\"[generateObject] JSON repair failed.\");\n throw error;\n }\n } else {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`[generateObject] Unknown error: ${message}`);\n throw error;\n }\n }\n}\n\n/**\n * Returns a function to repair JSON text\n */\nfunction getJsonRepairFunction(): (params: {\n text: string;\n error: unknown;\n}) => Promise<string | null> {\n return async ({ text, error }: { text: string; error: unknown }) => {\n try {\n if (error instanceof JSONParseError) {\n const cleanedText = text.replace(/```json\\n|\\n```|```/g, \"\");\n JSON.parse(cleanedText);\n return cleanedText;\n }\n return null;\n } catch (jsonError: unknown) {\n const message =\n jsonError instanceof Error ? jsonError.message : String(jsonError);\n logger.warn(`Failed to repair JSON text: ${message}`);\n return null;\n }\n };\n}\n\n/**\n * Emits a model usage event\n * @param runtime The runtime context\n * @param type The model type\n * @param prompt The prompt used\n * @param usage The LLM usage data\n */\nfunction emitModelUsageEvent(\n runtime: IAgentRuntime,\n type: ModelTypeName,\n prompt: string,\n usage: LanguageModelUsage,\n) {\n runtime.emitEvent(EventType.MODEL_USED, {\n provider: \"openai\",\n type,\n prompt,\n tokens: {\n prompt: usage.inputTokens,\n completion: usage.outputTokens,\n total: usage.totalTokens,\n },\n });\n}\n\n/**\n * function for text-to-speech\n */\nasync function fetchTextToSpeech(\n runtime: IAgentRuntime,\n options: OpenAITextToSpeechParams,\n) {\n const defaultModel = getSetting(\n runtime,\n \"OPENAI_TTS_MODEL\",\n \"gpt-4o-mini-tts\",\n );\n const defaultVoice = getSetting(runtime, \"OPENAI_TTS_VOICE\", \"nova\");\n const defaultInstructions = getSetting(\n runtime,\n \"OPENAI_TTS_INSTRUCTIONS\",\n \"\",\n );\n const baseURL = getBaseURL(runtime);\n\n const model = options.model || (defaultModel as string);\n const voice = options.voice || (defaultVoice as string);\n const instructions = options.instructions ?? (defaultInstructions as string);\n const format = options.format || \"mp3\";\n\n try {\n const res = await fetch(`${baseURL}/audio/speech`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime),\n \"Content-Type\": \"application/json\",\n // Hint desired audio format in Accept when possible\n ...(format === \"mp3\" ? { Accept: \"audio/mpeg\" } : {}),\n },\n body: JSON.stringify({\n model,\n voice,\n input: options.text,\n format,\n ...(instructions && { instructions }),\n }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`OpenAI TTS error ${res.status}: ${err}`);\n }\n\n return res.body;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to fetch speech from OpenAI TTS: ${message}`);\n }\n}\n\n/**\n * Defines the OpenAI plugin with its name, description, and configuration options.\n * @type {Plugin}\n */\nexport const openaiPlugin: Plugin = {\n name: \"openai\",\n description: \"OpenAI plugin\",\n config: {\n OPENAI_API_KEY: process.env.OPENAI_API_KEY,\n OPENAI_BASE_URL: process.env.OPENAI_BASE_URL,\n OPENAI_SMALL_MODEL: process.env.OPENAI_SMALL_MODEL,\n OPENAI_LARGE_MODEL: process.env.OPENAI_LARGE_MODEL,\n SMALL_MODEL: process.env.SMALL_MODEL,\n LARGE_MODEL: process.env.LARGE_MODEL,\n OPENAI_EMBEDDING_MODEL: process.env.OPENAI_EMBEDDING_MODEL,\n OPENAI_EMBEDDING_API_KEY: process.env.OPENAI_EMBEDDING_API_KEY,\n OPENAI_EMBEDDING_URL: process.env.OPENAI_EMBEDDING_URL,\n OPENAI_EMBEDDING_DIMENSIONS: process.env.OPENAI_EMBEDDING_DIMENSIONS,\n OPENAI_IMAGE_DESCRIPTION_MODEL: process.env.OPENAI_IMAGE_DESCRIPTION_MODEL,\n OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS:\n process.env.OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS,\n OPENAI_EXPERIMENTAL_TELEMETRY: process.env.OPENAI_EXPERIMENTAL_TELEMETRY,\n },\n async init(_config, runtime) {\n // do check in the background\n new Promise<void>(async (resolve) => {\n resolve();\n try {\n if (!getApiKey(runtime) && !isBrowser()) {\n logger.warn(\n \"OPENAI_API_KEY is not set in environment - OpenAI functionality will be limited\",\n );\n return;\n }\n try {\n const baseURL = getBaseURL(runtime);\n const response = await fetch(`${baseURL}/models`, {\n headers: { ...getAuthHeader(runtime) },\n });\n if (!response.ok) {\n logger.warn(\n `OpenAI API key validation failed: ${response.statusText}`,\n );\n logger.warn(\n \"OpenAI functionality will be limited until a valid API key is provided\",\n );\n } else {\n logger.log(\"OpenAI API key validated successfully\");\n }\n } catch (fetchError: unknown) {\n const message =\n fetchError instanceof Error\n ? fetchError.message\n : String(fetchError);\n logger.warn(`Error validating OpenAI API key: ${message}`);\n logger.warn(\n \"OpenAI functionality will be limited until a valid API key is provided\",\n );\n }\n } catch (error: unknown) {\n const message =\n (error as { errors?: Array<{ message: string }> })?.errors\n ?.map((e) => e.message)\n .join(\", \") ||\n (error instanceof Error ? error.message : String(error));\n logger.warn(\n `OpenAI plugin configuration issue: ${message} - You need to configure the OPENAI_API_KEY in your environment variables`,\n );\n }\n });\n },\n\n models: {\n [ModelType.TEXT_EMBEDDING]: async (\n runtime: IAgentRuntime,\n params: TextEmbeddingParams | string | null,\n ): Promise<number[]> => {\n const embeddingModelName = getSetting(\n runtime,\n \"OPENAI_EMBEDDING_MODEL\",\n \"text-embedding-3-small\",\n );\n const embeddingDimension = Number.parseInt(\n getSetting(runtime, \"OPENAI_EMBEDDING_DIMENSIONS\", \"1536\") || \"1536\",\n 10,\n ) as (typeof VECTOR_DIMS)[keyof typeof VECTOR_DIMS];\n\n if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {\n const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(\", \")}`;\n logger.error(errorMsg);\n throw new Error(errorMsg);\n }\n if (params === null) {\n logger.debug(\"Creating test embedding for initialization\");\n const testVector = Array(embeddingDimension).fill(0);\n testVector[0] = 0.1;\n return testVector;\n }\n let text: string;\n if (typeof params === \"string\") {\n text = params;\n } else if (typeof params === \"object\" && params.text) {\n text = params.text;\n } else {\n logger.warn(\"Invalid input format for embedding\");\n const fallbackVector = Array(embeddingDimension).fill(0);\n fallbackVector[0] = 0.2;\n return fallbackVector;\n }\n if (!text.trim()) {\n logger.warn(\"Empty text for embedding\");\n const emptyVector = Array(embeddingDimension).fill(0);\n emptyVector[0] = 0.3;\n return emptyVector;\n }\n\n const embeddingBaseURL = getEmbeddingBaseURL(runtime);\n\n try {\n const response = await fetch(`${embeddingBaseURL}/embeddings`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime, true),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: embeddingModelName,\n input: text,\n }),\n });\n\n // Clone available if needed for logging/debugging\n // const debugText = await response.clone().text().catch(() => \"\");\n\n if (!response.ok) {\n logger.error(\n `OpenAI API error: ${response.status} - ${response.statusText}`,\n );\n const errorVector = Array(embeddingDimension).fill(0);\n errorVector[0] = 0.4;\n return errorVector;\n }\n\n const data = (await response.json()) as {\n data: [{ embedding: number[] }];\n usage?: { prompt_tokens: number; total_tokens: number };\n };\n\n if (!data?.data?.[0]?.embedding) {\n logger.error(\"API returned invalid structure\");\n const errorVector = Array(embeddingDimension).fill(0);\n errorVector[0] = 0.5;\n return errorVector;\n }\n\n const embedding = data.data[0].embedding;\n\n if (data.usage) {\n const usage = {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: 0,\n totalTokens: data.usage.total_tokens,\n };\n\n emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage);\n }\n\n logger.log(`Got valid embedding with length ${embedding.length}`);\n return embedding;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error generating embedding: ${message}`);\n const errorVector = Array(embeddingDimension).fill(0);\n errorVector[0] = 0.6;\n return errorVector;\n }\n },\n [ModelType.TEXT_TOKENIZER_ENCODE]: async (\n _runtime,\n { prompt, modelType = ModelType.TEXT_LARGE }: TokenizeTextParams,\n ) => {\n return await tokenizeText(modelType ?? ModelType.TEXT_LARGE, prompt);\n },\n [ModelType.TEXT_TOKENIZER_DECODE]: async (\n _runtime,\n { tokens, modelType = ModelType.TEXT_LARGE }: DetokenizeTextParams,\n ) => {\n return await detokenizeText(modelType ?? ModelType.TEXT_LARGE, tokens);\n },\n [ModelType.TEXT_SMALL]: async (\n runtime: IAgentRuntime,\n {\n prompt,\n stopSequences = [],\n maxTokens = 8192,\n temperature = 0.7,\n frequencyPenalty = 0.7,\n presencePenalty = 0.7,\n }: GenerateTextParams,\n ) => {\n const openai = createOpenAIClient(runtime);\n const modelName = getSmallModel(runtime);\n const experimentalTelemetry = getExperimentalTelemetry(runtime);\n\n logger.log(`[OpenAI] Using TEXT_SMALL model: ${modelName}`);\n logger.log(prompt);\n\n const { text: openaiResponse, usage } = await generateText({\n model: openai.languageModel(modelName),\n prompt: prompt,\n system: runtime.character.system ?? undefined,\n temperature: temperature,\n maxOutputTokens: maxTokens,\n frequencyPenalty: frequencyPenalty,\n presencePenalty: presencePenalty,\n stopSequences: stopSequences,\n experimental_telemetry: {\n isEnabled: experimentalTelemetry,\n },\n });\n\n if (usage) {\n emitModelUsageEvent(runtime, ModelType.TEXT_SMALL, prompt, usage);\n }\n\n return openaiResponse;\n },\n [ModelType.TEXT_LARGE]: async (\n runtime: IAgentRuntime,\n {\n prompt,\n stopSequences = [],\n maxTokens = 8192,\n temperature = 0.7,\n frequencyPenalty = 0.7,\n presencePenalty = 0.7,\n }: GenerateTextParams,\n ) => {\n const openai = createOpenAIClient(runtime);\n const modelName = getLargeModel(runtime);\n const experimentalTelemetry = getExperimentalTelemetry(runtime);\n\n logger.log(`[OpenAI] Using TEXT_LARGE model: ${modelName}`);\n logger.log(prompt);\n\n const { text: openaiResponse, usage } = await generateText({\n model: openai.languageModel(modelName),\n prompt: prompt,\n system: runtime.character.system ?? undefined,\n temperature: temperature,\n maxOutputTokens: maxTokens,\n frequencyPenalty: frequencyPenalty,\n presencePenalty: presencePenalty,\n stopSequences: stopSequences,\n experimental_telemetry: {\n isEnabled: experimentalTelemetry,\n },\n });\n\n if (usage) {\n emitModelUsageEvent(runtime, ModelType.TEXT_LARGE, prompt, usage);\n }\n\n return openaiResponse;\n },\n [ModelType.IMAGE]: async (\n runtime: IAgentRuntime,\n params: {\n prompt: string;\n n?: number;\n size?: string;\n },\n ) => {\n const n = params.n || 1;\n const size = params.size || \"1024x1024\";\n const prompt = params.prompt;\n const modelName = \"gpt-image-1\"; // Updated image model\n logger.log(`[OpenAI] Using IMAGE model: ${modelName}`);\n\n const baseURL = getBaseURL(runtime);\n\n try {\n const response = await fetch(`${baseURL}/images/generations`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: modelName,\n prompt: prompt,\n n: n,\n size: size,\n }),\n });\n\n // const debugText = await response.clone().text().catch(() => \"\");\n\n if (!response.ok) {\n throw new Error(`Failed to generate image: ${response.statusText}`);\n }\n\n const data = await response.json();\n const typedData = data as { data: { url: string }[] };\n\n return typedData.data;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n throw error;\n }\n },\n [ModelType.IMAGE_DESCRIPTION]: async (\n runtime: IAgentRuntime,\n params: ImageDescriptionParams | string,\n ) => {\n let imageUrl: string;\n let promptText: string | undefined;\n const modelName = getImageDescriptionModel(runtime);\n logger.log(`[OpenAI] Using IMAGE_DESCRIPTION model: ${modelName}`);\n const maxTokens = Number.parseInt(\n getSetting(runtime, \"OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS\", \"8192\") ||\n \"8192\",\n 10,\n );\n\n if (typeof params === \"string\") {\n imageUrl = params;\n promptText =\n \"Please analyze this image and provide a title and detailed description.\";\n } else {\n imageUrl = params.imageUrl;\n promptText =\n params.prompt ||\n \"Please analyze this image and provide a title and detailed description.\";\n }\n\n const messages = [\n {\n role: \"user\",\n content: [\n { type: \"text\", text: promptText },\n { type: \"image_url\", image_url: { url: imageUrl } },\n ],\n },\n ];\n\n const baseURL = getBaseURL(runtime);\n\n try {\n const requestBody: Record<string, any> = {\n model: modelName,\n messages: messages,\n max_tokens: maxTokens,\n };\n\n const response = await fetch(`${baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...getAuthHeader(runtime),\n },\n body: JSON.stringify(requestBody),\n });\n\n // const debugText = await response.clone().text().catch(() => \"\");\n\n if (!response.ok) {\n throw new Error(`OpenAI API error: ${response.status}`);\n }\n\n const result: unknown = await response.json();\n\n type OpenAIResponseType = {\n choices?: Array<{\n message?: { content?: string };\n finish_reason?: string;\n }>;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n };\n };\n\n const typedResult = result as OpenAIResponseType;\n const content = typedResult.choices?.[0]?.message?.content;\n\n if (typedResult.usage) {\n emitModelUsageEvent(\n runtime,\n ModelType.IMAGE_DESCRIPTION,\n typeof params === \"string\" ? params : params.prompt || \"\",\n {\n inputTokens: typedResult.usage.prompt_tokens,\n outputTokens: typedResult.usage.completion_tokens,\n totalTokens: typedResult.usage.total_tokens,\n },\n );\n }\n\n if (!content) {\n return {\n title: \"Failed to analyze image\",\n description: \"No response from API\",\n };\n }\n\n // Check if a custom prompt was provided (not the default prompt)\n const isCustomPrompt =\n typeof params === \"object\" &&\n params.prompt &&\n params.prompt !==\n \"Please analyze this image and provide a title and detailed description.\";\n\n // If custom prompt is used, return the raw content\n if (isCustomPrompt) {\n return content;\n }\n\n // Otherwise, maintain backwards compatibility with object return\n const titleMatch = content.match(/title[:\\s]+(.+?)(?:\\n|$)/i);\n const title = titleMatch?.[1]?.trim() || \"Image Analysis\";\n const description = content\n .replace(/title[:\\s]+(.+?)(?:\\n|$)/i, \"\")\n .trim();\n\n const processedResult = { title, description };\n return processedResult;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error analyzing image: ${message}`);\n return {\n title: \"Failed to analyze image\",\n description: `Error: ${message}`,\n };\n }\n },\n [ModelType.TRANSCRIPTION]: async (\n runtime: IAgentRuntime,\n input: Blob | File | OpenAITranscriptionParams,\n ) => {\n let modelName = getSetting(\n runtime,\n \"OPENAI_TRANSCRIPTION_MODEL\",\n \"gpt-4o-mini-transcribe\",\n );\n logger.log(`[OpenAI] Using TRANSCRIPTION model: ${modelName}`);\n\n const baseURL = getBaseURL(runtime);\n\n // Support either Blob/File directly, or an object with { audio: Blob/File, ...options }\n let blob: Blob;\n let extraParams: OpenAITranscriptionParams | null = null;\n\n if (input instanceof Blob || input instanceof File) {\n blob = input as Blob;\n } else if (\n typeof input === \"object\" &&\n input !== null &&\n (input as any).audio != null\n ) {\n const params = input as any;\n if (\n !(params.audio instanceof Blob) &&\n !(params.audio instanceof File)\n ) {\n throw new Error(\n \"TRANSCRIPTION param 'audio' must be a Blob/File. Wrap buffers as: new Blob([buffer], { type: 'audio/mpeg' })\",\n );\n }\n blob = params.audio as Blob;\n extraParams = params as OpenAITranscriptionParams;\n if (typeof params.model === \"string\" && params.model) {\n modelName = params.model;\n }\n } else {\n throw new Error(\n \"TRANSCRIPTION expects a Blob/File or an object { audio: Blob/File, language?, response_format?, timestampGranularities?, prompt?, temperature?, model? }\",\n );\n }\n\n const mime = (blob as File).type || \"audio/webm\";\n const filename =\n (blob as File).name ||\n (mime.includes(\"mp3\") || mime.includes(\"mpeg\")\n ? \"recording.mp3\"\n : mime.includes(\"ogg\")\n ? \"recording.ogg\"\n : mime.includes(\"wav\")\n ? \"recording.wav\"\n : mime.includes(\"webm\")\n ? \"recording.webm\"\n : \"recording.bin\");\n\n const formData = new FormData();\n formData.append(\"file\", blob, filename);\n formData.append(\"model\", String(modelName));\n if (extraParams) {\n if (typeof extraParams.language === \"string\") {\n formData.append(\"language\", String(extraParams.language));\n }\n if (typeof extraParams.response_format === \"string\") {\n formData.append(\n \"response_format\",\n String(extraParams.response_format),\n );\n }\n if (typeof extraParams.prompt === \"string\") {\n formData.append(\"prompt\", String(extraParams.prompt));\n }\n if (typeof extraParams.temperature === \"number\") {\n formData.append(\"temperature\", String(extraParams.temperature));\n }\n if (Array.isArray(extraParams.timestampGranularities)) {\n for (const g of extraParams.timestampGranularities) {\n formData.append(\"timestamp_granularities[]\", String(g));\n }\n }\n }\n\n try {\n const response = await fetch(`${baseURL}/audio/transcriptions`, {\n method: \"POST\",\n headers: {\n ...getAuthHeader(runtime),\n },\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to transcribe audio: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = (await response.json()) as { text: string };\n return data.text || \"\";\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`TRANSCRIPTION error: ${message}`);\n throw error;\n }\n },\n [ModelType.TEXT_TO_SPEECH]: async (\n runtime: IAgentRuntime,\n input: string | OpenAITextToSpeechParams,\n ) => {\n // Normalize input into options with per-call overrides\n const options: OpenAITextToSpeechParams =\n typeof input === \"string\"\n ? { text: input }\n : (input as OpenAITextToSpeechParams);\n\n const resolvedModel =\n options.model ||\n (getSetting(runtime, \"OPENAI_TTS_MODEL\", \"gpt-4o-mini-tts\") as string);\n logger.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${resolvedModel}`);\n try {\n const speechStream = await fetchTextToSpeech(runtime, options);\n return speechStream;\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error in TEXT_TO_SPEECH: ${message}`);\n throw error;\n }\n },\n [ModelType.OBJECT_SMALL]: async (\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n ) => {\n return generateObjectByModelType(\n runtime,\n params,\n ModelType.OBJECT_SMALL,\n getSmallModel,\n );\n },\n [ModelType.OBJECT_LARGE]: async (\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n ) => {\n return generateObjectByModelType(\n runtime,\n params,\n ModelType.OBJECT_LARGE,\n getLargeModel,\n );\n },\n },\n tests: [\n {\n name: \"openai_plugin_tests\",\n tests: [\n {\n name: \"openai_test_url_and_api_key_validation\",\n fn: async (runtime: IAgentRuntime) => {\n const baseURL = getBaseURL(runtime);\n const response = await fetch(`${baseURL}/models`, {\n headers: {\n Authorization: `Bearer ${getApiKey(runtime)}`,\n },\n });\n const data = await response.json();\n logger.log(\n { data: (data as { data?: unknown[] })?.data?.length ?? \"N/A\" },\n \"Models Available\",\n );\n if (!response.ok) {\n throw new Error(\n `Failed to validate OpenAI API key: ${response.statusText}`,\n );\n }\n },\n },\n {\n name: \"openai_test_text_embedding\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const embedding = await runtime.useModel(\n ModelType.TEXT_EMBEDDING,\n {\n text: \"Hello, world!\",\n },\n );\n logger.log({ embedding }, \"embedding\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_text_embedding: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_text_large\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_LARGE, {\n prompt: \"What is the nature of reality in 10 words?\",\n });\n if (text.length === 0) {\n throw new Error(\"Failed to generate text\");\n }\n logger.log({ text }, \"generated with test_text_large\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_text_large: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_text_small\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const text = await runtime.useModel(ModelType.TEXT_SMALL, {\n prompt: \"What is the nature of reality in 10 words?\",\n });\n if (text.length === 0) {\n throw new Error(\"Failed to generate text\");\n }\n logger.log({ text }, \"generated with test_text_small\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_text_small: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_image_generation\",\n fn: async (runtime: IAgentRuntime) => {\n logger.log(\"openai_test_image_generation\");\n try {\n const image = await runtime.useModel(ModelType.IMAGE, {\n prompt: \"A beautiful sunset over a calm ocean\",\n n: 1,\n size: \"1024x1024\",\n });\n logger.log({ image }, \"generated with test_image_generation\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_image_generation: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"image-description\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n logger.log(\"openai_test_image_description\");\n try {\n const result = await runtime.useModel(\n ModelType.IMAGE_DESCRIPTION,\n \"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\",\n );\n\n if (\n result &&\n typeof result === \"object\" &&\n \"title\" in result &&\n \"description\" in result\n ) {\n logger.log({ result }, \"Image description\");\n } else {\n logger.error(\n \"Invalid image description result format:\",\n result,\n );\n }\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.error(`Error in image description test: ${message}`);\n }\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : String(e);\n logger.error(\n `Error in openai_test_image_description: ${message}`,\n );\n }\n },\n },\n {\n name: \"openai_test_transcription\",\n fn: async (runtime: IAgentRuntime) => {\n logger.log(\"openai_test_transcription\");\n try {\n const response = await fetch(\n \"https://upload.wikimedia.org/wikipedia/en/4/40/Chris_Benoit_Voice_Message.ogg\",\n );\n const arrayBuffer = await response.arrayBuffer();\n const transcription = await runtime.useModel(\n ModelType.TRANSCRIPTION,\n Buffer.from(new Uint8Array(arrayBuffer)),\n );\n logger.log(\n { transcription },\n \"generated with test_transcription\",\n );\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in test_transcription: ${message}`);\n throw error;\n }\n },\n },\n {\n name: \"openai_test_text_tokenizer_encode\",\n fn: async (runtime: IAgentRuntime) => {\n const prompt = \"Hello tokenizer encode!\";\n const tokens = await runtime.useModel(\n ModelType.TEXT_TOKENIZER_ENCODE,\n { prompt },\n );\n if (!Array.isArray(tokens) || tokens.length === 0) {\n throw new Error(\n \"Failed to tokenize text: expected non-empty array of tokens\",\n );\n }\n logger.log({ tokens }, \"Tokenized output\");\n },\n },\n {\n name: \"openai_test_text_tokenizer_decode\",\n fn: async (runtime: IAgentRuntime) => {\n const prompt = \"Hello tokenizer decode!\";\n const tokens = await runtime.useModel(\n ModelType.TEXT_TOKENIZER_ENCODE,\n { prompt },\n );\n const decodedText = await runtime.useModel(\n ModelType.TEXT_TOKENIZER_DECODE,\n { tokens },\n );\n if (decodedText !== prompt) {\n throw new Error(\n `Decoded text does not match original. Expected \"${prompt}\", got \"${decodedText}\"`,\n );\n }\n logger.log({ decodedText }, \"Decoded text\");\n },\n },\n {\n name: \"openai_test_text_to_speech\",\n fn: async (runtime: IAgentRuntime) => {\n try {\n const response = await fetchTextToSpeech(runtime, {\n text: \"Hello, this is a test for text-to-speech.\",\n });\n if (!response) {\n throw new Error(\"Failed to generate speech\");\n }\n logger.log(\"Generated speech successfully\");\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : String(error);\n logger.error(`Error in openai_test_text_to_speech: ${message}`);\n throw error;\n }\n },\n },\n ],\n },\n ],\n};\nexport default openaiPlugin;\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "C6DE2BE8B57F1DEB64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "89F51A79E528892264756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -189,22 +189,28 @@ function emitModelUsageEvent(runtime, type, prompt, usage) {
189
189
  }
190
190
  });
191
191
  }
192
- async function fetchTextToSpeech(runtime, text) {
193
- const model = getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
194
- const voice = getSetting(runtime, "OPENAI_TTS_VOICE", "nova");
195
- const instructions = getSetting(runtime, "OPENAI_TTS_INSTRUCTIONS", "");
192
+ async function fetchTextToSpeech(runtime, options) {
193
+ const defaultModel = getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
194
+ const defaultVoice = getSetting(runtime, "OPENAI_TTS_VOICE", "nova");
195
+ const defaultInstructions = getSetting(runtime, "OPENAI_TTS_INSTRUCTIONS", "");
196
196
  const baseURL = getBaseURL(runtime);
197
+ const model = options.model || defaultModel;
198
+ const voice = options.voice || defaultVoice;
199
+ const instructions = options.instructions ?? defaultInstructions;
200
+ const format = options.format || "mp3";
197
201
  try {
198
202
  const res = await fetch(`${baseURL}/audio/speech`, {
199
203
  method: "POST",
200
204
  headers: {
201
205
  ...getAuthHeader(runtime),
202
- "Content-Type": "application/json"
206
+ "Content-Type": "application/json",
207
+ ...format === "mp3" ? { Accept: "audio/mpeg" } : {}
203
208
  },
204
209
  body: JSON.stringify({
205
210
  model,
206
211
  voice,
207
- input: text,
212
+ input: options.text,
213
+ format,
208
214
  ...instructions && { instructions }
209
215
  })
210
216
  });
@@ -311,8 +317,6 @@ var openaiPlugin = {
311
317
  input: text
312
318
  })
313
319
  });
314
- const responseClone = response.clone();
315
- const rawResponseBody = await responseClone.text();
316
320
  if (!response.ok) {
317
321
  import_core.logger.error(`OpenAI API error: ${response.status} - ${response.statusText}`);
318
322
  const errorVector = Array(embeddingDimension).fill(0);
@@ -434,8 +438,6 @@ var openaiPlugin = {
434
438
  size
435
439
  })
436
440
  });
437
- const responseClone = response.clone();
438
- const rawResponseBody = await responseClone.text();
439
441
  if (!response.ok) {
440
442
  throw new Error(`Failed to generate image: ${response.statusText}`);
441
443
  }
@@ -484,8 +486,6 @@ var openaiPlugin = {
484
486
  },
485
487
  body: JSON.stringify(requestBody)
486
488
  });
487
- const responseClone = response.clone();
488
- const rawResponseBody = await responseClone.text();
489
489
  if (!response.ok) {
490
490
  throw new Error(`OpenAI API error: ${response.status}`);
491
491
  }
@@ -523,21 +523,51 @@ var openaiPlugin = {
523
523
  };
524
524
  }
525
525
  },
526
- [import_core.ModelType.TRANSCRIPTION]: async (runtime, audioBuffer) => {
527
- import_core.logger.debug({ size: audioBuffer?.length ?? 0 }, "audioBuffer received");
528
- const modelName = getSetting(runtime, "OPENAI_TRANSCRIPTION_MODEL", "gpt-4o-mini-transcribe");
526
+ [import_core.ModelType.TRANSCRIPTION]: async (runtime, input) => {
527
+ let modelName = getSetting(runtime, "OPENAI_TRANSCRIPTION_MODEL", "gpt-4o-mini-transcribe");
529
528
  import_core.logger.log(`[OpenAI] Using TRANSCRIPTION model: ${modelName}`);
530
529
  const baseURL = getBaseURL(runtime);
531
- if (!audioBuffer || audioBuffer.length === 0) {
532
- throw new Error("Audio buffer is empty or invalid for transcription");
530
+ let blob;
531
+ let extraParams = null;
532
+ if (input instanceof Blob || input instanceof File) {
533
+ blob = input;
534
+ } else if (typeof input === "object" && input !== null && input.audio != null) {
535
+ const params = input;
536
+ if (!(params.audio instanceof Blob) && !(params.audio instanceof File)) {
537
+ throw new Error("TRANSCRIPTION param 'audio' must be a Blob/File. Wrap buffers as: new Blob([buffer], { type: 'audio/mpeg' })");
538
+ }
539
+ blob = params.audio;
540
+ extraParams = params;
541
+ if (typeof params.model === "string" && params.model) {
542
+ modelName = params.model;
543
+ }
544
+ } else {
545
+ throw new Error("TRANSCRIPTION expects a Blob/File or an object { audio: Blob/File, language?, response_format?, timestampGranularities?, prompt?, temperature?, model? }");
533
546
  }
547
+ const mime = blob.type || "audio/webm";
548
+ 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");
534
549
  const formData = new FormData;
535
- const arrayBuffer = audioBuffer.buffer;
536
- const start = audioBuffer.byteOffset || 0;
537
- const end = start + (audioBuffer.byteLength || 0);
538
- const safeArrayBuffer = arrayBuffer.slice(start, end);
539
- formData.append("file", new Blob([safeArrayBuffer], { type: "audio/mpeg" }), "recording.mp3");
540
- formData.append("model", modelName);
550
+ formData.append("file", blob, filename);
551
+ formData.append("model", String(modelName));
552
+ if (extraParams) {
553
+ if (typeof extraParams.language === "string") {
554
+ formData.append("language", String(extraParams.language));
555
+ }
556
+ if (typeof extraParams.response_format === "string") {
557
+ formData.append("response_format", String(extraParams.response_format));
558
+ }
559
+ if (typeof extraParams.prompt === "string") {
560
+ formData.append("prompt", String(extraParams.prompt));
561
+ }
562
+ if (typeof extraParams.temperature === "number") {
563
+ formData.append("temperature", String(extraParams.temperature));
564
+ }
565
+ if (Array.isArray(extraParams.timestampGranularities)) {
566
+ for (const g of extraParams.timestampGranularities) {
567
+ formData.append("timestamp_granularities[]", String(g));
568
+ }
569
+ }
570
+ }
541
571
  try {
542
572
  const response = await fetch(`${baseURL}/audio/transcriptions`, {
543
573
  method: "POST",
@@ -546,28 +576,27 @@ var openaiPlugin = {
546
576
  },
547
577
  body: formData
548
578
  });
549
- const responseClone = response.clone();
550
- const rawResponseBody = await responseClone.text();
551
- import_core.logger.log({ response }, "response");
552
579
  if (!response.ok) {
553
- throw new Error(`Failed to transcribe audio: ${response.statusText}`);
580
+ throw new Error(`Failed to transcribe audio: ${response.status} ${response.statusText}`);
554
581
  }
555
582
  const data = await response.json();
556
- const processedText = data.text;
557
- return processedText;
583
+ return data.text || "";
558
584
  } catch (error) {
559
585
  const message = error instanceof Error ? error.message : String(error);
586
+ import_core.logger.error(`TRANSCRIPTION error: ${message}`);
560
587
  throw error;
561
588
  }
562
589
  },
563
- [import_core.ModelType.TEXT_TO_SPEECH]: async (runtime, text) => {
564
- const ttsModelName = getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
565
- import_core.logger.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${ttsModelName}`);
590
+ [import_core.ModelType.TEXT_TO_SPEECH]: async (runtime, input) => {
591
+ const options = typeof input === "string" ? { text: input } : input;
592
+ const resolvedModel = options.model || getSetting(runtime, "OPENAI_TTS_MODEL", "gpt-4o-mini-tts");
593
+ import_core.logger.log(`[OpenAI] Using TEXT_TO_SPEECH model: ${resolvedModel}`);
566
594
  try {
567
- const speechStream = await fetchTextToSpeech(runtime, text);
595
+ const speechStream = await fetchTextToSpeech(runtime, options);
568
596
  return speechStream;
569
597
  } catch (error) {
570
598
  const message = error instanceof Error ? error.message : String(error);
599
+ import_core.logger.error(`Error in TEXT_TO_SPEECH: ${message}`);
571
600
  throw error;
572
601
  }
573
602
  },
@@ -732,8 +761,9 @@ var openaiPlugin = {
732
761
  name: "openai_test_text_to_speech",
733
762
  fn: async (runtime) => {
734
763
  try {
735
- const text = "Hello, this is a test for text-to-speech.";
736
- const response = await fetchTextToSpeech(runtime, text);
764
+ const response = await fetchTextToSpeech(runtime, {
765
+ text: "Hello, this is a test for text-to-speech."
766
+ });
737
767
  if (!response) {
738
768
  throw new Error("Failed to generate speech");
739
769
  }
@@ -751,4 +781,4 @@ var openaiPlugin = {
751
781
  };
752
782
  var src_default = openaiPlugin;
753
783
 
754
- //# debugId=FADB016B192C107B64756E2164756E21
784
+ //# debugId=BF1EBFE59A12C26D64756E2164756E21