@elizaos/plugin-openrouter 1.5.15 → 2.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,430 +1,70 @@
1
- var __create = Object.create;
2
- var __getProtoOf = Object.getPrototypeOf;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __toESM = (mod, isNodeMode, target) => {
7
- target = mod != null ? __create(__getProtoOf(mod)) : {};
8
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
9
- for (let key of __getOwnPropNames(mod))
10
- if (!__hasOwnProp.call(to, key))
11
- __defProp(to, key, {
12
- get: () => mod[key],
13
- enumerable: true
14
- });
15
- return to;
16
- };
17
- var __export = (target, all) => {
18
- for (var name in all)
19
- __defProp(target, name, {
20
- get: all[name],
21
- enumerable: true,
22
- configurable: true,
23
- set: (newValue) => all[name] = () => newValue
24
- });
25
- };
26
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
27
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
28
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
29
- }) : x)(function(x) {
30
- if (typeof require !== "undefined")
31
- return require.apply(this, arguments);
32
- throw Error('Dynamic require of "' + x + '" is not supported');
33
- });
34
-
35
- // node:path
36
- var exports_path = {};
37
- __export(exports_path, {
38
- sep: () => sep,
39
- resolve: () => resolve,
40
- relative: () => relative,
41
- posix: () => posix,
42
- parse: () => parse,
43
- normalize: () => normalize,
44
- join: () => join,
45
- isAbsolute: () => isAbsolute,
46
- format: () => format,
47
- extname: () => extname,
48
- dirname: () => dirname,
49
- delimiter: () => delimiter,
50
- default: () => path_default,
51
- basename: () => basename,
52
- _makeLong: () => _makeLong
53
- });
54
- function assertPath(path) {
55
- if (typeof path !== "string")
56
- throw new TypeError("Path must be a string. Received " + JSON.stringify(path));
57
- }
58
- function normalizeStringPosix(path, allowAboveRoot) {
59
- var res = "", lastSegmentLength = 0, lastSlash = -1, dots = 0, code;
60
- for (var i = 0;i <= path.length; ++i) {
61
- if (i < path.length)
62
- code = path.charCodeAt(i);
63
- else if (code === 47)
64
- break;
65
- else
66
- code = 47;
67
- if (code === 47) {
68
- if (lastSlash === i - 1 || dots === 1)
69
- ;
70
- else if (lastSlash !== i - 1 && dots === 2) {
71
- if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 || res.charCodeAt(res.length - 2) !== 46) {
72
- if (res.length > 2) {
73
- var lastSlashIndex = res.lastIndexOf("/");
74
- if (lastSlashIndex !== res.length - 1) {
75
- if (lastSlashIndex === -1)
76
- res = "", lastSegmentLength = 0;
77
- else
78
- res = res.slice(0, lastSlashIndex), lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
79
- lastSlash = i, dots = 0;
80
- continue;
81
- }
82
- } else if (res.length === 2 || res.length === 1) {
83
- res = "", lastSegmentLength = 0, lastSlash = i, dots = 0;
84
- continue;
85
- }
86
- }
87
- if (allowAboveRoot) {
88
- if (res.length > 0)
89
- res += "/..";
90
- else
91
- res = "..";
92
- lastSegmentLength = 2;
93
- }
94
- } else {
95
- if (res.length > 0)
96
- res += "/" + path.slice(lastSlash + 1, i);
97
- else
98
- res = path.slice(lastSlash + 1, i);
99
- lastSegmentLength = i - lastSlash - 1;
100
- }
101
- lastSlash = i, dots = 0;
102
- } else if (code === 46 && dots !== -1)
103
- ++dots;
104
- else
105
- dots = -1;
106
- }
107
- return res;
108
- }
109
- function _format(sep, pathObject) {
110
- var dir = pathObject.dir || pathObject.root, base = pathObject.base || (pathObject.name || "") + (pathObject.ext || "");
111
- if (!dir)
112
- return base;
113
- if (dir === pathObject.root)
114
- return dir + base;
115
- return dir + sep + base;
116
- }
117
- function resolve() {
118
- var resolvedPath = "", resolvedAbsolute = false, cwd;
119
- for (var i = arguments.length - 1;i >= -1 && !resolvedAbsolute; i--) {
120
- var path;
121
- if (i >= 0)
122
- path = arguments[i];
123
- else {
124
- if (cwd === undefined)
125
- cwd = process.cwd();
126
- path = cwd;
127
- }
128
- if (assertPath(path), path.length === 0)
129
- continue;
130
- resolvedPath = path + "/" + resolvedPath, resolvedAbsolute = path.charCodeAt(0) === 47;
131
- }
132
- if (resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute), resolvedAbsolute)
133
- if (resolvedPath.length > 0)
134
- return "/" + resolvedPath;
135
- else
136
- return "/";
137
- else if (resolvedPath.length > 0)
138
- return resolvedPath;
139
- else
140
- return ".";
141
- }
142
- function normalize(path) {
143
- if (assertPath(path), path.length === 0)
144
- return ".";
145
- var isAbsolute = path.charCodeAt(0) === 47, trailingSeparator = path.charCodeAt(path.length - 1) === 47;
146
- if (path = normalizeStringPosix(path, !isAbsolute), path.length === 0 && !isAbsolute)
147
- path = ".";
148
- if (path.length > 0 && trailingSeparator)
149
- path += "/";
150
- if (isAbsolute)
151
- return "/" + path;
152
- return path;
153
- }
154
- function isAbsolute(path) {
155
- return assertPath(path), path.length > 0 && path.charCodeAt(0) === 47;
156
- }
157
- function join() {
158
- if (arguments.length === 0)
159
- return ".";
160
- var joined;
161
- for (var i = 0;i < arguments.length; ++i) {
162
- var arg = arguments[i];
163
- if (assertPath(arg), arg.length > 0)
164
- if (joined === undefined)
165
- joined = arg;
166
- else
167
- joined += "/" + arg;
168
- }
169
- if (joined === undefined)
170
- return ".";
171
- return normalize(joined);
172
- }
173
- function relative(from, to) {
174
- if (assertPath(from), assertPath(to), from === to)
175
- return "";
176
- if (from = resolve(from), to = resolve(to), from === to)
177
- return "";
178
- var fromStart = 1;
179
- for (;fromStart < from.length; ++fromStart)
180
- if (from.charCodeAt(fromStart) !== 47)
181
- break;
182
- var fromEnd = from.length, fromLen = fromEnd - fromStart, toStart = 1;
183
- for (;toStart < to.length; ++toStart)
184
- if (to.charCodeAt(toStart) !== 47)
185
- break;
186
- var toEnd = to.length, toLen = toEnd - toStart, length = fromLen < toLen ? fromLen : toLen, lastCommonSep = -1, i = 0;
187
- for (;i <= length; ++i) {
188
- if (i === length) {
189
- if (toLen > length) {
190
- if (to.charCodeAt(toStart + i) === 47)
191
- return to.slice(toStart + i + 1);
192
- else if (i === 0)
193
- return to.slice(toStart + i);
194
- } else if (fromLen > length) {
195
- if (from.charCodeAt(fromStart + i) === 47)
196
- lastCommonSep = i;
197
- else if (i === 0)
198
- lastCommonSep = 0;
199
- }
200
- break;
201
- }
202
- var fromCode = from.charCodeAt(fromStart + i), toCode = to.charCodeAt(toStart + i);
203
- if (fromCode !== toCode)
204
- break;
205
- else if (fromCode === 47)
206
- lastCommonSep = i;
207
- }
208
- var out = "";
209
- for (i = fromStart + lastCommonSep + 1;i <= fromEnd; ++i)
210
- if (i === fromEnd || from.charCodeAt(i) === 47)
211
- if (out.length === 0)
212
- out += "..";
213
- else
214
- out += "/..";
215
- if (out.length > 0)
216
- return out + to.slice(toStart + lastCommonSep);
217
- else {
218
- if (toStart += lastCommonSep, to.charCodeAt(toStart) === 47)
219
- ++toStart;
220
- return to.slice(toStart);
221
- }
222
- }
223
- function _makeLong(path) {
224
- return path;
225
- }
226
- function dirname(path) {
227
- if (assertPath(path), path.length === 0)
228
- return ".";
229
- var code = path.charCodeAt(0), hasRoot = code === 47, end = -1, matchedSlash = true;
230
- for (var i = path.length - 1;i >= 1; --i)
231
- if (code = path.charCodeAt(i), code === 47) {
232
- if (!matchedSlash) {
233
- end = i;
234
- break;
235
- }
236
- } else
237
- matchedSlash = false;
238
- if (end === -1)
239
- return hasRoot ? "/" : ".";
240
- if (hasRoot && end === 1)
241
- return "//";
242
- return path.slice(0, end);
243
- }
244
- function basename(path, ext) {
245
- if (ext !== undefined && typeof ext !== "string")
246
- throw new TypeError('"ext" argument must be a string');
247
- assertPath(path);
248
- var start = 0, end = -1, matchedSlash = true, i;
249
- if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
250
- if (ext.length === path.length && ext === path)
251
- return "";
252
- var extIdx = ext.length - 1, firstNonSlashEnd = -1;
253
- for (i = path.length - 1;i >= 0; --i) {
254
- var code = path.charCodeAt(i);
255
- if (code === 47) {
256
- if (!matchedSlash) {
257
- start = i + 1;
258
- break;
259
- }
260
- } else {
261
- if (firstNonSlashEnd === -1)
262
- matchedSlash = false, firstNonSlashEnd = i + 1;
263
- if (extIdx >= 0)
264
- if (code === ext.charCodeAt(extIdx)) {
265
- if (--extIdx === -1)
266
- end = i;
267
- } else
268
- extIdx = -1, end = firstNonSlashEnd;
269
- }
270
- }
271
- if (start === end)
272
- end = firstNonSlashEnd;
273
- else if (end === -1)
274
- end = path.length;
275
- return path.slice(start, end);
276
- } else {
277
- for (i = path.length - 1;i >= 0; --i)
278
- if (path.charCodeAt(i) === 47) {
279
- if (!matchedSlash) {
280
- start = i + 1;
281
- break;
282
- }
283
- } else if (end === -1)
284
- matchedSlash = false, end = i + 1;
285
- if (end === -1)
286
- return "";
287
- return path.slice(start, end);
288
- }
289
- }
290
- function extname(path) {
291
- assertPath(path);
292
- var startDot = -1, startPart = 0, end = -1, matchedSlash = true, preDotState = 0;
293
- for (var i = path.length - 1;i >= 0; --i) {
294
- var code = path.charCodeAt(i);
295
- if (code === 47) {
296
- if (!matchedSlash) {
297
- startPart = i + 1;
298
- break;
299
- }
300
- continue;
301
- }
302
- if (end === -1)
303
- matchedSlash = false, end = i + 1;
304
- if (code === 46) {
305
- if (startDot === -1)
306
- startDot = i;
307
- else if (preDotState !== 1)
308
- preDotState = 1;
309
- } else if (startDot !== -1)
310
- preDotState = -1;
311
- }
312
- if (startDot === -1 || end === -1 || preDotState === 0 || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)
313
- return "";
314
- return path.slice(startDot, end);
315
- }
316
- function format(pathObject) {
317
- if (pathObject === null || typeof pathObject !== "object")
318
- throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject);
319
- return _format("/", pathObject);
320
- }
321
- function parse(path) {
322
- assertPath(path);
323
- var ret = { root: "", dir: "", base: "", ext: "", name: "" };
324
- if (path.length === 0)
325
- return ret;
326
- var code = path.charCodeAt(0), isAbsolute2 = code === 47, start;
327
- if (isAbsolute2)
328
- ret.root = "/", start = 1;
329
- else
330
- start = 0;
331
- var startDot = -1, startPart = 0, end = -1, matchedSlash = true, i = path.length - 1, preDotState = 0;
332
- for (;i >= start; --i) {
333
- if (code = path.charCodeAt(i), code === 47) {
334
- if (!matchedSlash) {
335
- startPart = i + 1;
336
- break;
337
- }
338
- continue;
339
- }
340
- if (end === -1)
341
- matchedSlash = false, end = i + 1;
342
- if (code === 46) {
343
- if (startDot === -1)
344
- startDot = i;
345
- else if (preDotState !== 1)
346
- preDotState = 1;
347
- } else if (startDot !== -1)
348
- preDotState = -1;
349
- }
350
- if (startDot === -1 || end === -1 || preDotState === 0 || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
351
- if (end !== -1)
352
- if (startPart === 0 && isAbsolute2)
353
- ret.base = ret.name = path.slice(1, end);
354
- else
355
- ret.base = ret.name = path.slice(startPart, end);
356
- } else {
357
- if (startPart === 0 && isAbsolute2)
358
- ret.name = path.slice(1, startDot), ret.base = path.slice(1, end);
359
- else
360
- ret.name = path.slice(startPart, startDot), ret.base = path.slice(startPart, end);
361
- ret.ext = path.slice(startDot, end);
362
- }
363
- if (startPart > 0)
364
- ret.dir = path.slice(0, startPart - 1);
365
- else if (isAbsolute2)
366
- ret.dir = "/";
367
- return ret;
368
- }
369
- var sep = "/", delimiter = ":", posix, path_default;
370
- var init_path = __esm(() => {
371
- posix = ((p) => (p.posix = p, p))({ resolve, normalize, isAbsolute, join, relative, _makeLong, dirname, basename, extname, format, parse, sep, delimiter, win32: null, posix: null });
372
- path_default = posix;
373
- });
374
-
375
- // src/index.ts
1
+ // plugin.ts
376
2
  import {
377
- ModelType as ModelType4
3
+ logger as logger6,
4
+ ModelType as ModelType5
378
5
  } from "@elizaos/core";
379
6
 
380
- // src/init.ts
7
+ // init.ts
381
8
  import { logger } from "@elizaos/core";
382
- import { fetch as fetch2 } from "undici";
383
9
 
384
- // src/utils/config.ts
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
+ }
385
25
  function getSetting(runtime, key, defaultValue) {
386
- return runtime.getSetting(key) ?? process.env[key] ?? defaultValue;
26
+ const value = runtime.getSetting(key);
27
+ if (value !== undefined && value !== null) {
28
+ return String(value);
29
+ }
30
+ return getEnvValue(key) ?? defaultValue;
387
31
  }
388
32
  function getBaseURL(runtime) {
389
33
  const browserURL = getSetting(runtime, "OPENROUTER_BROWSER_BASE_URL");
390
34
  if (typeof globalThis !== "undefined" && globalThis.document && browserURL) {
391
35
  return browserURL;
392
36
  }
393
- return getSetting(runtime, "OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1") || "https://openrouter.ai/api/v1";
37
+ return getSetting(runtime, "OPENROUTER_BASE_URL", DEFAULT_BASE_URL) || DEFAULT_BASE_URL;
394
38
  }
395
39
  function getApiKey(runtime) {
396
40
  return getSetting(runtime, "OPENROUTER_API_KEY");
397
41
  }
398
42
  function getSmallModel(runtime) {
399
- return getSetting(runtime, "OPENROUTER_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", "google/gemini-2.0-flash-001") ?? "google/gemini-2.0-flash-001";
43
+ return getSetting(runtime, "OPENROUTER_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", DEFAULT_SMALL_MODEL) ?? DEFAULT_SMALL_MODEL;
400
44
  }
401
45
  function getLargeModel(runtime) {
402
- return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", "google/gemini-2.5-flash") ?? "google/gemini-2.5-flash";
46
+ return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", DEFAULT_LARGE_MODEL) ?? DEFAULT_LARGE_MODEL;
403
47
  }
404
48
  function getImageModel(runtime) {
405
- return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL", "x-ai/grok-2-vision-1212") ?? "x-ai/grok-2-vision-1212";
49
+ return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL", DEFAULT_IMAGE_MODEL) ?? DEFAULT_IMAGE_MODEL;
406
50
  }
407
51
  function getImageGenerationModel(runtime) {
408
- return getSetting(runtime, "OPENROUTER_IMAGE_GENERATION_MODEL") ?? getSetting(runtime, "IMAGE_GENERATION_MODEL", "google/gemini-2.5-flash-image-preview") ?? "google/gemini-2.5-flash-image-preview";
52
+ return getSetting(runtime, "OPENROUTER_IMAGE_GENERATION_MODEL") ?? getSetting(runtime, "IMAGE_GENERATION_MODEL", DEFAULT_IMAGE_GENERATION_MODEL) ?? DEFAULT_IMAGE_GENERATION_MODEL;
409
53
  }
410
54
  function getEmbeddingModel(runtime) {
411
- return getSetting(runtime, "OPENROUTER_EMBEDDING_MODEL") ?? getSetting(runtime, "EMBEDDING_MODEL", "openai/text-embedding-3-small") ?? "openai/text-embedding-3-small";
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;
412
60
  }
413
61
  function shouldAutoCleanupImages(runtime) {
414
62
  const setting = getSetting(runtime, "OPENROUTER_AUTO_CLEANUP_IMAGES", "false");
415
63
  return setting?.toLowerCase() === "true";
416
64
  }
417
- function getToolExecutionMaxSteps(runtime) {
418
- const setting = getSetting(runtime, "OPENROUTER_TOOL_EXECUTION_MAX_STEPS", "15");
419
- const value = parseInt(setting || "15", 10);
420
- if (Number.isNaN(value) || value < 1)
421
- return 15;
422
- if (value > 100)
423
- return 100;
424
- return value;
425
- }
426
65
 
427
- // src/init.ts
66
+ // init.ts
67
+ globalThis.AI_SDK_LOG_WARNINGS ??= false;
428
68
  function initializeOpenRouter(_config, runtime) {
429
69
  (async () => {
430
70
  try {
@@ -436,519 +76,55 @@ function initializeOpenRouter(_config, runtime) {
436
76
  logger.warn("OPENROUTER_API_KEY is not set in environment - OpenRouter functionality will be limited");
437
77
  return;
438
78
  }
439
- try {
440
- const baseURL = getBaseURL(runtime);
441
- const response = await fetch2(`${baseURL}/models`, {
442
- headers: { Authorization: `Bearer ${getApiKey(runtime)}` }
443
- });
444
- if (!response.ok) {
445
- logger.warn(`OpenRouter API key validation failed: ${response.statusText}`);
446
- logger.warn("OpenRouter functionality will be limited until a valid API key is provided");
447
- } else {
448
- logger.log("OpenRouter API key validated successfully");
449
- }
450
- } catch (fetchError) {
451
- const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
452
- logger.warn(`Error validating OpenRouter API key: ${message}`);
453
- 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");
454
87
  }
455
88
  } catch (error) {
456
- const message = error?.errors?.map((e) => e.message).join(", ") || (error instanceof Error ? error.message : String(error));
457
- logger.warn(`OpenRouter plugin configuration issue: ${message} - You need to configure the OPENROUTER_API_KEY in your environment variables`);
89
+ const message = error instanceof Error ? error.message : String(error);
90
+ logger.warn(`Error validating OpenRouter API key: ${message}`);
458
91
  }
459
92
  })();
460
- return;
461
93
  }
462
94
 
463
- // src/models/text.ts
464
- import { logger as logger3, ModelType } from "@elizaos/core";
465
- import { generateText, stepCountIs } from "ai";
95
+ // models/embedding.ts
96
+ import { logger as logger3, ModelType, VECTOR_DIMS } from "@elizaos/core";
466
97
 
467
- // src/providers/openrouter.ts
468
- import { createOpenRouter } from "@openrouter/ai-sdk-provider";
469
- function createOpenRouterProvider(runtime) {
470
- const apiKey = getApiKey(runtime);
471
- const isBrowser = typeof globalThis !== "undefined" && globalThis.document;
472
- const baseURL = getBaseURL(runtime);
473
- return createOpenRouter({
474
- apiKey: isBrowser ? undefined : apiKey,
475
- baseURL
476
- });
477
- }
478
- // src/utils/events.ts
479
- import {
480
- EventType
481
- } from "@elizaos/core";
482
- function emitModelUsageEvent(runtime, type, prompt, usage) {
483
- const truncatedPrompt = typeof prompt === "string" ? prompt.length > 200 ? `${prompt.slice(0, 200)}…` : prompt : "";
484
- const inputTokens = Number(usage.inputTokens || 0);
485
- const outputTokens = Number(usage.outputTokens || 0);
486
- const totalTokens = Number(usage.totalTokens != null ? usage.totalTokens : inputTokens + outputTokens);
487
- runtime.emitEvent(EventType.MODEL_USED, {
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,
488
107
  provider: "openrouter",
489
- type,
490
- prompt: truncatedPrompt,
491
- tokens: {
492
- prompt: inputTokens,
493
- completion: outputTokens,
494
- total: totalTokens
495
- }
108
+ prompt: prompt.substring(0, 100),
109
+ usage: {
110
+ promptTokens: inputTokens,
111
+ completionTokens: outputTokens,
112
+ totalTokens
113
+ },
114
+ timestamp: Date.now()
496
115
  });
497
116
  }
498
117
 
499
- // src/utils/helpers.ts
500
- import { logger as logger2 } from "@elizaos/core";
501
- import { JSONParseError } from "ai";
502
- function getJsonRepairFunction() {
503
- return async ({ text, error }) => {
504
- try {
505
- if (error instanceof JSONParseError) {
506
- const cleanedText = text.replace(/```json\n|\n```|```/g, "");
507
- JSON.parse(cleanedText);
508
- return cleanedText;
509
- }
510
- return null;
511
- } catch (jsonError) {
512
- const message = jsonError instanceof Error ? jsonError.message : String(jsonError);
513
- logger2.warn(`Failed to repair JSON text: ${message}`);
514
- return null;
515
- }
516
- };
517
- }
518
- function handleEmptyToolResponse(modelType) {
519
- logger2.warn(`[${modelType}] No text generated after tool execution`);
520
- const fallbackText = "I executed the requested action. The tool completed successfully.";
521
- logger2.warn(`[${modelType}] Using fallback response text`);
522
- return fallbackText;
523
- }
524
- function parseImageDescriptionResponse(responseText) {
525
- try {
526
- const jsonResponse = JSON.parse(responseText);
527
- if (jsonResponse.title && jsonResponse.description) {
528
- return jsonResponse;
529
- }
530
- } catch (e) {
531
- logger2.debug(`Parsing as JSON failed, processing as text: ${e}`);
532
- }
533
- const titleMatch = responseText.match(/title[:\s]+(.+?)(?:\n|$)/i);
534
- const title = titleMatch?.[1]?.trim() || "Image Analysis";
535
- const description = responseText.replace(/title[:\s]+(.+?)(?:\n|$)/i, "").trim();
536
- return { title, description };
537
- }
538
- async function handleObjectGenerationError(error) {
539
- if (error instanceof JSONParseError) {
540
- logger2.error(`[generateObject] Failed to parse JSON: ${error.message}`);
541
- const repairFunction = getJsonRepairFunction();
542
- const repairedJsonString = await repairFunction({
543
- text: error.text,
544
- error
545
- });
546
- if (repairedJsonString) {
547
- try {
548
- const repairedObject = JSON.parse(repairedJsonString);
549
- logger2.log("[generateObject] Successfully repaired JSON.");
550
- return repairedObject;
551
- } catch (repairParseError) {
552
- const message = repairParseError instanceof Error ? repairParseError.message : String(repairParseError);
553
- logger2.error(`[generateObject] Failed to parse repaired JSON: ${message}`);
554
- if (repairParseError instanceof Error)
555
- throw repairParseError;
556
- throw Object.assign(new Error(message), { cause: repairParseError });
557
- }
558
- } else {
559
- logger2.error("[generateObject] JSON repair failed.");
560
- throw error;
561
- }
562
- } else {
563
- const message = error instanceof Error ? error.message : String(error);
564
- logger2.error(`[generateObject] Unknown error: ${message}`);
565
- if (error instanceof Error)
566
- throw error;
567
- throw Object.assign(new Error(message), { cause: error });
568
- }
569
- }
570
- function isLikelyBase64(key, value) {
571
- const base64KeyPattern = /^(data|content|body|payload|encoded|b64|base64|document)$/i;
572
- if (!base64KeyPattern.test(key))
573
- return false;
574
- if (value.length < 20 || value.length > 1024 * 1024)
575
- return false;
576
- if (value.length % 4 !== 0)
577
- return false;
578
- if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value))
579
- return false;
580
- return true;
581
- }
582
- function decodeBase64Fields(obj, depth = 0) {
583
- if (depth > 5)
584
- return obj;
585
- if (!obj || typeof obj !== "object")
586
- return obj;
587
- if (Array.isArray(obj))
588
- return obj.map((item) => decodeBase64Fields(item, depth + 1));
589
- const decoded = {};
590
- for (const [key, value] of Object.entries(obj)) {
591
- if (typeof value === "string" && isLikelyBase64(key, value)) {
592
- try {
593
- decoded[key] = Buffer.from(value, "base64").toString("utf8");
594
- logger2.debug(`[decodeBase64] Decoded field '${key}' (${value.length} chars)`);
595
- } catch (error) {
596
- logger2.warn(`[decodeBase64] Failed to decode field '${key}': ${error}`);
597
- decoded[key] = value;
598
- }
599
- } else if (value && typeof value === "object") {
600
- decoded[key] = decodeBase64Fields(value, depth + 1);
601
- } else {
602
- decoded[key] = value;
603
- }
604
- }
605
- return decoded;
606
- }
607
-
608
- // src/models/text.ts
609
- async function generateTextWithModel(runtime, modelType, params) {
610
- const { prompt, stopSequences = [], tools, toolChoice } = params;
611
- const temperature = params.temperature ?? 0.7;
612
- const frequencyPenalty = params.frequencyPenalty ?? 0.7;
613
- const presencePenalty = params.presencePenalty ?? 0.7;
614
- const resolvedMaxOutput = params.maxOutputTokens ?? params.maxTokens ?? 8192;
615
- const openrouter = createOpenRouterProvider(runtime);
616
- const modelName = modelType === ModelType.TEXT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
617
- const modelLabel = modelType === ModelType.TEXT_SMALL ? "TEXT_SMALL" : "TEXT_LARGE";
618
- logger3.debug(`[OpenRouter] Generating text with ${modelLabel} model: ${modelName}`);
619
- const generateParams = {
620
- model: openrouter.chat(modelName),
621
- prompt,
622
- system: runtime.character.system ?? undefined,
623
- temperature,
624
- frequencyPenalty,
625
- presencePenalty,
626
- stopSequences
627
- };
628
- generateParams.maxOutputTokens = resolvedMaxOutput;
629
- if (tools) {
630
- generateParams.tools = tools;
631
- const maxSteps = getToolExecutionMaxSteps(runtime);
632
- generateParams.stopWhen = stepCountIs(maxSteps);
633
- logger3.debug(`[OpenRouter] Using maxSteps: ${maxSteps} for tool execution`);
634
- }
635
- if (toolChoice) {
636
- generateParams.toolChoice = toolChoice;
637
- }
638
- let capturedToolResults = [];
639
- let capturedToolCalls = [];
640
- if (tools) {
641
- generateParams.onStepFinish = async (stepResult) => {
642
- if (stepResult.toolCalls && stepResult.toolCalls.length > 0) {
643
- capturedToolCalls = [
644
- ...capturedToolCalls,
645
- ...stepResult.toolCalls
646
- ];
647
- }
648
- if (stepResult.content && Array.isArray(stepResult.content)) {
649
- const toolResultsFromContent = stepResult.content.filter((content) => content.type === "tool-result" && content.output).map((content) => ({
650
- toolCallId: content.toolCallId,
651
- result: decodeBase64Fields(content.output)
652
- }));
653
- if (toolResultsFromContent.length > 0) {
654
- capturedToolResults = [...capturedToolResults, ...toolResultsFromContent];
655
- }
656
- }
657
- };
658
- }
659
- const response = await generateText(generateParams);
660
- let responseText;
661
- if (tools && (!response.text || response.text.trim() === "" || response.text === "Tools executed successfully.")) {
662
- responseText = handleEmptyToolResponse(modelLabel);
663
- } else {
664
- responseText = response.text;
665
- }
666
- if (response.usage) {
667
- emitModelUsageEvent(runtime, modelType, prompt, response.usage);
668
- }
669
- if (tools && response.steps && response.steps.length > 0) {
670
- return {
671
- text: responseText,
672
- toolCalls: capturedToolCalls,
673
- toolResults: capturedToolResults,
674
- steps: response.steps,
675
- usage: response.usage,
676
- finishReason: response.finishReason
677
- };
678
- }
679
- return responseText;
680
- }
681
- async function handleTextSmall(runtime, params) {
682
- return generateTextWithModel(runtime, ModelType.TEXT_SMALL, params);
683
- }
684
- async function handleTextLarge(runtime, params) {
685
- return generateTextWithModel(runtime, ModelType.TEXT_LARGE, params);
686
- }
687
-
688
- // src/models/object.ts
689
- import {
690
- ModelType as ModelType2,
691
- logger as logger4
692
- } from "@elizaos/core";
693
- import { generateObject } from "ai";
694
- async function generateObjectWithModel(runtime, modelType, params) {
695
- const openrouter = createOpenRouterProvider(runtime);
696
- const modelName = modelType === ModelType2.OBJECT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
697
- const modelLabel = modelType === ModelType2.OBJECT_SMALL ? "OBJECT_SMALL" : "OBJECT_LARGE";
698
- logger4.log(`[OpenRouter] Using ${modelLabel} model: ${modelName}`);
699
- const temperature = params.temperature ?? 0.7;
700
- try {
701
- const { object, usage } = await generateObject({
702
- model: openrouter.chat(modelName),
703
- ...params.schema && { schema: params.schema },
704
- output: params.schema ? "object" : "no-schema",
705
- prompt: params.prompt,
706
- temperature,
707
- experimental_repairText: getJsonRepairFunction()
708
- });
709
- if (usage) {
710
- emitModelUsageEvent(runtime, modelType, params.prompt, usage);
711
- }
712
- return object;
713
- } catch (error) {
714
- return handleObjectGenerationError(error);
715
- }
716
- }
717
- async function handleObjectSmall(runtime, params) {
718
- return generateObjectWithModel(runtime, ModelType2.OBJECT_SMALL, params);
719
- }
720
- async function handleObjectLarge(runtime, params) {
721
- return generateObjectWithModel(runtime, ModelType2.OBJECT_LARGE, params);
722
- }
723
-
724
- // src/models/image.ts
725
- import {
726
- logger as logger6
727
- } from "@elizaos/core";
728
- import { generateText as generateText2 } from "ai";
729
-
730
- // src/utils/image-storage.ts
731
- import { logger as logger5, getGeneratedDir } from "@elizaos/core";
732
- function isBrowser() {
733
- return typeof globalThis !== "undefined" && globalThis.document;
734
- }
735
- function sanitizeId(id) {
736
- const src = (id ?? "").toString();
737
- const normalized = src.normalize("NFKC");
738
- let safe = normalized.replace(/[^a-zA-Z0-9_-]/g, "_");
739
- safe = safe.replace(/_+/g, "_");
740
- safe = safe.slice(0, 64);
741
- safe = safe.replace(/^_+|_+$/g, "");
742
- return safe || "agent";
743
- }
744
- function base64ToBytes(base64) {
745
- const cleaned = base64.replace(/\s+/g, "");
746
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
747
- const lookup = new Array(256).fill(-1);
748
- for (let i = 0;i < chars.length; i++)
749
- lookup[chars.charCodeAt(i)] = i;
750
- const len = cleaned.length;
751
- let pad = 0;
752
- if (len >= 2 && cleaned[len - 1] === "=")
753
- pad++;
754
- if (len >= 2 && cleaned[len - 2] === "=")
755
- pad++;
756
- const outLen = (len * 3 >> 2) - pad;
757
- const out = new Uint8Array(outLen);
758
- let o = 0;
759
- for (let i = 0;i < len; i += 4) {
760
- const c0 = lookup[cleaned.charCodeAt(i)];
761
- const c1 = lookup[cleaned.charCodeAt(i + 1)];
762
- const c2 = lookup[cleaned.charCodeAt(i + 2)];
763
- const c3 = lookup[cleaned.charCodeAt(i + 3)];
764
- const n = c0 << 18 | c1 << 12 | (c2 & 63) << 6 | c3 & 63;
765
- if (o < outLen)
766
- out[o++] = n >> 16 & 255;
767
- if (o < outLen)
768
- out[o++] = n >> 8 & 255;
769
- if (o < outLen)
770
- out[o++] = n & 255;
771
- }
772
- return out;
773
- }
774
- async function saveBase64Image(base64Url, agentId, index = 0) {
775
- if (isBrowser()) {
776
- return null;
777
- }
778
- const m = base64Url.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=]+)$/);
779
- if (!m)
780
- return null;
781
- const mime = m[1];
782
- const base64Data = m[2];
783
- const extMap = {
784
- "image/png": "png",
785
- "image/jpeg": "jpg",
786
- "image/jpg": "jpg",
787
- "image/webp": "webp",
788
- "image/gif": "gif",
789
- "image/bmp": "bmp",
790
- "image/tiff": "tiff"
791
- };
792
- const extension = extMap[mime];
793
- if (!extension)
794
- return null;
795
- const { join: join2 } = await Promise.resolve().then(() => (init_path(), exports_path));
796
- const safeAgentId = sanitizeId(agentId);
797
- const baseDir = join2(getGeneratedDir(), safeAgentId);
798
- const { existsSync } = await import("node:fs");
799
- if (!existsSync(baseDir)) {
800
- const { mkdir } = await import("node:fs/promises");
801
- await mkdir(baseDir, { recursive: true });
802
- }
803
- const timestamp = Date.now();
804
- const filename = `image_${timestamp}_${index}.${extension}`;
805
- const filepath = join2(baseDir, filename);
806
- const buffer = base64ToBytes(base64Data);
807
- const { writeFile } = await import("node:fs/promises");
808
- await writeFile(filepath, buffer);
809
- logger5.info(`[OpenRouter] Saved generated image to ${filepath}`);
810
- return filepath;
811
- }
812
- function deleteImage(filepath) {
813
- if (isBrowser()) {
814
- return;
815
- }
816
- try {
817
- (async () => {
818
- const { existsSync, unlinkSync } = await import("node:fs");
819
- if (existsSync(filepath)) {
820
- unlinkSync(filepath);
821
- logger5.debug(`[OpenRouter] Deleted image: ${filepath}`);
822
- }
823
- })().catch((error) => {
824
- logger5.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
825
- });
826
- } catch (error) {
827
- logger5.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
828
- }
829
- }
830
-
831
- // src/models/image.ts
832
- async function handleImageDescription(runtime, params) {
833
- let imageUrl;
834
- let promptText;
835
- const modelName = getImageModel(runtime);
836
- logger6.log(`[OpenRouter] Using IMAGE_DESCRIPTION model: ${modelName}`);
837
- const maxOutputTokens = 300;
838
- if (typeof params === "string") {
839
- imageUrl = params;
840
- promptText = "Please analyze this image and provide a title and detailed description.";
841
- } else {
842
- imageUrl = params.imageUrl;
843
- promptText = params.prompt || "Please analyze this image and provide a title and detailed description.";
844
- }
845
- const openrouter = createOpenRouterProvider(runtime);
846
- const messages = [
847
- {
848
- role: "user",
849
- content: [
850
- { type: "text", text: promptText },
851
- { type: "image", image: imageUrl }
852
- ]
853
- }
854
- ];
855
- try {
856
- const model = openrouter.chat(modelName);
857
- const { text: responseText } = await generateText2({
858
- model,
859
- messages,
860
- maxOutputTokens
861
- });
862
- return parseImageDescriptionResponse(responseText);
863
- } catch (error) {
864
- const message = error instanceof Error ? error.message : String(error);
865
- logger6.error(`Error analyzing image: ${message}`);
866
- return {
867
- title: "Failed to analyze image",
868
- description: `Error: ${message}`
869
- };
870
- }
871
- }
872
- async function handleImageGeneration(runtime, params) {
873
- const modelName = getImageGenerationModel(runtime);
874
- logger6.log(`[OpenRouter] Using IMAGE_GENERATION model: ${modelName}`);
875
- const apiKey = getApiKey(runtime);
876
- try {
877
- const baseUrl = getBaseURL(runtime);
878
- const isBrowser2 = typeof globalThis !== "undefined" && globalThis.document;
879
- const response = await fetch(`${baseUrl}/chat/completions`, {
880
- method: "POST",
881
- headers: {
882
- ...isBrowser2 ? {} : { Authorization: `Bearer ${apiKey}` },
883
- "Content-Type": "application/json"
884
- },
885
- body: JSON.stringify({
886
- model: modelName,
887
- messages: [
888
- {
889
- role: "user",
890
- content: params.prompt
891
- }
892
- ],
893
- modalities: ["image", "text"]
894
- }),
895
- signal: AbortSignal.timeout ? AbortSignal.timeout(60000) : undefined
896
- });
897
- if (!response.ok) {
898
- const errorText = await response.text().catch(() => "");
899
- throw new Error(`HTTP ${response.status} ${response.statusText} ${errorText}`);
900
- }
901
- const result = await response.json();
902
- const images = [];
903
- const savedPaths = [];
904
- if (result.choices?.[0]?.message?.images) {
905
- for (const [index, image] of result.choices[0].message.images.entries()) {
906
- const base64Url = image.image_url.url;
907
- const filepath = await saveBase64Image(base64Url, runtime.agentId, index);
908
- if (filepath) {
909
- logger6.log(`[OpenRouter] Returning image with filepath: ${filepath}`);
910
- images.push({
911
- url: filepath
912
- });
913
- savedPaths.push(filepath);
914
- } else if (!base64Url.startsWith("data:")) {
915
- images.push({ url: base64Url });
916
- } else {
917
- logger6.warn(`[OpenRouter] Failed to save image ${index + 1}, skipping`);
918
- }
919
- }
920
- }
921
- if (savedPaths.length > 0 && shouldAutoCleanupImages(runtime)) {
922
- setTimeout(() => {
923
- savedPaths.forEach((path) => {
924
- deleteImage(path);
925
- });
926
- }, 30000);
927
- }
928
- if (images.length === 0) {
929
- throw new Error("No images generated in response");
930
- }
931
- logger6.log(`[OpenRouter] Generated ${images.length} image(s)`);
932
- return images;
933
- } catch (error) {
934
- const message = error instanceof Error ? error.message : String(error);
935
- logger6.error(`[OpenRouter] Error generating image: ${message}`);
936
- return [];
937
- }
938
- }
939
-
940
- // src/models/embedding.ts
941
- import { logger as logger7, ModelType as ModelType3, VECTOR_DIMS } from "@elizaos/core";
118
+ // models/embedding.ts
942
119
  async function handleTextEmbedding(runtime, params) {
943
120
  const embeddingModelName = getEmbeddingModel(runtime);
944
121
  const embeddingDimension = Number.parseInt(getSetting(runtime, "OPENROUTER_EMBEDDING_DIMENSIONS") ?? getSetting(runtime, "EMBEDDING_DIMENSIONS") ?? "1536", 10);
945
122
  if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {
946
123
  const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(", ")}`;
947
- logger7.error(errorMsg);
124
+ logger3.error(errorMsg);
948
125
  throw new Error(errorMsg);
949
126
  }
950
127
  if (params === null) {
951
- logger7.debug("Creating test embedding for initialization");
952
128
  const testVector = Array(embeddingDimension).fill(0);
953
129
  testVector[0] = 0.1;
954
130
  return testVector;
@@ -960,14 +136,14 @@ async function handleTextEmbedding(runtime, params) {
960
136
  text = params.text;
961
137
  } else {
962
138
  const errorMsg = "Invalid input format for embedding";
963
- logger7.warn(errorMsg);
139
+ logger3.warn(errorMsg);
964
140
  const fallbackVector = Array(embeddingDimension).fill(0);
965
141
  fallbackVector[0] = 0.2;
966
142
  return fallbackVector;
967
143
  }
968
144
  if (!text.trim()) {
969
145
  const errorMsg = "Empty text for embedding";
970
- logger7.warn(errorMsg);
146
+ logger3.warn(errorMsg);
971
147
  const fallbackVector = Array(embeddingDimension).fill(0);
972
148
  fallbackVector[0] = 0.3;
973
149
  return fallbackVector;
@@ -975,7 +151,7 @@ async function handleTextEmbedding(runtime, params) {
975
151
  const apiKey = getApiKey(runtime);
976
152
  if (!apiKey) {
977
153
  const errorMsg = "OPENROUTER_API_KEY is not set";
978
- logger7.error(errorMsg);
154
+ logger3.error(errorMsg);
979
155
  throw new Error(errorMsg);
980
156
  }
981
157
  const baseURL = getBaseURL(runtime);
@@ -994,18 +170,18 @@ async function handleTextEmbedding(runtime, params) {
994
170
  })
995
171
  });
996
172
  if (!response.ok) {
997
- logger7.error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
173
+ logger3.error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
998
174
  throw new Error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
999
175
  }
1000
176
  const data = await response.json();
1001
177
  if (!data?.data?.[0]?.embedding) {
1002
- logger7.error("API returned invalid structure");
178
+ logger3.error("API returned invalid structure");
1003
179
  throw new Error("API returned invalid structure");
1004
180
  }
1005
181
  const embedding = data.data[0].embedding;
1006
182
  if (!Array.isArray(embedding) || embedding.length !== embeddingDimension) {
1007
183
  const errorMsg = `Embedding length ${embedding?.length ?? 0} does not match configured dimension ${embeddingDimension}`;
1008
- logger7.error(errorMsg);
184
+ logger3.error(errorMsg);
1009
185
  const fallbackVector = Array(embeddingDimension).fill(0);
1010
186
  fallbackVector[0] = 0.4;
1011
187
  return fallbackVector;
@@ -1016,69 +192,353 @@ async function handleTextEmbedding(runtime, params) {
1016
192
  outputTokens: 0,
1017
193
  totalTokens: data.usage.total_tokens
1018
194
  };
1019
- emitModelUsageEvent(runtime, ModelType3.TEXT_EMBEDDING, text, usage);
195
+ emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage);
1020
196
  }
1021
- logger7.log(`Got valid embedding with length ${embedding.length}`);
1022
197
  return embedding;
1023
198
  } catch (error) {
1024
199
  const message = error instanceof Error ? error.message : String(error);
1025
- logger7.error(`Error generating embedding: ${message}`);
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}`);
1026
269
  throw error instanceof Error ? error : new Error(message);
1027
270
  }
1028
271
  }
1029
272
 
1030
- // src/index.ts
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();
1031
395
  var openrouterPlugin = {
1032
396
  name: "openrouter",
1033
- description: "OpenRouter plugin",
397
+ description: "OpenRouter multi-model AI gateway plugin",
1034
398
  config: {
1035
- OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,
1036
- OPENROUTER_BASE_URL: process.env.OPENROUTER_BASE_URL,
1037
- OPENROUTER_SMALL_MODEL: process.env.OPENROUTER_SMALL_MODEL,
1038
- OPENROUTER_LARGE_MODEL: process.env.OPENROUTER_LARGE_MODEL,
1039
- OPENROUTER_IMAGE_MODEL: process.env.OPENROUTER_IMAGE_MODEL,
1040
- OPENROUTER_IMAGE_GENERATION_MODEL: process.env.OPENROUTER_IMAGE_GENERATION_MODEL,
1041
- OPENROUTER_EMBEDDING_MODEL: process.env.OPENROUTER_EMBEDDING_MODEL,
1042
- OPENROUTER_EMBEDDING_DIMENSIONS: process.env.OPENROUTER_EMBEDDING_DIMENSIONS,
1043
- OPENROUTER_AUTO_CLEANUP_IMAGES: process.env.OPENROUTER_AUTO_CLEANUP_IMAGES,
1044
- SMALL_MODEL: process.env.SMALL_MODEL,
1045
- LARGE_MODEL: process.env.LARGE_MODEL,
1046
- IMAGE_MODEL: process.env.IMAGE_MODEL,
1047
- IMAGE_GENERATION_MODEL: process.env.IMAGE_GENERATION_MODEL,
1048
- EMBEDDING_MODEL: process.env.EMBEDDING_MODEL,
1049
- EMBEDDING_DIMENSIONS: process.env.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
1050
414
  },
1051
415
  async init(config, runtime) {
1052
416
  initializeOpenRouter(config, runtime);
1053
417
  },
1054
418
  models: {
1055
- [ModelType4.TEXT_SMALL]: async (runtime, params) => {
419
+ [ModelType5.TEXT_SMALL]: async (runtime, params) => {
1056
420
  return handleTextSmall(runtime, params);
1057
421
  },
1058
- [ModelType4.TEXT_LARGE]: async (runtime, params) => {
422
+ [ModelType5.TEXT_LARGE]: async (runtime, params) => {
1059
423
  return handleTextLarge(runtime, params);
1060
424
  },
1061
- [ModelType4.OBJECT_SMALL]: async (runtime, params) => {
425
+ [ModelType5.OBJECT_SMALL]: async (runtime, params) => {
1062
426
  return handleObjectSmall(runtime, params);
1063
427
  },
1064
- [ModelType4.OBJECT_LARGE]: async (runtime, params) => {
428
+ [ModelType5.OBJECT_LARGE]: async (runtime, params) => {
1065
429
  return handleObjectLarge(runtime, params);
1066
430
  },
1067
- [ModelType4.IMAGE_DESCRIPTION]: async (runtime, params) => {
1068
- return handleImageDescription(runtime, params);
431
+ [ModelType5.IMAGE_DESCRIPTION]: async (runtime, params) => {
432
+ const description = await handleImageDescription(runtime, params);
433
+ return { title: "", description };
1069
434
  },
1070
- [ModelType4.IMAGE]: async (runtime, params) => {
1071
- return handleImageGeneration(runtime, params);
435
+ [ModelType5.IMAGE]: async (runtime, params) => {
436
+ const result = await handleImageGeneration(runtime, params);
437
+ return [{ url: result.imageUrl }];
1072
438
  },
1073
- [ModelType4.TEXT_EMBEDDING]: async (runtime, params) => {
439
+ [ModelType5.TEXT_EMBEDDING]: async (runtime, params) => {
1074
440
  return handleTextEmbedding(runtime, params);
1075
441
  }
1076
- }
442
+ },
443
+ tests: [
444
+ {
445
+ name: "openrouter_plugin_tests",
446
+ tests: [
447
+ {
448
+ name: "openrouter_test_text_small",
449
+ fn: async (runtime) => {
450
+ try {
451
+ const text = await runtime.useModel(ModelType5.TEXT_SMALL, {
452
+ prompt: "What is the nature of reality in 10 words?"
453
+ });
454
+ if (text.length === 0) {
455
+ throw new Error("Failed to generate text");
456
+ }
457
+ logger6.log({ text }, "generated with test_text_small");
458
+ } catch (error) {
459
+ const message = error instanceof Error ? error.message : String(error);
460
+ logger6.error(`Error in test_text_small: ${message}`);
461
+ throw error;
462
+ }
463
+ }
464
+ },
465
+ {
466
+ name: "openrouter_test_text_large",
467
+ fn: async (runtime) => {
468
+ try {
469
+ const text = await runtime.useModel(ModelType5.TEXT_LARGE, {
470
+ prompt: "What is the nature of reality in 10 words?"
471
+ });
472
+ if (text.length === 0) {
473
+ throw new Error("Failed to generate text");
474
+ }
475
+ logger6.log({ text }, "generated with test_text_large");
476
+ } catch (error) {
477
+ const message = error instanceof Error ? error.message : String(error);
478
+ logger6.error(`Error in test_text_large: ${message}`);
479
+ throw error;
480
+ }
481
+ }
482
+ },
483
+ {
484
+ name: "openrouter_test_object_small",
485
+ fn: async (runtime) => {
486
+ try {
487
+ const result = await runtime.useModel(ModelType5.OBJECT_SMALL, {
488
+ prompt: "Create a simple JSON object with a message field saying hello",
489
+ schema: { type: "object" }
490
+ });
491
+ logger6.log({ result }, "Generated object with test_object_small");
492
+ if (!result || typeof result === "object" && "error" in result) {
493
+ throw new Error("Failed to generate object");
494
+ }
495
+ } catch (error) {
496
+ const message = error instanceof Error ? error.message : String(error);
497
+ logger6.error(`Error in test_object_small: ${message}`);
498
+ throw error;
499
+ }
500
+ }
501
+ },
502
+ {
503
+ name: "openrouter_test_text_embedding",
504
+ fn: async (runtime) => {
505
+ try {
506
+ const embedding = await runtime.useModel(ModelType5.TEXT_EMBEDDING, {
507
+ text: "Hello, world!"
508
+ });
509
+ logger6.log({ embedding }, "embedding");
510
+ } catch (error) {
511
+ const message = error instanceof Error ? error.message : String(error);
512
+ logger6.error(`Error in test_text_embedding: ${message}`);
513
+ throw error;
514
+ }
515
+ }
516
+ }
517
+ ]
518
+ }
519
+ ]
1077
520
  };
1078
- var src_default = openrouterPlugin;
1079
521
  export {
522
+ shouldAutoCleanupImages,
1080
523
  openrouterPlugin,
1081
- src_default as default
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
1082
541
  };
1083
542
 
1084
- //# debugId=A21BECF40882BC4264756E2164756E21
543
+ //# debugId=E561D2F888727E6264756E2164756E21
544
+ //# sourceMappingURL=index.browser.js.map