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

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,5 +1,5 @@
1
1
  // index.ts
2
- import { logger as logger11, ModelType as ModelType7 } from "@elizaos/core";
2
+ import { logger as logger9, ModelType as ModelType6 } from "@elizaos/core";
3
3
 
4
4
  // init.ts
5
5
  import { logger as logger2 } from "@elizaos/core";
@@ -45,7 +45,24 @@ function isBrowser() {
45
45
  function isProxyMode(runtime) {
46
46
  return isBrowser() && !!getSetting(runtime, "OPENAI_BROWSER_BASE_URL");
47
47
  }
48
+ function isCerebrasMode(runtime) {
49
+ const explicitProvider = getSetting(runtime, "MILADY_PROVIDER");
50
+ if (explicitProvider && explicitProvider.toLowerCase() === "cerebras") {
51
+ return true;
52
+ }
53
+ const baseURL = getSetting(runtime, "OPENAI_BASE_URL");
54
+ if (baseURL && /(^|\.)cerebras\.ai(\/|$)/i.test(baseURL)) {
55
+ return true;
56
+ }
57
+ return false;
58
+ }
48
59
  function getApiKey(runtime) {
60
+ if (isCerebrasMode(runtime)) {
61
+ const cerebrasKey = getSetting(runtime, "CEREBRAS_API_KEY");
62
+ if (cerebrasKey) {
63
+ return cerebrasKey;
64
+ }
65
+ }
49
66
  return getSetting(runtime, "OPENAI_API_KEY");
50
67
  }
51
68
  function getEmbeddingApiKey(runtime) {
@@ -80,11 +97,26 @@ function getEmbeddingBaseURL(runtime) {
80
97
  return getBaseURL(runtime);
81
98
  }
82
99
  function getSmallModel(runtime) {
83
- return getSetting(runtime, "OPENAI_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL") ?? "gpt-5-mini";
100
+ return getSetting(runtime, "OPENAI_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL") ?? "gpt-5.4-mini";
101
+ }
102
+ function getNanoModel(runtime) {
103
+ return getSetting(runtime, "OPENAI_NANO_MODEL") ?? getSetting(runtime, "NANO_MODEL") ?? getSmallModel(runtime);
104
+ }
105
+ function getMediumModel(runtime) {
106
+ return getSetting(runtime, "OPENAI_MEDIUM_MODEL") ?? getSetting(runtime, "MEDIUM_MODEL") ?? getSmallModel(runtime);
84
107
  }
85
108
  function getLargeModel(runtime) {
86
109
  return getSetting(runtime, "OPENAI_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL") ?? "gpt-5";
87
110
  }
111
+ function getMegaModel(runtime) {
112
+ return getSetting(runtime, "OPENAI_MEGA_MODEL") ?? getSetting(runtime, "MEGA_MODEL") ?? getLargeModel(runtime);
113
+ }
114
+ function getResponseHandlerModel(runtime) {
115
+ return getSetting(runtime, "OPENAI_RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "OPENAI_SHOULD_RESPOND_MODEL") ?? getSetting(runtime, "RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "SHOULD_RESPOND_MODEL") ?? getSmallModel(runtime);
116
+ }
117
+ function getActionPlannerModel(runtime) {
118
+ return getSetting(runtime, "OPENAI_ACTION_PLANNER_MODEL") ?? getSetting(runtime, "OPENAI_PLANNER_MODEL") ?? getSetting(runtime, "ACTION_PLANNER_MODEL") ?? getSetting(runtime, "PLANNER_MODEL") ?? getMediumModel(runtime);
119
+ }
88
120
  function getEmbeddingModel(runtime) {
89
121
  return getSetting(runtime, "OPENAI_EMBEDDING_MODEL") ?? "text-embedding-3-small";
90
122
  }
@@ -153,7 +185,7 @@ async function validateOpenAIConfiguration(runtime) {
153
185
  }
154
186
 
155
187
  // models/audio.ts
156
- import { logger as logger4 } from "@elizaos/core";
188
+ import { logger as logger4, recordLlmCall } from "@elizaos/core";
157
189
 
158
190
  // utils/audio.ts
159
191
  import { logger as logger3 } from "@elizaos/core";
@@ -304,16 +336,34 @@ async function handleTranscription(runtime, input) {
304
336
  }
305
337
  }
306
338
  const baseURL = getBaseURL(runtime);
307
- const response = await fetch(`${baseURL}/audio/transcriptions`, {
308
- method: "POST",
309
- headers: getAuthHeader(runtime),
310
- body: formData
339
+ const details = {
340
+ model: modelName,
341
+ systemPrompt: extraParams.prompt ?? "",
342
+ userPrompt: [
343
+ `audio transcription request: filename=${filename}`,
344
+ `mimeType=${mimeType}`,
345
+ extraParams.language ? `language=${extraParams.language}` : "",
346
+ extraParams.responseFormat ? `responseFormat=${extraParams.responseFormat}` : ""
347
+ ].filter(Boolean).join(" "),
348
+ temperature: extraParams.temperature ?? 0,
349
+ maxTokens: 0,
350
+ purpose: "external_llm",
351
+ actionType: "openai.audio.transcriptions.create"
352
+ };
353
+ const data = await recordLlmCall(runtime, details, async () => {
354
+ const response = await fetch(`${baseURL}/audio/transcriptions`, {
355
+ method: "POST",
356
+ headers: getAuthHeader(runtime),
357
+ body: formData
358
+ });
359
+ if (!response.ok) {
360
+ const errorText = await response.text().catch(() => "Unknown error");
361
+ throw new Error(`OpenAI transcription failed: ${response.status} ${response.statusText} - ${errorText}`);
362
+ }
363
+ const result = await response.json();
364
+ details.response = result.text;
365
+ return result;
311
366
  });
312
- if (!response.ok) {
313
- const errorText = await response.text().catch(() => "Unknown error");
314
- throw new Error(`OpenAI transcription failed: ${response.status} ${response.statusText} - ${errorText}`);
315
- }
316
- const data = await response.json();
317
367
  return data.text;
318
368
  }
319
369
  async function handleTextToSpeech(runtime, input) {
@@ -362,20 +412,33 @@ async function handleTextToSpeech(runtime, input) {
362
412
  if (instructions && instructions.length > 0) {
363
413
  requestBody.instructions = instructions;
364
414
  }
365
- const response = await fetch(`${baseURL}/audio/speech`, {
366
- method: "POST",
367
- headers: {
368
- ...getAuthHeader(runtime),
369
- "Content-Type": "application/json",
370
- ...format === "mp3" ? { Accept: "audio/mpeg" } : {}
371
- },
372
- body: JSON.stringify(requestBody)
415
+ const details = {
416
+ model,
417
+ systemPrompt: instructions ?? "",
418
+ userPrompt: text,
419
+ temperature: 0,
420
+ maxTokens: 0,
421
+ purpose: "external_llm",
422
+ actionType: "openai.audio.speech.create"
423
+ };
424
+ return recordLlmCall(runtime, details, async () => {
425
+ const response = await fetch(`${baseURL}/audio/speech`, {
426
+ method: "POST",
427
+ headers: {
428
+ ...getAuthHeader(runtime),
429
+ "Content-Type": "application/json",
430
+ ...format === "mp3" ? { Accept: "audio/mpeg" } : {}
431
+ },
432
+ body: JSON.stringify(requestBody)
433
+ });
434
+ if (!response.ok) {
435
+ const errorText = await response.text().catch(() => "Unknown error");
436
+ throw new Error(`OpenAI TTS failed: ${response.status} ${response.statusText} - ${errorText}`);
437
+ }
438
+ const audioBuffer = await response.arrayBuffer();
439
+ details.response = `[audio bytes=${audioBuffer.byteLength} format=${format}]`;
440
+ return audioBuffer;
373
441
  });
374
- if (!response.ok) {
375
- const errorText = await response.text().catch(() => "Unknown error");
376
- throw new Error(`OpenAI TTS failed: ${response.status} ${response.statusText} - ${errorText}`);
377
- }
378
- return response.arrayBuffer();
379
442
  }
380
443
  // models/embedding.ts
381
444
  import { logger as logger5, ModelType, VECTOR_DIMS } from "@elizaos/core";
@@ -436,7 +499,6 @@ function emitModelUsageEvent(runtime, type, prompt, usage) {
436
499
  }
437
500
 
438
501
  // models/embedding.ts
439
- var MAX_EMBEDDING_TOKENS = 8000;
440
502
  function validateDimension(dimension) {
441
503
  const validDimensions = Object.values(VECTOR_DIMS);
442
504
  if (!validDimensions.includes(dimension)) {
@@ -456,6 +518,50 @@ function extractText(params) {
456
518
  }
457
519
  throw new Error("Invalid embedding params: expected string, { text: string }, or null");
458
520
  }
521
+ function hasExplicitEmbeddingEndpoint(runtime) {
522
+ const key = isBrowser() ? "OPENAI_BROWSER_EMBEDDING_URL" : "OPENAI_EMBEDDING_URL";
523
+ const value = getSetting(runtime, key);
524
+ return typeof value === "string" && value.trim().length > 0;
525
+ }
526
+ function shouldUseLocalEmbeddingFallback(runtime) {
527
+ return isCerebrasMode(runtime) && !hasExplicitEmbeddingEndpoint(runtime);
528
+ }
529
+ function hashFeature(feature) {
530
+ let hash = 2166136261;
531
+ for (let i = 0;i < feature.length; i += 1) {
532
+ hash ^= feature.charCodeAt(i);
533
+ hash = Math.imul(hash, 16777619);
534
+ }
535
+ return hash >>> 0;
536
+ }
537
+ function createDeterministicEmbedding(text, dimension) {
538
+ const vector = new Array(dimension).fill(0);
539
+ const normalized = text.toLowerCase();
540
+ const tokens = normalized.match(/[a-z0-9]+(?:[_-][a-z0-9]+)*/g) ?? [normalized];
541
+ const addFeature = (feature, weight) => {
542
+ const hash = hashFeature(feature);
543
+ const idx = hash % dimension;
544
+ const sign = (hash & 1) === 0 ? 1 : -1;
545
+ vector[idx] += sign * weight;
546
+ const secondHash = hashFeature(`b:${feature}`);
547
+ const secondIdx = secondHash % dimension;
548
+ const secondSign = (secondHash & 1) === 0 ? 1 : -1;
549
+ vector[secondIdx] += secondSign * weight * 0.5;
550
+ };
551
+ tokens.forEach((token, index) => {
552
+ addFeature(token, 1);
553
+ if (index > 0) {
554
+ addFeature(`${tokens[index - 1]} ${token}`, 0.35);
555
+ }
556
+ });
557
+ addFeature(normalized.slice(0, 512), 0.15);
558
+ const norm = Math.sqrt(vector.reduce((sum, value) => sum + value * value, 0));
559
+ if (norm === 0) {
560
+ vector[0] = 1;
561
+ return vector;
562
+ }
563
+ return vector.map((value) => value / norm);
564
+ }
459
565
  async function handleTextEmbedding(runtime, params) {
460
566
  const embeddingModel = getEmbeddingModel(runtime);
461
567
  const embeddingDimension = validateDimension(getEmbeddingDimensions(runtime));
@@ -470,11 +576,15 @@ async function handleTextEmbedding(runtime, params) {
470
576
  if (trimmedText.length === 0) {
471
577
  throw new Error("Cannot generate embedding for empty text");
472
578
  }
473
- const maxChars = MAX_EMBEDDING_TOKENS * 4;
579
+ const maxChars = 8000 * 4;
474
580
  if (trimmedText.length > maxChars) {
475
- logger5.warn(`[OpenAI] Embedding input too long (~${Math.ceil(trimmedText.length / 4)} tokens), truncating to ~${MAX_EMBEDDING_TOKENS} tokens`);
581
+ logger5.warn(`[OpenAI] Embedding input too long (~${Math.ceil(trimmedText.length / 4)} tokens), truncating to ~8000 tokens`);
476
582
  trimmedText = trimmedText.slice(0, maxChars);
477
583
  }
584
+ if (shouldUseLocalEmbeddingFallback(runtime)) {
585
+ logger5.debug("[OpenAI] Using deterministic local embedding fallback for Cerebras mode");
586
+ return createDeterministicEmbedding(trimmedText, embeddingDimension);
587
+ }
478
588
  const baseURL = getEmbeddingBaseURL(runtime);
479
589
  const url = `${baseURL}/embeddings`;
480
590
  logger5.debug(`[OpenAI] Generating embedding with model: ${embeddingModel}`);
@@ -495,7 +605,7 @@ async function handleTextEmbedding(runtime, params) {
495
605
  }
496
606
  const data = await response.json();
497
607
  const firstResult = data?.data?.[0];
498
- if (!firstResult || !firstResult.embedding) {
608
+ if (!firstResult?.embedding) {
499
609
  throw new Error("OpenAI API returned invalid embedding response structure");
500
610
  }
501
611
  const embedding = firstResult.embedding;
@@ -513,7 +623,7 @@ async function handleTextEmbedding(runtime, params) {
513
623
  return embedding;
514
624
  }
515
625
  // models/image.ts
516
- import { logger as logger6, ModelType as ModelType2 } from "@elizaos/core";
626
+ import { logger as logger6, ModelType as ModelType2, recordLlmCall as recordLlmCall2 } from "@elizaos/core";
517
627
  var DEFAULT_IMAGE_DESCRIPTION_PROMPT = "Please analyze this image and provide a title and detailed description.";
518
628
  async function handleImageGeneration(runtime, params) {
519
629
  const modelName = getImageModel(runtime);
@@ -521,7 +631,7 @@ async function handleImageGeneration(runtime, params) {
521
631
  const size = params.size ?? "1024x1024";
522
632
  const extendedParams = params;
523
633
  logger6.debug(`[OpenAI] Using IMAGE model: ${modelName}`);
524
- if (!params.prompt || params.prompt.trim().length === 0) {
634
+ if (params.prompt.trim().length === 0) {
525
635
  throw new Error("IMAGE generation requires a non-empty prompt");
526
636
  }
527
637
  if (count < 1 || count > 10) {
@@ -540,20 +650,33 @@ async function handleImageGeneration(runtime, params) {
540
650
  if (extendedParams.style) {
541
651
  requestBody.style = extendedParams.style;
542
652
  }
543
- const response = await fetch(`${baseURL}/images/generations`, {
544
- method: "POST",
545
- headers: {
546
- ...getAuthHeader(runtime),
547
- "Content-Type": "application/json"
548
- },
549
- body: JSON.stringify(requestBody)
653
+ const details = {
654
+ model: modelName,
655
+ systemPrompt: "",
656
+ userPrompt: params.prompt,
657
+ temperature: 0,
658
+ maxTokens: 0,
659
+ purpose: "external_llm",
660
+ actionType: "openai.images.generate"
661
+ };
662
+ const data = await recordLlmCall2(runtime, details, async () => {
663
+ const response = await fetch(`${baseURL}/images/generations`, {
664
+ method: "POST",
665
+ headers: {
666
+ ...getAuthHeader(runtime),
667
+ "Content-Type": "application/json"
668
+ },
669
+ body: JSON.stringify(requestBody)
670
+ });
671
+ if (!response.ok) {
672
+ const errorText = await response.text().catch(() => "Unknown error");
673
+ throw new Error(`OpenAI image generation failed: ${response.status} ${response.statusText} - ${errorText}`);
674
+ }
675
+ const responseData = await response.json();
676
+ details.response = JSON.stringify(responseData.data);
677
+ return responseData;
550
678
  });
551
- if (!response.ok) {
552
- const errorText = await response.text().catch(() => "Unknown error");
553
- throw new Error(`OpenAI image generation failed: ${response.status} ${response.statusText} - ${errorText}`);
554
- }
555
- const data = await response.json();
556
- if (!data.data || data.data.length === 0) {
679
+ if (data.data.length === 0) {
557
680
  throw new Error("OpenAI API returned no images");
558
681
  }
559
682
  return data.data.map((item) => ({
@@ -598,19 +721,36 @@ async function handleImageDescription(runtime, params) {
598
721
  ],
599
722
  max_tokens: maxTokens
600
723
  };
601
- const response = await fetch(`${baseURL}/chat/completions`, {
602
- method: "POST",
603
- headers: {
604
- ...getAuthHeader(runtime),
605
- "Content-Type": "application/json"
606
- },
607
- body: JSON.stringify(requestBody)
724
+ const details = {
725
+ model: modelName,
726
+ systemPrompt: "",
727
+ userPrompt: promptText,
728
+ temperature: 0,
729
+ maxTokens,
730
+ purpose: "external_llm",
731
+ actionType: "openai.chat.completions.create"
732
+ };
733
+ const data = await recordLlmCall2(runtime, details, async () => {
734
+ const response = await fetch(`${baseURL}/chat/completions`, {
735
+ method: "POST",
736
+ headers: {
737
+ ...getAuthHeader(runtime),
738
+ "Content-Type": "application/json"
739
+ },
740
+ body: JSON.stringify(requestBody)
741
+ });
742
+ if (!response.ok) {
743
+ const errorText = await response.text().catch(() => "Unknown error");
744
+ throw new Error(`OpenAI image description failed: ${response.status} ${response.statusText} - ${errorText}`);
745
+ }
746
+ const responseData = await response.json();
747
+ details.response = responseData.choices?.[0]?.message?.content ?? "";
748
+ if (responseData.usage) {
749
+ details.promptTokens = responseData.usage.prompt_tokens;
750
+ details.completionTokens = responseData.usage.completion_tokens;
751
+ }
752
+ return responseData;
608
753
  });
609
- if (!response.ok) {
610
- const errorText = await response.text().catch(() => "Unknown error");
611
- throw new Error(`OpenAI image description failed: ${response.status} ${response.statusText} - ${errorText}`);
612
- }
613
- const data = await response.json();
614
754
  if (data.usage) {
615
755
  emitModelUsageEvent(runtime, ModelType2.IMAGE_DESCRIPTION, typeof params === "string" ? params : params.prompt ?? "", {
616
756
  promptTokens: data.usage.prompt_tokens,
@@ -628,88 +768,8 @@ async function handleImageDescription(runtime, params) {
628
768
  description: parseDescriptionFromResponse(content)
629
769
  };
630
770
  }
631
- // models/object.ts
632
- import { logger as logger8, ModelType as ModelType3 } from "@elizaos/core";
633
- import { generateObject } from "ai";
634
-
635
- // providers/openai.ts
636
- import { createOpenAI } from "@ai-sdk/openai";
637
- var PROXY_API_KEY = "sk-proxy";
638
- function createOpenAIClient(runtime) {
639
- const baseURL = getBaseURL(runtime);
640
- const apiKey = getApiKey(runtime);
641
- if (!apiKey && isProxyMode(runtime)) {
642
- return createOpenAI({
643
- apiKey: PROXY_API_KEY,
644
- baseURL
645
- });
646
- }
647
- if (!apiKey) {
648
- throw new Error("OPENAI_API_KEY is required. Set it in your environment variables or runtime settings.");
649
- }
650
- return createOpenAI({
651
- apiKey,
652
- baseURL
653
- });
654
- }
655
- // utils/json.ts
656
- import { logger as logger7 } from "@elizaos/core";
657
- import { JSONParseError } from "ai";
658
- var JSON_CLEANUP_PATTERNS = {
659
- MARKDOWN_JSON: /```json\n|\n```|```/g,
660
- WHITESPACE: /^\s+|\s+$/g
661
- };
662
- function getJsonRepairFunction() {
663
- return async ({ text, error }) => {
664
- if (!(error instanceof JSONParseError)) {
665
- return null;
666
- }
667
- try {
668
- const cleanedText = text.replace(JSON_CLEANUP_PATTERNS.MARKDOWN_JSON, "");
669
- JSON.parse(cleanedText);
670
- logger7.debug("[JSON Repair] Successfully repaired JSON by removing markdown wrappers");
671
- return cleanedText;
672
- } catch {
673
- logger7.warn("[JSON Repair] Unable to repair JSON text");
674
- return null;
675
- }
676
- };
677
- }
678
-
679
- // models/object.ts
680
- async function generateObjectByModelType(runtime, params, modelType, getModelFn) {
681
- const openai = createOpenAIClient(runtime);
682
- const modelName = getModelFn(runtime);
683
- logger8.debug(`[OpenAI] Using ${modelType} model: ${modelName}`);
684
- if (!params.prompt || params.prompt.trim().length === 0) {
685
- throw new Error("Object generation requires a non-empty prompt");
686
- }
687
- if (params.schema) {
688
- logger8.debug("[OpenAI] Schema provided but using no-schema mode. " + "Structure is determined by prompt instructions.");
689
- }
690
- const model = openai.chat(modelName);
691
- const { object, usage } = await generateObject({
692
- model,
693
- output: "no-schema",
694
- prompt: params.prompt,
695
- experimental_repairText: getJsonRepairFunction()
696
- });
697
- if (usage) {
698
- emitModelUsageEvent(runtime, modelType, params.prompt, usage);
699
- }
700
- if (typeof object !== "object" || object === null) {
701
- throw new Error(`Object generation returned ${typeof object}, expected object`);
702
- }
703
- return object;
704
- }
705
- async function handleObjectSmall(runtime, params) {
706
- return generateObjectByModelType(runtime, params, ModelType3.OBJECT_SMALL, getSmallModel);
707
- }
708
- async function handleObjectLarge(runtime, params) {
709
- return generateObjectByModelType(runtime, params, ModelType3.OBJECT_LARGE, getLargeModel);
710
- }
711
771
  // models/research.ts
712
- import { logger as logger9 } from "@elizaos/core";
772
+ import { logger as logger7, recordLlmCall as recordLlmCall3 } from "@elizaos/core";
713
773
  function convertToolToApi(tool) {
714
774
  switch (tool.type) {
715
775
  case "web_search_preview":
@@ -850,11 +910,11 @@ async function handleResearch(runtime, params) {
850
910
  const baseURL = getBaseURL(runtime);
851
911
  const modelName = params.model ?? getResearchModel(runtime);
852
912
  const timeout = getResearchTimeout(runtime);
853
- logger9.debug(`[OpenAI] Starting deep research with model: ${modelName}`);
854
- logger9.debug(`[OpenAI] Research input: ${params.input.substring(0, 100)}...`);
913
+ logger7.debug(`[OpenAI] Starting deep research with model: ${modelName}`);
914
+ logger7.debug(`[OpenAI] Research input: ${params.input.substring(0, 100)}...`);
855
915
  const dataSourceTools = params.tools?.filter((t) => t.type === "web_search_preview" || t.type === "file_search" || t.type === "mcp");
856
916
  if (!dataSourceTools || dataSourceTools.length === 0) {
857
- logger9.debug("[OpenAI] No data source tools specified, defaulting to web_search_preview");
917
+ logger7.debug("[OpenAI] No data source tools specified, defaulting to web_search_preview");
858
918
  params.tools = [{ type: "web_search_preview" }, ...params.tools ?? []];
859
919
  }
860
920
  const requestBody = {
@@ -876,27 +936,40 @@ async function handleResearch(runtime, params) {
876
936
  if (params.reasoningSummary) {
877
937
  requestBody.reasoning = { summary: params.reasoningSummary };
878
938
  }
879
- logger9.debug(`[OpenAI] Research request body: ${JSON.stringify(requestBody, null, 2)}`);
880
- const response = await fetch(`${baseURL}/responses`, {
881
- method: "POST",
882
- headers: {
883
- Authorization: `Bearer ${apiKey}`,
884
- "Content-Type": "application/json"
885
- },
886
- body: JSON.stringify(requestBody),
887
- signal: AbortSignal.timeout(timeout)
939
+ logger7.debug(`[OpenAI] Research request body: ${JSON.stringify(requestBody, null, 2)}`);
940
+ const details = {
941
+ model: modelName,
942
+ systemPrompt: params.instructions ?? "",
943
+ userPrompt: params.input,
944
+ temperature: 0,
945
+ maxTokens: 0,
946
+ purpose: "external_llm",
947
+ actionType: "openai.responses.create"
948
+ };
949
+ const data = await recordLlmCall3(runtime, details, async () => {
950
+ const response = await fetch(`${baseURL}/responses`, {
951
+ method: "POST",
952
+ headers: {
953
+ Authorization: `Bearer ${apiKey}`,
954
+ "Content-Type": "application/json"
955
+ },
956
+ body: JSON.stringify(requestBody),
957
+ signal: AbortSignal.timeout(timeout)
958
+ });
959
+ if (!response.ok) {
960
+ const errorText = await response.text();
961
+ logger7.error(`[OpenAI] Research request failed: ${response.status} ${errorText}`);
962
+ throw new Error(`Deep research request failed: ${response.status} ${response.statusText}`);
963
+ }
964
+ const responseData = await response.json();
965
+ details.response = responseData.output_text ?? "";
966
+ return responseData;
888
967
  });
889
- if (!response.ok) {
890
- const errorText = await response.text();
891
- logger9.error(`[OpenAI] Research request failed: ${response.status} ${errorText}`);
892
- throw new Error(`Deep research request failed: ${response.status} ${response.statusText}`);
893
- }
894
- const data = await response.json();
895
968
  if (data.error) {
896
- logger9.error(`[OpenAI] Research API error: ${data.error.message}`);
969
+ logger7.error(`[OpenAI] Research API error: ${data.error.message}`);
897
970
  throw new Error(`Deep research error: ${data.error.message}`);
898
971
  }
899
- logger9.debug(`[OpenAI] Research response received. Status: ${data.status ?? "completed"}`);
972
+ logger7.debug(`[OpenAI] Research response received. Status: ${data.status ?? "completed"}`);
900
973
  const { text, annotations } = extractTextAndAnnotations(data);
901
974
  const outputItems = [];
902
975
  if (data.output) {
@@ -914,12 +987,65 @@ async function handleResearch(runtime, params) {
914
987
  outputItems,
915
988
  status: data.status
916
989
  };
917
- logger9.info(`[OpenAI] Research completed. Text length: ${text.length}, Annotations: ${annotations.length}, Output items: ${outputItems.length}`);
990
+ logger7.info(`[OpenAI] Research completed. Text length: ${text.length}, Annotations: ${annotations.length}, Output items: ${outputItems.length}`);
918
991
  return result;
919
992
  }
920
993
  // models/text.ts
921
- import { logger as logger10, ModelType as ModelType4 } from "@elizaos/core";
922
- import { generateText, streamText } from "ai";
994
+ import {
995
+ buildCanonicalSystemPrompt,
996
+ dropDuplicateLeadingSystemMessage,
997
+ logger as logger8,
998
+ ModelType as ModelType3,
999
+ normalizeSchemaForCerebras,
1000
+ recordLlmCall as recordLlmCall4,
1001
+ resolveEffectiveSystemPrompt,
1002
+ sanitizeFunctionNameForCerebras
1003
+ } from "@elizaos/core";
1004
+ import {
1005
+ generateText,
1006
+ jsonSchema,
1007
+ Output,
1008
+ streamText
1009
+ } from "ai";
1010
+
1011
+ // providers/openai.ts
1012
+ import { createOpenAI } from "@ai-sdk/openai";
1013
+ var PROXY_API_KEY = "sk-proxy";
1014
+ function createOpenAIClient(runtime) {
1015
+ const baseURL = getBaseURL(runtime);
1016
+ const apiKey = getApiKey(runtime);
1017
+ if (!apiKey && isProxyMode(runtime)) {
1018
+ return createOpenAI({
1019
+ apiKey: PROXY_API_KEY,
1020
+ baseURL
1021
+ });
1022
+ }
1023
+ if (!apiKey) {
1024
+ throw new Error("OPENAI_API_KEY is required. Set it in your environment variables or runtime settings.");
1025
+ }
1026
+ return createOpenAI({
1027
+ apiKey,
1028
+ baseURL
1029
+ });
1030
+ }
1031
+ // models/text.ts
1032
+ var TEXT_NANO_MODEL_TYPE = ModelType3.TEXT_NANO ?? "TEXT_NANO";
1033
+ var TEXT_MEDIUM_MODEL_TYPE = ModelType3.TEXT_MEDIUM ?? "TEXT_MEDIUM";
1034
+ var TEXT_MEGA_MODEL_TYPE = ModelType3.TEXT_MEGA ?? "TEXT_MEGA";
1035
+ var RESPONSE_HANDLER_MODEL_TYPE = ModelType3.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
1036
+ var ACTION_PLANNER_MODEL_TYPE = ModelType3.ACTION_PLANNER ?? "ACTION_PLANNER";
1037
+ function buildUserContent(params) {
1038
+ const content = [{ type: "text", text: params.prompt }];
1039
+ for (const attachment of params.attachments ?? []) {
1040
+ content.push({
1041
+ type: "file",
1042
+ data: attachment.data,
1043
+ mediaType: attachment.mediaType,
1044
+ ...attachment.filename ? { filename: attachment.filename } : {}
1045
+ });
1046
+ }
1047
+ return content;
1048
+ }
923
1049
  function convertUsage(usage) {
924
1050
  if (!usage) {
925
1051
  return;
@@ -927,13 +1053,31 @@ function convertUsage(usage) {
927
1053
  const promptTokens = usage.inputTokens ?? 0;
928
1054
  const completionTokens = usage.outputTokens ?? 0;
929
1055
  const usageWithCache = usage;
1056
+ const cachedInput = firstNumber(usageWithCache.cacheReadInputTokens, usageWithCache.cachedInputTokens, usageWithCache.inputTokenDetails?.cacheReadTokens, usageWithCache.inputTokenDetails?.cachedInputTokens, usageWithCache.input_tokens_details?.cache_read_input_tokens, usageWithCache.input_tokens_details?.cached_tokens, usageWithCache.prompt_tokens_details?.cached_tokens) ?? undefined;
1057
+ const cacheCreationInput = firstNumber(usageWithCache.cacheCreationInputTokens, usageWithCache.cacheWriteInputTokens, usageWithCache.inputTokenDetails?.cacheCreationInputTokens, usageWithCache.inputTokenDetails?.cacheCreationTokens, usageWithCache.inputTokenDetails?.cacheWriteTokens, usageWithCache.input_tokens_details?.cache_creation_input_tokens);
930
1058
  return {
931
1059
  promptTokens,
932
1060
  completionTokens,
933
1061
  totalTokens: promptTokens + completionTokens,
934
- cachedPromptTokens: usageWithCache.cachedInputTokens
1062
+ cachedPromptTokens: cachedInput,
1063
+ cacheReadInputTokens: cachedInput,
1064
+ cacheCreationInputTokens: cacheCreationInput
935
1065
  };
936
1066
  }
1067
+ function firstNumber(...values) {
1068
+ for (const value of values) {
1069
+ if (typeof value === "number" && Number.isFinite(value)) {
1070
+ return value;
1071
+ }
1072
+ if (typeof value === "string" && value.trim().length > 0) {
1073
+ const parsed = Number(value);
1074
+ if (Number.isFinite(parsed)) {
1075
+ return parsed;
1076
+ }
1077
+ }
1078
+ }
1079
+ return;
1080
+ }
937
1081
  function resolvePromptCacheOptions(params) {
938
1082
  const withOpenAIOptions = params;
939
1083
  return {
@@ -941,54 +1085,462 @@ function resolvePromptCacheOptions(params) {
941
1085
  promptCacheRetention: withOpenAIOptions.providerOptions?.openai?.promptCacheRetention
942
1086
  };
943
1087
  }
1088
+ function resolveProviderOptions(params, runtime) {
1089
+ const withOpenAIOptions = params;
1090
+ const rawProviderOptions = withOpenAIOptions.providerOptions;
1091
+ const promptCacheOptions = resolvePromptCacheOptions(params);
1092
+ if (!rawProviderOptions && !promptCacheOptions.promptCacheKey && !promptCacheOptions.promptCacheRetention) {
1093
+ return;
1094
+ }
1095
+ const skipCacheRetention = isCerebrasMode(runtime);
1096
+ const { agentName: _agentName, openai: rawOpenAIOptions, ...rest } = rawProviderOptions ?? {};
1097
+ const sanitizedRawOpenAIOptions = (() => {
1098
+ if (!rawOpenAIOptions || typeof rawOpenAIOptions !== "object")
1099
+ return rawOpenAIOptions;
1100
+ if (!skipCacheRetention)
1101
+ return rawOpenAIOptions;
1102
+ const { promptCacheRetention: _drop, ...rest2 } = rawOpenAIOptions;
1103
+ return rest2;
1104
+ })();
1105
+ const openaiOptions = {
1106
+ ...sanitizedRawOpenAIOptions ?? {},
1107
+ ...promptCacheOptions.promptCacheKey ? { promptCacheKey: promptCacheOptions.promptCacheKey } : {},
1108
+ ...!skipCacheRetention && promptCacheOptions.promptCacheRetention ? { promptCacheRetention: promptCacheOptions.promptCacheRetention } : {}
1109
+ };
1110
+ const providerOptions = {
1111
+ ...rest,
1112
+ ...Object.keys(openaiOptions).length > 0 ? { openai: openaiOptions } : {}
1113
+ };
1114
+ return Object.keys(providerOptions).length > 0 ? providerOptions : undefined;
1115
+ }
1116
+ function buildStructuredOutput(responseSchema) {
1117
+ if (responseSchema && typeof responseSchema === "object" && "responseFormat" in responseSchema && "parseCompleteOutput" in responseSchema) {
1118
+ return responseSchema;
1119
+ }
1120
+ const schemaOptions = responseSchema && typeof responseSchema === "object" && "schema" in responseSchema ? responseSchema : { schema: responseSchema };
1121
+ return Output.object({
1122
+ schema: jsonSchema(sanitizeJsonSchema(schemaOptions.schema, true)),
1123
+ ...schemaOptions.name ? { name: schemaOptions.name } : {},
1124
+ ...schemaOptions.description ? { description: schemaOptions.description } : {}
1125
+ });
1126
+ }
1127
+ function normalizeNativeTools(tools, options = {}) {
1128
+ if (!tools) {
1129
+ return;
1130
+ }
1131
+ if (!Array.isArray(tools)) {
1132
+ return tools;
1133
+ }
1134
+ const toolSet = {};
1135
+ for (const rawTool of tools) {
1136
+ const tool = asRecord(rawTool);
1137
+ const functionTool = asRecord(tool.function);
1138
+ const name = firstString(tool.name, functionTool.name);
1139
+ if (!name) {
1140
+ throw new Error("[OpenAI] Native tool definition is missing a name.");
1141
+ }
1142
+ const description = firstString(tool.description, functionTool.description);
1143
+ const rawSchema = tool.parameters ?? functionTool.parameters ?? { type: "object" };
1144
+ let inputSchema = sanitizeJsonSchema(rawSchema, true);
1145
+ if (options.cerebrasMode) {
1146
+ inputSchema = normalizeSchemaForCerebras(inputSchema);
1147
+ }
1148
+ const registeredName = options.cerebrasMode ? sanitizeFunctionNameForCerebras(name) : name;
1149
+ toolSet[registeredName] = {
1150
+ ...description ? { description } : {},
1151
+ inputSchema: jsonSchema(inputSchema)
1152
+ };
1153
+ }
1154
+ return Object.keys(toolSet).length > 0 ? toolSet : undefined;
1155
+ }
1156
+ function normalizeNativeMessages(messages) {
1157
+ if (!Array.isArray(messages)) {
1158
+ return;
1159
+ }
1160
+ return messages.map((message) => normalizeNativeMessage(message));
1161
+ }
1162
+ function normalizeNativeMessage(message) {
1163
+ const raw = asRecord(message);
1164
+ const providerOptions = asOptionalRecord(raw.providerOptions);
1165
+ if (raw.role === "system") {
1166
+ return {
1167
+ role: "system",
1168
+ content: stringifyMessageContent(raw.content),
1169
+ ...providerOptions ? { providerOptions } : {}
1170
+ };
1171
+ }
1172
+ if (raw.role === "assistant") {
1173
+ return {
1174
+ role: "assistant",
1175
+ content: normalizeAssistantContent(raw),
1176
+ ...providerOptions ? { providerOptions } : {}
1177
+ };
1178
+ }
1179
+ if (raw.role === "tool") {
1180
+ return {
1181
+ role: "tool",
1182
+ content: normalizeToolContent(raw),
1183
+ ...providerOptions ? { providerOptions } : {}
1184
+ };
1185
+ }
1186
+ return {
1187
+ role: "user",
1188
+ content: normalizeUserContent(raw.content),
1189
+ ...providerOptions ? { providerOptions } : {}
1190
+ };
1191
+ }
1192
+ function normalizeAssistantContent(message) {
1193
+ const toolCalls = Array.isArray(message.toolCalls) ? message.toolCalls : [];
1194
+ if (toolCalls.length === 0) {
1195
+ if (Array.isArray(message.content) || typeof message.content === "string") {
1196
+ return message.content;
1197
+ }
1198
+ return "";
1199
+ }
1200
+ const parts = [];
1201
+ if (typeof message.content === "string" && message.content.length > 0) {
1202
+ parts.push({ type: "text", text: message.content });
1203
+ } else if (Array.isArray(message.content)) {
1204
+ parts.push(...message.content);
1205
+ }
1206
+ for (const toolCall of toolCalls) {
1207
+ const rawCall = asRecord(toolCall);
1208
+ const rawFunction = asRecord(rawCall.function);
1209
+ const toolCallId = firstString(rawCall.toolCallId, rawCall.id);
1210
+ const toolName = firstString(rawCall.toolName, rawCall.name, rawFunction.name);
1211
+ if (!toolCallId || !toolName) {
1212
+ continue;
1213
+ }
1214
+ parts.push({
1215
+ type: "tool-call",
1216
+ toolCallId,
1217
+ toolName,
1218
+ input: parseToolCallInput(rawCall, rawFunction)
1219
+ });
1220
+ }
1221
+ return parts;
1222
+ }
1223
+ function normalizeToolContent(message) {
1224
+ if (Array.isArray(message.content)) {
1225
+ return message.content;
1226
+ }
1227
+ const toolCallId = firstString(message.toolCallId, message.id) ?? "tool-call";
1228
+ const toolName = firstString(message.toolName, message.name) ?? "tool";
1229
+ const parsed = parseJsonIfPossible(message.content);
1230
+ return [
1231
+ {
1232
+ type: "tool-result",
1233
+ toolCallId,
1234
+ toolName,
1235
+ output: typeof parsed === "string" ? { type: "text", value: parsed } : { type: "json", value: parsed }
1236
+ }
1237
+ ];
1238
+ }
1239
+ function normalizeUserContent(content) {
1240
+ if (Array.isArray(content)) {
1241
+ return content;
1242
+ }
1243
+ return stringifyMessageContent(content);
1244
+ }
1245
+ function stringifyMessageContent(content) {
1246
+ if (typeof content === "string") {
1247
+ return content;
1248
+ }
1249
+ if (content == null) {
1250
+ return "";
1251
+ }
1252
+ return typeof content === "object" ? JSON.stringify(content) : String(content);
1253
+ }
1254
+ function parseToolCallInput(rawCall, rawFunction) {
1255
+ if ("input" in rawCall) {
1256
+ return rawCall.input;
1257
+ }
1258
+ return parseJsonIfPossible(rawCall.arguments ?? rawFunction.arguments ?? {});
1259
+ }
1260
+ function parseJsonIfPossible(value) {
1261
+ if (typeof value !== "string") {
1262
+ return value ?? "";
1263
+ }
1264
+ try {
1265
+ return JSON.parse(value);
1266
+ } catch {
1267
+ return value;
1268
+ }
1269
+ }
1270
+ function normalizeToolChoice(toolChoice) {
1271
+ if (!toolChoice) {
1272
+ return;
1273
+ }
1274
+ if (typeof toolChoice === "string" && (toolChoice === "auto" || toolChoice === "none" || toolChoice === "required")) {
1275
+ return toolChoice;
1276
+ }
1277
+ const choice = asRecord(toolChoice);
1278
+ if (choice.type === "tool") {
1279
+ if (typeof choice.toolName === "string" && choice.toolName.length > 0) {
1280
+ return toolChoice;
1281
+ }
1282
+ const toolName = firstString(choice.toolName, choice.name);
1283
+ if (toolName) {
1284
+ return { type: "tool", toolName };
1285
+ }
1286
+ }
1287
+ if (choice.type === "function") {
1288
+ const fn = asRecord(choice.function);
1289
+ const toolName = firstString(fn.name);
1290
+ if (toolName) {
1291
+ return { type: "tool", toolName };
1292
+ }
1293
+ }
1294
+ const namedTool = firstString(choice.name);
1295
+ if (namedTool) {
1296
+ return { type: "tool", toolName: namedTool };
1297
+ }
1298
+ return toolChoice;
1299
+ }
1300
+ function sanitizeJsonSchema(schema, isRoot = false) {
1301
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
1302
+ return { type: "object" };
1303
+ }
1304
+ const record = schema;
1305
+ const sanitized = { ...record };
1306
+ if (typeof sanitized.type !== "string") {
1307
+ const inferredType = inferJsonSchemaType(sanitized, isRoot);
1308
+ if (inferredType) {
1309
+ sanitized.type = inferredType;
1310
+ }
1311
+ }
1312
+ if (sanitized.properties && typeof sanitized.properties === "object" && !Array.isArray(sanitized.properties)) {
1313
+ const properties = {};
1314
+ for (const [key, value] of Object.entries(sanitized.properties)) {
1315
+ properties[key] = sanitizeJsonSchema(value);
1316
+ }
1317
+ sanitized.properties = properties;
1318
+ const propertyKeys = Object.keys(properties);
1319
+ const existingRequired = Array.isArray(sanitized.required) ? sanitized.required.filter((key) => typeof key === "string") : [];
1320
+ sanitized.required = [...new Set([...existingRequired, ...propertyKeys])];
1321
+ }
1322
+ if (sanitized.type === "object" && sanitized.additionalProperties !== false) {
1323
+ sanitized.additionalProperties = false;
1324
+ }
1325
+ if (sanitized.items) {
1326
+ sanitized.items = Array.isArray(sanitized.items) ? sanitized.items.map((item) => sanitizeJsonSchema(item)) : sanitizeJsonSchema(sanitized.items);
1327
+ }
1328
+ for (const unionKey of ["anyOf", "oneOf", "allOf"]) {
1329
+ const value = sanitized[unionKey];
1330
+ if (Array.isArray(value)) {
1331
+ sanitized[unionKey] = value.map((item) => sanitizeJsonSchema(item));
1332
+ }
1333
+ }
1334
+ return sanitized;
1335
+ }
1336
+ function inferJsonSchemaType(schema, isRoot) {
1337
+ if ("properties" in schema || "required" in schema || "additionalProperties" in schema || isRoot) {
1338
+ return "object";
1339
+ }
1340
+ if ("items" in schema) {
1341
+ return "array";
1342
+ }
1343
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
1344
+ const types = new Set(schema.enum.map((value) => typeof value));
1345
+ if (types.size === 1) {
1346
+ const [type] = [...types];
1347
+ if (type === "string" || type === "number" || type === "boolean") {
1348
+ return type;
1349
+ }
1350
+ }
1351
+ }
1352
+ return;
1353
+ }
1354
+ function asRecord(value) {
1355
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1356
+ }
1357
+ function asOptionalRecord(value) {
1358
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
1359
+ }
1360
+ function firstString(...values) {
1361
+ for (const value of values) {
1362
+ if (typeof value === "string" && value.length > 0) {
1363
+ return value;
1364
+ }
1365
+ }
1366
+ return;
1367
+ }
1368
+ function usesNativeTextResult(params) {
1369
+ return Boolean(params.messages || params.tools || params.toolChoice || params.responseSchema);
1370
+ }
1371
+ function buildNativeTextResult(result, modelName) {
1372
+ return {
1373
+ text: result.text,
1374
+ toolCalls: result.toolCalls ?? [],
1375
+ finishReason: result.finishReason,
1376
+ usage: convertUsage(result.usage),
1377
+ providerMetadata: mergeProviderModelName(result.providerMetadata, modelName)
1378
+ };
1379
+ }
1380
+ function mergeProviderModelName(providerMetadata, modelName) {
1381
+ if (!modelName) {
1382
+ return providerMetadata;
1383
+ }
1384
+ if (providerMetadata && typeof providerMetadata === "object" && !Array.isArray(providerMetadata)) {
1385
+ return {
1386
+ ...providerMetadata,
1387
+ modelName
1388
+ };
1389
+ }
1390
+ return { modelName };
1391
+ }
1392
+ function createLlmCallDetails(modelName, params, systemPrompt, actionType, modelType, providerOptions, generateParams) {
1393
+ const originalParams = params;
1394
+ const nativeParams = generateParams;
1395
+ const nativePrompt = nativeParams && "prompt" in nativeParams ? nativeParams.prompt : undefined;
1396
+ const nativeMessages = nativeParams && "messages" in nativeParams && Array.isArray(nativeParams.messages) ? nativeParams.messages : undefined;
1397
+ const nativeSystem = typeof nativeParams?.system === "string" ? nativeParams.system : systemPrompt;
1398
+ return {
1399
+ model: modelName,
1400
+ modelType,
1401
+ provider: "vercel-ai-sdk",
1402
+ systemPrompt: nativeSystem ?? "",
1403
+ userPrompt: typeof nativePrompt === "string" ? nativePrompt : typeof params.prompt === "string" ? params.prompt : "",
1404
+ prompt: typeof nativePrompt === "string" ? nativePrompt : undefined,
1405
+ messages: nativeMessages,
1406
+ tools: nativeParams?.tools ?? originalParams.tools,
1407
+ toolChoice: nativeParams?.toolChoice ?? originalParams.toolChoice,
1408
+ output: nativeParams?.output !== undefined ? buildTrajectoryOutputDescriptor(originalParams.responseSchema, nativeParams.output) : undefined,
1409
+ responseSchema: originalParams.responseSchema,
1410
+ providerOptions: providerOptions ?? nativeParams?.providerOptions ?? originalParams.providerOptions,
1411
+ temperature: params.temperature ?? 0,
1412
+ maxTokens: typeof nativeParams?.maxOutputTokens === "number" ? nativeParams.maxOutputTokens : params.maxTokens ?? 8192,
1413
+ purpose: "external_llm",
1414
+ actionType
1415
+ };
1416
+ }
1417
+ function buildTrajectoryOutputDescriptor(responseSchema, output) {
1418
+ if (responseSchema !== undefined) {
1419
+ return {
1420
+ type: "object",
1421
+ schema: responseSchema
1422
+ };
1423
+ }
1424
+ return toTrajectoryJsonSafe(output);
1425
+ }
1426
+ function toTrajectoryJsonSafe(value) {
1427
+ try {
1428
+ return JSON.parse(JSON.stringify(value, (_key, nested) => {
1429
+ if (typeof nested === "function")
1430
+ return;
1431
+ if (typeof nested === "bigint")
1432
+ return nested.toString();
1433
+ return nested;
1434
+ }));
1435
+ } catch {
1436
+ return String(value);
1437
+ }
1438
+ }
1439
+ function applyUsageToDetails(details, usage) {
1440
+ if (!usage) {
1441
+ return;
1442
+ }
1443
+ details.promptTokens = usage.inputTokens ?? 0;
1444
+ details.completionTokens = usage.outputTokens ?? 0;
1445
+ }
944
1446
  async function generateTextByModelType(runtime, params, modelType, getModelFn) {
1447
+ const paramsWithAttachments = params;
945
1448
  const openai = createOpenAIClient(runtime);
946
1449
  const modelName = getModelFn(runtime);
947
- logger10.debug(`[OpenAI] Using ${modelType} model: ${modelName}`);
948
- const promptCacheOptions = resolvePromptCacheOptions(params);
949
- const systemPrompt = runtime.character.system ?? undefined;
1450
+ logger8.debug(`[OpenAI] Using ${modelType} model: ${modelName}`);
1451
+ const providerOptions = resolveProviderOptions(params, runtime);
1452
+ const hasAttachments = (paramsWithAttachments.attachments?.length ?? 0) > 0;
1453
+ const userContent = hasAttachments ? buildUserContent(paramsWithAttachments) : undefined;
1454
+ const shouldReturnNativeResult = usesNativeTextResult(paramsWithAttachments);
1455
+ const systemPrompt = resolveEffectiveSystemPrompt({
1456
+ params: paramsWithAttachments,
1457
+ fallback: buildCanonicalSystemPrompt({ character: runtime.character })
1458
+ });
1459
+ const agentName = paramsWithAttachments.providerOptions?.agentName;
1460
+ const telemetryConfig = {
1461
+ isEnabled: getExperimentalTelemetry(runtime),
1462
+ functionId: agentName ? `agent:${agentName}` : undefined,
1463
+ metadata: agentName ? { agentName } : undefined
1464
+ };
950
1465
  const model = openai.chat(modelName);
1466
+ const cerebrasMode = isCerebrasMode(runtime);
1467
+ const normalizedTools = normalizeNativeTools(paramsWithAttachments.tools, {
1468
+ cerebrasMode
1469
+ });
1470
+ const normalizedToolChoice = normalizeToolChoice(paramsWithAttachments.toolChoice);
1471
+ const normalizedMessages = normalizeNativeMessages(paramsWithAttachments.messages);
1472
+ const wireMessages = dropDuplicateLeadingSystemMessage(normalizedMessages, systemPrompt);
1473
+ const effectiveMessages = wireMessages && wireMessages.length > 0 ? wireMessages : normalizedMessages;
1474
+ const promptText = typeof params.prompt === "string" && params.prompt.length > 0 ? params.prompt : "";
1475
+ const promptOrMessages = effectiveMessages && effectiveMessages.length > 0 ? { messages: effectiveMessages } : userContent ? { messages: [{ role: "user", content: userContent }] } : { prompt: promptText };
951
1476
  const generateParams = {
952
1477
  model,
953
- prompt: params.prompt,
1478
+ ...promptOrMessages,
954
1479
  system: systemPrompt,
1480
+ allowSystemInMessages: true,
955
1481
  maxOutputTokens: params.maxTokens ?? 8192,
956
- experimental_telemetry: { isEnabled: getExperimentalTelemetry(runtime) },
957
- ...promptCacheOptions.promptCacheKey || promptCacheOptions.promptCacheRetention ? {
958
- providerOptions: {
959
- openai: {
960
- ...promptCacheOptions.promptCacheKey ? { promptCacheKey: promptCacheOptions.promptCacheKey } : {},
961
- ...promptCacheOptions.promptCacheRetention ? { promptCacheRetention: promptCacheOptions.promptCacheRetention } : {}
962
- }
963
- }
964
- } : {}
1482
+ experimental_telemetry: telemetryConfig,
1483
+ ...normalizedTools ? { tools: normalizedTools } : {},
1484
+ ...normalizedToolChoice ? { toolChoice: normalizedToolChoice } : {},
1485
+ ...paramsWithAttachments.responseSchema && !isCerebrasMode(runtime) ? { output: buildStructuredOutput(paramsWithAttachments.responseSchema) } : {},
1486
+ ...providerOptions ? { providerOptions } : {}
965
1487
  };
966
1488
  if (params.stream) {
967
- const result = streamText(generateParams);
1489
+ const details2 = createLlmCallDetails(modelName, params, systemPrompt, "ai.streamText", modelType, providerOptions, generateParams);
1490
+ details2.response = "";
1491
+ const result2 = await recordLlmCall4(runtime, details2, () => streamText(generateParams));
968
1492
  return {
969
- textStream: result.textStream,
970
- text: Promise.resolve(result.text),
971
- usage: Promise.resolve(result.usage).then(convertUsage),
972
- finishReason: Promise.resolve(result.finishReason).then((r) => r)
1493
+ textStream: result2.textStream,
1494
+ text: Promise.resolve(result2.text),
1495
+ ...shouldReturnNativeResult ? { toolCalls: Promise.resolve(result2.toolCalls) } : {},
1496
+ usage: Promise.resolve(result2.usage).then(convertUsage),
1497
+ finishReason: Promise.resolve(result2.finishReason).then((r) => r)
973
1498
  };
974
1499
  }
975
- const { text, usage } = await generateText(generateParams);
976
- if (usage) {
977
- emitModelUsageEvent(runtime, modelType, params.prompt, usage);
1500
+ const details = createLlmCallDetails(modelName, params, systemPrompt, "ai.generateText", modelType, providerOptions, generateParams);
1501
+ const result = await recordLlmCall4(runtime, details, async () => {
1502
+ const result2 = await generateText(generateParams);
1503
+ details.response = result2.text;
1504
+ details.toolCalls = result2.toolCalls ?? [];
1505
+ details.finishReason = result2.finishReason;
1506
+ details.providerMetadata = result2.providerMetadata;
1507
+ applyUsageToDetails(details, result2.usage);
1508
+ return result2;
1509
+ });
1510
+ if (result.usage) {
1511
+ emitModelUsageEvent(runtime, modelType, params.prompt ?? "", result.usage);
1512
+ }
1513
+ if (shouldReturnNativeResult) {
1514
+ return buildNativeTextResult(result, modelName);
978
1515
  }
979
- return text;
1516
+ return result.text;
980
1517
  }
981
1518
  async function handleTextSmall(runtime, params) {
982
- return generateTextByModelType(runtime, params, ModelType4.TEXT_SMALL, getSmallModel);
1519
+ return generateTextByModelType(runtime, params, ModelType3.TEXT_SMALL, getSmallModel);
1520
+ }
1521
+ async function handleTextNano(runtime, params) {
1522
+ return generateTextByModelType(runtime, params, TEXT_NANO_MODEL_TYPE, getNanoModel);
1523
+ }
1524
+ async function handleTextMedium(runtime, params) {
1525
+ return generateTextByModelType(runtime, params, TEXT_MEDIUM_MODEL_TYPE, getMediumModel);
983
1526
  }
984
1527
  async function handleTextLarge(runtime, params) {
985
- return generateTextByModelType(runtime, params, ModelType4.TEXT_LARGE, getLargeModel);
1528
+ return generateTextByModelType(runtime, params, ModelType3.TEXT_LARGE, getLargeModel);
1529
+ }
1530
+ async function handleTextMega(runtime, params) {
1531
+ return generateTextByModelType(runtime, params, TEXT_MEGA_MODEL_TYPE, getMegaModel);
1532
+ }
1533
+ async function handleResponseHandler(runtime, params) {
1534
+ return generateTextByModelType(runtime, params, RESPONSE_HANDLER_MODEL_TYPE, getResponseHandlerModel);
1535
+ }
1536
+ async function handleActionPlanner(runtime, params) {
1537
+ return generateTextByModelType(runtime, params, ACTION_PLANNER_MODEL_TYPE, getActionPlannerModel);
986
1538
  }
987
1539
  // models/tokenizer.ts
988
- import { ModelType as ModelType6 } from "@elizaos/core";
1540
+ import { ModelType as ModelType5 } from "@elizaos/core";
989
1541
 
990
1542
  // utils/tokenization.ts
991
- import { ModelType as ModelType5 } from "@elizaos/core";
1543
+ import { ModelType as ModelType4 } from "@elizaos/core";
992
1544
  import {
993
1545
  encodingForModel,
994
1546
  getEncoding
@@ -1003,7 +1555,7 @@ function resolveTokenizerEncoding(modelName) {
1003
1555
  }
1004
1556
  }
1005
1557
  function getModelName(runtime, modelType) {
1006
- if (modelType === ModelType5.TEXT_SMALL) {
1558
+ if (modelType === ModelType4.TEXT_SMALL) {
1007
1559
  return getSmallModel(runtime);
1008
1560
  }
1009
1561
  return getLargeModel(runtime);
@@ -1024,7 +1576,7 @@ async function handleTokenizerEncode(runtime, params) {
1024
1576
  if (!params.prompt) {
1025
1577
  throw new Error("Tokenization requires a non-empty prompt");
1026
1578
  }
1027
- const modelType = params.modelType ?? ModelType6.TEXT_LARGE;
1579
+ const modelType = params.modelType ?? ModelType5.TEXT_LARGE;
1028
1580
  return tokenizeText(runtime, modelType, params.prompt);
1029
1581
  }
1030
1582
  async function handleTokenizerDecode(runtime, params) {
@@ -1040,7 +1592,7 @@ async function handleTokenizerDecode(runtime, params) {
1040
1592
  throw new Error(`Invalid token at index ${i}: expected number`);
1041
1593
  }
1042
1594
  }
1043
- const modelType = params.modelType ?? ModelType6.TEXT_LARGE;
1595
+ const modelType = params.modelType ?? ModelType5.TEXT_LARGE;
1044
1596
  return detokenizeText(runtime, modelType, params.tokens);
1045
1597
  }
1046
1598
  // index.ts
@@ -1051,16 +1603,38 @@ function getProcessEnv() {
1051
1603
  return process.env;
1052
1604
  }
1053
1605
  var env = getProcessEnv();
1606
+ var TEXT_NANO_MODEL_TYPE2 = ModelType6.TEXT_NANO ?? "TEXT_NANO";
1607
+ var TEXT_MEDIUM_MODEL_TYPE2 = ModelType6.TEXT_MEDIUM ?? "TEXT_MEDIUM";
1608
+ var TEXT_MEGA_MODEL_TYPE2 = ModelType6.TEXT_MEGA ?? "TEXT_MEGA";
1609
+ var RESPONSE_HANDLER_MODEL_TYPE2 = ModelType6.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
1610
+ var ACTION_PLANNER_MODEL_TYPE2 = ModelType6.ACTION_PLANNER ?? "ACTION_PLANNER";
1054
1611
  var openaiPlugin = {
1055
1612
  name: "openai",
1056
1613
  description: "OpenAI API integration for text, image, audio, and embedding models",
1614
+ autoEnable: {
1615
+ envKeys: ["OPENAI_API_KEY"]
1616
+ },
1057
1617
  config: {
1058
1618
  OPENAI_API_KEY: env.OPENAI_API_KEY ?? null,
1059
1619
  OPENAI_BASE_URL: env.OPENAI_BASE_URL ?? null,
1620
+ OPENAI_NANO_MODEL: env.OPENAI_NANO_MODEL ?? null,
1621
+ OPENAI_MEDIUM_MODEL: env.OPENAI_MEDIUM_MODEL ?? null,
1060
1622
  OPENAI_SMALL_MODEL: env.OPENAI_SMALL_MODEL ?? null,
1061
1623
  OPENAI_LARGE_MODEL: env.OPENAI_LARGE_MODEL ?? null,
1624
+ OPENAI_MEGA_MODEL: env.OPENAI_MEGA_MODEL ?? null,
1625
+ OPENAI_RESPONSE_HANDLER_MODEL: env.OPENAI_RESPONSE_HANDLER_MODEL ?? null,
1626
+ OPENAI_SHOULD_RESPOND_MODEL: env.OPENAI_SHOULD_RESPOND_MODEL ?? null,
1627
+ OPENAI_ACTION_PLANNER_MODEL: env.OPENAI_ACTION_PLANNER_MODEL ?? null,
1628
+ OPENAI_PLANNER_MODEL: env.OPENAI_PLANNER_MODEL ?? null,
1629
+ NANO_MODEL: env.NANO_MODEL ?? null,
1630
+ MEDIUM_MODEL: env.MEDIUM_MODEL ?? null,
1062
1631
  SMALL_MODEL: env.SMALL_MODEL ?? null,
1063
1632
  LARGE_MODEL: env.LARGE_MODEL ?? null,
1633
+ MEGA_MODEL: env.MEGA_MODEL ?? null,
1634
+ RESPONSE_HANDLER_MODEL: env.RESPONSE_HANDLER_MODEL ?? null,
1635
+ SHOULD_RESPOND_MODEL: env.SHOULD_RESPOND_MODEL ?? null,
1636
+ ACTION_PLANNER_MODEL: env.ACTION_PLANNER_MODEL ?? null,
1637
+ PLANNER_MODEL: env.PLANNER_MODEL ?? null,
1064
1638
  OPENAI_EMBEDDING_MODEL: env.OPENAI_EMBEDDING_MODEL ?? null,
1065
1639
  OPENAI_EMBEDDING_API_KEY: env.OPENAI_EMBEDDING_API_KEY ?? null,
1066
1640
  OPENAI_EMBEDDING_URL: env.OPENAI_EMBEDDING_URL ?? null,
@@ -1075,40 +1649,49 @@ var openaiPlugin = {
1075
1649
  initializeOpenAI(config, runtime);
1076
1650
  },
1077
1651
  models: {
1078
- [ModelType7.TEXT_EMBEDDING]: async (runtime, params) => {
1652
+ [ModelType6.TEXT_EMBEDDING]: async (runtime, params) => {
1079
1653
  return handleTextEmbedding(runtime, params);
1080
1654
  },
1081
- [ModelType7.TEXT_TOKENIZER_ENCODE]: async (runtime, params) => {
1655
+ [ModelType6.TEXT_TOKENIZER_ENCODE]: async (runtime, params) => {
1082
1656
  return handleTokenizerEncode(runtime, params);
1083
1657
  },
1084
- [ModelType7.TEXT_TOKENIZER_DECODE]: async (runtime, params) => {
1658
+ [ModelType6.TEXT_TOKENIZER_DECODE]: async (runtime, params) => {
1085
1659
  return handleTokenizerDecode(runtime, params);
1086
1660
  },
1087
- [ModelType7.TEXT_SMALL]: async (runtime, params) => {
1661
+ [ModelType6.TEXT_SMALL]: async (runtime, params) => {
1088
1662
  return handleTextSmall(runtime, params);
1089
1663
  },
1090
- [ModelType7.TEXT_LARGE]: async (runtime, params) => {
1664
+ [TEXT_NANO_MODEL_TYPE2]: async (runtime, params) => {
1665
+ return handleTextNano(runtime, params);
1666
+ },
1667
+ [TEXT_MEDIUM_MODEL_TYPE2]: async (runtime, params) => {
1668
+ return handleTextMedium(runtime, params);
1669
+ },
1670
+ [ModelType6.TEXT_LARGE]: async (runtime, params) => {
1091
1671
  return handleTextLarge(runtime, params);
1092
1672
  },
1093
- [ModelType7.IMAGE]: async (runtime, params) => {
1673
+ [TEXT_MEGA_MODEL_TYPE2]: async (runtime, params) => {
1674
+ return handleTextMega(runtime, params);
1675
+ },
1676
+ [RESPONSE_HANDLER_MODEL_TYPE2]: async (runtime, params) => {
1677
+ return handleResponseHandler(runtime, params);
1678
+ },
1679
+ [ACTION_PLANNER_MODEL_TYPE2]: async (runtime, params) => {
1680
+ return handleActionPlanner(runtime, params);
1681
+ },
1682
+ [ModelType6.IMAGE]: async (runtime, params) => {
1094
1683
  return handleImageGeneration(runtime, params);
1095
1684
  },
1096
- [ModelType7.IMAGE_DESCRIPTION]: async (runtime, params) => {
1685
+ [ModelType6.IMAGE_DESCRIPTION]: async (runtime, params) => {
1097
1686
  return handleImageDescription(runtime, params);
1098
1687
  },
1099
- [ModelType7.TRANSCRIPTION]: async (runtime, input) => {
1688
+ [ModelType6.TRANSCRIPTION]: async (runtime, input) => {
1100
1689
  return handleTranscription(runtime, input);
1101
1690
  },
1102
- [ModelType7.TEXT_TO_SPEECH]: async (runtime, input) => {
1691
+ [ModelType6.TEXT_TO_SPEECH]: async (runtime, input) => {
1103
1692
  return handleTextToSpeech(runtime, input);
1104
1693
  },
1105
- [ModelType7.OBJECT_SMALL]: async (runtime, params) => {
1106
- return handleObjectSmall(runtime, params);
1107
- },
1108
- [ModelType7.OBJECT_LARGE]: async (runtime, params) => {
1109
- return handleObjectLarge(runtime, params);
1110
- },
1111
- [ModelType7.RESEARCH]: async (runtime, params) => {
1694
+ [ModelType6.RESEARCH]: async (runtime, params) => {
1112
1695
  return handleResearch(runtime, params);
1113
1696
  }
1114
1697
  },
@@ -1127,71 +1710,71 @@ var openaiPlugin = {
1127
1710
  throw new Error(`API connectivity test failed: ${response.status} ${response.statusText}`);
1128
1711
  }
1129
1712
  const data = await response.json();
1130
- logger11.info(`[OpenAI Test] API connected. ${data.data?.length ?? 0} models available.`);
1713
+ logger9.info(`[OpenAI Test] API connected. ${data.data?.length ?? 0} models available.`);
1131
1714
  }
1132
1715
  },
1133
1716
  {
1134
1717
  name: "openai_test_text_embedding",
1135
1718
  fn: async (runtime) => {
1136
- const embedding = await runtime.useModel(ModelType7.TEXT_EMBEDDING, {
1719
+ const embedding = await runtime.useModel(ModelType6.TEXT_EMBEDDING, {
1137
1720
  text: "Hello, world!"
1138
1721
  });
1139
1722
  if (!Array.isArray(embedding) || embedding.length === 0) {
1140
1723
  throw new Error("Embedding should return a non-empty array");
1141
1724
  }
1142
- logger11.info(`[OpenAI Test] Generated embedding with ${embedding.length} dimensions`);
1725
+ logger9.info(`[OpenAI Test] Generated embedding with ${embedding.length} dimensions`);
1143
1726
  }
1144
1727
  },
1145
1728
  {
1146
1729
  name: "openai_test_text_small",
1147
1730
  fn: async (runtime) => {
1148
- const text = await runtime.useModel(ModelType7.TEXT_SMALL, {
1731
+ const text = await runtime.useModel(ModelType6.TEXT_SMALL, {
1149
1732
  prompt: "Say hello in exactly 5 words."
1150
1733
  });
1151
1734
  if (typeof text !== "string" || text.length === 0) {
1152
1735
  throw new Error("TEXT_SMALL should return non-empty string");
1153
1736
  }
1154
- logger11.info(`[OpenAI Test] TEXT_SMALL generated: "${text.substring(0, 50)}..."`);
1737
+ logger9.info(`[OpenAI Test] TEXT_SMALL generated: "${text.substring(0, 50)}..."`);
1155
1738
  }
1156
1739
  },
1157
1740
  {
1158
1741
  name: "openai_test_text_large",
1159
1742
  fn: async (runtime) => {
1160
- const text = await runtime.useModel(ModelType7.TEXT_LARGE, {
1743
+ const text = await runtime.useModel(ModelType6.TEXT_LARGE, {
1161
1744
  prompt: "Explain quantum computing in 2 sentences."
1162
1745
  });
1163
1746
  if (typeof text !== "string" || text.length === 0) {
1164
1747
  throw new Error("TEXT_LARGE should return non-empty string");
1165
1748
  }
1166
- logger11.info(`[OpenAI Test] TEXT_LARGE generated: "${text.substring(0, 50)}..."`);
1749
+ logger9.info(`[OpenAI Test] TEXT_LARGE generated: "${text.substring(0, 50)}..."`);
1167
1750
  }
1168
1751
  },
1169
1752
  {
1170
1753
  name: "openai_test_tokenizer_roundtrip",
1171
1754
  fn: async (runtime) => {
1172
1755
  const originalText = "Hello, tokenizer test!";
1173
- const tokens = await runtime.useModel(ModelType7.TEXT_TOKENIZER_ENCODE, {
1756
+ const tokens = await runtime.useModel(ModelType6.TEXT_TOKENIZER_ENCODE, {
1174
1757
  prompt: originalText,
1175
- modelType: ModelType7.TEXT_SMALL
1758
+ modelType: ModelType6.TEXT_SMALL
1176
1759
  });
1177
1760
  if (!Array.isArray(tokens) || tokens.length === 0) {
1178
1761
  throw new Error("Tokenization should return non-empty token array");
1179
1762
  }
1180
- const decodedText = await runtime.useModel(ModelType7.TEXT_TOKENIZER_DECODE, {
1763
+ const decodedText = await runtime.useModel(ModelType6.TEXT_TOKENIZER_DECODE, {
1181
1764
  tokens,
1182
- modelType: ModelType7.TEXT_SMALL
1765
+ modelType: ModelType6.TEXT_SMALL
1183
1766
  });
1184
1767
  if (decodedText !== originalText) {
1185
1768
  throw new Error(`Tokenizer roundtrip failed: expected "${originalText}", got "${decodedText}"`);
1186
1769
  }
1187
- logger11.info(`[OpenAI Test] Tokenizer roundtrip successful (${tokens.length} tokens)`);
1770
+ logger9.info(`[OpenAI Test] Tokenizer roundtrip successful (${tokens.length} tokens)`);
1188
1771
  }
1189
1772
  },
1190
1773
  {
1191
1774
  name: "openai_test_streaming",
1192
1775
  fn: async (runtime) => {
1193
1776
  const chunks = [];
1194
- const result = await runtime.useModel(ModelType7.TEXT_LARGE, {
1777
+ const result = await runtime.useModel(ModelType6.TEXT_LARGE, {
1195
1778
  prompt: "Count from 1 to 5, one number per line.",
1196
1779
  stream: true,
1197
1780
  onStreamChunk: (chunk) => {
@@ -1204,18 +1787,18 @@ var openaiPlugin = {
1204
1787
  if (chunks.length === 0) {
1205
1788
  throw new Error("No streaming chunks received");
1206
1789
  }
1207
- logger11.info(`[OpenAI Test] Streaming test: ${chunks.length} chunks received`);
1790
+ logger9.info(`[OpenAI Test] Streaming test: ${chunks.length} chunks received`);
1208
1791
  }
1209
1792
  },
1210
1793
  {
1211
1794
  name: "openai_test_image_description",
1212
1795
  fn: async (runtime) => {
1213
1796
  const testImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Camponotus_flavomarginatus_ant.jpg/440px-Camponotus_flavomarginatus_ant.jpg";
1214
- const result = await runtime.useModel(ModelType7.IMAGE_DESCRIPTION, testImageUrl);
1797
+ const result = await runtime.useModel(ModelType6.IMAGE_DESCRIPTION, testImageUrl);
1215
1798
  if (!result || typeof result !== "object" || !("title" in result) || !("description" in result)) {
1216
1799
  throw new Error("Image description should return { title, description }");
1217
1800
  }
1218
- logger11.info(`[OpenAI Test] Image described: "${result.title}"`);
1801
+ logger9.info(`[OpenAI Test] Image described: "${result.title}"`);
1219
1802
  }
1220
1803
  },
1221
1804
  {
@@ -1225,41 +1808,50 @@ var openaiPlugin = {
1225
1808
  const response = await fetch(audioUrl);
1226
1809
  const arrayBuffer = await response.arrayBuffer();
1227
1810
  const audioBuffer = Buffer.from(new Uint8Array(arrayBuffer));
1228
- const transcription = await runtime.useModel(ModelType7.TRANSCRIPTION, audioBuffer);
1811
+ const transcription = await runtime.useModel(ModelType6.TRANSCRIPTION, audioBuffer);
1229
1812
  if (typeof transcription !== "string") {
1230
1813
  throw new Error("Transcription should return a string");
1231
1814
  }
1232
- logger11.info(`[OpenAI Test] Transcription: "${transcription.substring(0, 50)}..."`);
1815
+ logger9.info(`[OpenAI Test] Transcription: "${transcription.substring(0, 50)}..."`);
1233
1816
  }
1234
1817
  },
1235
1818
  {
1236
1819
  name: "openai_test_text_to_speech",
1237
1820
  fn: async (runtime) => {
1238
- const audioData = await runtime.useModel(ModelType7.TEXT_TO_SPEECH, {
1821
+ const audioData = await runtime.useModel(ModelType6.TEXT_TO_SPEECH, {
1239
1822
  text: "Hello, this is a text-to-speech test."
1240
1823
  });
1241
1824
  if (!(audioData instanceof ArrayBuffer) || audioData.byteLength === 0) {
1242
1825
  throw new Error("TTS should return non-empty ArrayBuffer");
1243
1826
  }
1244
- logger11.info(`[OpenAI Test] TTS generated ${audioData.byteLength} bytes of audio`);
1827
+ logger9.info(`[OpenAI Test] TTS generated ${audioData.byteLength} bytes of audio`);
1245
1828
  }
1246
1829
  },
1247
1830
  {
1248
- name: "openai_test_object_generation",
1831
+ name: "openai_test_structured_output_via_text_large",
1249
1832
  fn: async (runtime) => {
1250
- const result = await runtime.useModel(ModelType7.OBJECT_SMALL, {
1251
- prompt: "Return a JSON object with exactly these fields: name (string), age (number), active (boolean)"
1833
+ const result = await runtime.useModel(ModelType6.TEXT_LARGE, {
1834
+ prompt: "Return a JSON object with exactly these fields: name (string), age (number), active (boolean)",
1835
+ responseSchema: {
1836
+ type: "object",
1837
+ properties: {
1838
+ name: { type: "string" },
1839
+ age: { type: "number" },
1840
+ active: { type: "boolean" }
1841
+ },
1842
+ required: ["name", "age", "active"]
1843
+ }
1252
1844
  });
1253
- if (!result || typeof result !== "object") {
1254
- throw new Error("Object generation should return an object");
1845
+ if (!result || typeof result !== "object" && typeof result !== "string") {
1846
+ throw new Error("Structured output should return an object or text");
1255
1847
  }
1256
- logger11.info(`[OpenAI Test] Object generated: ${JSON.stringify(result).substring(0, 100)}`);
1848
+ logger9.info(`[OpenAI Test] Structured output: ${JSON.stringify(result).substring(0, 100)}`);
1257
1849
  }
1258
1850
  },
1259
1851
  {
1260
1852
  name: "openai_test_research",
1261
1853
  fn: async (runtime) => {
1262
- const result = await runtime.useModel(ModelType7.RESEARCH, {
1854
+ const result = await runtime.useModel(ModelType6.RESEARCH, {
1263
1855
  input: "What is the current date and time?",
1264
1856
  tools: [{ type: "web_search_preview" }],
1265
1857
  maxToolCalls: 3
@@ -1270,17 +1862,20 @@ var openaiPlugin = {
1270
1862
  if (typeof result.text !== "string" || result.text.length === 0) {
1271
1863
  throw new Error("Research result text should be a non-empty string");
1272
1864
  }
1273
- logger11.info(`[OpenAI Test] Research completed. Text length: ${result.text.length}, Annotations: ${result.annotations?.length ?? 0}`);
1865
+ logger9.info(`[OpenAI Test] Research completed. Text length: ${result.text.length}, Annotations: ${result.annotations?.length ?? 0}`);
1274
1866
  }
1275
1867
  }
1276
1868
  ]
1277
1869
  }
1278
1870
  ]
1279
1871
  };
1280
- var typescript_default = openaiPlugin;
1872
+ var plugin_openai_default = openaiPlugin;
1873
+
1874
+ // index.node.ts
1875
+ var index_node_default = plugin_openai_default;
1281
1876
  export {
1282
1877
  openaiPlugin,
1283
- typescript_default as default
1878
+ index_node_default as default
1284
1879
  };
1285
1880
 
1286
- //# debugId=A63C30D83B0EE8CA64756E2164756E21
1881
+ //# debugId=D3370FEEF676E11164756E2164756E21