@elizaos/plugin-openrouter 1.5.17 → 2.0.0-alpha.2
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 +1 -1
- package/dist/browser/index.browser.js +319 -919
- package/dist/browser/index.browser.js.map +13 -15
- package/dist/cjs/index.node.cjs +320 -554
- package/dist/cjs/index.node.cjs.map +19 -0
- package/dist/index.d.ts +4 -6
- package/dist/node/index.node.js +319 -564
- package/dist/node/index.node.js.map +13 -14
- package/package.json +39 -22
- package/README.md +0 -122
- package/dist/cjs/index.node.js.map +0 -20
- package/dist/index.browser.d.ts +0 -2
- package/dist/index.node.d.ts +0 -2
- package/dist/init.d.ts +0 -6
- package/dist/models/embedding.d.ts +0 -5
- package/dist/models/image.d.ts +0 -14
- package/dist/models/index.d.ts +0 -4
- package/dist/models/object.d.ts +0 -9
- package/dist/models/text.d.ts +0 -17
- package/dist/providers/index.d.ts +0 -1
- package/dist/providers/openrouter.d.ts +0 -8
- package/dist/types/index.d.ts +0 -28
- package/dist/utils/config.d.ts +0 -64
- package/dist/utils/events.d.ts +0 -6
- package/dist/utils/helpers.d.ts +0 -21
- package/dist/utils/image-storage.d.ts +0 -8
- package/dist/utils/index.d.ts +0 -2
package/dist/node/index.node.js
CHANGED
|
@@ -1,71 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
1
|
+
// plugin.ts
|
|
21
2
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
logger as logger6,
|
|
4
|
+
ModelType as ModelType5
|
|
24
5
|
} from "@elizaos/core";
|
|
25
6
|
|
|
26
|
-
//
|
|
7
|
+
// init.ts
|
|
27
8
|
import { logger } from "@elizaos/core";
|
|
28
|
-
import { fetch as fetch2 } from "undici";
|
|
29
9
|
|
|
30
|
-
//
|
|
10
|
+
// utils/config.ts
|
|
11
|
+
var DEFAULT_BASE_URL = "https://openrouter.ai/api/v1";
|
|
12
|
+
var DEFAULT_SMALL_MODEL = "google/gemini-2.0-flash-001";
|
|
13
|
+
var DEFAULT_LARGE_MODEL = "google/gemini-2.5-flash";
|
|
14
|
+
var DEFAULT_IMAGE_MODEL = "x-ai/grok-2-vision-1212";
|
|
15
|
+
var DEFAULT_IMAGE_GENERATION_MODEL = "google/gemini-2.5-flash-image-preview";
|
|
16
|
+
var DEFAULT_EMBEDDING_MODEL = "openai/text-embedding-3-small";
|
|
17
|
+
var DEFAULT_EMBEDDING_DIMENSIONS = 1536;
|
|
18
|
+
function getEnvValue(key) {
|
|
19
|
+
if (typeof process === "undefined" || !process.env) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const value = process.env[key];
|
|
23
|
+
return value === undefined ? undefined : String(value);
|
|
24
|
+
}
|
|
31
25
|
function getSetting(runtime, key, defaultValue) {
|
|
32
26
|
const value = runtime.getSetting(key);
|
|
33
27
|
if (value !== undefined && value !== null) {
|
|
34
28
|
return String(value);
|
|
35
29
|
}
|
|
36
|
-
return
|
|
30
|
+
return getEnvValue(key) ?? defaultValue;
|
|
37
31
|
}
|
|
38
32
|
function getBaseURL(runtime) {
|
|
39
33
|
const browserURL = getSetting(runtime, "OPENROUTER_BROWSER_BASE_URL");
|
|
40
34
|
if (typeof globalThis !== "undefined" && globalThis.document && browserURL) {
|
|
41
35
|
return browserURL;
|
|
42
36
|
}
|
|
43
|
-
return getSetting(runtime, "OPENROUTER_BASE_URL",
|
|
37
|
+
return getSetting(runtime, "OPENROUTER_BASE_URL", DEFAULT_BASE_URL) || DEFAULT_BASE_URL;
|
|
44
38
|
}
|
|
45
39
|
function getApiKey(runtime) {
|
|
46
40
|
return getSetting(runtime, "OPENROUTER_API_KEY");
|
|
47
41
|
}
|
|
48
42
|
function getSmallModel(runtime) {
|
|
49
|
-
return getSetting(runtime, "OPENROUTER_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL",
|
|
43
|
+
return getSetting(runtime, "OPENROUTER_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", DEFAULT_SMALL_MODEL) ?? DEFAULT_SMALL_MODEL;
|
|
50
44
|
}
|
|
51
45
|
function getLargeModel(runtime) {
|
|
52
|
-
return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL",
|
|
46
|
+
return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", DEFAULT_LARGE_MODEL) ?? DEFAULT_LARGE_MODEL;
|
|
53
47
|
}
|
|
54
48
|
function getImageModel(runtime) {
|
|
55
|
-
return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL",
|
|
49
|
+
return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL", DEFAULT_IMAGE_MODEL) ?? DEFAULT_IMAGE_MODEL;
|
|
56
50
|
}
|
|
57
51
|
function getImageGenerationModel(runtime) {
|
|
58
|
-
return getSetting(runtime, "OPENROUTER_IMAGE_GENERATION_MODEL") ?? getSetting(runtime, "IMAGE_GENERATION_MODEL",
|
|
52
|
+
return getSetting(runtime, "OPENROUTER_IMAGE_GENERATION_MODEL") ?? getSetting(runtime, "IMAGE_GENERATION_MODEL", DEFAULT_IMAGE_GENERATION_MODEL) ?? DEFAULT_IMAGE_GENERATION_MODEL;
|
|
59
53
|
}
|
|
60
54
|
function getEmbeddingModel(runtime) {
|
|
61
|
-
return getSetting(runtime, "OPENROUTER_EMBEDDING_MODEL") ?? getSetting(runtime, "EMBEDDING_MODEL",
|
|
55
|
+
return getSetting(runtime, "OPENROUTER_EMBEDDING_MODEL") ?? getSetting(runtime, "EMBEDDING_MODEL", DEFAULT_EMBEDDING_MODEL) ?? DEFAULT_EMBEDDING_MODEL;
|
|
56
|
+
}
|
|
57
|
+
function getEmbeddingDimensions(runtime) {
|
|
58
|
+
const setting = getSetting(runtime, "OPENROUTER_EMBEDDING_DIMENSIONS") ?? getSetting(runtime, "EMBEDDING_DIMENSIONS");
|
|
59
|
+
return setting ? parseInt(setting, 10) : DEFAULT_EMBEDDING_DIMENSIONS;
|
|
62
60
|
}
|
|
63
61
|
function shouldAutoCleanupImages(runtime) {
|
|
64
62
|
const setting = getSetting(runtime, "OPENROUTER_AUTO_CLEANUP_IMAGES", "false");
|
|
65
63
|
return setting?.toLowerCase() === "true";
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
//
|
|
66
|
+
// init.ts
|
|
67
|
+
globalThis.AI_SDK_LOG_WARNINGS ??= false;
|
|
69
68
|
function initializeOpenRouter(_config, runtime) {
|
|
70
69
|
(async () => {
|
|
71
70
|
try {
|
|
@@ -77,463 +76,55 @@ function initializeOpenRouter(_config, runtime) {
|
|
|
77
76
|
logger.warn("OPENROUTER_API_KEY is not set in environment - OpenRouter functionality will be limited");
|
|
78
77
|
return;
|
|
79
78
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
} else {
|
|
89
|
-
logger.log("OpenRouter API key validated successfully");
|
|
90
|
-
}
|
|
91
|
-
} catch (fetchError) {
|
|
92
|
-
const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
93
|
-
logger.warn(`Error validating OpenRouter API key: ${message}`);
|
|
94
|
-
logger.warn("OpenRouter functionality will be limited until a valid API key is provided");
|
|
79
|
+
const baseURL = getBaseURL(runtime);
|
|
80
|
+
const response = await fetch(`${baseURL}/models`, {
|
|
81
|
+
headers: { Authorization: `Bearer ${getApiKey(runtime)}` }
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
logger.warn(`OpenRouter API key validation failed: ${response.statusText}`);
|
|
85
|
+
} else {
|
|
86
|
+
logger.log("OpenRouter API key validated successfully");
|
|
95
87
|
}
|
|
96
88
|
} catch (error) {
|
|
97
|
-
const message = error
|
|
98
|
-
logger.warn(`OpenRouter
|
|
89
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
90
|
+
logger.warn(`Error validating OpenRouter API key: ${message}`);
|
|
99
91
|
}
|
|
100
92
|
})();
|
|
101
|
-
return;
|
|
102
93
|
}
|
|
103
94
|
|
|
104
|
-
//
|
|
105
|
-
import { logger as
|
|
106
|
-
import { generateText, streamText } from "ai";
|
|
95
|
+
// models/embedding.ts
|
|
96
|
+
import { logger as logger3, ModelType, VECTOR_DIMS } from "@elizaos/core";
|
|
107
97
|
|
|
108
|
-
//
|
|
109
|
-
import {
|
|
110
|
-
function
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
// src/utils/events.ts
|
|
120
|
-
import {
|
|
121
|
-
EventType
|
|
122
|
-
} from "@elizaos/core";
|
|
123
|
-
function emitModelUsageEvent(runtime, type, prompt, usage) {
|
|
124
|
-
const truncatedPrompt = typeof prompt === "string" ? prompt.length > 200 ? `${prompt.slice(0, 200)}…` : prompt : "";
|
|
125
|
-
const inputTokens = Number(usage.inputTokens || 0);
|
|
126
|
-
const outputTokens = Number(usage.outputTokens || 0);
|
|
127
|
-
const totalTokens = Number(usage.totalTokens != null ? usage.totalTokens : inputTokens + outputTokens);
|
|
128
|
-
runtime.emitEvent(EventType.MODEL_USED, {
|
|
129
|
-
runtime,
|
|
130
|
-
source: "openrouter",
|
|
98
|
+
// utils/events.ts
|
|
99
|
+
import { logger as logger2 } from "@elizaos/core";
|
|
100
|
+
function emitModelUsageEvent(_runtime, modelType, prompt, usage) {
|
|
101
|
+
const inputTokens = usage.inputTokens ?? usage.promptTokens ?? 0;
|
|
102
|
+
const outputTokens = usage.outputTokens ?? usage.completionTokens ?? 0;
|
|
103
|
+
const totalTokens = usage.totalTokens ?? inputTokens + outputTokens;
|
|
104
|
+
logger2.debug({
|
|
105
|
+
event: "model:usage",
|
|
106
|
+
modelType,
|
|
131
107
|
provider: "openrouter",
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
108
|
+
prompt: prompt.substring(0, 100),
|
|
109
|
+
usage: {
|
|
110
|
+
promptTokens: inputTokens,
|
|
111
|
+
completionTokens: outputTokens,
|
|
112
|
+
totalTokens
|
|
113
|
+
},
|
|
114
|
+
timestamp: Date.now()
|
|
139
115
|
});
|
|
140
116
|
}
|
|
141
117
|
|
|
142
|
-
//
|
|
143
|
-
function buildGenerateParams(runtime, modelType, params) {
|
|
144
|
-
const { prompt, stopSequences = [] } = params;
|
|
145
|
-
const temperature = params.temperature ?? 0.7;
|
|
146
|
-
const frequencyPenalty = params.frequencyPenalty ?? 0.7;
|
|
147
|
-
const presencePenalty = params.presencePenalty ?? 0.7;
|
|
148
|
-
const resolvedMaxOutput = params.maxOutputTokens ?? params.maxTokens ?? 8192;
|
|
149
|
-
const openrouter = createOpenRouterProvider(runtime);
|
|
150
|
-
const modelName = modelType === ModelType.TEXT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
|
|
151
|
-
const modelLabel = modelType === ModelType.TEXT_SMALL ? "TEXT_SMALL" : "TEXT_LARGE";
|
|
152
|
-
const generateParams = {
|
|
153
|
-
model: openrouter.chat(modelName),
|
|
154
|
-
prompt,
|
|
155
|
-
system: runtime.character.system ?? undefined,
|
|
156
|
-
temperature,
|
|
157
|
-
frequencyPenalty,
|
|
158
|
-
presencePenalty,
|
|
159
|
-
stopSequences
|
|
160
|
-
};
|
|
161
|
-
generateParams.maxOutputTokens = resolvedMaxOutput;
|
|
162
|
-
return { generateParams, modelName, modelLabel, prompt };
|
|
163
|
-
}
|
|
164
|
-
function handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelLabel) {
|
|
165
|
-
logger2.debug(`[OpenRouter] Streaming text with ${modelLabel} model`);
|
|
166
|
-
const streamResult = streamText(generateParams);
|
|
167
|
-
return {
|
|
168
|
-
textStream: streamResult.textStream,
|
|
169
|
-
text: streamResult.text,
|
|
170
|
-
usage: streamResult.usage.then((usage) => {
|
|
171
|
-
if (usage) {
|
|
172
|
-
emitModelUsageEvent(runtime, modelType, prompt, usage);
|
|
173
|
-
const inputTokens = usage.inputTokens ?? 0;
|
|
174
|
-
const outputTokens = usage.outputTokens ?? 0;
|
|
175
|
-
return {
|
|
176
|
-
promptTokens: inputTokens,
|
|
177
|
-
completionTokens: outputTokens,
|
|
178
|
-
totalTokens: inputTokens + outputTokens
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
return;
|
|
182
|
-
}),
|
|
183
|
-
finishReason: streamResult.finishReason
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
async function generateTextWithModel(runtime, modelType, params) {
|
|
187
|
-
const { generateParams, modelName, modelLabel, prompt } = buildGenerateParams(runtime, modelType, params);
|
|
188
|
-
logger2.debug(`[OpenRouter] Generating text with ${modelLabel} model: ${modelName}`);
|
|
189
|
-
if (params.stream) {
|
|
190
|
-
return handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelLabel);
|
|
191
|
-
}
|
|
192
|
-
const response = await generateText(generateParams);
|
|
193
|
-
if (response.usage) {
|
|
194
|
-
emitModelUsageEvent(runtime, modelType, prompt, response.usage);
|
|
195
|
-
}
|
|
196
|
-
return response.text;
|
|
197
|
-
}
|
|
198
|
-
async function handleTextSmall(runtime, params) {
|
|
199
|
-
return generateTextWithModel(runtime, ModelType.TEXT_SMALL, params);
|
|
200
|
-
}
|
|
201
|
-
async function handleTextLarge(runtime, params) {
|
|
202
|
-
return generateTextWithModel(runtime, ModelType.TEXT_LARGE, params);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// src/models/object.ts
|
|
206
|
-
import {
|
|
207
|
-
ModelType as ModelType2,
|
|
208
|
-
logger as logger4
|
|
209
|
-
} from "@elizaos/core";
|
|
210
|
-
import { generateObject, jsonSchema } from "ai";
|
|
211
|
-
|
|
212
|
-
// src/utils/helpers.ts
|
|
213
|
-
import { logger as logger3 } from "@elizaos/core";
|
|
214
|
-
import { JSONParseError } from "ai";
|
|
215
|
-
function getJsonRepairFunction() {
|
|
216
|
-
return async ({ text, error }) => {
|
|
217
|
-
try {
|
|
218
|
-
if (error instanceof JSONParseError) {
|
|
219
|
-
const cleanedText = text.replace(/```json\n|\n```|```/g, "");
|
|
220
|
-
JSON.parse(cleanedText);
|
|
221
|
-
return cleanedText;
|
|
222
|
-
}
|
|
223
|
-
return null;
|
|
224
|
-
} catch (jsonError) {
|
|
225
|
-
const message = jsonError instanceof Error ? jsonError.message : String(jsonError);
|
|
226
|
-
logger3.warn(`Failed to repair JSON text: ${message}`);
|
|
227
|
-
return null;
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
function parseImageDescriptionResponse(responseText) {
|
|
232
|
-
try {
|
|
233
|
-
const jsonResponse = JSON.parse(responseText);
|
|
234
|
-
if (jsonResponse.title && jsonResponse.description) {
|
|
235
|
-
return jsonResponse;
|
|
236
|
-
}
|
|
237
|
-
} catch (e) {
|
|
238
|
-
logger3.debug(`Parsing as JSON failed, processing as text: ${e}`);
|
|
239
|
-
}
|
|
240
|
-
const titleMatch = responseText.match(/title[:\s]+(.+?)(?:\n|$)/i);
|
|
241
|
-
const title = titleMatch?.[1]?.trim() || "Image Analysis";
|
|
242
|
-
const description = responseText.replace(/title[:\s]+(.+?)(?:\n|$)/i, "").trim();
|
|
243
|
-
return { title, description };
|
|
244
|
-
}
|
|
245
|
-
async function handleObjectGenerationError(error) {
|
|
246
|
-
if (error instanceof JSONParseError) {
|
|
247
|
-
logger3.error(`[generateObject] Failed to parse JSON: ${error.message}`);
|
|
248
|
-
const repairFunction = getJsonRepairFunction();
|
|
249
|
-
const repairedJsonString = await repairFunction({
|
|
250
|
-
text: error.text,
|
|
251
|
-
error
|
|
252
|
-
});
|
|
253
|
-
if (repairedJsonString) {
|
|
254
|
-
try {
|
|
255
|
-
const repairedObject = JSON.parse(repairedJsonString);
|
|
256
|
-
logger3.log("[generateObject] Successfully repaired JSON.");
|
|
257
|
-
return repairedObject;
|
|
258
|
-
} catch (repairParseError) {
|
|
259
|
-
const message = repairParseError instanceof Error ? repairParseError.message : String(repairParseError);
|
|
260
|
-
logger3.error(`[generateObject] Failed to parse repaired JSON: ${message}`);
|
|
261
|
-
if (repairParseError instanceof Error)
|
|
262
|
-
throw repairParseError;
|
|
263
|
-
throw Object.assign(new Error(message), { cause: repairParseError });
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
logger3.error("[generateObject] JSON repair failed.");
|
|
267
|
-
throw error;
|
|
268
|
-
}
|
|
269
|
-
} else {
|
|
270
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
271
|
-
logger3.error(`[generateObject] Unknown error: ${message}`);
|
|
272
|
-
if (error instanceof Error)
|
|
273
|
-
throw error;
|
|
274
|
-
throw Object.assign(new Error(message), { cause: error });
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// src/models/object.ts
|
|
279
|
-
async function generateObjectWithModel(runtime, modelType, params) {
|
|
280
|
-
const openrouter = createOpenRouterProvider(runtime);
|
|
281
|
-
const modelName = modelType === ModelType2.OBJECT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
|
|
282
|
-
const modelLabel = modelType === ModelType2.OBJECT_SMALL ? "OBJECT_SMALL" : "OBJECT_LARGE";
|
|
283
|
-
logger4.log(`[OpenRouter] Using ${modelLabel} model: ${modelName}`);
|
|
284
|
-
const temperature = params.temperature ?? 0.7;
|
|
285
|
-
try {
|
|
286
|
-
const { object, usage } = await generateObject({
|
|
287
|
-
model: openrouter.chat(modelName),
|
|
288
|
-
...params.schema && { schema: jsonSchema(params.schema) },
|
|
289
|
-
output: params.schema ? "object" : "no-schema",
|
|
290
|
-
prompt: params.prompt,
|
|
291
|
-
temperature,
|
|
292
|
-
experimental_repairText: getJsonRepairFunction()
|
|
293
|
-
});
|
|
294
|
-
if (usage) {
|
|
295
|
-
emitModelUsageEvent(runtime, modelType, params.prompt, usage);
|
|
296
|
-
}
|
|
297
|
-
return object;
|
|
298
|
-
} catch (error) {
|
|
299
|
-
return handleObjectGenerationError(error);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
async function handleObjectSmall(runtime, params) {
|
|
303
|
-
return generateObjectWithModel(runtime, ModelType2.OBJECT_SMALL, params);
|
|
304
|
-
}
|
|
305
|
-
async function handleObjectLarge(runtime, params) {
|
|
306
|
-
return generateObjectWithModel(runtime, ModelType2.OBJECT_LARGE, params);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// src/models/image.ts
|
|
310
|
-
import {
|
|
311
|
-
logger as logger6
|
|
312
|
-
} from "@elizaos/core";
|
|
313
|
-
import { generateText as generateText2 } from "ai";
|
|
314
|
-
|
|
315
|
-
// src/utils/image-storage.ts
|
|
316
|
-
import { logger as logger5, getGeneratedDir } from "@elizaos/core";
|
|
317
|
-
function isBrowser() {
|
|
318
|
-
return typeof globalThis !== "undefined" && globalThis.document;
|
|
319
|
-
}
|
|
320
|
-
function sanitizeId(id) {
|
|
321
|
-
const src = (id ?? "").toString();
|
|
322
|
-
const normalized = src.normalize("NFKC");
|
|
323
|
-
let safe = normalized.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
324
|
-
safe = safe.replace(/_+/g, "_");
|
|
325
|
-
safe = safe.slice(0, 64);
|
|
326
|
-
safe = safe.replace(/^_+|_+$/g, "");
|
|
327
|
-
return safe || "agent";
|
|
328
|
-
}
|
|
329
|
-
function base64ToBytes(base64) {
|
|
330
|
-
const cleaned = base64.replace(/\s+/g, "");
|
|
331
|
-
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
332
|
-
const lookup = new Array(256).fill(-1);
|
|
333
|
-
for (let i = 0;i < chars.length; i++)
|
|
334
|
-
lookup[chars.charCodeAt(i)] = i;
|
|
335
|
-
const len = cleaned.length;
|
|
336
|
-
let pad = 0;
|
|
337
|
-
if (len >= 2 && cleaned[len - 1] === "=")
|
|
338
|
-
pad++;
|
|
339
|
-
if (len >= 2 && cleaned[len - 2] === "=")
|
|
340
|
-
pad++;
|
|
341
|
-
const outLen = (len * 3 >> 2) - pad;
|
|
342
|
-
const out = new Uint8Array(outLen);
|
|
343
|
-
let o = 0;
|
|
344
|
-
for (let i = 0;i < len; i += 4) {
|
|
345
|
-
const c0 = lookup[cleaned.charCodeAt(i)];
|
|
346
|
-
const c1 = lookup[cleaned.charCodeAt(i + 1)];
|
|
347
|
-
const c2 = lookup[cleaned.charCodeAt(i + 2)];
|
|
348
|
-
const c3 = lookup[cleaned.charCodeAt(i + 3)];
|
|
349
|
-
const n = c0 << 18 | c1 << 12 | (c2 & 63) << 6 | c3 & 63;
|
|
350
|
-
if (o < outLen)
|
|
351
|
-
out[o++] = n >> 16 & 255;
|
|
352
|
-
if (o < outLen)
|
|
353
|
-
out[o++] = n >> 8 & 255;
|
|
354
|
-
if (o < outLen)
|
|
355
|
-
out[o++] = n & 255;
|
|
356
|
-
}
|
|
357
|
-
return out;
|
|
358
|
-
}
|
|
359
|
-
async function saveBase64Image(base64Url, agentId, index = 0) {
|
|
360
|
-
if (isBrowser()) {
|
|
361
|
-
return null;
|
|
362
|
-
}
|
|
363
|
-
const m = base64Url.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=]+)$/);
|
|
364
|
-
if (!m)
|
|
365
|
-
return null;
|
|
366
|
-
const mime = m[1];
|
|
367
|
-
const base64Data = m[2];
|
|
368
|
-
const extMap = {
|
|
369
|
-
"image/png": "png",
|
|
370
|
-
"image/jpeg": "jpg",
|
|
371
|
-
"image/jpg": "jpg",
|
|
372
|
-
"image/webp": "webp",
|
|
373
|
-
"image/gif": "gif",
|
|
374
|
-
"image/bmp": "bmp",
|
|
375
|
-
"image/tiff": "tiff"
|
|
376
|
-
};
|
|
377
|
-
const extension = extMap[mime];
|
|
378
|
-
if (!extension)
|
|
379
|
-
return null;
|
|
380
|
-
const { join } = await import("node:path");
|
|
381
|
-
const safeAgentId = sanitizeId(agentId);
|
|
382
|
-
const baseDir = join(getGeneratedDir(), safeAgentId);
|
|
383
|
-
const { existsSync } = await import("node:fs");
|
|
384
|
-
if (!existsSync(baseDir)) {
|
|
385
|
-
const { mkdir } = await import("node:fs/promises");
|
|
386
|
-
await mkdir(baseDir, { recursive: true });
|
|
387
|
-
}
|
|
388
|
-
const timestamp = Date.now();
|
|
389
|
-
const filename = `image_${timestamp}_${index}.${extension}`;
|
|
390
|
-
const filepath = join(baseDir, filename);
|
|
391
|
-
const buffer = base64ToBytes(base64Data);
|
|
392
|
-
const { writeFile } = await import("node:fs/promises");
|
|
393
|
-
await writeFile(filepath, buffer);
|
|
394
|
-
logger5.info(`[OpenRouter] Saved generated image to ${filepath}`);
|
|
395
|
-
return filepath;
|
|
396
|
-
}
|
|
397
|
-
function deleteImage(filepath) {
|
|
398
|
-
if (isBrowser()) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
try {
|
|
402
|
-
(async () => {
|
|
403
|
-
const { existsSync, unlinkSync } = await import("node:fs");
|
|
404
|
-
if (existsSync(filepath)) {
|
|
405
|
-
unlinkSync(filepath);
|
|
406
|
-
logger5.debug(`[OpenRouter] Deleted image: ${filepath}`);
|
|
407
|
-
}
|
|
408
|
-
})().catch((error) => {
|
|
409
|
-
logger5.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
|
|
410
|
-
});
|
|
411
|
-
} catch (error) {
|
|
412
|
-
logger5.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// src/models/image.ts
|
|
417
|
-
async function handleImageDescription(runtime, params) {
|
|
418
|
-
let imageUrl;
|
|
419
|
-
let promptText;
|
|
420
|
-
const modelName = getImageModel(runtime);
|
|
421
|
-
logger6.log(`[OpenRouter] Using IMAGE_DESCRIPTION model: ${modelName}`);
|
|
422
|
-
const maxOutputTokens = 300;
|
|
423
|
-
if (typeof params === "string") {
|
|
424
|
-
imageUrl = params;
|
|
425
|
-
promptText = "Please analyze this image and provide a title and detailed description.";
|
|
426
|
-
} else {
|
|
427
|
-
imageUrl = params.imageUrl;
|
|
428
|
-
promptText = params.prompt || "Please analyze this image and provide a title and detailed description.";
|
|
429
|
-
}
|
|
430
|
-
const openrouter = createOpenRouterProvider(runtime);
|
|
431
|
-
const messages = [
|
|
432
|
-
{
|
|
433
|
-
role: "user",
|
|
434
|
-
content: [
|
|
435
|
-
{ type: "text", text: promptText },
|
|
436
|
-
{ type: "image", image: imageUrl }
|
|
437
|
-
]
|
|
438
|
-
}
|
|
439
|
-
];
|
|
440
|
-
try {
|
|
441
|
-
const model = openrouter.chat(modelName);
|
|
442
|
-
const { text: responseText } = await generateText2({
|
|
443
|
-
model,
|
|
444
|
-
messages,
|
|
445
|
-
maxOutputTokens
|
|
446
|
-
});
|
|
447
|
-
return parseImageDescriptionResponse(responseText);
|
|
448
|
-
} catch (error) {
|
|
449
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
450
|
-
logger6.error(`Error analyzing image: ${message}`);
|
|
451
|
-
return {
|
|
452
|
-
title: "Failed to analyze image",
|
|
453
|
-
description: `Error: ${message}`
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
async function handleImageGeneration(runtime, params) {
|
|
458
|
-
const modelName = getImageGenerationModel(runtime);
|
|
459
|
-
logger6.log(`[OpenRouter] Using IMAGE_GENERATION model: ${modelName}`);
|
|
460
|
-
const apiKey = getApiKey(runtime);
|
|
461
|
-
try {
|
|
462
|
-
const baseUrl = getBaseURL(runtime);
|
|
463
|
-
const isBrowser2 = typeof globalThis !== "undefined" && globalThis.document;
|
|
464
|
-
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
465
|
-
method: "POST",
|
|
466
|
-
headers: {
|
|
467
|
-
...isBrowser2 ? {} : { Authorization: `Bearer ${apiKey}` },
|
|
468
|
-
"Content-Type": "application/json"
|
|
469
|
-
},
|
|
470
|
-
body: JSON.stringify({
|
|
471
|
-
model: modelName,
|
|
472
|
-
messages: [
|
|
473
|
-
{
|
|
474
|
-
role: "user",
|
|
475
|
-
content: params.prompt
|
|
476
|
-
}
|
|
477
|
-
],
|
|
478
|
-
modalities: ["image", "text"]
|
|
479
|
-
}),
|
|
480
|
-
signal: AbortSignal.timeout ? AbortSignal.timeout(60000) : undefined
|
|
481
|
-
});
|
|
482
|
-
if (!response.ok) {
|
|
483
|
-
const errorText = await response.text().catch(() => "");
|
|
484
|
-
throw new Error(`HTTP ${response.status} ${response.statusText} ${errorText}`);
|
|
485
|
-
}
|
|
486
|
-
const result = await response.json();
|
|
487
|
-
const images = [];
|
|
488
|
-
const savedPaths = [];
|
|
489
|
-
if (result.choices?.[0]?.message?.images) {
|
|
490
|
-
for (const [index, image] of result.choices[0].message.images.entries()) {
|
|
491
|
-
const base64Url = image.image_url.url;
|
|
492
|
-
const filepath = await saveBase64Image(base64Url, runtime.agentId, index);
|
|
493
|
-
if (filepath) {
|
|
494
|
-
logger6.log(`[OpenRouter] Returning image with filepath: ${filepath}`);
|
|
495
|
-
images.push({
|
|
496
|
-
url: filepath
|
|
497
|
-
});
|
|
498
|
-
savedPaths.push(filepath);
|
|
499
|
-
} else if (!base64Url.startsWith("data:")) {
|
|
500
|
-
images.push({ url: base64Url });
|
|
501
|
-
} else {
|
|
502
|
-
logger6.warn(`[OpenRouter] Failed to save image ${index + 1}, skipping`);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
if (savedPaths.length > 0 && shouldAutoCleanupImages(runtime)) {
|
|
507
|
-
setTimeout(() => {
|
|
508
|
-
savedPaths.forEach((path) => {
|
|
509
|
-
deleteImage(path);
|
|
510
|
-
});
|
|
511
|
-
}, 30000);
|
|
512
|
-
}
|
|
513
|
-
if (images.length === 0) {
|
|
514
|
-
throw new Error("No images generated in response");
|
|
515
|
-
}
|
|
516
|
-
logger6.log(`[OpenRouter] Generated ${images.length} image(s)`);
|
|
517
|
-
return images;
|
|
518
|
-
} catch (error) {
|
|
519
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
520
|
-
logger6.error(`[OpenRouter] Error generating image: ${message}`);
|
|
521
|
-
return [];
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// src/models/embedding.ts
|
|
526
|
-
import { logger as logger7, ModelType as ModelType3, VECTOR_DIMS } from "@elizaos/core";
|
|
118
|
+
// models/embedding.ts
|
|
527
119
|
async function handleTextEmbedding(runtime, params) {
|
|
528
120
|
const embeddingModelName = getEmbeddingModel(runtime);
|
|
529
121
|
const embeddingDimension = Number.parseInt(getSetting(runtime, "OPENROUTER_EMBEDDING_DIMENSIONS") ?? getSetting(runtime, "EMBEDDING_DIMENSIONS") ?? "1536", 10);
|
|
530
122
|
if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {
|
|
531
123
|
const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(", ")}`;
|
|
532
|
-
|
|
124
|
+
logger3.error(errorMsg);
|
|
533
125
|
throw new Error(errorMsg);
|
|
534
126
|
}
|
|
535
127
|
if (params === null) {
|
|
536
|
-
logger7.debug("Creating test embedding for initialization");
|
|
537
128
|
const testVector = Array(embeddingDimension).fill(0);
|
|
538
129
|
testVector[0] = 0.1;
|
|
539
130
|
return testVector;
|
|
@@ -545,14 +136,14 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
545
136
|
text = params.text;
|
|
546
137
|
} else {
|
|
547
138
|
const errorMsg = "Invalid input format for embedding";
|
|
548
|
-
|
|
139
|
+
logger3.warn(errorMsg);
|
|
549
140
|
const fallbackVector = Array(embeddingDimension).fill(0);
|
|
550
141
|
fallbackVector[0] = 0.2;
|
|
551
142
|
return fallbackVector;
|
|
552
143
|
}
|
|
553
144
|
if (!text.trim()) {
|
|
554
145
|
const errorMsg = "Empty text for embedding";
|
|
555
|
-
|
|
146
|
+
logger3.warn(errorMsg);
|
|
556
147
|
const fallbackVector = Array(embeddingDimension).fill(0);
|
|
557
148
|
fallbackVector[0] = 0.3;
|
|
558
149
|
return fallbackVector;
|
|
@@ -560,7 +151,7 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
560
151
|
const apiKey = getApiKey(runtime);
|
|
561
152
|
if (!apiKey) {
|
|
562
153
|
const errorMsg = "OPENROUTER_API_KEY is not set";
|
|
563
|
-
|
|
154
|
+
logger3.error(errorMsg);
|
|
564
155
|
throw new Error(errorMsg);
|
|
565
156
|
}
|
|
566
157
|
const baseURL = getBaseURL(runtime);
|
|
@@ -579,18 +170,18 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
579
170
|
})
|
|
580
171
|
});
|
|
581
172
|
if (!response.ok) {
|
|
582
|
-
|
|
173
|
+
logger3.error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
|
|
583
174
|
throw new Error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
|
|
584
175
|
}
|
|
585
176
|
const data = await response.json();
|
|
586
177
|
if (!data?.data?.[0]?.embedding) {
|
|
587
|
-
|
|
178
|
+
logger3.error("API returned invalid structure");
|
|
588
179
|
throw new Error("API returned invalid structure");
|
|
589
180
|
}
|
|
590
181
|
const embedding = data.data[0].embedding;
|
|
591
182
|
if (!Array.isArray(embedding) || embedding.length !== embeddingDimension) {
|
|
592
183
|
const errorMsg = `Embedding length ${embedding?.length ?? 0} does not match configured dimension ${embeddingDimension}`;
|
|
593
|
-
|
|
184
|
+
logger3.error(errorMsg);
|
|
594
185
|
const fallbackVector = Array(embeddingDimension).fill(0);
|
|
595
186
|
fallbackVector[0] = 0.4;
|
|
596
187
|
return fallbackVector;
|
|
@@ -601,61 +192,251 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
601
192
|
outputTokens: 0,
|
|
602
193
|
totalTokens: data.usage.total_tokens
|
|
603
194
|
};
|
|
604
|
-
emitModelUsageEvent(runtime,
|
|
195
|
+
emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage);
|
|
605
196
|
}
|
|
606
|
-
logger7.log(`Got valid embedding with length ${embedding.length}`);
|
|
607
197
|
return embedding;
|
|
608
198
|
} catch (error) {
|
|
609
199
|
const message = error instanceof Error ? error.message : String(error);
|
|
610
|
-
|
|
200
|
+
logger3.error(`Error generating embedding: ${message}`);
|
|
201
|
+
throw error instanceof Error ? error : new Error(message);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// models/image.ts
|
|
206
|
+
import { logger as logger4, ModelType as ModelType2 } from "@elizaos/core";
|
|
207
|
+
import { generateText } from "ai";
|
|
208
|
+
|
|
209
|
+
// providers/openrouter.ts
|
|
210
|
+
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
211
|
+
function createOpenRouterProvider(runtime) {
|
|
212
|
+
const apiKey = getApiKey(runtime);
|
|
213
|
+
const isBrowser = typeof globalThis !== "undefined" && globalThis.document;
|
|
214
|
+
const baseURL = getBaseURL(runtime);
|
|
215
|
+
return createOpenRouter({
|
|
216
|
+
apiKey: isBrowser ? undefined : apiKey,
|
|
217
|
+
baseURL
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
// models/image.ts
|
|
221
|
+
async function handleImageDescription(runtime, params) {
|
|
222
|
+
const openrouter = createOpenRouterProvider(runtime);
|
|
223
|
+
const modelName = getImageModel(runtime);
|
|
224
|
+
const imageUrl = typeof params === "string" ? params : params.imageUrl;
|
|
225
|
+
const prompt = typeof params === "string" ? "Describe this image" : params.prompt || "Describe this image";
|
|
226
|
+
try {
|
|
227
|
+
const generateParams = {
|
|
228
|
+
model: openrouter.chat(modelName),
|
|
229
|
+
messages: [
|
|
230
|
+
{
|
|
231
|
+
role: "user",
|
|
232
|
+
content: [
|
|
233
|
+
{ type: "text", text: prompt },
|
|
234
|
+
{ type: "image", image: imageUrl }
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
};
|
|
239
|
+
const response = await generateText(generateParams);
|
|
240
|
+
if (response.usage) {
|
|
241
|
+
emitModelUsageEvent(runtime, ModelType2.IMAGE_DESCRIPTION, prompt, response.usage);
|
|
242
|
+
}
|
|
243
|
+
return response.text;
|
|
244
|
+
} catch (error) {
|
|
245
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
246
|
+
logger4.error(`Error describing image: ${message}`);
|
|
247
|
+
throw error instanceof Error ? error : new Error(message);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async function handleImageGeneration(runtime, params) {
|
|
251
|
+
const openrouter = createOpenRouterProvider(runtime);
|
|
252
|
+
const modelName = getImageGenerationModel(runtime);
|
|
253
|
+
try {
|
|
254
|
+
const generateParams = {
|
|
255
|
+
model: openrouter.chat(modelName),
|
|
256
|
+
prompt: `Generate an image: ${params.prompt}`
|
|
257
|
+
};
|
|
258
|
+
const response = await generateText(generateParams);
|
|
259
|
+
if (response.usage) {
|
|
260
|
+
emitModelUsageEvent(runtime, ModelType2.IMAGE, params.prompt, response.usage);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
imageUrl: response.text,
|
|
264
|
+
caption: params.prompt
|
|
265
|
+
};
|
|
266
|
+
} catch (error) {
|
|
267
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
268
|
+
logger4.error(`Error generating image: ${message}`);
|
|
611
269
|
throw error instanceof Error ? error : new Error(message);
|
|
612
270
|
}
|
|
613
271
|
}
|
|
614
272
|
|
|
615
|
-
//
|
|
273
|
+
// models/object.ts
|
|
274
|
+
import {
|
|
275
|
+
ModelType as ModelType3
|
|
276
|
+
} from "@elizaos/core";
|
|
277
|
+
import { generateObject, jsonSchema } from "ai";
|
|
278
|
+
|
|
279
|
+
// utils/helpers.ts
|
|
280
|
+
import { logger as logger5 } from "@elizaos/core";
|
|
281
|
+
function handleObjectGenerationError(error) {
|
|
282
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
283
|
+
logger5.error(`Error generating object: ${message}`);
|
|
284
|
+
return { error: message };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// models/object.ts
|
|
288
|
+
async function generateObjectWithModel(runtime, modelType, params) {
|
|
289
|
+
const openrouter = createOpenRouterProvider(runtime);
|
|
290
|
+
const modelName = modelType === ModelType3.OBJECT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
|
|
291
|
+
const temperature = params.temperature ?? 0.7;
|
|
292
|
+
try {
|
|
293
|
+
const generateParams = {
|
|
294
|
+
model: openrouter.chat(modelName),
|
|
295
|
+
...params.schema && {
|
|
296
|
+
schema: jsonSchema(params.schema)
|
|
297
|
+
},
|
|
298
|
+
output: params.schema ? "object" : "no-schema",
|
|
299
|
+
prompt: params.prompt,
|
|
300
|
+
temperature
|
|
301
|
+
};
|
|
302
|
+
const { object, usage } = await generateObject(generateParams);
|
|
303
|
+
if (usage) {
|
|
304
|
+
emitModelUsageEvent(runtime, modelType, params.prompt, usage);
|
|
305
|
+
}
|
|
306
|
+
return object;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
return handleObjectGenerationError(error);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async function handleObjectSmall(runtime, params) {
|
|
312
|
+
return generateObjectWithModel(runtime, ModelType3.OBJECT_SMALL, params);
|
|
313
|
+
}
|
|
314
|
+
async function handleObjectLarge(runtime, params) {
|
|
315
|
+
return generateObjectWithModel(runtime, ModelType3.OBJECT_LARGE, params);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// models/text.ts
|
|
319
|
+
import { ModelType as ModelType4 } from "@elizaos/core";
|
|
320
|
+
import { generateText as generateText2, streamText } from "ai";
|
|
321
|
+
function buildGenerateParams(runtime, modelType, params) {
|
|
322
|
+
const { prompt, stopSequences = [] } = params;
|
|
323
|
+
const temperature = params.temperature ?? 0.7;
|
|
324
|
+
const frequencyPenalty = params.frequencyPenalty ?? 0.7;
|
|
325
|
+
const presencePenalty = params.presencePenalty ?? 0.7;
|
|
326
|
+
const paramsWithMax = params;
|
|
327
|
+
const resolvedMaxOutput = paramsWithMax.maxOutputTokens ?? paramsWithMax.maxTokens ?? 8192;
|
|
328
|
+
const openrouter = createOpenRouterProvider(runtime);
|
|
329
|
+
const modelName = modelType === ModelType4.TEXT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
|
|
330
|
+
const modelLabel = modelType === ModelType4.TEXT_SMALL ? "TEXT_SMALL" : "TEXT_LARGE";
|
|
331
|
+
const generateParams = {
|
|
332
|
+
model: openrouter.chat(modelName),
|
|
333
|
+
prompt,
|
|
334
|
+
system: runtime.character?.system ?? undefined,
|
|
335
|
+
temperature,
|
|
336
|
+
frequencyPenalty,
|
|
337
|
+
presencePenalty,
|
|
338
|
+
stopSequences,
|
|
339
|
+
maxOutputTokens: resolvedMaxOutput
|
|
340
|
+
};
|
|
341
|
+
return { generateParams, modelName, modelLabel, prompt };
|
|
342
|
+
}
|
|
343
|
+
function handleStreamingGeneration(runtime, modelType, generateParams, prompt, _modelLabel) {
|
|
344
|
+
const streamResult = streamText(generateParams);
|
|
345
|
+
return {
|
|
346
|
+
textStream: streamResult.textStream,
|
|
347
|
+
text: Promise.resolve(streamResult.text),
|
|
348
|
+
usage: Promise.resolve(streamResult.usage).then((usage) => {
|
|
349
|
+
if (usage) {
|
|
350
|
+
emitModelUsageEvent(runtime, modelType, prompt, usage);
|
|
351
|
+
const inputTokens = usage.inputTokens ?? 0;
|
|
352
|
+
const outputTokens = usage.outputTokens ?? 0;
|
|
353
|
+
return {
|
|
354
|
+
promptTokens: inputTokens,
|
|
355
|
+
completionTokens: outputTokens,
|
|
356
|
+
totalTokens: inputTokens + outputTokens
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
return;
|
|
360
|
+
}),
|
|
361
|
+
finishReason: Promise.resolve(streamResult.finishReason)
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
async function generateTextWithModel(runtime, modelType, params) {
|
|
365
|
+
const {
|
|
366
|
+
generateParams,
|
|
367
|
+
modelName: _modelName,
|
|
368
|
+
modelLabel,
|
|
369
|
+
prompt
|
|
370
|
+
} = buildGenerateParams(runtime, modelType, params);
|
|
371
|
+
if (params.stream) {
|
|
372
|
+
return handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelLabel);
|
|
373
|
+
}
|
|
374
|
+
const response = await generateText2(generateParams);
|
|
375
|
+
if (response.usage) {
|
|
376
|
+
emitModelUsageEvent(runtime, modelType, prompt, response.usage);
|
|
377
|
+
}
|
|
378
|
+
return response.text;
|
|
379
|
+
}
|
|
380
|
+
async function handleTextSmall(runtime, params) {
|
|
381
|
+
return generateTextWithModel(runtime, ModelType4.TEXT_SMALL, params);
|
|
382
|
+
}
|
|
383
|
+
async function handleTextLarge(runtime, params) {
|
|
384
|
+
return generateTextWithModel(runtime, ModelType4.TEXT_LARGE, params);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// plugin.ts
|
|
388
|
+
function getProcessEnv() {
|
|
389
|
+
if (typeof process === "undefined" || !process.env) {
|
|
390
|
+
return {};
|
|
391
|
+
}
|
|
392
|
+
return process.env;
|
|
393
|
+
}
|
|
394
|
+
var env = getProcessEnv();
|
|
616
395
|
var openrouterPlugin = {
|
|
617
396
|
name: "openrouter",
|
|
618
|
-
description: "OpenRouter plugin",
|
|
397
|
+
description: "OpenRouter multi-model AI gateway plugin",
|
|
619
398
|
config: {
|
|
620
|
-
OPENROUTER_API_KEY:
|
|
621
|
-
OPENROUTER_BASE_URL:
|
|
622
|
-
OPENROUTER_SMALL_MODEL:
|
|
623
|
-
OPENROUTER_LARGE_MODEL:
|
|
624
|
-
OPENROUTER_IMAGE_MODEL:
|
|
625
|
-
OPENROUTER_IMAGE_GENERATION_MODEL:
|
|
626
|
-
OPENROUTER_EMBEDDING_MODEL:
|
|
627
|
-
OPENROUTER_EMBEDDING_DIMENSIONS:
|
|
628
|
-
OPENROUTER_AUTO_CLEANUP_IMAGES:
|
|
629
|
-
SMALL_MODEL:
|
|
630
|
-
LARGE_MODEL:
|
|
631
|
-
IMAGE_MODEL:
|
|
632
|
-
IMAGE_GENERATION_MODEL:
|
|
633
|
-
EMBEDDING_MODEL:
|
|
634
|
-
EMBEDDING_DIMENSIONS:
|
|
399
|
+
OPENROUTER_API_KEY: env.OPENROUTER_API_KEY ?? null,
|
|
400
|
+
OPENROUTER_BASE_URL: env.OPENROUTER_BASE_URL ?? null,
|
|
401
|
+
OPENROUTER_SMALL_MODEL: env.OPENROUTER_SMALL_MODEL ?? null,
|
|
402
|
+
OPENROUTER_LARGE_MODEL: env.OPENROUTER_LARGE_MODEL ?? null,
|
|
403
|
+
OPENROUTER_IMAGE_MODEL: env.OPENROUTER_IMAGE_MODEL ?? null,
|
|
404
|
+
OPENROUTER_IMAGE_GENERATION_MODEL: env.OPENROUTER_IMAGE_GENERATION_MODEL ?? null,
|
|
405
|
+
OPENROUTER_EMBEDDING_MODEL: env.OPENROUTER_EMBEDDING_MODEL ?? null,
|
|
406
|
+
OPENROUTER_EMBEDDING_DIMENSIONS: env.OPENROUTER_EMBEDDING_DIMENSIONS ?? null,
|
|
407
|
+
OPENROUTER_AUTO_CLEANUP_IMAGES: env.OPENROUTER_AUTO_CLEANUP_IMAGES ?? null,
|
|
408
|
+
SMALL_MODEL: env.SMALL_MODEL ?? null,
|
|
409
|
+
LARGE_MODEL: env.LARGE_MODEL ?? null,
|
|
410
|
+
IMAGE_MODEL: env.IMAGE_MODEL ?? null,
|
|
411
|
+
IMAGE_GENERATION_MODEL: env.IMAGE_GENERATION_MODEL ?? null,
|
|
412
|
+
EMBEDDING_MODEL: env.EMBEDDING_MODEL ?? null,
|
|
413
|
+
EMBEDDING_DIMENSIONS: env.EMBEDDING_DIMENSIONS ?? null
|
|
635
414
|
},
|
|
636
415
|
async init(config, runtime) {
|
|
637
416
|
initializeOpenRouter(config, runtime);
|
|
638
417
|
},
|
|
639
418
|
models: {
|
|
640
|
-
[
|
|
419
|
+
[ModelType5.TEXT_SMALL]: async (runtime, params) => {
|
|
641
420
|
return handleTextSmall(runtime, params);
|
|
642
421
|
},
|
|
643
|
-
[
|
|
422
|
+
[ModelType5.TEXT_LARGE]: async (runtime, params) => {
|
|
644
423
|
return handleTextLarge(runtime, params);
|
|
645
424
|
},
|
|
646
|
-
[
|
|
425
|
+
[ModelType5.OBJECT_SMALL]: async (runtime, params) => {
|
|
647
426
|
return handleObjectSmall(runtime, params);
|
|
648
427
|
},
|
|
649
|
-
[
|
|
428
|
+
[ModelType5.OBJECT_LARGE]: async (runtime, params) => {
|
|
650
429
|
return handleObjectLarge(runtime, params);
|
|
651
430
|
},
|
|
652
|
-
[
|
|
653
|
-
|
|
431
|
+
[ModelType5.IMAGE_DESCRIPTION]: async (runtime, params) => {
|
|
432
|
+
const description = await handleImageDescription(runtime, params);
|
|
433
|
+
return { title: "", description };
|
|
654
434
|
},
|
|
655
|
-
[
|
|
656
|
-
|
|
435
|
+
[ModelType5.IMAGE]: async (runtime, params) => {
|
|
436
|
+
const result = await handleImageGeneration(runtime, params);
|
|
437
|
+
return [{ url: result.imageUrl }];
|
|
657
438
|
},
|
|
658
|
-
[
|
|
439
|
+
[ModelType5.TEXT_EMBEDDING]: async (runtime, params) => {
|
|
659
440
|
return handleTextEmbedding(runtime, params);
|
|
660
441
|
}
|
|
661
442
|
},
|
|
@@ -667,16 +448,16 @@ var openrouterPlugin = {
|
|
|
667
448
|
name: "openrouter_test_text_small",
|
|
668
449
|
fn: async (runtime) => {
|
|
669
450
|
try {
|
|
670
|
-
const text = await runtime.useModel(
|
|
451
|
+
const text = await runtime.useModel(ModelType5.TEXT_SMALL, {
|
|
671
452
|
prompt: "What is the nature of reality in 10 words?"
|
|
672
453
|
});
|
|
673
454
|
if (text.length === 0) {
|
|
674
455
|
throw new Error("Failed to generate text");
|
|
675
456
|
}
|
|
676
|
-
|
|
457
|
+
logger6.log({ text }, "generated with test_text_small");
|
|
677
458
|
} catch (error) {
|
|
678
459
|
const message = error instanceof Error ? error.message : String(error);
|
|
679
|
-
|
|
460
|
+
logger6.error(`Error in test_text_small: ${message}`);
|
|
680
461
|
throw error;
|
|
681
462
|
}
|
|
682
463
|
}
|
|
@@ -685,59 +466,16 @@ var openrouterPlugin = {
|
|
|
685
466
|
name: "openrouter_test_text_large",
|
|
686
467
|
fn: async (runtime) => {
|
|
687
468
|
try {
|
|
688
|
-
const text = await runtime.useModel(
|
|
469
|
+
const text = await runtime.useModel(ModelType5.TEXT_LARGE, {
|
|
689
470
|
prompt: "What is the nature of reality in 10 words?"
|
|
690
471
|
});
|
|
691
472
|
if (text.length === 0) {
|
|
692
473
|
throw new Error("Failed to generate text");
|
|
693
474
|
}
|
|
694
|
-
|
|
695
|
-
} catch (error) {
|
|
696
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
697
|
-
logger8.error(`Error in test_text_large: ${message}`);
|
|
698
|
-
throw error;
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
},
|
|
702
|
-
{
|
|
703
|
-
name: "openrouter_test_text_generation_large",
|
|
704
|
-
fn: async (runtime) => {
|
|
705
|
-
try {
|
|
706
|
-
const result = await runtime.useModel(ModelType4.TEXT_LARGE, {
|
|
707
|
-
prompt: "Say hello in 5 words."
|
|
708
|
-
});
|
|
709
|
-
if (!result || result.length === 0) {
|
|
710
|
-
throw new Error("Text generation returned empty result");
|
|
711
|
-
}
|
|
712
|
-
logger8.log({ result }, "Text generation test completed");
|
|
713
|
-
} catch (error) {
|
|
714
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
715
|
-
logger8.error(`Error in openrouter_test_text_generation_large: ${message}`);
|
|
716
|
-
throw error;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
},
|
|
720
|
-
{
|
|
721
|
-
name: "openrouter_test_streaming",
|
|
722
|
-
fn: async (runtime) => {
|
|
723
|
-
try {
|
|
724
|
-
const chunks = [];
|
|
725
|
-
const result = await runtime.useModel(ModelType4.TEXT_LARGE, {
|
|
726
|
-
prompt: "Count from 1 to 5.",
|
|
727
|
-
onStreamChunk: (chunk) => {
|
|
728
|
-
chunks.push(chunk);
|
|
729
|
-
}
|
|
730
|
-
});
|
|
731
|
-
if (!result || result.length === 0) {
|
|
732
|
-
throw new Error("Streaming returned empty result");
|
|
733
|
-
}
|
|
734
|
-
if (chunks.length === 0) {
|
|
735
|
-
throw new Error("No streaming chunks received");
|
|
736
|
-
}
|
|
737
|
-
logger8.log({ chunks: chunks.length, result: result.substring(0, 50) }, "Streaming test completed");
|
|
475
|
+
logger6.log({ text }, "generated with test_text_large");
|
|
738
476
|
} catch (error) {
|
|
739
477
|
const message = error instanceof Error ? error.message : String(error);
|
|
740
|
-
|
|
478
|
+
logger6.error(`Error in test_text_large: ${message}`);
|
|
741
479
|
throw error;
|
|
742
480
|
}
|
|
743
481
|
}
|
|
@@ -746,17 +484,17 @@ var openrouterPlugin = {
|
|
|
746
484
|
name: "openrouter_test_object_small",
|
|
747
485
|
fn: async (runtime) => {
|
|
748
486
|
try {
|
|
749
|
-
const result = await runtime.useModel(
|
|
487
|
+
const result = await runtime.useModel(ModelType5.OBJECT_SMALL, {
|
|
750
488
|
prompt: "Create a simple JSON object with a message field saying hello",
|
|
751
489
|
schema: { type: "object" }
|
|
752
490
|
});
|
|
753
|
-
|
|
491
|
+
logger6.log({ result }, "Generated object with test_object_small");
|
|
754
492
|
if (!result || typeof result === "object" && "error" in result) {
|
|
755
493
|
throw new Error("Failed to generate object");
|
|
756
494
|
}
|
|
757
495
|
} catch (error) {
|
|
758
496
|
const message = error instanceof Error ? error.message : String(error);
|
|
759
|
-
|
|
497
|
+
logger6.error(`Error in test_object_small: ${message}`);
|
|
760
498
|
throw error;
|
|
761
499
|
}
|
|
762
500
|
}
|
|
@@ -765,13 +503,13 @@ var openrouterPlugin = {
|
|
|
765
503
|
name: "openrouter_test_text_embedding",
|
|
766
504
|
fn: async (runtime) => {
|
|
767
505
|
try {
|
|
768
|
-
const embedding = await runtime.useModel(
|
|
506
|
+
const embedding = await runtime.useModel(ModelType5.TEXT_EMBEDDING, {
|
|
769
507
|
text: "Hello, world!"
|
|
770
508
|
});
|
|
771
|
-
|
|
509
|
+
logger6.log({ embedding }, "embedding");
|
|
772
510
|
} catch (error) {
|
|
773
511
|
const message = error instanceof Error ? error.message : String(error);
|
|
774
|
-
|
|
512
|
+
logger6.error(`Error in test_text_embedding: ${message}`);
|
|
775
513
|
throw error;
|
|
776
514
|
}
|
|
777
515
|
}
|
|
@@ -780,10 +518,27 @@ var openrouterPlugin = {
|
|
|
780
518
|
}
|
|
781
519
|
]
|
|
782
520
|
};
|
|
783
|
-
var src_default = openrouterPlugin;
|
|
784
521
|
export {
|
|
522
|
+
shouldAutoCleanupImages,
|
|
785
523
|
openrouterPlugin,
|
|
786
|
-
|
|
524
|
+
getSmallModel,
|
|
525
|
+
getSetting,
|
|
526
|
+
getLargeModel,
|
|
527
|
+
getImageModel,
|
|
528
|
+
getImageGenerationModel,
|
|
529
|
+
getEmbeddingModel,
|
|
530
|
+
getEmbeddingDimensions,
|
|
531
|
+
getBaseURL,
|
|
532
|
+
getApiKey,
|
|
533
|
+
openrouterPlugin as default,
|
|
534
|
+
DEFAULT_SMALL_MODEL,
|
|
535
|
+
DEFAULT_LARGE_MODEL,
|
|
536
|
+
DEFAULT_IMAGE_MODEL,
|
|
537
|
+
DEFAULT_IMAGE_GENERATION_MODEL,
|
|
538
|
+
DEFAULT_EMBEDDING_MODEL,
|
|
539
|
+
DEFAULT_EMBEDDING_DIMENSIONS,
|
|
540
|
+
DEFAULT_BASE_URL
|
|
787
541
|
};
|
|
788
542
|
|
|
789
|
-
//# debugId=
|
|
543
|
+
//# debugId=22E4EFC6A1BE14DB64756E2164756E21
|
|
544
|
+
//# sourceMappingURL=index.node.js.map
|