@elizaos/plugin-openai 2.0.0-beta.1 → 2.0.3-beta.3

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 logger9, ModelType as ModelType6 } from "@elizaos/core";
2
+ import { logger as logger9, ModelType as ModelType5 } from "@elizaos/core";
3
3
 
4
4
  // init.ts
5
5
  import { logger as logger2 } from "@elizaos/core";
@@ -46,7 +46,7 @@ function isProxyMode(runtime) {
46
46
  return isBrowser() && !!getSetting(runtime, "OPENAI_BROWSER_BASE_URL");
47
47
  }
48
48
  function isCerebrasMode(runtime) {
49
- const explicitProvider = getSetting(runtime, "MILADY_PROVIDER");
49
+ const explicitProvider = getSetting(runtime, "ELIZA_PROVIDER");
50
50
  if (explicitProvider && explicitProvider.toLowerCase() === "cerebras") {
51
51
  return true;
52
52
  }
@@ -54,6 +54,25 @@ function isCerebrasMode(runtime) {
54
54
  if (baseURL && /(^|\.)cerebras\.ai(\/|$)/i.test(baseURL)) {
55
55
  return true;
56
56
  }
57
+ const cerebrasKey = getSetting(runtime, "CEREBRAS_API_KEY");
58
+ if (cerebrasKey && !getSetting(runtime, "OPENAI_API_KEY") && !getSetting(runtime, "OPENAI_BASE_URL")) {
59
+ return true;
60
+ }
61
+ return false;
62
+ }
63
+ function isEvoLinkMode(runtime) {
64
+ const explicitProvider = getSetting(runtime, "ELIZA_PROVIDER");
65
+ if (explicitProvider && explicitProvider.toLowerCase() === "evolink") {
66
+ return true;
67
+ }
68
+ const baseURL = getSetting(runtime, "OPENAI_BASE_URL");
69
+ if (baseURL && /(^|\.)evolink\.ai(\/|$)/i.test(baseURL)) {
70
+ return true;
71
+ }
72
+ const evolinkKey = getSetting(runtime, "EVOLINK_API_KEY");
73
+ if (evolinkKey && !getSetting(runtime, "OPENAI_API_KEY") && !getSetting(runtime, "OPENAI_BASE_URL")) {
74
+ return true;
75
+ }
57
76
  return false;
58
77
  }
59
78
  function getApiKey(runtime) {
@@ -63,6 +82,12 @@ function getApiKey(runtime) {
63
82
  return cerebrasKey;
64
83
  }
65
84
  }
85
+ if (isEvoLinkMode(runtime)) {
86
+ const evolinkKey = getSetting(runtime, "EVOLINK_API_KEY");
87
+ if (evolinkKey) {
88
+ return evolinkKey;
89
+ }
90
+ }
66
91
  return getSetting(runtime, "OPENAI_API_KEY");
67
92
  }
68
93
  function getEmbeddingApiKey(runtime) {
@@ -81,9 +106,22 @@ function getAuthHeader(runtime, forEmbedding = false) {
81
106
  const key = forEmbedding ? getEmbeddingApiKey(runtime) : getApiKey(runtime);
82
107
  return key ? { Authorization: `Bearer ${key}` } : {};
83
108
  }
109
+ function authHeaderForKey(runtime, key) {
110
+ if (isBrowser() && !getBooleanSetting(runtime, "OPENAI_ALLOW_BROWSER_API_KEY", false)) {
111
+ return {};
112
+ }
113
+ return key ? { Authorization: `Bearer ${key}` } : {};
114
+ }
115
+ function getMockBaseURL() {
116
+ const base = getEnvValue("ELIZA_MOCK_OPENAI_BASE")?.trim();
117
+ return base ? base : undefined;
118
+ }
84
119
  function getBaseURL(runtime) {
85
120
  const browserURL = getSetting(runtime, "OPENAI_BROWSER_BASE_URL");
86
- const baseURL = isBrowser() && browserURL ? browserURL : getSetting(runtime, "OPENAI_BASE_URL") ?? "https://api.openai.com/v1";
121
+ const mockBaseURL = getMockBaseURL();
122
+ const cerebrasBaseURL = isCerebrasMode(runtime) && !getSetting(runtime, "OPENAI_BASE_URL") ? getSetting(runtime, "CEREBRAS_BASE_URL") ?? "https://api.cerebras.ai/v1" : undefined;
123
+ const evolinkBaseURL = isEvoLinkMode(runtime) && !getSetting(runtime, "OPENAI_BASE_URL") ? getSetting(runtime, "EVOLINK_BASE_URL") ?? "https://direct.evolink.ai/v1" : undefined;
124
+ const baseURL = isBrowser() && browserURL ? browserURL : mockBaseURL ?? getSetting(runtime, "OPENAI_BASE_URL") ?? cerebrasBaseURL ?? evolinkBaseURL ?? "https://api.openai.com/v1";
87
125
  logger.debug(`[OpenAI] Base URL: ${baseURL}`);
88
126
  return baseURL;
89
127
  }
@@ -96,26 +134,54 @@ function getEmbeddingBaseURL(runtime) {
96
134
  logger.debug("[OpenAI] Falling back to general base URL for embeddings");
97
135
  return getBaseURL(runtime);
98
136
  }
137
+ function getImageDescriptionApiKey(runtime) {
138
+ const imageDescriptionApiKey = getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_API_KEY");
139
+ if (imageDescriptionApiKey) {
140
+ return imageDescriptionApiKey;
141
+ }
142
+ const imageDescriptionURL = getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_BASE_URL");
143
+ if (imageDescriptionURL && /(^|\.)openai\.com(\/|$)/i.test(imageDescriptionURL)) {
144
+ return getSetting(runtime, "OPENAI_API_KEY");
145
+ }
146
+ return getApiKey(runtime);
147
+ }
148
+ function getImageDescriptionAuthHeader(runtime) {
149
+ return authHeaderForKey(runtime, getImageDescriptionApiKey(runtime));
150
+ }
151
+ function getImageDescriptionBaseURL(runtime) {
152
+ const imageDescriptionURL = getSetting(runtime, "OPENAI_IMAGE_DESCRIPTION_BASE_URL");
153
+ if (imageDescriptionURL) {
154
+ logger.debug(`[OpenAI] Using image-description base URL: ${imageDescriptionURL}`);
155
+ return imageDescriptionURL;
156
+ }
157
+ return getBaseURL(runtime);
158
+ }
159
+ function getCerebrasModel(runtime) {
160
+ return isCerebrasMode(runtime) ? getSetting(runtime, "CEREBRAS_MODEL") : undefined;
161
+ }
162
+ function getEvoLinkModel(runtime) {
163
+ return isEvoLinkMode(runtime) ? getSetting(runtime, "EVOLINK_MODEL") ?? "gpt-5.2" : undefined;
164
+ }
99
165
  function getSmallModel(runtime) {
100
- return getSetting(runtime, "OPENAI_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL") ?? "gpt-5.4-mini";
166
+ return getSetting(runtime, "OPENAI_SMALL_MODEL") ?? getCerebrasModel(runtime) ?? getEvoLinkModel(runtime) ?? getSetting(runtime, "SMALL_MODEL") ?? "gpt-5.4-mini";
101
167
  }
102
168
  function getNanoModel(runtime) {
103
- return getSetting(runtime, "OPENAI_NANO_MODEL") ?? getSetting(runtime, "NANO_MODEL") ?? getSmallModel(runtime);
169
+ return getSetting(runtime, "OPENAI_NANO_MODEL") ?? getCerebrasModel(runtime) ?? getEvoLinkModel(runtime) ?? getSetting(runtime, "NANO_MODEL") ?? getSmallModel(runtime);
104
170
  }
105
171
  function getMediumModel(runtime) {
106
- return getSetting(runtime, "OPENAI_MEDIUM_MODEL") ?? getSetting(runtime, "MEDIUM_MODEL") ?? getSmallModel(runtime);
172
+ return getSetting(runtime, "OPENAI_MEDIUM_MODEL") ?? getCerebrasModel(runtime) ?? getEvoLinkModel(runtime) ?? getSetting(runtime, "MEDIUM_MODEL") ?? getSmallModel(runtime);
107
173
  }
108
174
  function getLargeModel(runtime) {
109
- return getSetting(runtime, "OPENAI_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL") ?? "gpt-5";
175
+ return getSetting(runtime, "OPENAI_LARGE_MODEL") ?? getCerebrasModel(runtime) ?? getEvoLinkModel(runtime) ?? getSetting(runtime, "LARGE_MODEL") ?? "gpt-5";
110
176
  }
111
177
  function getMegaModel(runtime) {
112
178
  return getSetting(runtime, "OPENAI_MEGA_MODEL") ?? getSetting(runtime, "MEGA_MODEL") ?? getLargeModel(runtime);
113
179
  }
114
180
  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);
181
+ return getSetting(runtime, "OPENAI_RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "OPENAI_SHOULD_RESPOND_MODEL") ?? getCerebrasModel(runtime) ?? getEvoLinkModel(runtime) ?? getSetting(runtime, "RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "SHOULD_RESPOND_MODEL") ?? getSmallModel(runtime);
116
182
  }
117
183
  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);
184
+ return getSetting(runtime, "OPENAI_ACTION_PLANNER_MODEL") ?? getSetting(runtime, "OPENAI_PLANNER_MODEL") ?? getCerebrasModel(runtime) ?? getEvoLinkModel(runtime) ?? getSetting(runtime, "ACTION_PLANNER_MODEL") ?? getSetting(runtime, "PLANNER_MODEL") ?? getMediumModel(runtime);
119
185
  }
120
186
  function getEmbeddingModel(runtime) {
121
187
  return getSetting(runtime, "OPENAI_EMBEDDING_MODEL") ?? "text-embedding-3-small";
@@ -127,7 +193,7 @@ function getTranscriptionModel(runtime) {
127
193
  return getSetting(runtime, "OPENAI_TRANSCRIPTION_MODEL") ?? "gpt-5-mini-transcribe";
128
194
  }
129
195
  function getTTSModel(runtime) {
130
- return getSetting(runtime, "OPENAI_TTS_MODEL") ?? "tts-1";
196
+ return getSetting(runtime, "OPENAI_TTS_MODEL") ?? "gpt-5-mini-tts";
131
197
  }
132
198
  function getTTSVoice(runtime) {
133
199
  return getSetting(runtime, "OPENAI_TTS_VOICE") ?? "nova";
@@ -414,7 +480,7 @@ async function handleTextToSpeech(runtime, input) {
414
480
  }
415
481
  const details = {
416
482
  model,
417
- systemPrompt: instructions ?? "",
483
+ systemPrompt: instructions,
418
484
  userPrompt: text,
419
485
  temperature: 0,
420
486
  maxTokens: 0,
@@ -523,6 +589,10 @@ function hasExplicitEmbeddingEndpoint(runtime) {
523
589
  const value = getSetting(runtime, key);
524
590
  return typeof value === "string" && value.trim().length > 0;
525
591
  }
592
+ function hasExplicitEmbeddingDimensions(runtime) {
593
+ const value = getSetting(runtime, "OPENAI_EMBEDDING_DIMENSIONS");
594
+ return typeof value === "string" && value.trim().length > 0;
595
+ }
526
596
  function shouldUseLocalEmbeddingFallback(runtime) {
527
597
  return isCerebrasMode(runtime) && !hasExplicitEmbeddingEndpoint(runtime);
528
598
  }
@@ -596,7 +666,8 @@ async function handleTextEmbedding(runtime, params) {
596
666
  },
597
667
  body: JSON.stringify({
598
668
  model: embeddingModel,
599
- input: trimmedText
669
+ input: trimmedText,
670
+ ...hasExplicitEmbeddingDimensions(runtime) ? { dimensions: embeddingDimension } : {}
600
671
  })
601
672
  });
602
673
  if (!response.ok) {
@@ -604,7 +675,7 @@ async function handleTextEmbedding(runtime, params) {
604
675
  throw new Error(`OpenAI embedding API error: ${response.status} ${response.statusText} - ${errorText}`);
605
676
  }
606
677
  const data = await response.json();
607
- const firstResult = data?.data?.[0];
678
+ const firstResult = Array.isArray(data.data) ? data.data[0] : undefined;
608
679
  if (!firstResult?.embedding) {
609
680
  throw new Error("OpenAI API returned invalid embedding response structure");
610
681
  }
@@ -631,7 +702,7 @@ async function handleImageGeneration(runtime, params) {
631
702
  const size = params.size ?? "1024x1024";
632
703
  const extendedParams = params;
633
704
  logger6.debug(`[OpenAI] Using IMAGE model: ${modelName}`);
634
- if (params.prompt.trim().length === 0) {
705
+ if (typeof params.prompt !== "string" || params.prompt.trim().length === 0) {
635
706
  throw new Error("IMAGE generation requires a non-empty prompt");
636
707
  }
637
708
  if (count < 1 || count > 10) {
@@ -693,7 +764,8 @@ function parseDescriptionFromResponse(content) {
693
764
  }
694
765
  async function handleImageDescription(runtime, params) {
695
766
  const modelName = getImageDescriptionModel(runtime);
696
- const maxTokens = getImageDescriptionMaxTokens(runtime);
767
+ const paramsWithMaxTokens = params;
768
+ const maxTokens = typeof params === "object" && typeof paramsWithMaxTokens.maxTokens === "number" ? paramsWithMaxTokens.maxTokens : getImageDescriptionMaxTokens(runtime);
697
769
  logger6.debug(`[OpenAI] Using IMAGE_DESCRIPTION model: ${modelName}`);
698
770
  let imageUrl;
699
771
  let promptText;
@@ -707,7 +779,7 @@ async function handleImageDescription(runtime, params) {
707
779
  if (!imageUrl || imageUrl.trim().length === 0) {
708
780
  throw new Error("IMAGE_DESCRIPTION requires a valid image URL");
709
781
  }
710
- const baseURL = getBaseURL(runtime);
782
+ const baseURL = getImageDescriptionBaseURL(runtime);
711
783
  const requestBody = {
712
784
  model: modelName,
713
785
  messages: [
@@ -734,7 +806,7 @@ async function handleImageDescription(runtime, params) {
734
806
  const response = await fetch(`${baseURL}/chat/completions`, {
735
807
  method: "POST",
736
808
  headers: {
737
- ...getAuthHeader(runtime),
809
+ ...getImageDescriptionAuthHeader(runtime),
738
810
  "Content-Type": "application/json"
739
811
  },
740
812
  body: JSON.stringify(requestBody)
@@ -744,7 +816,11 @@ async function handleImageDescription(runtime, params) {
744
816
  throw new Error(`OpenAI image description failed: ${response.status} ${response.statusText} - ${errorText}`);
745
817
  }
746
818
  const responseData = await response.json();
747
- details.response = responseData.choices?.[0]?.message?.content ?? "";
819
+ const responseContent = responseData.choices[0]?.message.content;
820
+ if (!responseContent) {
821
+ throw new Error("OpenAI API returned empty image description");
822
+ }
823
+ details.response = responseContent;
748
824
  if (responseData.usage) {
749
825
  details.promptTokens = responseData.usage.prompt_tokens;
750
826
  details.completionTokens = responseData.usage.completion_tokens;
@@ -758,8 +834,8 @@ async function handleImageDescription(runtime, params) {
758
834
  totalTokens: data.usage.total_tokens
759
835
  });
760
836
  }
761
- const firstChoice = data.choices?.[0];
762
- const content = firstChoice?.message?.content;
837
+ const firstChoice = data.choices[0];
838
+ const content = firstChoice?.message.content;
763
839
  if (!content) {
764
840
  throw new Error("OpenAI API returned empty image description");
765
841
  }
@@ -1029,13 +1105,16 @@ function createOpenAIClient(runtime) {
1029
1105
  });
1030
1106
  }
1031
1107
  // 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";
1108
+ var TEXT_NANO_MODEL_TYPE = ModelType3.TEXT_NANO;
1109
+ var TEXT_MEDIUM_MODEL_TYPE = ModelType3.TEXT_MEDIUM;
1110
+ var TEXT_MEGA_MODEL_TYPE = ModelType3.TEXT_MEGA;
1111
+ var RESPONSE_HANDLER_MODEL_TYPE = ModelType3.RESPONSE_HANDLER;
1112
+ var ACTION_PLANNER_MODEL_TYPE = ModelType3.ACTION_PLANNER;
1113
+ function resolveRequestedModelName(params, runtime, getModelFn) {
1114
+ return typeof params.model === "string" && params.model.trim().length > 0 ? params.model.trim() : getModelFn(runtime);
1115
+ }
1037
1116
  function buildUserContent(params) {
1038
- const content = [{ type: "text", text: params.prompt }];
1117
+ const content = [{ type: "text", text: params.prompt ?? "" }];
1039
1118
  for (const attachment of params.attachments ?? []) {
1040
1119
  content.push({
1041
1120
  type: "file",
@@ -1085,11 +1164,33 @@ function resolvePromptCacheOptions(params) {
1085
1164
  promptCacheRetention: withOpenAIOptions.providerOptions?.openai?.promptCacheRetention
1086
1165
  };
1087
1166
  }
1088
- function resolveProviderOptions(params, runtime) {
1167
+ var VALID_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
1168
+ function isReasoningModel(modelName) {
1169
+ if (!modelName)
1170
+ return false;
1171
+ const m = modelName.toLowerCase();
1172
+ return m.includes("gpt-oss") || m.includes("o1") || m.includes("o3") || m.includes("o4") || m.includes("deepseek-r1") || m.includes("thinking") || m.includes("reasoning") || m.includes("qwq");
1173
+ }
1174
+ function resolveReasoningEffort(runtime, modelName) {
1175
+ const raw = runtime.getSetting("OPENAI_REASONING_EFFORT");
1176
+ const normalized = typeof raw === "string" ? raw.trim().toLowerCase() : "";
1177
+ if (normalized) {
1178
+ if (VALID_REASONING_EFFORTS.includes(normalized)) {
1179
+ return normalized;
1180
+ }
1181
+ logger8.warn(`[OpenAI] OPENAI_REASONING_EFFORT=${raw} is not a valid reasoning effort; ignoring. Expected one of: ${VALID_REASONING_EFFORTS.join(", ")}.`);
1182
+ }
1183
+ if (isCerebrasMode(runtime) && isReasoningModel(modelName)) {
1184
+ return "low";
1185
+ }
1186
+ return;
1187
+ }
1188
+ function resolveProviderOptions(params, runtime, modelName) {
1089
1189
  const withOpenAIOptions = params;
1090
1190
  const rawProviderOptions = withOpenAIOptions.providerOptions;
1091
1191
  const promptCacheOptions = resolvePromptCacheOptions(params);
1092
- if (!rawProviderOptions && !promptCacheOptions.promptCacheKey && !promptCacheOptions.promptCacheRetention) {
1192
+ const reasoningEffort = resolveReasoningEffort(runtime, modelName);
1193
+ if (!rawProviderOptions && !promptCacheOptions.promptCacheKey && !promptCacheOptions.promptCacheRetention && !reasoningEffort) {
1093
1194
  return;
1094
1195
  }
1095
1196
  const skipCacheRetention = isCerebrasMode(runtime);
@@ -1105,7 +1206,8 @@ function resolveProviderOptions(params, runtime) {
1105
1206
  const openaiOptions = {
1106
1207
  ...sanitizedRawOpenAIOptions ?? {},
1107
1208
  ...promptCacheOptions.promptCacheKey ? { promptCacheKey: promptCacheOptions.promptCacheKey } : {},
1108
- ...!skipCacheRetention && promptCacheOptions.promptCacheRetention ? { promptCacheRetention: promptCacheOptions.promptCacheRetention } : {}
1209
+ ...!skipCacheRetention && promptCacheOptions.promptCacheRetention ? { promptCacheRetention: promptCacheOptions.promptCacheRetention } : {},
1210
+ ...sanitizedRawOpenAIOptions?.reasoningEffort === undefined && reasoningEffort ? { reasoningEffort } : {}
1109
1211
  };
1110
1212
  const providerOptions = {
1111
1213
  ...rest,
@@ -1143,7 +1245,7 @@ function normalizeNativeTools(tools, options = {}) {
1143
1245
  const rawSchema = tool.parameters ?? functionTool.parameters ?? { type: "object" };
1144
1246
  let inputSchema = sanitizeJsonSchema(rawSchema, true);
1145
1247
  if (options.cerebrasMode) {
1146
- inputSchema = normalizeSchemaForCerebras(inputSchema);
1248
+ inputSchema = normalizeSchemaForCerebras(inputSchema, true);
1147
1249
  }
1148
1250
  const registeredName = options.cerebrasMode ? sanitizeFunctionNameForCerebras(name) : name;
1149
1251
  toolSet[registeredName] = {
@@ -1189,10 +1291,21 @@ function normalizeNativeMessage(message) {
1189
1291
  ...providerOptions ? { providerOptions } : {}
1190
1292
  };
1191
1293
  }
1294
+ function stripReasoningParts(content) {
1295
+ return content.filter((part) => {
1296
+ if (!part || typeof part !== "object")
1297
+ return true;
1298
+ const type = part.type;
1299
+ return type !== "reasoning" && type !== "thinking";
1300
+ });
1301
+ }
1192
1302
  function normalizeAssistantContent(message) {
1193
1303
  const toolCalls = Array.isArray(message.toolCalls) ? message.toolCalls : [];
1194
1304
  if (toolCalls.length === 0) {
1195
- if (Array.isArray(message.content) || typeof message.content === "string") {
1305
+ if (Array.isArray(message.content)) {
1306
+ return stripReasoningParts(message.content);
1307
+ }
1308
+ if (typeof message.content === "string") {
1196
1309
  return message.content;
1197
1310
  }
1198
1311
  return "";
@@ -1201,7 +1314,7 @@ function normalizeAssistantContent(message) {
1201
1314
  if (typeof message.content === "string" && message.content.length > 0) {
1202
1315
  parts.push({ type: "text", text: message.content });
1203
1316
  } else if (Array.isArray(message.content)) {
1204
- parts.push(...message.content);
1317
+ parts.push(...stripReasoningParts(message.content));
1205
1318
  }
1206
1319
  for (const toolCall of toolCalls) {
1207
1320
  const rawCall = asRecord(toolCall);
@@ -1297,18 +1410,39 @@ function normalizeToolChoice(toolChoice) {
1297
1410
  }
1298
1411
  return toolChoice;
1299
1412
  }
1413
+ function hasIllegalStrictRoot(node) {
1414
+ if (node.type !== "object")
1415
+ return true;
1416
+ if (Array.isArray(node.oneOf) && node.oneOf.length > 0)
1417
+ return true;
1418
+ if (Array.isArray(node.anyOf) && node.anyOf.length > 0)
1419
+ return true;
1420
+ if (Array.isArray(node.enum))
1421
+ return true;
1422
+ if (node.not !== undefined)
1423
+ return true;
1424
+ return false;
1425
+ }
1300
1426
  function sanitizeJsonSchema(schema, isRoot = false) {
1301
1427
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
1302
1428
  return { type: "object" };
1303
1429
  }
1304
1430
  const record = schema;
1305
- const sanitized = { ...record };
1431
+ let sanitized = { ...record };
1306
1432
  if (typeof sanitized.type !== "string") {
1307
1433
  const inferredType = inferJsonSchemaType(sanitized, isRoot);
1308
1434
  if (inferredType) {
1309
1435
  sanitized.type = inferredType;
1310
1436
  }
1311
1437
  }
1438
+ if (isRoot && hasIllegalStrictRoot(sanitized)) {
1439
+ sanitized = {
1440
+ type: "object",
1441
+ properties: { value: { ...record } },
1442
+ required: ["value"],
1443
+ additionalProperties: false
1444
+ };
1445
+ }
1312
1446
  if (sanitized.properties && typeof sanitized.properties === "object" && !Array.isArray(sanitized.properties)) {
1313
1447
  const properties = {};
1314
1448
  for (const [key, value] of Object.entries(sanitized.properties)) {
@@ -1377,6 +1511,14 @@ function buildNativeTextResult(result, modelName) {
1377
1511
  providerMetadata: mergeProviderModelName(result.providerMetadata, modelName)
1378
1512
  };
1379
1513
  }
1514
+ function handledPromise(value) {
1515
+ const promise = Promise.resolve(value);
1516
+ promise.catch(() => {});
1517
+ return promise;
1518
+ }
1519
+ function handledMappedPromise(value, mapper) {
1520
+ return handledPromise(handledPromise(value).then(mapper));
1521
+ }
1380
1522
  function mergeProviderModelName(providerMetadata, modelName) {
1381
1523
  if (!modelName) {
1382
1524
  return providerMetadata;
@@ -1409,7 +1551,8 @@ function createLlmCallDetails(modelName, params, systemPrompt, actionType, model
1409
1551
  responseSchema: originalParams.responseSchema,
1410
1552
  providerOptions: providerOptions ?? nativeParams?.providerOptions ?? originalParams.providerOptions,
1411
1553
  temperature: params.temperature ?? 0,
1412
- maxTokens: typeof nativeParams?.maxOutputTokens === "number" ? nativeParams.maxOutputTokens : params.maxTokens ?? 8192,
1554
+ maxTokens: typeof nativeParams?.maxOutputTokens === "number" ? nativeParams.maxOutputTokens : params.omitMaxTokens ? 0 : params.maxTokens ?? 8192,
1555
+ maxTokensOmitted: params.omitMaxTokens && typeof nativeParams?.maxOutputTokens !== "number" ? true : undefined,
1413
1556
  purpose: "external_llm",
1414
1557
  actionType
1415
1558
  };
@@ -1446,9 +1589,9 @@ function applyUsageToDetails(details, usage) {
1446
1589
  async function generateTextByModelType(runtime, params, modelType, getModelFn) {
1447
1590
  const paramsWithAttachments = params;
1448
1591
  const openai = createOpenAIClient(runtime);
1449
- const modelName = getModelFn(runtime);
1592
+ const modelName = resolveRequestedModelName(paramsWithAttachments, runtime, getModelFn);
1450
1593
  logger8.debug(`[OpenAI] Using ${modelType} model: ${modelName}`);
1451
- const providerOptions = resolveProviderOptions(params, runtime);
1594
+ const providerOptions = resolveProviderOptions(params, runtime, modelName);
1452
1595
  const hasAttachments = (paramsWithAttachments.attachments?.length ?? 0) > 0;
1453
1596
  const userContent = hasAttachments ? buildUserContent(paramsWithAttachments) : undefined;
1454
1597
  const shouldReturnNativeResult = usesNativeTextResult(paramsWithAttachments);
@@ -1473,16 +1616,20 @@ async function generateTextByModelType(runtime, params, modelType, getModelFn) {
1473
1616
  const effectiveMessages = wireMessages && wireMessages.length > 0 ? wireMessages : normalizedMessages;
1474
1617
  const promptText = typeof params.prompt === "string" && params.prompt.length > 0 ? params.prompt : "";
1475
1618
  const promptOrMessages = effectiveMessages && effectiveMessages.length > 0 ? { messages: effectiveMessages } : userContent ? { messages: [{ role: "user", content: userContent }] } : { prompt: promptText };
1619
+ const callerResponseFormat = paramsWithAttachments.responseFormat;
1620
+ const responseFormatType = typeof callerResponseFormat === "string" ? callerResponseFormat : callerResponseFormat && typeof callerResponseFormat === "object" && ("type" in callerResponseFormat) ? callerResponseFormat.type : undefined;
1621
+ const wireResponseFormat = responseFormatType === "json_object" ? { type: "json" } : responseFormatType === "text" ? { type: "text" } : undefined;
1476
1622
  const generateParams = {
1477
1623
  model,
1478
1624
  ...promptOrMessages,
1479
1625
  system: systemPrompt,
1480
1626
  allowSystemInMessages: true,
1481
- maxOutputTokens: params.maxTokens ?? 8192,
1627
+ ...params.omitMaxTokens ? {} : { maxOutputTokens: params.maxTokens ?? 8192 },
1482
1628
  experimental_telemetry: telemetryConfig,
1483
1629
  ...normalizedTools ? { tools: normalizedTools } : {},
1484
1630
  ...normalizedToolChoice ? { toolChoice: normalizedToolChoice } : {},
1485
1631
  ...paramsWithAttachments.responseSchema && !isCerebrasMode(runtime) ? { output: buildStructuredOutput(paramsWithAttachments.responseSchema) } : {},
1632
+ ...wireResponseFormat ? { responseFormat: wireResponseFormat } : {},
1486
1633
  ...providerOptions ? { providerOptions } : {}
1487
1634
  };
1488
1635
  if (params.stream) {
@@ -1490,18 +1637,23 @@ async function generateTextByModelType(runtime, params, modelType, getModelFn) {
1490
1637
  details2.response = "";
1491
1638
  const result2 = await recordLlmCall4(runtime, details2, () => streamText(generateParams));
1492
1639
  return {
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)
1640
+ textStream: async function* textStreamWithCallback() {
1641
+ for await (const chunk of result2.textStream) {
1642
+ params.onStreamChunk?.(chunk);
1643
+ yield chunk;
1644
+ }
1645
+ }(),
1646
+ text: handledPromise(result2.text),
1647
+ ...shouldReturnNativeResult ? { toolCalls: handledPromise(result2.toolCalls) } : {},
1648
+ usage: handledMappedPromise(result2.usage, convertUsage),
1649
+ finishReason: handledMappedPromise(result2.finishReason, (r) => r)
1498
1650
  };
1499
1651
  }
1500
1652
  const details = createLlmCallDetails(modelName, params, systemPrompt, "ai.generateText", modelType, providerOptions, generateParams);
1501
1653
  const result = await recordLlmCall4(runtime, details, async () => {
1502
1654
  const result2 = await generateText(generateParams);
1503
1655
  details.response = result2.text;
1504
- details.toolCalls = result2.toolCalls ?? [];
1656
+ details.toolCalls = result2.toolCalls;
1505
1657
  details.finishReason = result2.finishReason;
1506
1658
  details.providerMetadata = result2.providerMetadata;
1507
1659
  applyUsageToDetails(details, result2.usage);
@@ -1536,9 +1688,6 @@ async function handleResponseHandler(runtime, params) {
1536
1688
  async function handleActionPlanner(runtime, params) {
1537
1689
  return generateTextByModelType(runtime, params, ACTION_PLANNER_MODEL_TYPE, getActionPlannerModel);
1538
1690
  }
1539
- // models/tokenizer.ts
1540
- import { ModelType as ModelType5 } from "@elizaos/core";
1541
-
1542
1691
  // utils/tokenization.ts
1543
1692
  import { ModelType as ModelType4 } from "@elizaos/core";
1544
1693
  import {
@@ -1576,7 +1725,7 @@ async function handleTokenizerEncode(runtime, params) {
1576
1725
  if (!params.prompt) {
1577
1726
  throw new Error("Tokenization requires a non-empty prompt");
1578
1727
  }
1579
- const modelType = params.modelType ?? ModelType5.TEXT_LARGE;
1728
+ const modelType = params.modelType;
1580
1729
  return tokenizeText(runtime, modelType, params.prompt);
1581
1730
  }
1582
1731
  async function handleTokenizerDecode(runtime, params) {
@@ -1592,7 +1741,7 @@ async function handleTokenizerDecode(runtime, params) {
1592
1741
  throw new Error(`Invalid token at index ${i}: expected number`);
1593
1742
  }
1594
1743
  }
1595
- const modelType = params.modelType ?? ModelType5.TEXT_LARGE;
1744
+ const modelType = params.modelType;
1596
1745
  return detokenizeText(runtime, modelType, params.tokens);
1597
1746
  }
1598
1747
  // index.ts
@@ -1603,20 +1752,56 @@ function getProcessEnv() {
1603
1752
  return process.env;
1604
1753
  }
1605
1754
  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";
1755
+ var TEXT_NANO_MODEL_TYPE2 = ModelType5.TEXT_NANO;
1756
+ var TEXT_MEDIUM_MODEL_TYPE2 = ModelType5.TEXT_MEDIUM;
1757
+ var TEXT_MEGA_MODEL_TYPE2 = ModelType5.TEXT_MEGA;
1758
+ var RESPONSE_HANDLER_MODEL_TYPE2 = ModelType5.RESPONSE_HANDLER;
1759
+ var ACTION_PLANNER_MODEL_TYPE2 = ModelType5.ACTION_PLANNER;
1760
+ function hasExplicitCapabilityOverride(runtime, overrideKeys) {
1761
+ return overrideKeys.some((key) => {
1762
+ const value = getSetting(runtime, key);
1763
+ return typeof value === "string" && value.trim().length > 0;
1764
+ });
1765
+ }
1766
+ var mediaModelOverrideKeys = {
1767
+ [ModelType5.IMAGE_DESCRIPTION]: ["OPENAI_IMAGE_DESCRIPTION_BASE_URL"]
1768
+ };
1769
+ var mediaModels = {
1770
+ [ModelType5.IMAGE]: async (runtime, params) => {
1771
+ return handleImageGeneration(runtime, params);
1772
+ },
1773
+ [ModelType5.IMAGE_DESCRIPTION]: async (runtime, params) => {
1774
+ return handleImageDescription(runtime, params);
1775
+ },
1776
+ [ModelType5.TRANSCRIPTION]: async (runtime, input) => {
1777
+ return handleTranscription(runtime, input);
1778
+ },
1779
+ [ModelType5.TEXT_TO_SPEECH]: async (runtime, input) => {
1780
+ return handleTextToSpeech(runtime, input);
1781
+ }
1782
+ };
1783
+ function registerMediaModels(runtime) {
1784
+ const cerebras = isCerebrasMode(runtime);
1785
+ for (const [modelType, handler] of Object.entries(mediaModels)) {
1786
+ if (cerebras && !hasExplicitCapabilityOverride(runtime, mediaModelOverrideKeys[modelType] ?? [])) {
1787
+ logger9.info(`[OpenAI] Not registering ${modelType}: the Cerebras endpoint does not serve it`);
1788
+ continue;
1789
+ }
1790
+ runtime.registerModel(modelType, handler, openaiPlugin.name, openaiPlugin.priority);
1791
+ }
1792
+ }
1611
1793
  var openaiPlugin = {
1612
1794
  name: "openai",
1613
1795
  description: "OpenAI API integration for text, image, audio, and embedding models",
1614
1796
  autoEnable: {
1615
- envKeys: ["OPENAI_API_KEY"]
1797
+ envKeys: ["OPENAI_API_KEY", "CEREBRAS_API_KEY", "EVOLINK_API_KEY"]
1616
1798
  },
1617
1799
  config: {
1618
1800
  OPENAI_API_KEY: env.OPENAI_API_KEY ?? null,
1619
1801
  OPENAI_BASE_URL: env.OPENAI_BASE_URL ?? null,
1802
+ EVOLINK_API_KEY: env.EVOLINK_API_KEY ?? null,
1803
+ EVOLINK_BASE_URL: env.EVOLINK_BASE_URL ?? null,
1804
+ EVOLINK_MODEL: env.EVOLINK_MODEL ?? null,
1620
1805
  OPENAI_NANO_MODEL: env.OPENAI_NANO_MODEL ?? null,
1621
1806
  OPENAI_MEDIUM_MODEL: env.OPENAI_MEDIUM_MODEL ?? null,
1622
1807
  OPENAI_SMALL_MODEL: env.OPENAI_SMALL_MODEL ?? null,
@@ -1639,6 +1824,8 @@ var openaiPlugin = {
1639
1824
  OPENAI_EMBEDDING_API_KEY: env.OPENAI_EMBEDDING_API_KEY ?? null,
1640
1825
  OPENAI_EMBEDDING_URL: env.OPENAI_EMBEDDING_URL ?? null,
1641
1826
  OPENAI_EMBEDDING_DIMENSIONS: env.OPENAI_EMBEDDING_DIMENSIONS ?? null,
1827
+ OPENAI_IMAGE_DESCRIPTION_API_KEY: env.OPENAI_IMAGE_DESCRIPTION_API_KEY ?? null,
1828
+ OPENAI_IMAGE_DESCRIPTION_BASE_URL: env.OPENAI_IMAGE_DESCRIPTION_BASE_URL ?? null,
1642
1829
  OPENAI_IMAGE_DESCRIPTION_MODEL: env.OPENAI_IMAGE_DESCRIPTION_MODEL ?? null,
1643
1830
  OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS: env.OPENAI_IMAGE_DESCRIPTION_MAX_TOKENS ?? null,
1644
1831
  OPENAI_EXPERIMENTAL_TELEMETRY: env.OPENAI_EXPERIMENTAL_TELEMETRY ?? null,
@@ -1647,18 +1834,19 @@ var openaiPlugin = {
1647
1834
  },
1648
1835
  async init(config, runtime) {
1649
1836
  initializeOpenAI(config, runtime);
1837
+ registerMediaModels(runtime);
1650
1838
  },
1651
1839
  models: {
1652
- [ModelType6.TEXT_EMBEDDING]: async (runtime, params) => {
1840
+ [ModelType5.TEXT_EMBEDDING]: async (runtime, params) => {
1653
1841
  return handleTextEmbedding(runtime, params);
1654
1842
  },
1655
- [ModelType6.TEXT_TOKENIZER_ENCODE]: async (runtime, params) => {
1843
+ [ModelType5.TEXT_TOKENIZER_ENCODE]: async (runtime, params) => {
1656
1844
  return handleTokenizerEncode(runtime, params);
1657
1845
  },
1658
- [ModelType6.TEXT_TOKENIZER_DECODE]: async (runtime, params) => {
1846
+ [ModelType5.TEXT_TOKENIZER_DECODE]: async (runtime, params) => {
1659
1847
  return handleTokenizerDecode(runtime, params);
1660
1848
  },
1661
- [ModelType6.TEXT_SMALL]: async (runtime, params) => {
1849
+ [ModelType5.TEXT_SMALL]: async (runtime, params) => {
1662
1850
  return handleTextSmall(runtime, params);
1663
1851
  },
1664
1852
  [TEXT_NANO_MODEL_TYPE2]: async (runtime, params) => {
@@ -1667,7 +1855,7 @@ var openaiPlugin = {
1667
1855
  [TEXT_MEDIUM_MODEL_TYPE2]: async (runtime, params) => {
1668
1856
  return handleTextMedium(runtime, params);
1669
1857
  },
1670
- [ModelType6.TEXT_LARGE]: async (runtime, params) => {
1858
+ [ModelType5.TEXT_LARGE]: async (runtime, params) => {
1671
1859
  return handleTextLarge(runtime, params);
1672
1860
  },
1673
1861
  [TEXT_MEGA_MODEL_TYPE2]: async (runtime, params) => {
@@ -1679,19 +1867,7 @@ var openaiPlugin = {
1679
1867
  [ACTION_PLANNER_MODEL_TYPE2]: async (runtime, params) => {
1680
1868
  return handleActionPlanner(runtime, params);
1681
1869
  },
1682
- [ModelType6.IMAGE]: async (runtime, params) => {
1683
- return handleImageGeneration(runtime, params);
1684
- },
1685
- [ModelType6.IMAGE_DESCRIPTION]: async (runtime, params) => {
1686
- return handleImageDescription(runtime, params);
1687
- },
1688
- [ModelType6.TRANSCRIPTION]: async (runtime, input) => {
1689
- return handleTranscription(runtime, input);
1690
- },
1691
- [ModelType6.TEXT_TO_SPEECH]: async (runtime, input) => {
1692
- return handleTextToSpeech(runtime, input);
1693
- },
1694
- [ModelType6.RESEARCH]: async (runtime, params) => {
1870
+ [ModelType5.RESEARCH]: async (runtime, params) => {
1695
1871
  return handleResearch(runtime, params);
1696
1872
  }
1697
1873
  },
@@ -1716,7 +1892,7 @@ var openaiPlugin = {
1716
1892
  {
1717
1893
  name: "openai_test_text_embedding",
1718
1894
  fn: async (runtime) => {
1719
- const embedding = await runtime.useModel(ModelType6.TEXT_EMBEDDING, {
1895
+ const embedding = await runtime.useModel(ModelType5.TEXT_EMBEDDING, {
1720
1896
  text: "Hello, world!"
1721
1897
  });
1722
1898
  if (!Array.isArray(embedding) || embedding.length === 0) {
@@ -1728,7 +1904,7 @@ var openaiPlugin = {
1728
1904
  {
1729
1905
  name: "openai_test_text_small",
1730
1906
  fn: async (runtime) => {
1731
- const text = await runtime.useModel(ModelType6.TEXT_SMALL, {
1907
+ const text = await runtime.useModel(ModelType5.TEXT_SMALL, {
1732
1908
  prompt: "Say hello in exactly 5 words."
1733
1909
  });
1734
1910
  if (typeof text !== "string" || text.length === 0) {
@@ -1740,7 +1916,7 @@ var openaiPlugin = {
1740
1916
  {
1741
1917
  name: "openai_test_text_large",
1742
1918
  fn: async (runtime) => {
1743
- const text = await runtime.useModel(ModelType6.TEXT_LARGE, {
1919
+ const text = await runtime.useModel(ModelType5.TEXT_LARGE, {
1744
1920
  prompt: "Explain quantum computing in 2 sentences."
1745
1921
  });
1746
1922
  if (typeof text !== "string" || text.length === 0) {
@@ -1753,16 +1929,16 @@ var openaiPlugin = {
1753
1929
  name: "openai_test_tokenizer_roundtrip",
1754
1930
  fn: async (runtime) => {
1755
1931
  const originalText = "Hello, tokenizer test!";
1756
- const tokens = await runtime.useModel(ModelType6.TEXT_TOKENIZER_ENCODE, {
1932
+ const tokens = await runtime.useModel(ModelType5.TEXT_TOKENIZER_ENCODE, {
1757
1933
  prompt: originalText,
1758
- modelType: ModelType6.TEXT_SMALL
1934
+ modelType: ModelType5.TEXT_SMALL
1759
1935
  });
1760
1936
  if (!Array.isArray(tokens) || tokens.length === 0) {
1761
1937
  throw new Error("Tokenization should return non-empty token array");
1762
1938
  }
1763
- const decodedText = await runtime.useModel(ModelType6.TEXT_TOKENIZER_DECODE, {
1939
+ const decodedText = await runtime.useModel(ModelType5.TEXT_TOKENIZER_DECODE, {
1764
1940
  tokens,
1765
- modelType: ModelType6.TEXT_SMALL
1941
+ modelType: ModelType5.TEXT_SMALL
1766
1942
  });
1767
1943
  if (decodedText !== originalText) {
1768
1944
  throw new Error(`Tokenizer roundtrip failed: expected "${originalText}", got "${decodedText}"`);
@@ -1774,7 +1950,7 @@ var openaiPlugin = {
1774
1950
  name: "openai_test_streaming",
1775
1951
  fn: async (runtime) => {
1776
1952
  const chunks = [];
1777
- const result = await runtime.useModel(ModelType6.TEXT_LARGE, {
1953
+ const result = await runtime.useModel(ModelType5.TEXT_LARGE, {
1778
1954
  prompt: "Count from 1 to 5, one number per line.",
1779
1955
  stream: true,
1780
1956
  onStreamChunk: (chunk) => {
@@ -1794,7 +1970,7 @@ var openaiPlugin = {
1794
1970
  name: "openai_test_image_description",
1795
1971
  fn: async (runtime) => {
1796
1972
  const testImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Camponotus_flavomarginatus_ant.jpg/440px-Camponotus_flavomarginatus_ant.jpg";
1797
- const result = await runtime.useModel(ModelType6.IMAGE_DESCRIPTION, testImageUrl);
1973
+ const result = await runtime.useModel(ModelType5.IMAGE_DESCRIPTION, testImageUrl);
1798
1974
  if (!result || typeof result !== "object" || !("title" in result) || !("description" in result)) {
1799
1975
  throw new Error("Image description should return { title, description }");
1800
1976
  }
@@ -1808,7 +1984,7 @@ var openaiPlugin = {
1808
1984
  const response = await fetch(audioUrl);
1809
1985
  const arrayBuffer = await response.arrayBuffer();
1810
1986
  const audioBuffer = Buffer.from(new Uint8Array(arrayBuffer));
1811
- const transcription = await runtime.useModel(ModelType6.TRANSCRIPTION, audioBuffer);
1987
+ const transcription = await runtime.useModel(ModelType5.TRANSCRIPTION, audioBuffer);
1812
1988
  if (typeof transcription !== "string") {
1813
1989
  throw new Error("Transcription should return a string");
1814
1990
  }
@@ -1818,7 +1994,7 @@ var openaiPlugin = {
1818
1994
  {
1819
1995
  name: "openai_test_text_to_speech",
1820
1996
  fn: async (runtime) => {
1821
- const audioData = await runtime.useModel(ModelType6.TEXT_TO_SPEECH, {
1997
+ const audioData = await runtime.useModel(ModelType5.TEXT_TO_SPEECH, {
1822
1998
  text: "Hello, this is a text-to-speech test."
1823
1999
  });
1824
2000
  if (!(audioData instanceof ArrayBuffer) || audioData.byteLength === 0) {
@@ -1830,7 +2006,7 @@ var openaiPlugin = {
1830
2006
  {
1831
2007
  name: "openai_test_structured_output_via_text_large",
1832
2008
  fn: async (runtime) => {
1833
- const result = await runtime.useModel(ModelType6.TEXT_LARGE, {
2009
+ const result = await runtime.useModel(ModelType5.TEXT_LARGE, {
1834
2010
  prompt: "Return a JSON object with exactly these fields: name (string), age (number), active (boolean)",
1835
2011
  responseSchema: {
1836
2012
  type: "object",
@@ -1851,7 +2027,7 @@ var openaiPlugin = {
1851
2027
  {
1852
2028
  name: "openai_test_research",
1853
2029
  fn: async (runtime) => {
1854
- const result = await runtime.useModel(ModelType6.RESEARCH, {
2030
+ const result = await runtime.useModel(ModelType5.RESEARCH, {
1855
2031
  input: "What is the current date and time?",
1856
2032
  tools: [{ type: "web_search_preview" }],
1857
2033
  maxToolCalls: 3
@@ -1862,7 +2038,7 @@ var openaiPlugin = {
1862
2038
  if (typeof result.text !== "string" || result.text.length === 0) {
1863
2039
  throw new Error("Research result text should be a non-empty string");
1864
2040
  }
1865
- logger9.info(`[OpenAI Test] Research completed. Text length: ${result.text.length}, Annotations: ${result.annotations?.length ?? 0}`);
2041
+ logger9.info(`[OpenAI Test] Research completed. Text length: ${result.text.length}, Annotations: ${result.annotations.length}`);
1866
2042
  }
1867
2043
  }
1868
2044
  ]
@@ -1878,4 +2054,4 @@ export {
1878
2054
  index_node_default as default
1879
2055
  };
1880
2056
 
1881
- //# debugId=D3370FEEF676E11164756E2164756E21
2057
+ //# debugId=BCCE52F3E7079C4E64756E2164756E21