@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.
- package/LICENSE +21 -0
- package/README.md +163 -0
- package/auto-enable.ts +17 -0
- package/dist/browser/index.browser.js +2 -2
- package/dist/browser/index.browser.js.map +12 -13
- package/dist/build.d.ts +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.node.cjs +1531 -1098
- package/dist/cjs/index.node.js.map +9 -8
- package/dist/generated/specs/specs.d.ts +27 -27
- package/dist/index.browser.d.ts +2 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.node.d.ts +2 -1
- package/dist/index.node.d.ts.map +1 -1
- package/dist/models/audio.d.ts.map +1 -1
- package/dist/models/embedding.d.ts.map +1 -1
- package/dist/models/image.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -2
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/object.d.ts.map +1 -1
- package/dist/models/research.d.ts.map +1 -1
- package/dist/models/text.d.ts +5 -0
- package/dist/models/text.d.ts.map +1 -1
- package/dist/node/index.node.js +832 -237
- package/dist/node/index.node.js.map +12 -13
- package/dist/types/index.d.ts +19 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/json.d.ts.map +1 -1
- package/package.json +30 -15
package/dist/node/index.node.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// index.ts
|
|
2
|
-
import { logger as
|
|
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
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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 (
|
|
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
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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
|
|
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
|
-
|
|
854
|
-
|
|
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
|
-
|
|
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
|
-
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
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
|
-
|
|
969
|
+
logger7.error(`[OpenAI] Research API error: ${data.error.message}`);
|
|
897
970
|
throw new Error(`Deep research error: ${data.error.message}`);
|
|
898
971
|
}
|
|
899
|
-
|
|
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
|
-
|
|
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 {
|
|
922
|
-
|
|
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:
|
|
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
|
-
|
|
948
|
-
const
|
|
949
|
-
const
|
|
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
|
-
|
|
1478
|
+
...promptOrMessages,
|
|
954
1479
|
system: systemPrompt,
|
|
1480
|
+
allowSystemInMessages: true,
|
|
955
1481
|
maxOutputTokens: params.maxTokens ?? 8192,
|
|
956
|
-
experimental_telemetry:
|
|
957
|
-
...
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
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
|
|
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:
|
|
970
|
-
text: Promise.resolve(
|
|
971
|
-
|
|
972
|
-
|
|
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
|
|
976
|
-
|
|
977
|
-
|
|
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,
|
|
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,
|
|
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
|
|
1540
|
+
import { ModelType as ModelType5 } from "@elizaos/core";
|
|
989
1541
|
|
|
990
1542
|
// utils/tokenization.ts
|
|
991
|
-
import { ModelType as
|
|
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 ===
|
|
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 ??
|
|
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 ??
|
|
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
|
-
[
|
|
1652
|
+
[ModelType6.TEXT_EMBEDDING]: async (runtime, params) => {
|
|
1079
1653
|
return handleTextEmbedding(runtime, params);
|
|
1080
1654
|
},
|
|
1081
|
-
[
|
|
1655
|
+
[ModelType6.TEXT_TOKENIZER_ENCODE]: async (runtime, params) => {
|
|
1082
1656
|
return handleTokenizerEncode(runtime, params);
|
|
1083
1657
|
},
|
|
1084
|
-
[
|
|
1658
|
+
[ModelType6.TEXT_TOKENIZER_DECODE]: async (runtime, params) => {
|
|
1085
1659
|
return handleTokenizerDecode(runtime, params);
|
|
1086
1660
|
},
|
|
1087
|
-
[
|
|
1661
|
+
[ModelType6.TEXT_SMALL]: async (runtime, params) => {
|
|
1088
1662
|
return handleTextSmall(runtime, params);
|
|
1089
1663
|
},
|
|
1090
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
1685
|
+
[ModelType6.IMAGE_DESCRIPTION]: async (runtime, params) => {
|
|
1097
1686
|
return handleImageDescription(runtime, params);
|
|
1098
1687
|
},
|
|
1099
|
-
[
|
|
1688
|
+
[ModelType6.TRANSCRIPTION]: async (runtime, input) => {
|
|
1100
1689
|
return handleTranscription(runtime, input);
|
|
1101
1690
|
},
|
|
1102
|
-
[
|
|
1691
|
+
[ModelType6.TEXT_TO_SPEECH]: async (runtime, input) => {
|
|
1103
1692
|
return handleTextToSpeech(runtime, input);
|
|
1104
1693
|
},
|
|
1105
|
-
[
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
1756
|
+
const tokens = await runtime.useModel(ModelType6.TEXT_TOKENIZER_ENCODE, {
|
|
1174
1757
|
prompt: originalText,
|
|
1175
|
-
modelType:
|
|
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(
|
|
1763
|
+
const decodedText = await runtime.useModel(ModelType6.TEXT_TOKENIZER_DECODE, {
|
|
1181
1764
|
tokens,
|
|
1182
|
-
modelType:
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
1827
|
+
logger9.info(`[OpenAI Test] TTS generated ${audioData.byteLength} bytes of audio`);
|
|
1245
1828
|
}
|
|
1246
1829
|
},
|
|
1247
1830
|
{
|
|
1248
|
-
name: "
|
|
1831
|
+
name: "openai_test_structured_output_via_text_large",
|
|
1249
1832
|
fn: async (runtime) => {
|
|
1250
|
-
const result = await runtime.useModel(
|
|
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("
|
|
1845
|
+
if (!result || typeof result !== "object" && typeof result !== "string") {
|
|
1846
|
+
throw new Error("Structured output should return an object or text");
|
|
1255
1847
|
}
|
|
1256
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1878
|
+
index_node_default as default
|
|
1284
1879
|
};
|
|
1285
1880
|
|
|
1286
|
-
//# debugId=
|
|
1881
|
+
//# debugId=D3370FEEF676E11164756E2164756E21
|