@elizaos/plugin-openrouter 1.3.1 → 1.5.13

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.
@@ -0,0 +1,643 @@
1
+ var __create = Object.create;
2
+ var __getProtoOf = Object.getPrototypeOf;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
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 __moduleCache = /* @__PURE__ */ new WeakMap;
19
+ var __toCommonJS = (from) => {
20
+ var entry = __moduleCache.get(from), desc;
21
+ if (entry)
22
+ return entry;
23
+ entry = __defProp({}, "__esModule", { value: true });
24
+ if (from && typeof from === "object" || typeof from === "function")
25
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
26
+ get: () => from[key],
27
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
28
+ }));
29
+ __moduleCache.set(from, entry);
30
+ return entry;
31
+ };
32
+ var __export = (target, all) => {
33
+ for (var name in all)
34
+ __defProp(target, name, {
35
+ get: all[name],
36
+ enumerable: true,
37
+ configurable: true,
38
+ set: (newValue) => all[name] = () => newValue
39
+ });
40
+ };
41
+
42
+ // src/index.node.ts
43
+ var exports_index_node = {};
44
+ __export(exports_index_node, {
45
+ openrouterPlugin: () => openrouterPlugin,
46
+ default: () => src_default
47
+ });
48
+ module.exports = __toCommonJS(exports_index_node);
49
+
50
+ // src/index.ts
51
+ var import_core8 = require("@elizaos/core");
52
+
53
+ // src/init.ts
54
+ var import_core = require("@elizaos/core");
55
+ var import_undici = require("undici");
56
+
57
+ // src/utils/config.ts
58
+ function getSetting(runtime, key, defaultValue) {
59
+ return runtime.getSetting(key) ?? process.env[key] ?? defaultValue;
60
+ }
61
+ function getBaseURL(runtime) {
62
+ const browserURL = getSetting(runtime, "OPENROUTER_BROWSER_BASE_URL");
63
+ if (typeof globalThis !== "undefined" && globalThis.document && browserURL) {
64
+ return browserURL;
65
+ }
66
+ return getSetting(runtime, "OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1") || "https://openrouter.ai/api/v1";
67
+ }
68
+ function getApiKey(runtime) {
69
+ return getSetting(runtime, "OPENROUTER_API_KEY");
70
+ }
71
+ function getSmallModel(runtime) {
72
+ return getSetting(runtime, "OPENROUTER_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", "google/gemini-2.0-flash-001") ?? "google/gemini-2.0-flash-001";
73
+ }
74
+ function getLargeModel(runtime) {
75
+ return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", "google/gemini-2.5-flash") ?? "google/gemini-2.5-flash";
76
+ }
77
+ function getImageModel(runtime) {
78
+ return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL", "x-ai/grok-2-vision-1212") ?? "x-ai/grok-2-vision-1212";
79
+ }
80
+ function getImageGenerationModel(runtime) {
81
+ 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";
82
+ }
83
+ function shouldAutoCleanupImages(runtime) {
84
+ const setting = getSetting(runtime, "OPENROUTER_AUTO_CLEANUP_IMAGES", "false");
85
+ return setting?.toLowerCase() === "true";
86
+ }
87
+ function getToolExecutionMaxSteps(runtime) {
88
+ const setting = getSetting(runtime, "OPENROUTER_TOOL_EXECUTION_MAX_STEPS", "15");
89
+ const value = parseInt(setting || "15", 10);
90
+ if (Number.isNaN(value) || value < 1)
91
+ return 15;
92
+ if (value > 100)
93
+ return 100;
94
+ return value;
95
+ }
96
+
97
+ // src/init.ts
98
+ function initializeOpenRouter(_config, runtime) {
99
+ (async () => {
100
+ try {
101
+ const isBrowser = typeof globalThis !== "undefined" && globalThis.document;
102
+ if (isBrowser) {
103
+ return;
104
+ }
105
+ if (!getApiKey(runtime)) {
106
+ import_core.logger.warn("OPENROUTER_API_KEY is not set in environment - OpenRouter functionality will be limited");
107
+ return;
108
+ }
109
+ try {
110
+ const baseURL = getBaseURL(runtime);
111
+ const response = await import_undici.fetch(`${baseURL}/models`, {
112
+ headers: { Authorization: `Bearer ${getApiKey(runtime)}` }
113
+ });
114
+ if (!response.ok) {
115
+ import_core.logger.warn(`OpenRouter API key validation failed: ${response.statusText}`);
116
+ import_core.logger.warn("OpenRouter functionality will be limited until a valid API key is provided");
117
+ } else {
118
+ import_core.logger.log("OpenRouter API key validated successfully");
119
+ }
120
+ } catch (fetchError) {
121
+ const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
122
+ import_core.logger.warn(`Error validating OpenRouter API key: ${message}`);
123
+ import_core.logger.warn("OpenRouter functionality will be limited until a valid API key is provided");
124
+ }
125
+ } catch (error) {
126
+ const message = error?.errors?.map((e) => e.message).join(", ") || (error instanceof Error ? error.message : String(error));
127
+ import_core.logger.warn(`OpenRouter plugin configuration issue: ${message} - You need to configure the OPENROUTER_API_KEY in your environment variables`);
128
+ }
129
+ })();
130
+ return;
131
+ }
132
+
133
+ // src/models/text.ts
134
+ var import_core4 = require("@elizaos/core");
135
+ var import_ai2 = require("ai");
136
+
137
+ // src/providers/openrouter.ts
138
+ var import_ai_sdk_provider = require("@openrouter/ai-sdk-provider");
139
+ function createOpenRouterProvider(runtime) {
140
+ const apiKey = getApiKey(runtime);
141
+ const isBrowser = typeof globalThis !== "undefined" && globalThis.document;
142
+ const baseURL = getBaseURL(runtime);
143
+ return import_ai_sdk_provider.createOpenRouter({
144
+ apiKey: isBrowser ? undefined : apiKey,
145
+ baseURL
146
+ });
147
+ }
148
+ // src/utils/events.ts
149
+ var import_core2 = require("@elizaos/core");
150
+ function emitModelUsageEvent(runtime, type, prompt, usage) {
151
+ const truncatedPrompt = typeof prompt === "string" ? prompt.length > 200 ? `${prompt.slice(0, 200)}…` : prompt : "";
152
+ const inputTokens = Number(usage.inputTokens || 0);
153
+ const outputTokens = Number(usage.outputTokens || 0);
154
+ const totalTokens = Number(usage.totalTokens != null ? usage.totalTokens : inputTokens + outputTokens);
155
+ runtime.emitEvent(import_core2.EventType.MODEL_USED, {
156
+ provider: "openrouter",
157
+ type,
158
+ prompt: truncatedPrompt,
159
+ tokens: {
160
+ prompt: inputTokens,
161
+ completion: outputTokens,
162
+ total: totalTokens
163
+ }
164
+ });
165
+ }
166
+
167
+ // src/utils/helpers.ts
168
+ var import_core3 = require("@elizaos/core");
169
+ var import_ai = require("ai");
170
+ function getJsonRepairFunction() {
171
+ return async ({ text, error }) => {
172
+ try {
173
+ if (error instanceof import_ai.JSONParseError) {
174
+ const cleanedText = text.replace(/```json\n|\n```|```/g, "");
175
+ JSON.parse(cleanedText);
176
+ return cleanedText;
177
+ }
178
+ return null;
179
+ } catch (jsonError) {
180
+ const message = jsonError instanceof Error ? jsonError.message : String(jsonError);
181
+ import_core3.logger.warn(`Failed to repair JSON text: ${message}`);
182
+ return null;
183
+ }
184
+ };
185
+ }
186
+ function handleEmptyToolResponse(modelType) {
187
+ import_core3.logger.warn(`[${modelType}] No text generated after tool execution`);
188
+ const fallbackText = "I executed the requested action. The tool completed successfully.";
189
+ import_core3.logger.warn(`[${modelType}] Using fallback response text`);
190
+ return fallbackText;
191
+ }
192
+ function parseImageDescriptionResponse(responseText) {
193
+ try {
194
+ const jsonResponse = JSON.parse(responseText);
195
+ if (jsonResponse.title && jsonResponse.description) {
196
+ return jsonResponse;
197
+ }
198
+ } catch (e) {
199
+ import_core3.logger.debug(`Parsing as JSON failed, processing as text: ${e}`);
200
+ }
201
+ const titleMatch = responseText.match(/title[:\s]+(.+?)(?:\n|$)/i);
202
+ const title = titleMatch?.[1]?.trim() || "Image Analysis";
203
+ const description = responseText.replace(/title[:\s]+(.+?)(?:\n|$)/i, "").trim();
204
+ return { title, description };
205
+ }
206
+ async function handleObjectGenerationError(error) {
207
+ if (error instanceof import_ai.JSONParseError) {
208
+ import_core3.logger.error(`[generateObject] Failed to parse JSON: ${error.message}`);
209
+ const repairFunction = getJsonRepairFunction();
210
+ const repairedJsonString = await repairFunction({
211
+ text: error.text,
212
+ error
213
+ });
214
+ if (repairedJsonString) {
215
+ try {
216
+ const repairedObject = JSON.parse(repairedJsonString);
217
+ import_core3.logger.log("[generateObject] Successfully repaired JSON.");
218
+ return repairedObject;
219
+ } catch (repairParseError) {
220
+ const message = repairParseError instanceof Error ? repairParseError.message : String(repairParseError);
221
+ import_core3.logger.error(`[generateObject] Failed to parse repaired JSON: ${message}`);
222
+ if (repairParseError instanceof Error)
223
+ throw repairParseError;
224
+ throw Object.assign(new Error(message), { cause: repairParseError });
225
+ }
226
+ } else {
227
+ import_core3.logger.error("[generateObject] JSON repair failed.");
228
+ throw error;
229
+ }
230
+ } else {
231
+ const message = error instanceof Error ? error.message : String(error);
232
+ import_core3.logger.error(`[generateObject] Unknown error: ${message}`);
233
+ if (error instanceof Error)
234
+ throw error;
235
+ throw Object.assign(new Error(message), { cause: error });
236
+ }
237
+ }
238
+ function isLikelyBase64(key, value) {
239
+ const base64KeyPattern = /^(data|content|body|payload|encoded|b64|base64|document)$/i;
240
+ if (!base64KeyPattern.test(key))
241
+ return false;
242
+ if (value.length < 20 || value.length > 1024 * 1024)
243
+ return false;
244
+ if (value.length % 4 !== 0)
245
+ return false;
246
+ if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value))
247
+ return false;
248
+ return true;
249
+ }
250
+ function decodeBase64Fields(obj, depth = 0) {
251
+ if (depth > 5)
252
+ return obj;
253
+ if (!obj || typeof obj !== "object")
254
+ return obj;
255
+ if (Array.isArray(obj))
256
+ return obj.map((item) => decodeBase64Fields(item, depth + 1));
257
+ const decoded = {};
258
+ for (const [key, value] of Object.entries(obj)) {
259
+ if (typeof value === "string" && isLikelyBase64(key, value)) {
260
+ try {
261
+ decoded[key] = Buffer.from(value, "base64").toString("utf8");
262
+ import_core3.logger.debug(`[decodeBase64] Decoded field '${key}' (${value.length} chars)`);
263
+ } catch (error) {
264
+ import_core3.logger.warn(`[decodeBase64] Failed to decode field '${key}': ${error}`);
265
+ decoded[key] = value;
266
+ }
267
+ } else if (value && typeof value === "object") {
268
+ decoded[key] = decodeBase64Fields(value, depth + 1);
269
+ } else {
270
+ decoded[key] = value;
271
+ }
272
+ }
273
+ return decoded;
274
+ }
275
+
276
+ // src/models/text.ts
277
+ async function generateTextWithModel(runtime, modelType, params) {
278
+ const { prompt, stopSequences = [], tools, toolChoice } = params;
279
+ const temperature = params.temperature ?? 0.7;
280
+ const frequencyPenalty = params.frequencyPenalty ?? 0.7;
281
+ const presencePenalty = params.presencePenalty ?? 0.7;
282
+ const resolvedMaxOutput = params.maxOutputTokens ?? params.maxTokens ?? 8192;
283
+ const openrouter = createOpenRouterProvider(runtime);
284
+ const modelName = modelType === import_core4.ModelType.TEXT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
285
+ const modelLabel = modelType === import_core4.ModelType.TEXT_SMALL ? "TEXT_SMALL" : "TEXT_LARGE";
286
+ import_core4.logger.log(`[OpenRouter] Generating text with ${modelLabel} model: ${modelName}`);
287
+ const generateParams = {
288
+ model: openrouter.chat(modelName),
289
+ prompt,
290
+ system: runtime.character.system ?? undefined,
291
+ temperature,
292
+ frequencyPenalty,
293
+ presencePenalty,
294
+ stopSequences
295
+ };
296
+ generateParams.maxOutputTokens = resolvedMaxOutput;
297
+ if (tools) {
298
+ generateParams.tools = tools;
299
+ const maxSteps = getToolExecutionMaxSteps(runtime);
300
+ generateParams.maxSteps = maxSteps;
301
+ import_core4.logger.log(`[OpenRouter] Using maxSteps: ${maxSteps} for tool execution`);
302
+ }
303
+ if (toolChoice) {
304
+ generateParams.toolChoice = toolChoice;
305
+ }
306
+ let capturedToolResults = [];
307
+ let capturedToolCalls = [];
308
+ if (tools) {
309
+ generateParams.onStepFinish = async (stepResult) => {
310
+ if (stepResult.toolCalls && stepResult.toolCalls.length > 0) {
311
+ capturedToolCalls = [
312
+ ...capturedToolCalls,
313
+ ...stepResult.toolCalls
314
+ ];
315
+ }
316
+ if (stepResult.toolResults && stepResult.toolResults.length > 0) {
317
+ const decodedToolResults = stepResult.toolResults.map((result) => ({
318
+ toolCallId: result.toolCallId,
319
+ result: decodeBase64Fields(result.result)
320
+ }));
321
+ capturedToolResults = [...capturedToolResults, ...decodedToolResults];
322
+ }
323
+ };
324
+ }
325
+ const response = await import_ai2.generateText(generateParams);
326
+ let responseText;
327
+ if (tools && (!response.text || response.text.trim() === "" || response.text === "Tools executed successfully.")) {
328
+ responseText = handleEmptyToolResponse(modelLabel);
329
+ } else {
330
+ responseText = response.text;
331
+ }
332
+ if (response.usage) {
333
+ emitModelUsageEvent(runtime, modelType, prompt, response.usage);
334
+ }
335
+ if (tools && (capturedToolCalls.length > 0 || capturedToolResults.length > 0)) {
336
+ return {
337
+ text: responseText,
338
+ toolCalls: capturedToolCalls,
339
+ toolResults: capturedToolResults,
340
+ usage: response.usage,
341
+ finishReason: response.finishReason
342
+ };
343
+ }
344
+ return responseText;
345
+ }
346
+ async function handleTextSmall(runtime, params) {
347
+ return generateTextWithModel(runtime, import_core4.ModelType.TEXT_SMALL, params);
348
+ }
349
+ async function handleTextLarge(runtime, params) {
350
+ return generateTextWithModel(runtime, import_core4.ModelType.TEXT_LARGE, params);
351
+ }
352
+
353
+ // src/models/object.ts
354
+ var import_core5 = require("@elizaos/core");
355
+ var import_ai3 = require("ai");
356
+ async function generateObjectWithModel(runtime, modelType, params) {
357
+ const openrouter = createOpenRouterProvider(runtime);
358
+ const modelName = modelType === import_core5.ModelType.OBJECT_SMALL ? getSmallModel(runtime) : getLargeModel(runtime);
359
+ const modelLabel = modelType === import_core5.ModelType.OBJECT_SMALL ? "OBJECT_SMALL" : "OBJECT_LARGE";
360
+ import_core5.logger.log(`[OpenRouter] Using ${modelLabel} model: ${modelName}`);
361
+ const temperature = params.temperature ?? 0.7;
362
+ try {
363
+ const { object, usage } = await import_ai3.generateObject({
364
+ model: openrouter.chat(modelName),
365
+ ...params.schema && { schema: params.schema },
366
+ output: params.schema ? "object" : "no-schema",
367
+ prompt: params.prompt,
368
+ temperature,
369
+ experimental_repairText: getJsonRepairFunction()
370
+ });
371
+ if (usage) {
372
+ emitModelUsageEvent(runtime, modelType, params.prompt, usage);
373
+ }
374
+ return object;
375
+ } catch (error) {
376
+ return handleObjectGenerationError(error);
377
+ }
378
+ }
379
+ async function handleObjectSmall(runtime, params) {
380
+ return generateObjectWithModel(runtime, import_core5.ModelType.OBJECT_SMALL, params);
381
+ }
382
+ async function handleObjectLarge(runtime, params) {
383
+ return generateObjectWithModel(runtime, import_core5.ModelType.OBJECT_LARGE, params);
384
+ }
385
+
386
+ // src/models/image.ts
387
+ var import_core7 = require("@elizaos/core");
388
+ var import_ai4 = require("ai");
389
+
390
+ // src/utils/image-storage.ts
391
+ var import_core6 = require("@elizaos/core");
392
+ function isBrowser() {
393
+ return typeof globalThis !== "undefined" && globalThis.document;
394
+ }
395
+ function sanitizeId(id) {
396
+ const src = (id ?? "").toString();
397
+ const normalized = src.normalize("NFKC");
398
+ let safe = normalized.replace(/[^a-zA-Z0-9_-]/g, "_");
399
+ safe = safe.replace(/_+/g, "_");
400
+ safe = safe.slice(0, 64);
401
+ safe = safe.replace(/^_+|_+$/g, "");
402
+ return safe || "agent";
403
+ }
404
+ function base64ToBytes(base64) {
405
+ const cleaned = base64.replace(/\s+/g, "");
406
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
407
+ const lookup = new Array(256).fill(-1);
408
+ for (let i = 0;i < chars.length; i++)
409
+ lookup[chars.charCodeAt(i)] = i;
410
+ const len = cleaned.length;
411
+ let pad = 0;
412
+ if (len >= 2 && cleaned[len - 1] === "=")
413
+ pad++;
414
+ if (len >= 2 && cleaned[len - 2] === "=")
415
+ pad++;
416
+ const outLen = (len * 3 >> 2) - pad;
417
+ const out = new Uint8Array(outLen);
418
+ let o = 0;
419
+ for (let i = 0;i < len; i += 4) {
420
+ const c0 = lookup[cleaned.charCodeAt(i)];
421
+ const c1 = lookup[cleaned.charCodeAt(i + 1)];
422
+ const c2 = lookup[cleaned.charCodeAt(i + 2)];
423
+ const c3 = lookup[cleaned.charCodeAt(i + 3)];
424
+ const n = c0 << 18 | c1 << 12 | (c2 & 63) << 6 | c3 & 63;
425
+ if (o < outLen)
426
+ out[o++] = n >> 16 & 255;
427
+ if (o < outLen)
428
+ out[o++] = n >> 8 & 255;
429
+ if (o < outLen)
430
+ out[o++] = n & 255;
431
+ }
432
+ return out;
433
+ }
434
+ async function saveBase64Image(base64Url, agentId, index = 0) {
435
+ if (isBrowser()) {
436
+ return null;
437
+ }
438
+ const m = base64Url.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=]+)$/);
439
+ if (!m)
440
+ return null;
441
+ const mime = m[1];
442
+ const base64Data = m[2];
443
+ const extMap = {
444
+ "image/png": "png",
445
+ "image/jpeg": "jpg",
446
+ "image/jpg": "jpg",
447
+ "image/webp": "webp",
448
+ "image/gif": "gif",
449
+ "image/bmp": "bmp",
450
+ "image/tiff": "tiff"
451
+ };
452
+ const extension = extMap[mime];
453
+ if (!extension)
454
+ return null;
455
+ const { join } = await import("node:path");
456
+ const safeAgentId = sanitizeId(agentId);
457
+ const baseDir = join(import_core6.getGeneratedDir(), safeAgentId);
458
+ const { existsSync } = await import("node:fs");
459
+ if (!existsSync(baseDir)) {
460
+ const { mkdir } = await import("node:fs/promises");
461
+ await mkdir(baseDir, { recursive: true });
462
+ }
463
+ const timestamp = Date.now();
464
+ const filename = `image_${timestamp}_${index}.${extension}`;
465
+ const filepath = join(baseDir, filename);
466
+ const buffer = base64ToBytes(base64Data);
467
+ const { writeFile } = await import("node:fs/promises");
468
+ await writeFile(filepath, buffer);
469
+ import_core6.logger.info(`[OpenRouter] Saved generated image to ${filepath}`);
470
+ return filepath;
471
+ }
472
+ function deleteImage(filepath) {
473
+ if (isBrowser()) {
474
+ return;
475
+ }
476
+ try {
477
+ (async () => {
478
+ const { existsSync, unlinkSync } = await import("node:fs");
479
+ if (existsSync(filepath)) {
480
+ unlinkSync(filepath);
481
+ import_core6.logger.debug(`[OpenRouter] Deleted image: ${filepath}`);
482
+ }
483
+ })().catch((error) => {
484
+ import_core6.logger.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
485
+ });
486
+ } catch (error) {
487
+ import_core6.logger.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
488
+ }
489
+ }
490
+
491
+ // src/models/image.ts
492
+ async function handleImageDescription(runtime, params) {
493
+ let imageUrl;
494
+ let promptText;
495
+ const modelName = getImageModel(runtime);
496
+ import_core7.logger.log(`[OpenRouter] Using IMAGE_DESCRIPTION model: ${modelName}`);
497
+ const maxOutputTokens = 300;
498
+ if (typeof params === "string") {
499
+ imageUrl = params;
500
+ promptText = "Please analyze this image and provide a title and detailed description.";
501
+ } else {
502
+ imageUrl = params.imageUrl;
503
+ promptText = params.prompt || "Please analyze this image and provide a title and detailed description.";
504
+ }
505
+ const openrouter = createOpenRouterProvider(runtime);
506
+ const messages = [
507
+ {
508
+ role: "user",
509
+ content: [
510
+ { type: "text", text: promptText },
511
+ { type: "image", image: imageUrl }
512
+ ]
513
+ }
514
+ ];
515
+ try {
516
+ const model = openrouter.chat(modelName);
517
+ const { text: responseText } = await import_ai4.generateText({
518
+ model,
519
+ messages,
520
+ maxOutputTokens
521
+ });
522
+ return parseImageDescriptionResponse(responseText);
523
+ } catch (error) {
524
+ const message = error instanceof Error ? error.message : String(error);
525
+ import_core7.logger.error(`Error analyzing image: ${message}`);
526
+ return {
527
+ title: "Failed to analyze image",
528
+ description: `Error: ${message}`
529
+ };
530
+ }
531
+ }
532
+ async function handleImageGeneration(runtime, params) {
533
+ const modelName = getImageGenerationModel(runtime);
534
+ import_core7.logger.log(`[OpenRouter] Using IMAGE_GENERATION model: ${modelName}`);
535
+ const apiKey = getApiKey(runtime);
536
+ try {
537
+ const baseUrl = getBaseURL(runtime);
538
+ const isBrowser2 = typeof globalThis !== "undefined" && globalThis.document;
539
+ const response = await fetch(`${baseUrl}/chat/completions`, {
540
+ method: "POST",
541
+ headers: {
542
+ ...isBrowser2 ? {} : { Authorization: `Bearer ${apiKey}` },
543
+ "Content-Type": "application/json"
544
+ },
545
+ body: JSON.stringify({
546
+ model: modelName,
547
+ messages: [
548
+ {
549
+ role: "user",
550
+ content: params.prompt
551
+ }
552
+ ],
553
+ modalities: ["image", "text"]
554
+ }),
555
+ signal: AbortSignal.timeout ? AbortSignal.timeout(60000) : undefined
556
+ });
557
+ if (!response.ok) {
558
+ const errorText = await response.text().catch(() => "");
559
+ throw new Error(`HTTP ${response.status} ${response.statusText} ${errorText}`);
560
+ }
561
+ const result = await response.json();
562
+ const images = [];
563
+ const savedPaths = [];
564
+ if (result.choices?.[0]?.message?.images) {
565
+ for (const [index, image] of result.choices[0].message.images.entries()) {
566
+ const base64Url = image.image_url.url;
567
+ const filepath = await saveBase64Image(base64Url, runtime.agentId, index);
568
+ if (filepath) {
569
+ import_core7.logger.log(`[OpenRouter] Returning image with filepath: ${filepath}`);
570
+ images.push({
571
+ url: filepath
572
+ });
573
+ savedPaths.push(filepath);
574
+ } else if (!base64Url.startsWith("data:")) {
575
+ images.push({ url: base64Url });
576
+ } else {
577
+ import_core7.logger.warn(`[OpenRouter] Failed to save image ${index + 1}, skipping`);
578
+ }
579
+ }
580
+ }
581
+ if (savedPaths.length > 0 && shouldAutoCleanupImages(runtime)) {
582
+ setTimeout(() => {
583
+ savedPaths.forEach((path) => {
584
+ deleteImage(path);
585
+ });
586
+ }, 30000);
587
+ }
588
+ if (images.length === 0) {
589
+ throw new Error("No images generated in response");
590
+ }
591
+ import_core7.logger.log(`[OpenRouter] Generated ${images.length} image(s)`);
592
+ return images;
593
+ } catch (error) {
594
+ const message = error instanceof Error ? error.message : String(error);
595
+ import_core7.logger.error(`[OpenRouter] Error generating image: ${message}`);
596
+ return [];
597
+ }
598
+ }
599
+
600
+ // src/index.ts
601
+ var openrouterPlugin = {
602
+ name: "openrouter",
603
+ description: "OpenRouter plugin",
604
+ config: {
605
+ OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,
606
+ OPENROUTER_BASE_URL: process.env.OPENROUTER_BASE_URL,
607
+ OPENROUTER_SMALL_MODEL: process.env.OPENROUTER_SMALL_MODEL,
608
+ OPENROUTER_LARGE_MODEL: process.env.OPENROUTER_LARGE_MODEL,
609
+ OPENROUTER_IMAGE_MODEL: process.env.OPENROUTER_IMAGE_MODEL,
610
+ OPENROUTER_IMAGE_GENERATION_MODEL: process.env.OPENROUTER_IMAGE_GENERATION_MODEL,
611
+ OPENROUTER_AUTO_CLEANUP_IMAGES: process.env.OPENROUTER_AUTO_CLEANUP_IMAGES,
612
+ SMALL_MODEL: process.env.SMALL_MODEL,
613
+ LARGE_MODEL: process.env.LARGE_MODEL,
614
+ IMAGE_MODEL: process.env.IMAGE_MODEL,
615
+ IMAGE_GENERATION_MODEL: process.env.IMAGE_GENERATION_MODEL
616
+ },
617
+ async init(config, runtime) {
618
+ initializeOpenRouter(config, runtime);
619
+ },
620
+ models: {
621
+ [import_core8.ModelType.TEXT_SMALL]: async (runtime, params) => {
622
+ return handleTextSmall(runtime, params);
623
+ },
624
+ [import_core8.ModelType.TEXT_LARGE]: async (runtime, params) => {
625
+ return handleTextLarge(runtime, params);
626
+ },
627
+ [import_core8.ModelType.OBJECT_SMALL]: async (runtime, params) => {
628
+ return handleObjectSmall(runtime, params);
629
+ },
630
+ [import_core8.ModelType.OBJECT_LARGE]: async (runtime, params) => {
631
+ return handleObjectLarge(runtime, params);
632
+ },
633
+ [import_core8.ModelType.IMAGE_DESCRIPTION]: async (runtime, params) => {
634
+ return handleImageDescription(runtime, params);
635
+ },
636
+ [import_core8.ModelType.IMAGE]: async (runtime, params) => {
637
+ return handleImageGeneration(runtime, params);
638
+ }
639
+ }
640
+ };
641
+ var src_default = openrouterPlugin;
642
+
643
+ //# debugId=BF0B06B4BCE7A94F64756E2164756E21