@elizaos/plugin-openrouter 1.2.5 → 1.3.0
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/README.md +12 -4
- package/dist/index.js +200 -14
- package/dist/index.js.map +1 -1
- package/package.json +30 -9
package/README.md
CHANGED
|
@@ -23,10 +23,12 @@ The plugin requires the OpenRouter API key and can be configured via environment
|
|
|
23
23
|
"OPENROUTER_SMALL_MODEL": "google/gemini-flash", // Optional: Overrides default small model
|
|
24
24
|
"OPENROUTER_LARGE_MODEL": "google/gemini-pro", // Optional: Overrides default large model
|
|
25
25
|
"OPENROUTER_IMAGE_MODEL": "x-ai/grok-2-vision-1212", // Optional: Overrides default image model
|
|
26
|
+
"OPENROUTER_IMAGE_GENERATION_MODEL": "google/gemini-2.5-flash-image-preview", // Optional: Overrides default image generation model
|
|
26
27
|
// Fallbacks if specific OPENROUTER models are not set
|
|
27
28
|
"SMALL_MODEL": "google/gemini-flash",
|
|
28
29
|
"LARGE_MODEL": "google/gemini-pro",
|
|
29
|
-
"IMAGE_MODEL": "x-ai/grok-2-vision-1212"
|
|
30
|
+
"IMAGE_MODEL": "x-ai/grok-2-vision-1212",
|
|
31
|
+
"IMAGE_GENERATION_MODEL": "google/gemini-2.5-flash-image-preview"
|
|
30
32
|
}
|
|
31
33
|
```
|
|
32
34
|
|
|
@@ -39,10 +41,12 @@ OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
|
|
|
39
41
|
OPENROUTER_SMALL_MODEL=google/gemini-flash
|
|
40
42
|
OPENROUTER_LARGE_MODEL=google/gemini-pro
|
|
41
43
|
OPENROUTER_IMAGE_MODEL=x-ai/grok-2-vision-1212
|
|
44
|
+
OPENROUTER_IMAGE_GENERATION_MODEL=google/gemini-2.5-flash-image-preview
|
|
42
45
|
# Fallbacks if specific OPENROUTER models are not set
|
|
43
46
|
SMALL_MODEL=google/gemini-flash
|
|
44
47
|
LARGE_MODEL=google/gemini-pro
|
|
45
48
|
IMAGE_MODEL=x-ai/grok-2-vision-1212
|
|
49
|
+
IMAGE_GENERATION_MODEL=google/gemini-2.5-flash-image-preview
|
|
46
50
|
```
|
|
47
51
|
|
|
48
52
|
### Configuration Options
|
|
@@ -52,9 +56,12 @@ IMAGE_MODEL=x-ai/grok-2-vision-1212
|
|
|
52
56
|
- `OPENROUTER_SMALL_MODEL`: Specific model to use for `TEXT_SMALL` and `OBJECT_SMALL`. Overrides `SMALL_MODEL` if set.
|
|
53
57
|
- `OPENROUTER_LARGE_MODEL`: Specific model to use for `TEXT_LARGE` and `OBJECT_LARGE`. Overrides `LARGE_MODEL` if set.
|
|
54
58
|
- `OPENROUTER_IMAGE_MODEL`: Specific model to use for `IMAGE_DESCRIPTION`. Overrides `IMAGE_MODEL` if set.
|
|
55
|
-
- `
|
|
56
|
-
- `
|
|
59
|
+
- `OPENROUTER_IMAGE_GENERATION_MODEL`: Specific model to use for `IMAGE` generation. Overrides `IMAGE_GENERATION_MODEL` if set.
|
|
60
|
+
- `OPENROUTER_AUTO_CLEANUP_IMAGES`: Whether to automatically delete generated images after 30 seconds (default: "false"). Set to "true" to enable auto-cleanup.
|
|
61
|
+
- `SMALL_MODEL`: Fallback model for small tasks (default: "google/gemini-2.0-flash-001"). Used if `OPENROUTER_SMALL_MODEL` is not set.
|
|
62
|
+
- `LARGE_MODEL`: Fallback model for large tasks (default: "openai/gpt-4.1-nano"). Used if `OPENROUTER_LARGE_MODEL` is not set.
|
|
57
63
|
- `IMAGE_MODEL`: Fallback model for image analysis (default: "x-ai/grok-2-vision-1212"). Used if `OPENROUTER_IMAGE_MODEL` is not set.
|
|
64
|
+
- `IMAGE_GENERATION_MODEL`: Fallback model for image generation (default: "google/gemini-2.5-flash-image-preview"). Used if `OPENROUTER_IMAGE_GENERATION_MODEL` is not set.
|
|
58
65
|
|
|
59
66
|
## Provided Models
|
|
60
67
|
|
|
@@ -65,5 +72,6 @@ The plugin currently provides these model types:
|
|
|
65
72
|
- `OBJECT_SMALL`: Generates structured JSON objects based on a prompt, using the configured small model.
|
|
66
73
|
- `OBJECT_LARGE`: Generates structured JSON objects based on a prompt, using the configured large model.
|
|
67
74
|
- `IMAGE_DESCRIPTION`: Analyzes images and provides descriptive text and titles, using the configured image model.
|
|
75
|
+
- `IMAGE`: Generates images from text prompts using the configured image generation model (e.g., Gemini 2.5 Flash Image Preview).
|
|
68
76
|
|
|
69
|
-
_Note: Features like
|
|
77
|
+
_Note: Features like Audio Transcription and Embeddings are not currently implemented in this specific OpenRouter plugin._
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/init.ts
|
|
7
7
|
import { logger } from "@elizaos/core";
|
|
8
|
-
import { fetch } from "undici";
|
|
8
|
+
import { fetch as fetch2 } from "undici";
|
|
9
9
|
|
|
10
10
|
// src/utils/config.ts
|
|
11
11
|
function getSetting(runtime, key, defaultValue) {
|
|
@@ -28,12 +28,19 @@ function getLargeModel(runtime) {
|
|
|
28
28
|
return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(
|
|
29
29
|
runtime,
|
|
30
30
|
"LARGE_MODEL",
|
|
31
|
-
"google/gemini-2.5-flash
|
|
32
|
-
) ?? "google/gemini-2.5-flash
|
|
31
|
+
"google/gemini-2.5-flash"
|
|
32
|
+
) ?? "google/gemini-2.5-flash";
|
|
33
33
|
}
|
|
34
34
|
function getImageModel(runtime) {
|
|
35
35
|
return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL", "x-ai/grok-2-vision-1212") ?? "x-ai/grok-2-vision-1212";
|
|
36
36
|
}
|
|
37
|
+
function getImageGenerationModel(runtime) {
|
|
38
|
+
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";
|
|
39
|
+
}
|
|
40
|
+
function shouldAutoCleanupImages(runtime) {
|
|
41
|
+
const setting = getSetting(runtime, "OPENROUTER_AUTO_CLEANUP_IMAGES", "false");
|
|
42
|
+
return setting?.toLowerCase() === "true";
|
|
43
|
+
}
|
|
37
44
|
|
|
38
45
|
// src/init.ts
|
|
39
46
|
function initializeOpenRouter(_config, runtime) {
|
|
@@ -47,7 +54,7 @@ function initializeOpenRouter(_config, runtime) {
|
|
|
47
54
|
}
|
|
48
55
|
try {
|
|
49
56
|
const baseURL = getBaseURL(runtime);
|
|
50
|
-
const response = await
|
|
57
|
+
const response = await fetch2(`${baseURL}/models`, {
|
|
51
58
|
headers: { Authorization: `Bearer ${getApiKey(runtime)}` }
|
|
52
59
|
});
|
|
53
60
|
if (!response.ok) {
|
|
@@ -78,10 +85,7 @@ function initializeOpenRouter(_config, runtime) {
|
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
// src/models/text.ts
|
|
81
|
-
import {
|
|
82
|
-
ModelType,
|
|
83
|
-
logger as logger4
|
|
84
|
-
} from "@elizaos/core";
|
|
88
|
+
import { logger as logger4, ModelType } from "@elizaos/core";
|
|
85
89
|
import { generateText } from "ai";
|
|
86
90
|
|
|
87
91
|
// src/providers/openrouter.ts
|
|
@@ -176,7 +180,8 @@ async function handleObjectGenerationError(error) {
|
|
|
176
180
|
logger3.error(
|
|
177
181
|
`[generateObject] Failed to parse repaired JSON: ${message}`
|
|
178
182
|
);
|
|
179
|
-
|
|
183
|
+
if (repairParseError instanceof Error) throw repairParseError;
|
|
184
|
+
throw Object.assign(new Error(message), { cause: repairParseError });
|
|
180
185
|
}
|
|
181
186
|
} else {
|
|
182
187
|
logger3.error("[generateObject] JSON repair failed.");
|
|
@@ -185,8 +190,39 @@ async function handleObjectGenerationError(error) {
|
|
|
185
190
|
} else {
|
|
186
191
|
const message = error instanceof Error ? error.message : String(error);
|
|
187
192
|
logger3.error(`[generateObject] Unknown error: ${message}`);
|
|
188
|
-
|
|
193
|
+
if (error instanceof Error) throw error;
|
|
194
|
+
throw Object.assign(new Error(message), { cause: error });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function isLikelyBase64(key, value) {
|
|
198
|
+
const base64KeyPattern = /^(data|content|body|payload|encoded|b64|base64|document)$/i;
|
|
199
|
+
if (!base64KeyPattern.test(key)) return false;
|
|
200
|
+
if (value.length < 20 || value.length > 1024 * 1024) return false;
|
|
201
|
+
if (value.length % 4 !== 0) return false;
|
|
202
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value)) return false;
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
function decodeBase64Fields(obj, depth = 0) {
|
|
206
|
+
if (depth > 5) return obj;
|
|
207
|
+
if (!obj || typeof obj !== "object") return obj;
|
|
208
|
+
if (Array.isArray(obj)) return obj.map((item) => decodeBase64Fields(item, depth + 1));
|
|
209
|
+
const decoded = {};
|
|
210
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
211
|
+
if (typeof value === "string" && isLikelyBase64(key, value)) {
|
|
212
|
+
try {
|
|
213
|
+
decoded[key] = Buffer.from(value, "base64").toString("utf8");
|
|
214
|
+
logger3.debug(`[decodeBase64] Decoded field '${key}' (${value.length} chars)`);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
logger3.warn(`[decodeBase64] Failed to decode field '${key}': ${error}`);
|
|
217
|
+
decoded[key] = value;
|
|
218
|
+
}
|
|
219
|
+
} else if (value && typeof value === "object") {
|
|
220
|
+
decoded[key] = decodeBase64Fields(value, depth + 1);
|
|
221
|
+
} else {
|
|
222
|
+
decoded[key] = value;
|
|
223
|
+
}
|
|
189
224
|
}
|
|
225
|
+
return decoded;
|
|
190
226
|
}
|
|
191
227
|
|
|
192
228
|
// src/models/text.ts
|
|
@@ -224,6 +260,22 @@ async function generateTextWithModel(runtime, modelType, params) {
|
|
|
224
260
|
if (toolChoice) {
|
|
225
261
|
generateParams.toolChoice = toolChoice;
|
|
226
262
|
}
|
|
263
|
+
let capturedToolResults = [];
|
|
264
|
+
let capturedToolCalls = [];
|
|
265
|
+
if (tools) {
|
|
266
|
+
generateParams.onStepFinish = async (stepResult) => {
|
|
267
|
+
if (stepResult.toolCalls && stepResult.toolCalls.length > 0) {
|
|
268
|
+
capturedToolCalls = [...capturedToolCalls, ...stepResult.toolCalls];
|
|
269
|
+
}
|
|
270
|
+
if (stepResult.toolResults && stepResult.toolResults.length > 0) {
|
|
271
|
+
const decodedToolResults = stepResult.toolResults.map((result) => ({
|
|
272
|
+
...result,
|
|
273
|
+
result: decodeBase64Fields(result.result)
|
|
274
|
+
}));
|
|
275
|
+
capturedToolResults = [...capturedToolResults, ...decodedToolResults];
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
227
279
|
const response = await generateText(generateParams);
|
|
228
280
|
let responseText;
|
|
229
281
|
if (tools && (!response.text || response.text.trim() === "" || response.text === "Tools executed successfully.")) {
|
|
@@ -234,6 +286,16 @@ async function generateTextWithModel(runtime, modelType, params) {
|
|
|
234
286
|
if (response.usage) {
|
|
235
287
|
emitModelUsageEvent(runtime, modelType, prompt, response.usage);
|
|
236
288
|
}
|
|
289
|
+
if (tools && (capturedToolCalls.length > 0 || capturedToolResults.length > 0)) {
|
|
290
|
+
return {
|
|
291
|
+
text: responseText,
|
|
292
|
+
toolCalls: capturedToolCalls,
|
|
293
|
+
toolResults: capturedToolResults,
|
|
294
|
+
// Include other useful properties
|
|
295
|
+
usage: response.usage,
|
|
296
|
+
finishReason: response.finishReason
|
|
297
|
+
};
|
|
298
|
+
}
|
|
237
299
|
return responseText;
|
|
238
300
|
}
|
|
239
301
|
async function handleTextSmall(runtime, params) {
|
|
@@ -280,14 +342,60 @@ async function handleObjectLarge(runtime, params) {
|
|
|
280
342
|
|
|
281
343
|
// src/models/image.ts
|
|
282
344
|
import {
|
|
283
|
-
logger as
|
|
345
|
+
logger as logger7
|
|
284
346
|
} from "@elizaos/core";
|
|
285
347
|
import { generateText as generateText2 } from "ai";
|
|
348
|
+
|
|
349
|
+
// src/utils/image-storage.ts
|
|
350
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
351
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
352
|
+
import { join } from "node:path";
|
|
353
|
+
import { logger as logger6, getGeneratedDir } from "@elizaos/core";
|
|
354
|
+
async function saveBase64Image(base64Url, agentId, index = 0) {
|
|
355
|
+
const m = base64Url.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=]+)$/);
|
|
356
|
+
if (!m) return null;
|
|
357
|
+
const mime = m[1];
|
|
358
|
+
const base64Data = m[2];
|
|
359
|
+
const extMap = {
|
|
360
|
+
"image/png": "png",
|
|
361
|
+
"image/jpeg": "jpg",
|
|
362
|
+
"image/jpg": "jpg",
|
|
363
|
+
"image/webp": "webp",
|
|
364
|
+
"image/gif": "gif",
|
|
365
|
+
"image/bmp": "bmp",
|
|
366
|
+
"image/tiff": "tiff"
|
|
367
|
+
};
|
|
368
|
+
const extension = extMap[mime];
|
|
369
|
+
if (!extension) return null;
|
|
370
|
+
const baseDir = join(getGeneratedDir(), agentId);
|
|
371
|
+
if (!existsSync(baseDir)) {
|
|
372
|
+
await mkdir(baseDir, { recursive: true });
|
|
373
|
+
}
|
|
374
|
+
const timestamp = Date.now();
|
|
375
|
+
const filename = `image_${timestamp}_${index}.${extension}`;
|
|
376
|
+
const filepath = join(baseDir, filename);
|
|
377
|
+
const buffer = Buffer.from(base64Data, "base64");
|
|
378
|
+
await writeFile(filepath, buffer);
|
|
379
|
+
logger6.info(`[OpenRouter] Saved generated image to ${filepath}`);
|
|
380
|
+
return filepath;
|
|
381
|
+
}
|
|
382
|
+
function deleteImage(filepath) {
|
|
383
|
+
try {
|
|
384
|
+
if (existsSync(filepath)) {
|
|
385
|
+
unlinkSync(filepath);
|
|
386
|
+
logger6.debug(`[OpenRouter] Deleted image: ${filepath}`);
|
|
387
|
+
}
|
|
388
|
+
} catch (error) {
|
|
389
|
+
logger6.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/models/image.ts
|
|
286
394
|
async function handleImageDescription(runtime, params) {
|
|
287
395
|
let imageUrl;
|
|
288
396
|
let promptText;
|
|
289
397
|
const modelName = getImageModel(runtime);
|
|
290
|
-
|
|
398
|
+
logger7.log(`[OpenRouter] Using IMAGE_DESCRIPTION model: ${modelName}`);
|
|
291
399
|
const maxTokens = 300;
|
|
292
400
|
if (typeof params === "string") {
|
|
293
401
|
imageUrl = params;
|
|
@@ -316,13 +424,85 @@ async function handleImageDescription(runtime, params) {
|
|
|
316
424
|
return parseImageDescriptionResponse(responseText);
|
|
317
425
|
} catch (error) {
|
|
318
426
|
const message = error instanceof Error ? error.message : String(error);
|
|
319
|
-
|
|
427
|
+
logger7.error(`Error analyzing image: ${message}`);
|
|
320
428
|
return {
|
|
321
429
|
title: "Failed to analyze image",
|
|
322
430
|
description: `Error: ${message}`
|
|
323
431
|
};
|
|
324
432
|
}
|
|
325
433
|
}
|
|
434
|
+
async function handleImageGeneration(runtime, params) {
|
|
435
|
+
const modelName = getImageGenerationModel(runtime);
|
|
436
|
+
logger7.log(`[OpenRouter] Using IMAGE_GENERATION model: ${modelName}`);
|
|
437
|
+
const apiKey = getApiKey(runtime);
|
|
438
|
+
try {
|
|
439
|
+
if (!apiKey) {
|
|
440
|
+
logger7.error("[OpenRouter] OpenRouter API key is missing");
|
|
441
|
+
return [];
|
|
442
|
+
}
|
|
443
|
+
const baseUrl = getBaseURL(runtime);
|
|
444
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
445
|
+
method: "POST",
|
|
446
|
+
headers: {
|
|
447
|
+
Authorization: `Bearer ${apiKey}`,
|
|
448
|
+
"Content-Type": "application/json"
|
|
449
|
+
},
|
|
450
|
+
body: JSON.stringify({
|
|
451
|
+
model: modelName,
|
|
452
|
+
messages: [
|
|
453
|
+
{
|
|
454
|
+
role: "user",
|
|
455
|
+
content: params.prompt
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
modalities: ["image", "text"]
|
|
459
|
+
}),
|
|
460
|
+
// 60 seconds timeout
|
|
461
|
+
signal: AbortSignal.timeout ? AbortSignal.timeout(6e4) : void 0
|
|
462
|
+
});
|
|
463
|
+
if (!response.ok) {
|
|
464
|
+
const errorText = await response.text().catch(() => "");
|
|
465
|
+
throw new Error(`HTTP ${response.status} ${response.statusText} ${errorText}`);
|
|
466
|
+
}
|
|
467
|
+
const result = await response.json();
|
|
468
|
+
const images = [];
|
|
469
|
+
const savedPaths = [];
|
|
470
|
+
if (result.choices?.[0]?.message?.images) {
|
|
471
|
+
for (const [index, image] of result.choices[0].message.images.entries()) {
|
|
472
|
+
const base64Url = image.image_url.url;
|
|
473
|
+
const filepath = await saveBase64Image(base64Url, runtime.agentId, index);
|
|
474
|
+
if (filepath) {
|
|
475
|
+
logger7.log(`[OpenRouter] Returning image with filepath: ${filepath}`);
|
|
476
|
+
images.push({
|
|
477
|
+
url: filepath
|
|
478
|
+
// Use actual file path
|
|
479
|
+
});
|
|
480
|
+
savedPaths.push(filepath);
|
|
481
|
+
} else if (!base64Url.startsWith("data:")) {
|
|
482
|
+
images.push({ url: base64Url });
|
|
483
|
+
} else {
|
|
484
|
+
logger7.warn(`[OpenRouter] Failed to save image ${index + 1}, skipping`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (savedPaths.length > 0 && shouldAutoCleanupImages(runtime)) {
|
|
489
|
+
setTimeout(() => {
|
|
490
|
+
savedPaths.forEach((path) => {
|
|
491
|
+
deleteImage(path);
|
|
492
|
+
});
|
|
493
|
+
}, 3e4);
|
|
494
|
+
}
|
|
495
|
+
if (images.length === 0) {
|
|
496
|
+
throw new Error("No images generated in response");
|
|
497
|
+
}
|
|
498
|
+
logger7.log(`[OpenRouter] Generated ${images.length} image(s)`);
|
|
499
|
+
return images;
|
|
500
|
+
} catch (error) {
|
|
501
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
502
|
+
logger7.error(`[OpenRouter] Error generating image: ${message}`);
|
|
503
|
+
return [];
|
|
504
|
+
}
|
|
505
|
+
}
|
|
326
506
|
|
|
327
507
|
// src/index.ts
|
|
328
508
|
var openrouterPlugin = {
|
|
@@ -334,9 +514,12 @@ var openrouterPlugin = {
|
|
|
334
514
|
OPENROUTER_SMALL_MODEL: process.env.OPENROUTER_SMALL_MODEL,
|
|
335
515
|
OPENROUTER_LARGE_MODEL: process.env.OPENROUTER_LARGE_MODEL,
|
|
336
516
|
OPENROUTER_IMAGE_MODEL: process.env.OPENROUTER_IMAGE_MODEL,
|
|
517
|
+
OPENROUTER_IMAGE_GENERATION_MODEL: process.env.OPENROUTER_IMAGE_GENERATION_MODEL,
|
|
518
|
+
OPENROUTER_AUTO_CLEANUP_IMAGES: process.env.OPENROUTER_AUTO_CLEANUP_IMAGES,
|
|
337
519
|
SMALL_MODEL: process.env.SMALL_MODEL,
|
|
338
520
|
LARGE_MODEL: process.env.LARGE_MODEL,
|
|
339
|
-
IMAGE_MODEL: process.env.IMAGE_MODEL
|
|
521
|
+
IMAGE_MODEL: process.env.IMAGE_MODEL,
|
|
522
|
+
IMAGE_GENERATION_MODEL: process.env.IMAGE_GENERATION_MODEL
|
|
340
523
|
},
|
|
341
524
|
async init(config, runtime) {
|
|
342
525
|
initializeOpenRouter(config, runtime);
|
|
@@ -356,6 +539,9 @@ var openrouterPlugin = {
|
|
|
356
539
|
},
|
|
357
540
|
[ModelType3.IMAGE_DESCRIPTION]: async (runtime, params) => {
|
|
358
541
|
return handleImageDescription(runtime, params);
|
|
542
|
+
},
|
|
543
|
+
[ModelType3.IMAGE]: async (runtime, params) => {
|
|
544
|
+
return handleImageGeneration(runtime, params);
|
|
359
545
|
}
|
|
360
546
|
}
|
|
361
547
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/init.ts","../src/utils/config.ts","../src/models/text.ts","../src/providers/openrouter.ts","../src/utils/events.ts","../src/utils/helpers.ts","../src/models/object.ts","../src/models/image.ts"],"sourcesContent":["import {\n ModelType,\n type Plugin,\n type IAgentRuntime,\n type GenerateTextParams,\n type ObjectGenerationParams,\n type ImageDescriptionParams,\n} from \"@elizaos/core\";\nimport type { Tool, ToolChoice } from \"ai\";\nimport { initializeOpenRouter } from \"./init\";\nimport { handleTextSmall, handleTextLarge } from \"./models/text\";\nimport { handleObjectSmall, handleObjectLarge } from \"./models/object\";\nimport { handleImageDescription } from \"./models/image\";\n\n/**\n * Defines the OpenRouter plugin with its name, description, and configuration options.\n * @type {Plugin}\n */\nexport const openrouterPlugin: Plugin = {\n name: \"openrouter\",\n description: \"OpenRouter plugin\",\n config: {\n OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,\n OPENROUTER_BASE_URL: process.env.OPENROUTER_BASE_URL,\n OPENROUTER_SMALL_MODEL: process.env.OPENROUTER_SMALL_MODEL,\n OPENROUTER_LARGE_MODEL: process.env.OPENROUTER_LARGE_MODEL,\n OPENROUTER_IMAGE_MODEL: process.env.OPENROUTER_IMAGE_MODEL,\n SMALL_MODEL: process.env.SMALL_MODEL,\n LARGE_MODEL: process.env.LARGE_MODEL,\n IMAGE_MODEL: process.env.IMAGE_MODEL,\n },\n async init(config, runtime) {\n // Note: We intentionally don't await here because ElizaOS expects\n // the init method to return quickly. The initializeOpenRouter function\n // only performs synchronous validation and logging, so it's safe to\n // call without await. This prevents blocking the plugin initialization.\n initializeOpenRouter(config, runtime);\n },\n models: {\n [ModelType.TEXT_SMALL]: async (\n runtime: IAgentRuntime,\n params: GenerateTextParams & {\n tools?: Record<string, Tool>;\n toolChoice?: ToolChoice<Record<string, Tool>>;\n },\n ) => {\n return handleTextSmall(runtime, params);\n },\n [ModelType.TEXT_LARGE]: async (\n runtime: IAgentRuntime,\n params: GenerateTextParams & {\n tools?: Record<string, Tool>;\n toolChoice?: ToolChoice<Record<string, Tool>>;\n },\n ) => {\n return handleTextLarge(runtime, params);\n },\n [ModelType.OBJECT_SMALL]: async (\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n ) => {\n return handleObjectSmall(runtime, params);\n },\n [ModelType.OBJECT_LARGE]: async (\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n ) => {\n return handleObjectLarge(runtime, params);\n },\n [ModelType.IMAGE_DESCRIPTION]: async (\n runtime: IAgentRuntime,\n params: ImageDescriptionParams | string,\n ) => {\n return handleImageDescription(runtime, params);\n },\n },\n};\n\nexport default openrouterPlugin;\n","import { logger, type IAgentRuntime } from \"@elizaos/core\";\nimport { fetch } from \"undici\";\nimport { getApiKey, getBaseURL } from \"./utils/config\";\n\n/**\n * Initialize and validate OpenRouter configuration\n * Returns the exact same function that works inline\n */\nexport function initializeOpenRouter(_config: any, runtime: IAgentRuntime) {\n // do check in the background\n (async () => {\n try {\n if (!getApiKey(runtime)) {\n logger.warn(\n \"OPENROUTER_API_KEY is not set in environment - OpenRouter functionality will be limited\",\n );\n return;\n }\n try {\n const baseURL = getBaseURL(runtime);\n const response = await fetch(`${baseURL}/models`, {\n headers: { Authorization: `Bearer ${getApiKey(runtime)}` },\n });\n if (!response.ok) {\n logger.warn(\n `OpenRouter API key validation failed: ${response.statusText}`,\n );\n logger.warn(\n \"OpenRouter functionality will be limited until a valid API key is provided\",\n );\n } else {\n logger.log(\"OpenRouter API key validated successfully\");\n }\n } catch (fetchError: unknown) {\n const message =\n fetchError instanceof Error ? fetchError.message : String(fetchError);\n logger.warn(`Error validating OpenRouter API key: ${message}`);\n logger.warn(\n \"OpenRouter functionality will be limited until a valid API key is provided\",\n );\n }\n } catch (error: unknown) {\n const message =\n (error as { errors?: Array<{ message: string }> })?.errors\n ?.map((e) => e.message)\n .join(\", \") ||\n (error instanceof Error ? error.message : String(error));\n logger.warn(\n `OpenRouter plugin configuration issue: ${message} - You need to configure the OPENROUTER_API_KEY in your environment variables`,\n );\n }\n })();\n return;\n}\n","import type { IAgentRuntime } from \"@elizaos/core\";\n\n/**\n * Retrieves a configuration setting from the runtime, falling back to environment variables or a default value if not found.\n *\n * @param key - The name of the setting to retrieve.\n * @param defaultValue - The value to return if the setting is not found in the runtime or environment.\n * @returns The resolved setting value, or {@link defaultValue} if not found.\n */\nexport function getSetting(\n runtime: IAgentRuntime,\n key: string,\n defaultValue?: string,\n): string | undefined {\n return runtime.getSetting(key) ?? process.env[key] ?? defaultValue;\n}\n\n/**\n * Retrieves the OpenRouter API base URL from runtime settings, environment variables, or defaults.\n *\n * @returns The resolved base URL for OpenRouter API requests.\n */\nexport function getBaseURL(runtime: IAgentRuntime): string {\n return (\n getSetting(\n runtime,\n \"OPENROUTER_BASE_URL\",\n \"https://openrouter.ai/api/v1\",\n ) || \"https://openrouter.ai/api/v1\"\n );\n}\n\n/**\n * Helper function to get the API key for OpenRouter\n *\n * @param runtime The runtime context\n * @returns The configured API key\n */\nexport function getApiKey(runtime: IAgentRuntime): string | undefined {\n return getSetting(runtime, \"OPENROUTER_API_KEY\");\n}\n\n/**\n * Helper function to get the small model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured small model name\n */\nexport function getSmallModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENROUTER_SMALL_MODEL\") ??\n getSetting(runtime, \"SMALL_MODEL\", \"google/gemini-2.0-flash-001\") ??\n \"google/gemini-2.0-flash-001\"\n );\n}\n\n/**\n * Helper function to get the large model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured large model name\n */\nexport function getLargeModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENROUTER_LARGE_MODEL\") ??\n getSetting(\n runtime,\n \"LARGE_MODEL\",\n \"google/gemini-2.5-flash-preview-05-20\",\n ) ??\n \"google/gemini-2.5-flash-preview-05-20\"\n );\n}\n\n/**\n * Helper function to get the image model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured image model name\n */\nexport function getImageModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENROUTER_IMAGE_MODEL\") ??\n getSetting(runtime, \"IMAGE_MODEL\", \"x-ai/grok-2-vision-1212\") ??\n \"x-ai/grok-2-vision-1212\"\n );\n}\n","import {\n ModelType,\n logger,\n type IAgentRuntime,\n type GenerateTextParams,\n} from \"@elizaos/core\";\nimport type { Tool, ToolChoice } from \"ai\";\nimport { generateText } from \"ai\";\nimport { createOpenRouterProvider } from \"../providers\";\nimport { getSmallModel, getLargeModel } from \"../utils/config\";\nimport { emitModelUsageEvent } from \"../utils/events\";\nimport { handleEmptyToolResponse } from \"../utils/helpers\";\n\n/**\n * Common text generation logic for both small and large models\n */\nasync function generateTextWithModel(\n runtime: IAgentRuntime,\n modelType: typeof ModelType.TEXT_SMALL | typeof ModelType.TEXT_LARGE,\n params: GenerateTextParams & {\n tools?: Record<string, Tool>;\n toolChoice?: ToolChoice<Record<string, Tool>>;\n },\n): Promise<string> {\n const { prompt, stopSequences = [], tools, toolChoice } = params;\n const temperature = params.temperature ?? 0.7;\n const frequencyPenalty = params.frequencyPenalty ?? 0.7;\n const presencePenalty = params.presencePenalty ?? 0.7;\n const maxResponseLength = params.maxTokens ?? 8192;\n\n const openrouter = createOpenRouterProvider(runtime);\n const modelName =\n modelType === ModelType.TEXT_SMALL\n ? getSmallModel(runtime)\n : getLargeModel(runtime);\n const modelLabel =\n modelType === ModelType.TEXT_SMALL ? \"TEXT_SMALL\" : \"TEXT_LARGE\";\n\n logger.log(\n `[OpenRouter] Generating text with ${modelLabel} model: ${modelName}`,\n );\n\n const generateParams: Parameters<typeof generateText>[0] & {\n extra_body?: { provider?: { require_parameters?: boolean } };\n } = {\n model: openrouter.chat(modelName),\n prompt: prompt,\n system: runtime.character.system ?? undefined,\n temperature: temperature,\n maxTokens: maxResponseLength,\n frequencyPenalty: frequencyPenalty,\n presencePenalty: presencePenalty,\n stopSequences: stopSequences,\n };\n\n // Add tools if provided\n if (tools) {\n generateParams.tools = tools;\n generateParams.maxSteps = 10; // Allow tool call + response generation\n // For OpenRouter: ensure request is only routed to providers that support function calling\n generateParams.extra_body = {\n provider: {\n require_parameters: true,\n },\n };\n }\n\n // Add toolChoice if provided\n if (toolChoice) {\n generateParams.toolChoice = toolChoice;\n }\n\n const response = await generateText(generateParams);\n\n // Handle cases where tool execution doesn't generate text\n let responseText: string;\n if (\n tools &&\n (!response.text ||\n response.text.trim() === \"\" ||\n response.text === \"Tools executed successfully.\")\n ) {\n responseText = handleEmptyToolResponse(modelLabel);\n } else {\n responseText = response.text;\n }\n\n if (response.usage) {\n emitModelUsageEvent(runtime, modelType, prompt, response.usage);\n }\n\n return responseText;\n}\n\n/**\n * TEXT_SMALL model handler\n */\nexport async function handleTextSmall(\n runtime: IAgentRuntime,\n params: GenerateTextParams & {\n tools?: Record<string, Tool>;\n toolChoice?: ToolChoice<Record<string, Tool>>;\n },\n): Promise<string> {\n return generateTextWithModel(runtime, ModelType.TEXT_SMALL, params);\n}\n\n/**\n * TEXT_LARGE model handler\n */\nexport async function handleTextLarge(\n runtime: IAgentRuntime,\n params: GenerateTextParams & {\n tools?: Record<string, Tool>;\n toolChoice?: ToolChoice<Record<string, Tool>>;\n },\n): Promise<string> {\n return generateTextWithModel(runtime, ModelType.TEXT_LARGE, params);\n}\n","import { createOpenRouter } from \"@openrouter/ai-sdk-provider\";\nimport { logger, type IAgentRuntime } from \"@elizaos/core\";\nimport { getApiKey } from \"../utils/config\";\n\n/**\n * Create an OpenRouter provider instance with proper configuration\n *\n * @param runtime The runtime context\n * @returns Configured OpenRouter provider instance\n */\nexport function createOpenRouterProvider(runtime: IAgentRuntime) {\n const apiKey = getApiKey(runtime);\n if (!apiKey) {\n // This case should ideally be caught in init, but good practice to check\n logger.error(\n \"OpenRouter API Key is missing when trying to create provider\",\n );\n throw new Error(\"OpenRouter API Key is missing.\");\n }\n\n // Note: createOpenRouter doesn't seem to take baseURL directly in the documentation.\n // It might pick it up from OPENROUTER_BASE_URL env var automatically,\n // or it might not be needed/configurable in the same way as createOpenRouter.\n // We'll rely on the apiKey for now.\n return createOpenRouter({\n apiKey: apiKey,\n // We might need to handle baseURL differently if required.\n // The @ai-sdk/provider utils might handle OPENROUTER_BASE_URL env var.\n });\n}\n","import {\n EventType,\n type IAgentRuntime,\n type ModelTypeName,\n} from \"@elizaos/core\";\nimport type { LanguageModelUsage } from \"ai\";\n\n/**\n * Emits a model usage event\n */\nexport function emitModelUsageEvent(\n runtime: IAgentRuntime,\n type: ModelTypeName,\n prompt: string,\n usage: LanguageModelUsage,\n) {\n runtime.emitEvent(EventType.MODEL_USED, {\n provider: \"openrouter\",\n type,\n prompt,\n tokens: {\n prompt: usage.promptTokens,\n completion: usage.completionTokens,\n total: usage.totalTokens,\n },\n });\n}\n","import { logger } from \"@elizaos/core\";\nimport { JSONParseError } from \"ai\";\nimport type { GenerateTextResponse, ImageDescriptionResult } from \"../types\";\nimport { emitModelUsageEvent } from \"./events\";\n\n/**\n * Returns a function to repair JSON text\n */\nexport function getJsonRepairFunction(): (params: {\n text: string;\n error: unknown;\n}) => Promise<string | null> {\n return async ({ text, error }: { text: string; error: unknown }) => {\n try {\n if (error instanceof JSONParseError) {\n const cleanedText = text.replace(/```json\\n|\\n```|```/g, \"\");\n JSON.parse(cleanedText);\n return cleanedText;\n }\n return null;\n } catch (jsonError: unknown) {\n const message =\n jsonError instanceof Error ? jsonError.message : String(jsonError);\n logger.warn(`Failed to repair JSON text: ${message}`);\n return null;\n }\n };\n}\n\n// Re-export for backward compatibility\nexport { emitModelUsageEvent } from \"./events\";\n\n/**\n * Logs response structure for debugging (debug level only)\n */\nexport function logResponseStructure(\n modelType: string,\n response: GenerateTextResponse,\n) {\n logger.debug(`[${modelType}] Response structure:`, {\n hasText: !!response.text,\n textLength: response.text?.length || 0,\n hasSteps: !!response.steps,\n stepsCount: response.steps?.length || 0,\n finishReason: response.finishReason,\n usage: response.usage,\n });\n}\n\n/**\n * Handles cases where tool execution doesn't generate text\n */\nexport function handleEmptyToolResponse(modelType: string): string {\n logger.warn(`[${modelType}] No text generated after tool execution`);\n\n const fallbackText =\n \"I executed the requested action. The tool completed successfully.\";\n logger.warn(`[${modelType}] Using fallback response text`);\n return fallbackText;\n}\n\n/**\n * Parses image description response from text or JSON format\n */\nexport function parseImageDescriptionResponse(\n responseText: string,\n): ImageDescriptionResult {\n // Try to parse as JSON first\n try {\n const jsonResponse = JSON.parse(responseText);\n if (jsonResponse.title && jsonResponse.description) {\n return jsonResponse;\n }\n } catch (e) {\n // If not valid JSON, process as text\n logger.debug(`Parsing as JSON failed, processing as text: ${e}`);\n }\n\n // Extract title and description from text format\n const titleMatch = responseText.match(/title[:\\s]+(.+?)(?:\\n|$)/i);\n const title = titleMatch?.[1]?.trim() || \"Image Analysis\";\n const description = responseText\n .replace(/title[:\\s]+(.+?)(?:\\n|$)/i, \"\")\n .trim();\n\n return { title, description };\n}\n\n/**\n * Handles errors during object generation, including JSON repair attempts\n */\nexport async function handleObjectGenerationError(\n error: unknown,\n): Promise<unknown> {\n if (error instanceof JSONParseError) {\n logger.error(`[generateObject] Failed to parse JSON: ${error.message}`);\n const repairFunction = getJsonRepairFunction();\n const repairedJsonString = await repairFunction({\n text: error.text,\n error,\n });\n\n if (repairedJsonString) {\n try {\n const repairedObject = JSON.parse(repairedJsonString);\n logger.log(\"[generateObject] Successfully repaired JSON.\");\n return repairedObject;\n } catch (repairParseError: unknown) {\n const message =\n repairParseError instanceof Error\n ? repairParseError.message\n : String(repairParseError);\n logger.error(\n `[generateObject] Failed to parse repaired JSON: ${message}`,\n );\n throw repairParseError instanceof Error\n ? repairParseError\n : new Error(message);\n }\n } else {\n logger.error(\"[generateObject] JSON repair failed.\");\n throw error;\n }\n } else {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`[generateObject] Unknown error: ${message}`);\n throw error instanceof Error ? error : new Error(message);\n }\n}\n","import {\n ModelType,\n logger,\n type IAgentRuntime,\n type ObjectGenerationParams,\n} from \"@elizaos/core\";\nimport { generateObject } from \"ai\";\nimport { createOpenRouterProvider } from \"../providers\";\nimport { getSmallModel, getLargeModel } from \"../utils/config\";\nimport { emitModelUsageEvent } from \"../utils/events\";\nimport {\n getJsonRepairFunction,\n handleObjectGenerationError,\n} from \"../utils/helpers\";\n\n/**\n * Common object generation logic for both small and large models\n */\nasync function generateObjectWithModel(\n runtime: IAgentRuntime,\n modelType: typeof ModelType.OBJECT_SMALL | typeof ModelType.OBJECT_LARGE,\n params: ObjectGenerationParams,\n): Promise<unknown> {\n const openrouter = createOpenRouterProvider(runtime);\n const modelName =\n modelType === ModelType.OBJECT_SMALL\n ? getSmallModel(runtime)\n : getLargeModel(runtime);\n const modelLabel =\n modelType === ModelType.OBJECT_SMALL ? \"OBJECT_SMALL\" : \"OBJECT_LARGE\";\n\n logger.log(`[OpenRouter] Using ${modelLabel} model: ${modelName}`);\n const temperature = params.temperature ?? 0.7;\n\n try {\n const { object, usage } = await generateObject({\n model: openrouter.chat(modelName),\n output: \"no-schema\",\n prompt: params.prompt,\n temperature: temperature,\n experimental_repairText: getJsonRepairFunction(),\n });\n\n if (usage) {\n emitModelUsageEvent(runtime, modelType, params.prompt, usage);\n }\n return object;\n } catch (error: unknown) {\n return handleObjectGenerationError(error);\n }\n}\n\n/**\n * OBJECT_SMALL model handler\n */\nexport async function handleObjectSmall(\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n): Promise<unknown> {\n return generateObjectWithModel(runtime, ModelType.OBJECT_SMALL, params);\n}\n\n/**\n * OBJECT_LARGE model handler\n */\nexport async function handleObjectLarge(\n runtime: IAgentRuntime,\n params: ObjectGenerationParams,\n): Promise<unknown> {\n return generateObjectWithModel(runtime, ModelType.OBJECT_LARGE, params);\n}\n","import {\n logger,\n type IAgentRuntime,\n type ImageDescriptionParams,\n} from \"@elizaos/core\";\nimport { generateText } from \"ai\";\nimport { createOpenRouterProvider } from \"../providers\";\nimport { getImageModel } from \"../utils/config\";\nimport { parseImageDescriptionResponse } from \"../utils/helpers\";\n\n/**\n * IMAGE_DESCRIPTION model handler\n */\nexport async function handleImageDescription(\n runtime: IAgentRuntime,\n params: ImageDescriptionParams | string,\n): Promise<{ title: string; description: string }> {\n let imageUrl: string;\n let promptText: string | undefined;\n const modelName = getImageModel(runtime);\n logger.log(`[OpenRouter] Using IMAGE_DESCRIPTION model: ${modelName}`);\n const maxTokens = 300;\n\n if (typeof params === \"string\") {\n imageUrl = params;\n promptText =\n \"Please analyze this image and provide a title and detailed description.\";\n } else {\n imageUrl = params.imageUrl;\n promptText =\n params.prompt ||\n \"Please analyze this image and provide a title and detailed description.\";\n }\n\n const openrouter = createOpenRouterProvider(runtime);\n\n const messages = [\n {\n role: \"user\" as const,\n content: [\n { type: \"text\" as const, text: promptText },\n { type: \"image\" as const, image: imageUrl },\n ],\n },\n ];\n\n try {\n const model = openrouter.chat(modelName);\n\n const { text: responseText } = await generateText({\n model: model,\n messages: messages,\n maxTokens: maxTokens,\n });\n\n return parseImageDescriptionResponse(responseText);\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Error analyzing image: ${message}`);\n return {\n title: \"Failed to analyze image\",\n description: `Error: ${message}`,\n };\n }\n}\n"],"mappings":"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","names":["ModelType","logger","logger","logger","logger","logger","logger","ModelType","logger","ModelType","logger","logger","generateText","logger","generateText","ModelType"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/init.ts","../src/utils/config.ts","../src/models/text.ts","../src/providers/openrouter.ts","../src/utils/events.ts","../src/utils/helpers.ts","../src/models/object.ts","../src/models/image.ts","../src/utils/image-storage.ts"],"sourcesContent":["import {\n\tModelType,\n\ttype Plugin,\n\ttype IAgentRuntime,\n\ttype GenerateTextParams,\n\ttype ObjectGenerationParams,\n\ttype ImageDescriptionParams,\n\ttype ImageGenerationParams,\n} from \"@elizaos/core\";\nimport type { Tool, ToolChoice } from \"ai\";\nimport { initializeOpenRouter } from \"./init\";\nimport { handleTextSmall, handleTextLarge } from \"./models/text\";\nimport { handleObjectSmall, handleObjectLarge } from \"./models/object\";\nimport { handleImageDescription, handleImageGeneration } from \"./models/image\";\n\n/**\n * Defines the OpenRouter plugin with its name, description, and configuration options.\n * @type {Plugin}\n */\nexport const openrouterPlugin: Plugin = {\n\tname: \"openrouter\",\n\tdescription: \"OpenRouter plugin\",\n\tconfig: {\n\t\tOPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,\n\t\tOPENROUTER_BASE_URL: process.env.OPENROUTER_BASE_URL,\n\t\tOPENROUTER_SMALL_MODEL: process.env.OPENROUTER_SMALL_MODEL,\n\t\tOPENROUTER_LARGE_MODEL: process.env.OPENROUTER_LARGE_MODEL,\n\t\tOPENROUTER_IMAGE_MODEL: process.env.OPENROUTER_IMAGE_MODEL,\n\t\tOPENROUTER_IMAGE_GENERATION_MODEL: process.env.OPENROUTER_IMAGE_GENERATION_MODEL,\n\t\tOPENROUTER_AUTO_CLEANUP_IMAGES: process.env.OPENROUTER_AUTO_CLEANUP_IMAGES,\n\t\tSMALL_MODEL: process.env.SMALL_MODEL,\n\t\tLARGE_MODEL: process.env.LARGE_MODEL,\n\t\tIMAGE_MODEL: process.env.IMAGE_MODEL,\n\t\tIMAGE_GENERATION_MODEL: process.env.IMAGE_GENERATION_MODEL,\n\t},\n\tasync init(config, runtime) {\n\t\t// Note: We intentionally don't await here because ElizaOS expects\n\t\t// the init method to return quickly. The initializeOpenRouter function\n\t\t// only performs synchronous validation and logging, so it's safe to\n\t\t// call without await. This prevents blocking the plugin initialization.\n\t\tinitializeOpenRouter(config, runtime);\n\t},\n\tmodels: {\n\t\t[ModelType.TEXT_SMALL]: async (\n\t\t\truntime: IAgentRuntime,\n\t\t\tparams: GenerateTextParams & {\n\t\t\t\ttools?: Record<string, Tool>;\n\t\t\t\ttoolChoice?: ToolChoice<Record<string, Tool>>;\n\t\t\t},\n\t\t) => {\n\t\t\treturn handleTextSmall(runtime, params);\n\t\t},\n\t\t[ModelType.TEXT_LARGE]: async (\n\t\t\truntime: IAgentRuntime,\n\t\t\tparams: GenerateTextParams & {\n\t\t\t\ttools?: Record<string, Tool>;\n\t\t\t\ttoolChoice?: ToolChoice<Record<string, Tool>>;\n\t\t\t},\n\t\t) => {\n\t\t\treturn handleTextLarge(runtime, params);\n\t\t},\n\t\t[ModelType.OBJECT_SMALL]: async (\n\t\t\truntime: IAgentRuntime,\n\t\t\tparams: ObjectGenerationParams,\n\t\t) => {\n\t\t\treturn handleObjectSmall(runtime, params);\n\t\t},\n\t\t[ModelType.OBJECT_LARGE]: async (\n\t\t\truntime: IAgentRuntime,\n\t\t\tparams: ObjectGenerationParams,\n\t\t) => {\n\t\t\treturn handleObjectLarge(runtime, params);\n\t\t},\n\t\t[ModelType.IMAGE_DESCRIPTION]: async (\n\t\t\truntime: IAgentRuntime,\n\t\t\tparams: ImageDescriptionParams | string,\n\t\t) => {\n\t\t\treturn handleImageDescription(runtime, params);\n\t\t},\n\t\t[ModelType.IMAGE]: async (\n\t\t\truntime: IAgentRuntime,\n\t\t\tparams: ImageGenerationParams,\n\t\t) => {\n\t\t\treturn handleImageGeneration(runtime, params);\n\t\t},\n\t},\n};\n\nexport default openrouterPlugin;\n","import { logger, type IAgentRuntime } from \"@elizaos/core\";\nimport { fetch } from \"undici\";\nimport { getApiKey, getBaseURL } from \"./utils/config\";\n\n/**\n * Initialize and validate OpenRouter configuration\n * Returns the exact same function that works inline\n */\nexport function initializeOpenRouter(_config: any, runtime: IAgentRuntime) {\n\t// do check in the background\n\t(async () => {\n\t\ttry {\n\t\t\tif (!getApiKey(runtime)) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t\"OPENROUTER_API_KEY is not set in environment - OpenRouter functionality will be limited\",\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst baseURL = getBaseURL(runtime);\n\t\t\t\tconst response = await fetch(`${baseURL}/models`, {\n\t\t\t\t\theaders: { Authorization: `Bearer ${getApiKey(runtime)}` },\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t`OpenRouter API key validation failed: ${response.statusText}`,\n\t\t\t\t\t);\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\"OpenRouter functionality will be limited until a valid API key is provided\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.log(\"OpenRouter API key validated successfully\");\n\t\t\t\t}\n\t\t\t} catch (fetchError: unknown) {\n\t\t\t\tconst message =\n\t\t\t\t\tfetchError instanceof Error ? fetchError.message : String(fetchError);\n\t\t\t\tlogger.warn(`Error validating OpenRouter API key: ${message}`);\n\t\t\t\tlogger.warn(\n\t\t\t\t\t\"OpenRouter functionality will be limited until a valid API key is provided\",\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tconst message =\n\t\t\t\t(error as { errors?: Array<{ message: string }> })?.errors\n\t\t\t\t\t?.map((e) => e.message)\n\t\t\t\t\t.join(\", \") ||\n\t\t\t\t(error instanceof Error ? error.message : String(error));\n\t\t\tlogger.warn(\n\t\t\t\t`OpenRouter plugin configuration issue: ${message} - You need to configure the OPENROUTER_API_KEY in your environment variables`,\n\t\t\t);\n\t\t}\n\t})();\n\treturn;\n}\n","import type { IAgentRuntime } from \"@elizaos/core\";\n\n/**\n * Retrieves a configuration setting from the runtime, falling back to environment variables or a default value if not found.\n *\n * @param key - The name of the setting to retrieve.\n * @param defaultValue - The value to return if the setting is not found in the runtime or environment.\n * @returns The resolved setting value, or {@link defaultValue} if not found.\n */\nexport function getSetting(\n\truntime: IAgentRuntime,\n\tkey: string,\n\tdefaultValue?: string,\n): string | undefined {\n\treturn runtime.getSetting(key) ?? process.env[key] ?? defaultValue;\n}\n\n/**\n * Retrieves the OpenRouter API base URL from runtime settings, environment variables, or defaults.\n *\n * @returns The resolved base URL for OpenRouter API requests.\n */\nexport function getBaseURL(runtime: IAgentRuntime): string {\n\treturn (\n\t\tgetSetting(\n\t\t\truntime,\n\t\t\t\"OPENROUTER_BASE_URL\",\n\t\t\t\"https://openrouter.ai/api/v1\",\n\t\t) || \"https://openrouter.ai/api/v1\"\n\t);\n}\n\n/**\n * Helper function to get the API key for OpenRouter\n *\n * @param runtime The runtime context\n * @returns The configured API key\n */\nexport function getApiKey(runtime: IAgentRuntime): string | undefined {\n\treturn getSetting(runtime, \"OPENROUTER_API_KEY\");\n}\n\n/**\n * Helper function to get the small model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured small model name\n */\nexport function getSmallModel(runtime: IAgentRuntime): string {\n\treturn (\n\t\tgetSetting(runtime, \"OPENROUTER_SMALL_MODEL\") ??\n\t\tgetSetting(runtime, \"SMALL_MODEL\", \"google/gemini-2.0-flash-001\") ??\n\t\t\"google/gemini-2.0-flash-001\"\n\t);\n}\n\n/**\n * Helper function to get the large model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured large model name\n */\nexport function getLargeModel(runtime: IAgentRuntime): string {\n return (\n getSetting(runtime, \"OPENROUTER_LARGE_MODEL\") ??\n getSetting(\n runtime,\n \"LARGE_MODEL\",\n \"google/gemini-2.5-flash\",\n ) ??\n \"google/gemini-2.5-flash\"\n );\n}\n\n/**\n * Helper function to get the image model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured image model name\n */\nexport function getImageModel(runtime: IAgentRuntime): string {\n\treturn (\n\t\tgetSetting(runtime, \"OPENROUTER_IMAGE_MODEL\") ??\n\t\tgetSetting(runtime, \"IMAGE_MODEL\", \"x-ai/grok-2-vision-1212\") ??\n\t\t\"x-ai/grok-2-vision-1212\"\n\t);\n}\n\n/**\n * Helper function to get the image generation model name with fallbacks\n *\n * @param runtime The runtime context\n * @returns The configured image generation model name\n */\nexport function getImageGenerationModel(runtime: IAgentRuntime): string {\n\treturn (\n\t\tgetSetting(runtime, \"OPENROUTER_IMAGE_GENERATION_MODEL\") ??\n\t\tgetSetting(runtime, \"IMAGE_GENERATION_MODEL\", \"google/gemini-2.5-flash-image-preview\") ??\n\t\t\"google/gemini-2.5-flash-image-preview\"\n\t);\n}\n\n/**\n * Helper function to check if auto cleanup is enabled for generated images\n *\n * @param runtime The runtime context\n * @returns Whether to auto-cleanup generated images (default: false)\n */\nexport function shouldAutoCleanupImages(runtime: IAgentRuntime): boolean {\n\tconst setting = getSetting(runtime, \"OPENROUTER_AUTO_CLEANUP_IMAGES\", \"false\");\n\treturn setting?.toLowerCase() === \"true\";\n}\n","import type { GenerateTextParams, IAgentRuntime } from \"@elizaos/core\";\nimport { logger, ModelType } from \"@elizaos/core\";\nimport { generateText } from \"ai\";\nimport type { Tool, ToolChoice } from \"ai\";\n\nimport { createOpenRouterProvider } from \"../providers\";\nimport type { ToolCall, ToolResponse, ToolResult } from \"../types\";\nimport { getSmallModel, getLargeModel } from \"../utils/config\";\nimport { emitModelUsageEvent } from \"../utils/events\";\nimport { handleEmptyToolResponse, decodeBase64Fields } from \"../utils/helpers\";\n\n/**\n * Common text generation logic for both small and large models\n */\nasync function generateTextWithModel(\n\truntime: IAgentRuntime,\n\tmodelType: typeof ModelType.TEXT_SMALL | typeof ModelType.TEXT_LARGE,\n\tparams: GenerateTextParams & {\n\t\ttools?: Record<string, Tool>;\n\t\ttoolChoice?: ToolChoice<Record<string, Tool>>;\n\t},\n): Promise<string | ToolResponse> {\n\tconst { prompt, stopSequences = [], tools, toolChoice } = params;\n\tconst temperature = params.temperature ?? 0.7;\n\tconst frequencyPenalty = params.frequencyPenalty ?? 0.7;\n\tconst presencePenalty = params.presencePenalty ?? 0.7;\n\tconst maxResponseLength = params.maxTokens ?? 8192;\n\n\tconst openrouter = createOpenRouterProvider(runtime);\n\tconst modelName =\n\t\tmodelType === ModelType.TEXT_SMALL\n\t\t\t? getSmallModel(runtime)\n\t\t\t: getLargeModel(runtime);\n\tconst modelLabel =\n\t\tmodelType === ModelType.TEXT_SMALL ? \"TEXT_SMALL\" : \"TEXT_LARGE\";\n\n\tlogger.log(\n\t\t`[OpenRouter] Generating text with ${modelLabel} model: ${modelName}`,\n\t);\n\n\tconst generateParams: Parameters<typeof generateText>[0] & {\n\t\textra_body?: { provider?: { require_parameters?: boolean } };\n\t} = {\n\t\tmodel: openrouter.chat(modelName),\n\t\tprompt: prompt,\n\t\tsystem: runtime.character.system ?? undefined,\n\t\ttemperature: temperature,\n\t\tmaxTokens: maxResponseLength,\n\t\tfrequencyPenalty: frequencyPenalty,\n\t\tpresencePenalty: presencePenalty,\n\t\tstopSequences: stopSequences,\n\t};\n\n\t// Add tools if provided\n\tif (tools) {\n\t\tgenerateParams.tools = tools;\n\t\tgenerateParams.maxSteps = 10; // Allow tool call + response generation\n\t\t// For OpenRouter: ensure request is only routed to providers that support function calling\n\t\tgenerateParams.extra_body = {\n\t\t\tprovider: {\n\t\t\t\trequire_parameters: true,\n\t\t\t},\n\t\t};\n\t}\n\n\t// Add toolChoice if provided\n\tif (toolChoice) {\n\t\tgenerateParams.toolChoice = toolChoice;\n\t}\n\n\t// Capture tool results if tools are used\n\tlet capturedToolResults: ToolResult[] = [];\n\tlet capturedToolCalls: ToolCall[] = [];\n\n\tif (tools) {\n\t\tgenerateParams.onStepFinish = async (stepResult) => {\n\t\t\tif (stepResult.toolCalls && stepResult.toolCalls.length > 0) {\n\t\t\t\tcapturedToolCalls = [...capturedToolCalls, ...stepResult.toolCalls];\n\t\t\t}\n\t\t\tif (stepResult.toolResults && stepResult.toolResults.length > 0) {\n\t\t\t\t// Decode base64 fields in tool results before capturing them\n\t\t\t\tconst decodedToolResults = stepResult.toolResults.map((result: ToolResult) => ({\n\t\t\t\t\t...result,\n\t\t\t\t\tresult: decodeBase64Fields(result.result),\n\t\t\t\t}));\n\t\t\t\tcapturedToolResults = [...capturedToolResults, ...decodedToolResults];\n\t\t\t}\n\t\t};\n\t}\n\n\tconst response = await generateText(generateParams);\n\n\t// Handle cases where tool execution doesn't generate text\n\tlet responseText: string;\n\tif (\n\t\ttools &&\n\t\t(!response.text ||\n\t\t\tresponse.text.trim() === \"\" ||\n\t\t\tresponse.text === \"Tools executed successfully.\")\n\t) {\n\t\tresponseText = handleEmptyToolResponse(modelLabel);\n\t} else {\n\t\tresponseText = response.text;\n\t}\n\n\tif (response.usage) {\n\t\temitModelUsageEvent(runtime, modelType, prompt, response.usage);\n\t}\n\n\t// If tools were used, return the full response object to access toolCalls and toolResults\n\tif (\n\t\ttools &&\n\t\t(capturedToolCalls.length > 0 || capturedToolResults.length > 0)\n\t) {\n\t\treturn {\n\t\t\ttext: responseText,\n\t\t\ttoolCalls: capturedToolCalls,\n\t\t\ttoolResults: capturedToolResults,\n\t\t\t// Include other useful properties\n\t\t\tusage: response.usage,\n\t\t\tfinishReason: response.finishReason,\n\t\t};\n\t}\n\n\treturn responseText;\n}\n\n/**\n * TEXT_SMALL model handler\n */\nexport async function handleTextSmall(\n\truntime: IAgentRuntime,\n\tparams: GenerateTextParams & {\n\t\ttools?: Record<string, Tool>;\n\t\ttoolChoice?: ToolChoice<Record<string, Tool>>;\n\t},\n): Promise<string | ToolResponse> {\n\treturn generateTextWithModel(runtime, ModelType.TEXT_SMALL, params);\n}\n\n/**\n * TEXT_LARGE model handler\n */\nexport async function handleTextLarge(\n\truntime: IAgentRuntime,\n\tparams: GenerateTextParams & {\n\t\ttools?: Record<string, Tool>;\n\t\ttoolChoice?: ToolChoice<Record<string, Tool>>;\n\t},\n): Promise<string | ToolResponse> {\n\treturn generateTextWithModel(runtime, ModelType.TEXT_LARGE, params);\n}\n","import { createOpenRouter } from \"@openrouter/ai-sdk-provider\";\nimport { logger, type IAgentRuntime } from \"@elizaos/core\";\nimport { getApiKey } from \"../utils/config\";\n\n/**\n * Create an OpenRouter provider instance with proper configuration\n *\n * @param runtime The runtime context\n * @returns Configured OpenRouter provider instance\n */\nexport function createOpenRouterProvider(runtime: IAgentRuntime) {\n\tconst apiKey = getApiKey(runtime);\n\tif (!apiKey) {\n\t\t// This case should ideally be caught in init, but good practice to check\n\t\tlogger.error(\n\t\t\t\"OpenRouter API Key is missing when trying to create provider\",\n\t\t);\n\t\tthrow new Error(\"OpenRouter API Key is missing.\");\n\t}\n\n\t// Note: createOpenRouter doesn't seem to take baseURL directly in the documentation.\n\t// It might pick it up from OPENROUTER_BASE_URL env var automatically,\n\t// or it might not be needed/configurable in the same way as createOpenRouter.\n\t// We'll rely on the apiKey for now.\n\treturn createOpenRouter({\n\t\tapiKey: apiKey,\n\t\t// We might need to handle baseURL differently if required.\n\t\t// The @ai-sdk/provider utils might handle OPENROUTER_BASE_URL env var.\n\t});\n}\n","import {\n\tEventType,\n\ttype IAgentRuntime,\n\ttype ModelTypeName,\n} from \"@elizaos/core\";\nimport type { LanguageModelUsage } from \"ai\";\n\n/**\n * Emits a model usage event\n */\nexport function emitModelUsageEvent(\n\truntime: IAgentRuntime,\n\ttype: ModelTypeName,\n\tprompt: string,\n\tusage: LanguageModelUsage,\n) {\n\truntime.emitEvent(EventType.MODEL_USED, {\n\t\tprovider: \"openrouter\",\n\t\ttype,\n\t\tprompt,\n\t\ttokens: {\n\t\t\tprompt: usage.promptTokens,\n\t\t\tcompletion: usage.completionTokens,\n\t\t\ttotal: usage.totalTokens,\n\t\t},\n\t});\n}\n","import { logger } from \"@elizaos/core\";\nimport { JSONParseError } from \"ai\";\nimport type { GenerateTextResponse, ImageDescriptionResult } from \"../types\";\n\n/**\n * Returns a function to repair JSON text\n */\nexport function getJsonRepairFunction(): (params: {\n\ttext: string;\n\terror: unknown;\n}) => Promise<string | null> {\n\treturn async ({ text, error }: { text: string; error: unknown }) => {\n\t\ttry {\n\t\t\tif (error instanceof JSONParseError) {\n\t\t\t\tconst cleanedText = text.replace(/```json\\n|\\n```|```/g, \"\");\n\t\t\t\tJSON.parse(cleanedText);\n\t\t\t\treturn cleanedText;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch (jsonError: unknown) {\n\t\t\tconst message =\n\t\t\t\tjsonError instanceof Error ? jsonError.message : String(jsonError);\n\t\t\tlogger.warn(`Failed to repair JSON text: ${message}`);\n\t\t\treturn null;\n\t\t}\n\t};\n}\n\n// Re-export for backward compatibility\nexport { emitModelUsageEvent } from \"./events\";\n\n/**\n * Logs response structure for debugging (debug level only)\n */\nexport function logResponseStructure(\n\tmodelType: string,\n\tresponse: GenerateTextResponse,\n) {\n\tlogger.debug(`[${modelType}] Response structure: ${JSON.stringify({\n\t\thasText: !!response.text,\n\t\ttextLength: response.text?.length || 0,\n\t\thasSteps: !!response.steps,\n\t\tstepsCount: response.steps?.length || 0,\n\t\tfinishReason: response.finishReason,\n\t\tusage: response.usage,\n\t}, null, 2)}`);\n}\n\n/**\n * Handles cases where tool execution doesn't generate text\n */\nexport function handleEmptyToolResponse(modelType: string): string {\n\tlogger.warn(`[${modelType}] No text generated after tool execution`);\n\n\tconst fallbackText =\n\t\t\"I executed the requested action. The tool completed successfully.\";\n\tlogger.warn(`[${modelType}] Using fallback response text`);\n\treturn fallbackText;\n}\n\n/**\n * Parses image description response from text or JSON format\n */\nexport function parseImageDescriptionResponse(\n\tresponseText: string,\n): ImageDescriptionResult {\n\t// Try to parse as JSON first\n\ttry {\n\t\tconst jsonResponse = JSON.parse(responseText);\n\t\tif (jsonResponse.title && jsonResponse.description) {\n\t\t\treturn jsonResponse;\n\t\t}\n\t} catch (e) {\n\t\t// If not valid JSON, process as text\n\t\tlogger.debug(`Parsing as JSON failed, processing as text: ${e}`);\n\t}\n\n\t// Extract title and description from text format\n\tconst titleMatch = responseText.match(/title[:\\s]+(.+?)(?:\\n|$)/i);\n\tconst title = titleMatch?.[1]?.trim() || \"Image Analysis\";\n\tconst description = responseText\n\t\t.replace(/title[:\\s]+(.+?)(?:\\n|$)/i, \"\")\n\t\t.trim();\n\n\treturn { title, description };\n}\n\n/**\n * Handles errors during object generation, including JSON repair attempts\n */\nexport async function handleObjectGenerationError(\n\terror: unknown,\n): Promise<unknown> {\n\tif (error instanceof JSONParseError) {\n\t\tlogger.error(`[generateObject] Failed to parse JSON: ${error.message}`);\n\t\tconst repairFunction = getJsonRepairFunction();\n\t\tconst repairedJsonString = await repairFunction({\n\t\t\ttext: error.text,\n\t\t\terror,\n\t\t});\n\n\t\tif (repairedJsonString) {\n\t\t\ttry {\n\t\t\t\tconst repairedObject = JSON.parse(repairedJsonString);\n\t\t\t\tlogger.log(\"[generateObject] Successfully repaired JSON.\");\n\t\t\t\treturn repairedObject;\n\t\t\t} catch (repairParseError: unknown) {\n\t\t\t\tconst message =\n\t\t\t\t\trepairParseError instanceof Error\n\t\t\t\t\t\t? repairParseError.message\n\t\t\t\t\t\t: String(repairParseError);\n\t\t\t\tlogger.error(\n\t\t\t\t\t`[generateObject] Failed to parse repaired JSON: ${message}`,\n\t\t\t\t);\n\t\t\t\tif (repairParseError instanceof Error) throw repairParseError;\n\t\t\t\tthrow Object.assign(new Error(message), { cause: repairParseError });\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.error(\"[generateObject] JSON repair failed.\");\n\t\t\tthrow error;\n\t\t}\n\t} else {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlogger.error(`[generateObject] Unknown error: ${message}`);\n\t\tif (error instanceof Error) throw error;\n\t\tthrow Object.assign(new Error(message), { cause: error });\n\t}\n}\n\n/**\n * Quick heuristic to detect if a field likely contains base64 data\n */\nfunction isLikelyBase64(key: string, value: string): boolean {\n\t// Check key name patterns (expanded base64 field names)\n\tconst base64KeyPattern = /^(data|content|body|payload|encoded|b64|base64|document)$/i;\n\tif (!base64KeyPattern.test(key)) return false;\n\t\n\t// Basic format checks\n\tif (value.length < 20 || value.length > 1024 * 1024) return false; // Size limits\n\tif (value.length % 4 !== 0) return false; // Invalid base64 length\n\tif (!/^[A-Za-z0-9+/]*={0,2}$/.test(value)) return false; // Invalid chars\n\t\n\treturn true;\n}\n\n/**\n * Recursively decodes base64 fields in tool results\n */\nexport function decodeBase64Fields(obj: unknown, depth = 0): unknown {\n\t// Simple depth protection\n\tif (depth > 5) return obj;\n\tif (!obj || typeof obj !== \"object\") return obj;\n\tif (Array.isArray(obj)) return obj.map(item => decodeBase64Fields(item, depth + 1));\n\t\n\tconst decoded: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (typeof value === \"string\" && isLikelyBase64(key, value)) {\n\t\t\ttry {\n\t\t\t\tdecoded[key] = Buffer.from(value, \"base64\").toString(\"utf8\");\n\t\t\t\tlogger.debug(`[decodeBase64] Decoded field '${key}' (${value.length} chars)`);\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(`[decodeBase64] Failed to decode field '${key}': ${error}`);\n\t\t\t\tdecoded[key] = value; // Keep original if decode fails\n\t\t\t}\n\t\t} else if (value && typeof value === \"object\") {\n\t\t\tdecoded[key] = decodeBase64Fields(value, depth + 1);\n\t\t} else {\n\t\t\tdecoded[key] = value;\n\t\t}\n\t}\n\treturn decoded;\n}\n","import {\n\tModelType,\n\tlogger,\n\ttype IAgentRuntime,\n\ttype ObjectGenerationParams,\n} from \"@elizaos/core\";\nimport { generateObject } from \"ai\";\nimport { createOpenRouterProvider } from \"../providers\";\nimport { getSmallModel, getLargeModel } from \"../utils/config\";\nimport { emitModelUsageEvent } from \"../utils/events\";\nimport {\n\tgetJsonRepairFunction,\n\thandleObjectGenerationError,\n} from \"../utils/helpers\";\n\n/**\n * Common object generation logic for both small and large models\n */\nasync function generateObjectWithModel(\n\truntime: IAgentRuntime,\n\tmodelType: typeof ModelType.OBJECT_SMALL | typeof ModelType.OBJECT_LARGE,\n\tparams: ObjectGenerationParams,\n): Promise<unknown> {\n\tconst openrouter = createOpenRouterProvider(runtime);\n\tconst modelName =\n\t\tmodelType === ModelType.OBJECT_SMALL\n\t\t\t? getSmallModel(runtime)\n\t\t\t: getLargeModel(runtime);\n\tconst modelLabel =\n\t\tmodelType === ModelType.OBJECT_SMALL ? \"OBJECT_SMALL\" : \"OBJECT_LARGE\";\n\n\tlogger.log(`[OpenRouter] Using ${modelLabel} model: ${modelName}`);\n\tconst temperature = params.temperature ?? 0.7;\n\n\ttry {\n\t\tconst { object, usage } = await generateObject({\n\t\t\tmodel: openrouter.chat(modelName),\n\t\t\toutput: \"no-schema\",\n\t\t\tprompt: params.prompt,\n\t\t\ttemperature: temperature,\n\t\t\texperimental_repairText: getJsonRepairFunction(),\n\t\t});\n\n\t\tif (usage) {\n\t\t\temitModelUsageEvent(runtime, modelType, params.prompt, usage);\n\t\t}\n\t\treturn object;\n\t} catch (error: unknown) {\n\t\treturn handleObjectGenerationError(error);\n\t}\n}\n\n/**\n * OBJECT_SMALL model handler\n */\nexport async function handleObjectSmall(\n\truntime: IAgentRuntime,\n\tparams: ObjectGenerationParams,\n): Promise<unknown> {\n\treturn generateObjectWithModel(runtime, ModelType.OBJECT_SMALL, params);\n}\n\n/**\n * OBJECT_LARGE model handler\n */\nexport async function handleObjectLarge(\n\truntime: IAgentRuntime,\n\tparams: ObjectGenerationParams,\n): Promise<unknown> {\n\treturn generateObjectWithModel(runtime, ModelType.OBJECT_LARGE, params);\n}\n","import {\n\tlogger,\n\ttype IAgentRuntime,\n\ttype ImageDescriptionParams,\n\ttype ImageGenerationParams,\n} from \"@elizaos/core\";\nimport { generateText } from \"ai\";\nimport type { OpenRouterImageResponse } from \"../types\";\nimport { createOpenRouterProvider } from \"../providers\";\nimport { getApiKey, getBaseURL, getImageGenerationModel, getImageModel, shouldAutoCleanupImages } from \"../utils/config\";\nimport { parseImageDescriptionResponse } from \"../utils/helpers\";\nimport { deleteImage, saveBase64Image } from \"../utils/image-storage\";\n\n/**\n * IMAGE_DESCRIPTION model handler\n */\nexport async function handleImageDescription(\n\truntime: IAgentRuntime,\n\tparams: ImageDescriptionParams | string,\n): Promise<{ title: string; description: string }> {\n\tlet imageUrl: string;\n\tlet promptText: string | undefined;\n\tconst modelName = getImageModel(runtime);\n\tlogger.log(`[OpenRouter] Using IMAGE_DESCRIPTION model: ${modelName}`);\n\tconst maxTokens = 300;\n\n\tif (typeof params === \"string\") {\n\t\timageUrl = params;\n\t\tpromptText =\n\t\t\t\"Please analyze this image and provide a title and detailed description.\";\n\t} else {\n\t\timageUrl = params.imageUrl;\n\t\tpromptText =\n\t\t\tparams.prompt ||\n\t\t\t\"Please analyze this image and provide a title and detailed description.\";\n\t}\n\n\tconst openrouter = createOpenRouterProvider(runtime);\n\n\tconst messages = [\n\t\t{\n\t\t\trole: \"user\" as const,\n\t\t\tcontent: [\n\t\t\t\t{ type: \"text\" as const, text: promptText },\n\t\t\t\t{ type: \"image\" as const, image: imageUrl },\n\t\t\t],\n\t\t},\n\t];\n\n\ttry {\n\t\tconst model = openrouter.chat(modelName);\n\n\t\tconst { text: responseText } = await generateText({\n\t\t\tmodel: model,\n\t\t\tmessages: messages,\n\t\t\tmaxTokens: maxTokens,\n\t\t});\n\n\t\treturn parseImageDescriptionResponse(responseText);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlogger.error(`Error analyzing image: ${message}`);\n\t\treturn {\n\t\t\ttitle: \"Failed to analyze image\",\n\t\t\tdescription: `Error: ${message}`,\n\t\t};\n\t}\n}\n\n/**\n * IMAGE model handler for image generation\n */\nexport async function handleImageGeneration(\n\truntime: IAgentRuntime,\n\tparams: ImageGenerationParams,\n): Promise<{ url: string }[]> {\n\tconst modelName = getImageGenerationModel(runtime);\n\tlogger.log(`[OpenRouter] Using IMAGE_GENERATION model: ${modelName}`);\n\tconst apiKey = getApiKey(runtime);\n\n\ttry {\n\t\tif (!apiKey) {\n\t\t\tlogger.error(\"[OpenRouter] OpenRouter API key is missing\");\n\t\t\treturn [];\n\t\t}\n\t\tconst baseUrl = getBaseURL(runtime);\n\t\tconst response = await fetch(`${baseUrl}/chat/completions`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${apiKey}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: modelName,\n\t\t\t\tmessages: [\n\t\t\t\t\t{\n\t\t\t\t\t\trole: 'user',\n\t\t\t\t\t\tcontent: params.prompt,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tmodalities: ['image', 'text'],\n\t\t\t}),\n\t\t\t// 60 seconds timeout\n\t\t\tsignal: AbortSignal.timeout ? AbortSignal.timeout(60000) : undefined,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text().catch(() => \"\");\n\t\t\tthrow new Error(`HTTP ${response.status} ${response.statusText} ${errorText}`);\n\t\t}\n\n\t\tconst result = await response.json() as OpenRouterImageResponse;\n\t\t\n\t\tconst images: { url: string; filepath?: string }[] = [];\n\t\tconst savedPaths: string[] = [];\n\n\t\t// Extract images from the response\n\t\tif (result.choices?.[0]?.message?.images) {\n\t\t\tfor (const [index, image] of result.choices[0].message.images.entries()) {\n\t\t\t\tconst base64Url = image.image_url.url;\n\t\t\t\t\n\t\t\t\t// Save image to disk\n\t\t\t\tconst filepath = await saveBase64Image(base64Url, runtime.agentId, index);\n\t\t\t\tif (filepath) {\n\t\t\t\t\t// Return the actual file path for Discord/Telegram compatibility\n\t\t\t\t\tlogger.log(`[OpenRouter] Returning image with filepath: ${filepath}`);\n\t\t\t\t\timages.push({ \n\t\t\t\t\t\turl: filepath // Use actual file path\n\t\t\t\t\t});\n\t\t\t\t\tsavedPaths.push(filepath);\n\t\t\t\t} else if (!base64Url.startsWith('data:')) {\n\t\t\t\t\t// If not base64, return as is (might be a URL)\n\t\t\t\t\timages.push({ url: base64Url });\n\t\t\t\t} else {\n\t\t\t\t\t// Failed to save base64 image\n\t\t\t\t\tlogger.warn(`[OpenRouter] Failed to save image ${index + 1}, skipping`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Clean up images after a short delay if auto-cleanup is enabled\n\t\tif (savedPaths.length > 0 && shouldAutoCleanupImages(runtime)) {\n\t\t\tsetTimeout(() => {\n\t\t\t\tsavedPaths.forEach(path => {\n\t\t\t\t\tdeleteImage(path);\n\t\t\t\t});\n\t\t\t}, 30000); // Delete after 30 seconds\n\t\t}\n\n\t\tif (images.length === 0) {\n\t\t\tthrow new Error(\"No images generated in response\");\n\t\t}\n\n\t\tlogger.log(`[OpenRouter] Generated ${images.length} image(s)`);\n\t\treturn images;\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tlogger.error(`[OpenRouter] Error generating image: ${message}`);\n\t\treturn [];\n\t}\n}\n","import { existsSync, unlinkSync } from \"node:fs\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { logger, getGeneratedDir } from \"@elizaos/core\";\n\n/**\n * Save base64 image to disk and return the file path\n */\nexport async function saveBase64Image(base64Url: string, agentId: string, index: number = 0): Promise<string | null> {\n\t// Extract base64 data and extension with MIME type validation\n\tconst m = base64Url.match(/^data:(image\\/[a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=]+)$/);\n\tif (!m) return null;\n\t\n\tconst mime = m[1];\n\tconst base64Data = m[2];\n\t\n\t// Whitelist of allowed MIME types mapped to extensions\n\tconst extMap: Record<string, string> = {\n\t\t\"image/png\": \"png\",\n\t\t\"image/jpeg\": \"jpg\",\n\t\t\"image/jpg\": \"jpg\",\n\t\t\"image/webp\": \"webp\",\n\t\t\"image/gif\": \"gif\",\n\t\t\"image/bmp\": \"bmp\",\n\t\t\"image/tiff\": \"tiff\"\n\t};\n\t\n\tconst extension = extMap[mime];\n\tif (!extension) return null;\n\n\t// Use ElizaOS convention: .eliza/data/generated/{agentId}/\n\tconst baseDir = join(getGeneratedDir(), agentId);\n\t\n\t// Create directory if it doesn't exist\n\tif (!existsSync(baseDir)) {\n\t\tawait mkdir(baseDir, { recursive: true });\n\t}\n\n\t// Generate filename with timestamp\n\tconst timestamp = Date.now();\n\tconst filename = `image_${timestamp}_${index}.${extension}`;\n\tconst filepath = join(baseDir, filename);\n\n\t// Save image to disk\n\tconst buffer = Buffer.from(base64Data, \"base64\");\n\tawait writeFile(filepath, buffer);\n\n\tlogger.info(`[OpenRouter] Saved generated image to ${filepath}`);\n\n\t// Return only the file path for Discord/Telegram to read\n\treturn filepath;\n}\n\n/**\n * Delete a specific image file\n */\nexport function deleteImage(filepath: string): void {\n\ttry {\n\t\tif (existsSync(filepath)) {\n\t\t\tunlinkSync(filepath);\n\t\t\tlogger.debug(`[OpenRouter] Deleted image: ${filepath}`);\n\t\t}\n\t} catch (error) {\n\t\tlogger.warn(`[OpenRouter] Failed to delete image ${filepath}:`, String(error));\n\t}\n}"],"mappings":";AAAA;AAAA,EACC,aAAAA;AAAA,OAOM;;;ACRP,SAAS,cAAkC;AAC3C,SAAS,SAAAC,cAAa;;;ACQf,SAAS,WACf,SACA,KACA,cACqB;AACrB,SAAO,QAAQ,WAAW,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK;AACvD;AAOO,SAAS,WAAW,SAAgC;AAC1D,SACC;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,EACD,KAAK;AAEP;AAQO,SAAS,UAAU,SAA4C;AACrE,SAAO,WAAW,SAAS,oBAAoB;AAChD;AAQO,SAAS,cAAc,SAAgC;AAC7D,SACC,WAAW,SAAS,wBAAwB,KAC5C,WAAW,SAAS,eAAe,6BAA6B,KAChE;AAEF;AAQO,SAAS,cAAc,SAAgC;AAC5D,SACE,WAAW,SAAS,wBAAwB,KAC5C;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EACF,KACA;AAEJ;AAQO,SAAS,cAAc,SAAgC;AAC7D,SACC,WAAW,SAAS,wBAAwB,KAC5C,WAAW,SAAS,eAAe,yBAAyB,KAC5D;AAEF;AAQO,SAAS,wBAAwB,SAAgC;AACvE,SACC,WAAW,SAAS,mCAAmC,KACvD,WAAW,SAAS,0BAA0B,uCAAuC,KACrF;AAEF;AAQO,SAAS,wBAAwB,SAAiC;AACxE,QAAM,UAAU,WAAW,SAAS,kCAAkC,OAAO;AAC7E,SAAO,SAAS,YAAY,MAAM;AACnC;;;ADvGO,SAAS,qBAAqB,SAAc,SAAwB;AAE1E,GAAC,YAAY;AACZ,QAAI;AACH,UAAI,CAAC,UAAU,OAAO,GAAG;AACxB,eAAO;AAAA,UACN;AAAA,QACD;AACA;AAAA,MACD;AACA,UAAI;AACH,cAAM,UAAU,WAAW,OAAO;AAClC,cAAM,WAAW,MAAMC,OAAM,GAAG,OAAO,WAAW;AAAA,UACjD,SAAS,EAAE,eAAe,UAAU,UAAU,OAAO,CAAC,GAAG;AAAA,QAC1D,CAAC;AACD,YAAI,CAAC,SAAS,IAAI;AACjB,iBAAO;AAAA,YACN,yCAAyC,SAAS,UAAU;AAAA,UAC7D;AACA,iBAAO;AAAA,YACN;AAAA,UACD;AAAA,QACD,OAAO;AACN,iBAAO,IAAI,2CAA2C;AAAA,QACvD;AAAA,MACD,SAAS,YAAqB;AAC7B,cAAM,UACL,sBAAsB,QAAQ,WAAW,UAAU,OAAO,UAAU;AACrE,eAAO,KAAK,wCAAwC,OAAO,EAAE;AAC7D,eAAO;AAAA,UACN;AAAA,QACD;AAAA,MACD;AAAA,IACD,SAAS,OAAgB;AACxB,YAAM,UACJ,OAAmD,QACjD,IAAI,CAAC,MAAM,EAAE,OAAO,EACrB,KAAK,IAAI,MACV,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACvD,aAAO;AAAA,QACN,0CAA0C,OAAO;AAAA,MAClD;AAAA,IACD;AAAA,EACD,GAAG;AACH;AACD;;;AEpDA,SAAS,UAAAC,SAAQ,iBAAiB;AAClC,SAAS,oBAAoB;;;ACF7B,SAAS,wBAAwB;AACjC,SAAS,UAAAC,eAAkC;AASpC,SAAS,yBAAyB,SAAwB;AAChE,QAAM,SAAS,UAAU,OAAO;AAChC,MAAI,CAAC,QAAQ;AAEZ,IAAAC,QAAO;AAAA,MACN;AAAA,IACD;AACA,UAAM,IAAI,MAAM,gCAAgC;AAAA,EACjD;AAMA,SAAO,iBAAiB;AAAA,IACvB;AAAA;AAAA;AAAA,EAGD,CAAC;AACF;;;AC7BA;AAAA,EACC;AAAA,OAGM;AAMA,SAAS,oBACf,SACA,MACA,QACA,OACC;AACD,UAAQ,UAAU,UAAU,YAAY;AAAA,IACvC,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACP,QAAQ,MAAM;AAAA,MACd,YAAY,MAAM;AAAA,MAClB,OAAO,MAAM;AAAA,IACd;AAAA,EACD,CAAC;AACF;;;AC1BA,SAAS,UAAAC,eAAc;AACvB,SAAS,sBAAsB;AAMxB,SAAS,wBAGa;AAC5B,SAAO,OAAO,EAAE,MAAM,MAAM,MAAwC;AACnE,QAAI;AACH,UAAI,iBAAiB,gBAAgB;AACpC,cAAM,cAAc,KAAK,QAAQ,wBAAwB,EAAE;AAC3D,aAAK,MAAM,WAAW;AACtB,eAAO;AAAA,MACR;AACA,aAAO;AAAA,IACR,SAAS,WAAoB;AAC5B,YAAM,UACL,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS;AAClE,MAAAA,QAAO,KAAK,+BAA+B,OAAO,EAAE;AACpD,aAAO;AAAA,IACR;AAAA,EACD;AACD;AAyBO,SAAS,wBAAwB,WAA2B;AAClE,EAAAC,QAAO,KAAK,IAAI,SAAS,0CAA0C;AAEnE,QAAM,eACL;AACD,EAAAA,QAAO,KAAK,IAAI,SAAS,gCAAgC;AACzD,SAAO;AACR;AAKO,SAAS,8BACf,cACyB;AAEzB,MAAI;AACH,UAAM,eAAe,KAAK,MAAM,YAAY;AAC5C,QAAI,aAAa,SAAS,aAAa,aAAa;AACnD,aAAO;AAAA,IACR;AAAA,EACD,SAAS,GAAG;AAEX,IAAAA,QAAO,MAAM,+CAA+C,CAAC,EAAE;AAAA,EAChE;AAGA,QAAM,aAAa,aAAa,MAAM,2BAA2B;AACjE,QAAM,QAAQ,aAAa,CAAC,GAAG,KAAK,KAAK;AACzC,QAAM,cAAc,aAClB,QAAQ,6BAA6B,EAAE,EACvC,KAAK;AAEP,SAAO,EAAE,OAAO,YAAY;AAC7B;AAKA,eAAsB,4BACrB,OACmB;AACnB,MAAI,iBAAiB,gBAAgB;AACpC,IAAAA,QAAO,MAAM,0CAA0C,MAAM,OAAO,EAAE;AACtE,UAAM,iBAAiB,sBAAsB;AAC7C,UAAM,qBAAqB,MAAM,eAAe;AAAA,MAC/C,MAAM,MAAM;AAAA,MACZ;AAAA,IACD,CAAC;AAED,QAAI,oBAAoB;AACvB,UAAI;AACH,cAAM,iBAAiB,KAAK,MAAM,kBAAkB;AACpD,QAAAA,QAAO,IAAI,8CAA8C;AACzD,eAAO;AAAA,MACR,SAAS,kBAA2B;AACnC,cAAM,UACL,4BAA4B,QACzB,iBAAiB,UACjB,OAAO,gBAAgB;AAC3B,QAAAA,QAAO;AAAA,UACN,mDAAmD,OAAO;AAAA,QAC3D;AACA,YAAI,4BAA4B,MAAO,OAAM;AAC7C,cAAM,OAAO,OAAO,IAAI,MAAM,OAAO,GAAG,EAAE,OAAO,iBAAiB,CAAC;AAAA,MACpE;AAAA,IACD,OAAO;AACN,MAAAA,QAAO,MAAM,sCAAsC;AACnD,YAAM;AAAA,IACP;AAAA,EACD,OAAO;AACN,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,IAAAA,QAAO,MAAM,mCAAmC,OAAO,EAAE;AACzD,QAAI,iBAAiB,MAAO,OAAM;AAClC,UAAM,OAAO,OAAO,IAAI,MAAM,OAAO,GAAG,EAAE,OAAO,MAAM,CAAC;AAAA,EACzD;AACD;AAKA,SAAS,eAAe,KAAa,OAAwB;AAE5D,QAAM,mBAAmB;AACzB,MAAI,CAAC,iBAAiB,KAAK,GAAG,EAAG,QAAO;AAGxC,MAAI,MAAM,SAAS,MAAM,MAAM,SAAS,OAAO,KAAM,QAAO;AAC5D,MAAI,MAAM,SAAS,MAAM,EAAG,QAAO;AACnC,MAAI,CAAC,yBAAyB,KAAK,KAAK,EAAG,QAAO;AAElD,SAAO;AACR;AAKO,SAAS,mBAAmB,KAAc,QAAQ,GAAY;AAEpE,MAAI,QAAQ,EAAG,QAAO;AACtB,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,IAAI,IAAI,UAAQ,mBAAmB,MAAM,QAAQ,CAAC,CAAC;AAElF,QAAM,UAAmC,CAAC;AAC1C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC/C,QAAI,OAAO,UAAU,YAAY,eAAe,KAAK,KAAK,GAAG;AAC5D,UAAI;AACH,gBAAQ,GAAG,IAAI,OAAO,KAAK,OAAO,QAAQ,EAAE,SAAS,MAAM;AAC3D,QAAAA,QAAO,MAAM,iCAAiC,GAAG,MAAM,MAAM,MAAM,SAAS;AAAA,MAC7E,SAAS,OAAO;AACf,QAAAA,QAAO,KAAK,0CAA0C,GAAG,MAAM,KAAK,EAAE;AACtE,gBAAQ,GAAG,IAAI;AAAA,MAChB;AAAA,IACD,WAAW,SAAS,OAAO,UAAU,UAAU;AAC9C,cAAQ,GAAG,IAAI,mBAAmB,OAAO,QAAQ,CAAC;AAAA,IACnD,OAAO;AACN,cAAQ,GAAG,IAAI;AAAA,IAChB;AAAA,EACD;AACA,SAAO;AACR;;;AH7JA,eAAe,sBACd,SACA,WACA,QAIiC;AACjC,QAAM,EAAE,QAAQ,gBAAgB,CAAC,GAAG,OAAO,WAAW,IAAI;AAC1D,QAAM,cAAc,OAAO,eAAe;AAC1C,QAAM,mBAAmB,OAAO,oBAAoB;AACpD,QAAM,kBAAkB,OAAO,mBAAmB;AAClD,QAAM,oBAAoB,OAAO,aAAa;AAE9C,QAAM,aAAa,yBAAyB,OAAO;AACnD,QAAM,YACL,cAAc,UAAU,aACrB,cAAc,OAAO,IACrB,cAAc,OAAO;AACzB,QAAM,aACL,cAAc,UAAU,aAAa,eAAe;AAErD,EAAAC,QAAO;AAAA,IACN,qCAAqC,UAAU,WAAW,SAAS;AAAA,EACpE;AAEA,QAAM,iBAEF;AAAA,IACH,OAAO,WAAW,KAAK,SAAS;AAAA,IAChC;AAAA,IACA,QAAQ,QAAQ,UAAU,UAAU;AAAA,IACpC;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAGA,MAAI,OAAO;AACV,mBAAe,QAAQ;AACvB,mBAAe,WAAW;AAE1B,mBAAe,aAAa;AAAA,MAC3B,UAAU;AAAA,QACT,oBAAoB;AAAA,MACrB;AAAA,IACD;AAAA,EACD;AAGA,MAAI,YAAY;AACf,mBAAe,aAAa;AAAA,EAC7B;AAGA,MAAI,sBAAoC,CAAC;AACzC,MAAI,oBAAgC,CAAC;AAErC,MAAI,OAAO;AACV,mBAAe,eAAe,OAAO,eAAe;AACnD,UAAI,WAAW,aAAa,WAAW,UAAU,SAAS,GAAG;AAC5D,4BAAoB,CAAC,GAAG,mBAAmB,GAAG,WAAW,SAAS;AAAA,MACnE;AACA,UAAI,WAAW,eAAe,WAAW,YAAY,SAAS,GAAG;AAEhE,cAAM,qBAAqB,WAAW,YAAY,IAAI,CAAC,YAAwB;AAAA,UAC9E,GAAG;AAAA,UACH,QAAQ,mBAAmB,OAAO,MAAM;AAAA,QACzC,EAAE;AACF,8BAAsB,CAAC,GAAG,qBAAqB,GAAG,kBAAkB;AAAA,MACrE;AAAA,IACD;AAAA,EACD;AAEA,QAAM,WAAW,MAAM,aAAa,cAAc;AAGlD,MAAI;AACJ,MACC,UACC,CAAC,SAAS,QACV,SAAS,KAAK,KAAK,MAAM,MACzB,SAAS,SAAS,iCAClB;AACD,mBAAe,wBAAwB,UAAU;AAAA,EAClD,OAAO;AACN,mBAAe,SAAS;AAAA,EACzB;AAEA,MAAI,SAAS,OAAO;AACnB,wBAAoB,SAAS,WAAW,QAAQ,SAAS,KAAK;AAAA,EAC/D;AAGA,MACC,UACC,kBAAkB,SAAS,KAAK,oBAAoB,SAAS,IAC7D;AACD,WAAO;AAAA,MACN,MAAM;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA;AAAA,MAEb,OAAO,SAAS;AAAA,MAChB,cAAc,SAAS;AAAA,IACxB;AAAA,EACD;AAEA,SAAO;AACR;AAKA,eAAsB,gBACrB,SACA,QAIiC;AACjC,SAAO,sBAAsB,SAAS,UAAU,YAAY,MAAM;AACnE;AAKA,eAAsB,gBACrB,SACA,QAIiC;AACjC,SAAO,sBAAsB,SAAS,UAAU,YAAY,MAAM;AACnE;;;AIvJA;AAAA,EACC,aAAAC;AAAA,EACA,UAAAC;AAAA,OAGM;AACP,SAAS,sBAAsB;AAY/B,eAAe,wBACd,SACA,WACA,QACmB;AACnB,QAAM,aAAa,yBAAyB,OAAO;AACnD,QAAM,YACL,cAAcC,WAAU,eACrB,cAAc,OAAO,IACrB,cAAc,OAAO;AACzB,QAAM,aACL,cAAcA,WAAU,eAAe,iBAAiB;AAEzD,EAAAC,QAAO,IAAI,sBAAsB,UAAU,WAAW,SAAS,EAAE;AACjE,QAAM,cAAc,OAAO,eAAe;AAE1C,MAAI;AACH,UAAM,EAAE,QAAQ,MAAM,IAAI,MAAM,eAAe;AAAA,MAC9C,OAAO,WAAW,KAAK,SAAS;AAAA,MAChC,QAAQ;AAAA,MACR,QAAQ,OAAO;AAAA,MACf;AAAA,MACA,yBAAyB,sBAAsB;AAAA,IAChD,CAAC;AAED,QAAI,OAAO;AACV,0BAAoB,SAAS,WAAW,OAAO,QAAQ,KAAK;AAAA,IAC7D;AACA,WAAO;AAAA,EACR,SAAS,OAAgB;AACxB,WAAO,4BAA4B,KAAK;AAAA,EACzC;AACD;AAKA,eAAsB,kBACrB,SACA,QACmB;AACnB,SAAO,wBAAwB,SAASD,WAAU,cAAc,MAAM;AACvE;AAKA,eAAsB,kBACrB,SACA,QACmB;AACnB,SAAO,wBAAwB,SAASA,WAAU,cAAc,MAAM;AACvE;;;ACtEA;AAAA,EACC,UAAAE;AAAA,OAIM;AACP,SAAS,gBAAAC,qBAAoB;;;ACN7B,SAAS,YAAY,kBAAkB;AACvC,SAAS,OAAO,iBAAiB;AACjC,SAAS,YAAY;AACrB,SAAS,UAAAC,SAAQ,uBAAuB;AAKxC,eAAsB,gBAAgB,WAAmB,SAAiB,QAAgB,GAA2B;AAEpH,QAAM,IAAI,UAAU,MAAM,0DAA0D;AACpF,MAAI,CAAC,EAAG,QAAO;AAEf,QAAM,OAAO,EAAE,CAAC;AAChB,QAAM,aAAa,EAAE,CAAC;AAGtB,QAAM,SAAiC;AAAA,IACtC,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb,cAAc;AAAA,EACf;AAEA,QAAM,YAAY,OAAO,IAAI;AAC7B,MAAI,CAAC,UAAW,QAAO;AAGvB,QAAM,UAAU,KAAK,gBAAgB,GAAG,OAAO;AAG/C,MAAI,CAAC,WAAW,OAAO,GAAG;AACzB,UAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EACzC;AAGA,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,WAAW,SAAS,SAAS,IAAI,KAAK,IAAI,SAAS;AACzD,QAAM,WAAW,KAAK,SAAS,QAAQ;AAGvC,QAAM,SAAS,OAAO,KAAK,YAAY,QAAQ;AAC/C,QAAM,UAAU,UAAU,MAAM;AAEhC,EAAAA,QAAO,KAAK,yCAAyC,QAAQ,EAAE;AAG/D,SAAO;AACR;AAKO,SAAS,YAAY,UAAwB;AACnD,MAAI;AACH,QAAI,WAAW,QAAQ,GAAG;AACzB,iBAAW,QAAQ;AACnB,MAAAA,QAAO,MAAM,+BAA+B,QAAQ,EAAE;AAAA,IACvD;AAAA,EACD,SAAS,OAAO;AACf,IAAAA,QAAO,KAAK,uCAAuC,QAAQ,KAAK,OAAO,KAAK,CAAC;AAAA,EAC9E;AACD;;;ADjDA,eAAsB,uBACrB,SACA,QACkD;AAClD,MAAI;AACJ,MAAI;AACJ,QAAM,YAAY,cAAc,OAAO;AACvC,EAAAC,QAAO,IAAI,+CAA+C,SAAS,EAAE;AACrE,QAAM,YAAY;AAElB,MAAI,OAAO,WAAW,UAAU;AAC/B,eAAW;AACX,iBACC;AAAA,EACF,OAAO;AACN,eAAW,OAAO;AAClB,iBACC,OAAO,UACP;AAAA,EACF;AAEA,QAAM,aAAa,yBAAyB,OAAO;AAEnD,QAAM,WAAW;AAAA,IAChB;AAAA,MACC,MAAM;AAAA,MACN,SAAS;AAAA,QACR,EAAE,MAAM,QAAiB,MAAM,WAAW;AAAA,QAC1C,EAAE,MAAM,SAAkB,OAAO,SAAS;AAAA,MAC3C;AAAA,IACD;AAAA,EACD;AAEA,MAAI;AACH,UAAM,QAAQ,WAAW,KAAK,SAAS;AAEvC,UAAM,EAAE,MAAM,aAAa,IAAI,MAAMC,cAAa;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC;AAED,WAAO,8BAA8B,YAAY;AAAA,EAClD,SAAS,OAAgB;AACxB,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,IAAAD,QAAO,MAAM,0BAA0B,OAAO,EAAE;AAChD,WAAO;AAAA,MACN,OAAO;AAAA,MACP,aAAa,UAAU,OAAO;AAAA,IAC/B;AAAA,EACD;AACD;AAKA,eAAsB,sBACrB,SACA,QAC6B;AAC7B,QAAM,YAAY,wBAAwB,OAAO;AACjD,EAAAA,QAAO,IAAI,8CAA8C,SAAS,EAAE;AACpE,QAAM,SAAS,UAAU,OAAO;AAEhC,MAAI;AACH,QAAI,CAAC,QAAQ;AACZ,MAAAA,QAAO,MAAM,4CAA4C;AACzD,aAAO,CAAC;AAAA,IACT;AACA,UAAM,UAAU,WAAW,OAAO;AAClC,UAAM,WAAW,MAAM,MAAM,GAAG,OAAO,qBAAqB;AAAA,MAC3D,QAAQ;AAAA,MACR,SAAS;AAAA,QACR,eAAe,UAAU,MAAM;AAAA,QAC/B,gBAAgB;AAAA,MACjB;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACpB,OAAO;AAAA,QACP,UAAU;AAAA,UACT;AAAA,YACC,MAAM;AAAA,YACN,SAAS,OAAO;AAAA,UACjB;AAAA,QACD;AAAA,QACA,YAAY,CAAC,SAAS,MAAM;AAAA,MAC7B,CAAC;AAAA;AAAA,MAED,QAAQ,YAAY,UAAU,YAAY,QAAQ,GAAK,IAAI;AAAA,IAC5D,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACtD,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,IAAI,SAAS,UAAU,IAAI,SAAS,EAAE;AAAA,IAC9E;AAEA,UAAM,SAAS,MAAM,SAAS,KAAK;AAEnC,UAAM,SAA+C,CAAC;AACtD,UAAM,aAAuB,CAAC;AAG9B,QAAI,OAAO,UAAU,CAAC,GAAG,SAAS,QAAQ;AACzC,iBAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,CAAC,EAAE,QAAQ,OAAO,QAAQ,GAAG;AACxE,cAAM,YAAY,MAAM,UAAU;AAGlC,cAAM,WAAW,MAAM,gBAAgB,WAAW,QAAQ,SAAS,KAAK;AACxE,YAAI,UAAU;AAEb,UAAAA,QAAO,IAAI,+CAA+C,QAAQ,EAAE;AACpE,iBAAO,KAAK;AAAA,YACX,KAAK;AAAA;AAAA,UACN,CAAC;AACD,qBAAW,KAAK,QAAQ;AAAA,QACzB,WAAW,CAAC,UAAU,WAAW,OAAO,GAAG;AAE1C,iBAAO,KAAK,EAAE,KAAK,UAAU,CAAC;AAAA,QAC/B,OAAO;AAEN,UAAAA,QAAO,KAAK,qCAAqC,QAAQ,CAAC,YAAY;AAAA,QACvE;AAAA,MACD;AAAA,IACD;AAGA,QAAI,WAAW,SAAS,KAAK,wBAAwB,OAAO,GAAG;AAC9D,iBAAW,MAAM;AAChB,mBAAW,QAAQ,UAAQ;AAC1B,sBAAY,IAAI;AAAA,QACjB,CAAC;AAAA,MACF,GAAG,GAAK;AAAA,IACT;AAEA,QAAI,OAAO,WAAW,GAAG;AACxB,YAAM,IAAI,MAAM,iCAAiC;AAAA,IAClD;AAEA,IAAAA,QAAO,IAAI,0BAA0B,OAAO,MAAM,WAAW;AAC7D,WAAO;AAAA,EACR,SAAS,OAAgB;AACxB,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,IAAAA,QAAO,MAAM,wCAAwC,OAAO,EAAE;AAC9D,WAAO,CAAC;AAAA,EACT;AACD;;;AR7IO,IAAM,mBAA2B;AAAA,EACvC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ;AAAA,IACP,oBAAoB,QAAQ,IAAI;AAAA,IAChC,qBAAqB,QAAQ,IAAI;AAAA,IACjC,wBAAwB,QAAQ,IAAI;AAAA,IACpC,wBAAwB,QAAQ,IAAI;AAAA,IACpC,wBAAwB,QAAQ,IAAI;AAAA,IACpC,mCAAmC,QAAQ,IAAI;AAAA,IAC/C,gCAAgC,QAAQ,IAAI;AAAA,IAC5C,aAAa,QAAQ,IAAI;AAAA,IACzB,aAAa,QAAQ,IAAI;AAAA,IACzB,aAAa,QAAQ,IAAI;AAAA,IACzB,wBAAwB,QAAQ,IAAI;AAAA,EACrC;AAAA,EACA,MAAM,KAAK,QAAQ,SAAS;AAK3B,yBAAqB,QAAQ,OAAO;AAAA,EACrC;AAAA,EACA,QAAQ;AAAA,IACP,CAACE,WAAU,UAAU,GAAG,OACvB,SACA,WAII;AACJ,aAAO,gBAAgB,SAAS,MAAM;AAAA,IACvC;AAAA,IACA,CAACA,WAAU,UAAU,GAAG,OACvB,SACA,WAII;AACJ,aAAO,gBAAgB,SAAS,MAAM;AAAA,IACvC;AAAA,IACA,CAACA,WAAU,YAAY,GAAG,OACzB,SACA,WACI;AACJ,aAAO,kBAAkB,SAAS,MAAM;AAAA,IACzC;AAAA,IACA,CAACA,WAAU,YAAY,GAAG,OACzB,SACA,WACI;AACJ,aAAO,kBAAkB,SAAS,MAAM;AAAA,IACzC;AAAA,IACA,CAACA,WAAU,iBAAiB,GAAG,OAC9B,SACA,WACI;AACJ,aAAO,uBAAuB,SAAS,MAAM;AAAA,IAC9C;AAAA,IACA,CAACA,WAAU,KAAK,GAAG,OAClB,SACA,WACI;AACJ,aAAO,sBAAsB,SAAS,MAAM;AAAA,IAC7C;AAAA,EACD;AACD;AAEA,IAAO,gBAAQ;","names":["ModelType","fetch","fetch","logger","logger","logger","logger","logger","logger","ModelType","logger","ModelType","logger","logger","generateText","logger","logger","generateText","ModelType"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-openrouter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -24,18 +24,18 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ai-sdk/openai": "^1.3.22",
|
|
26
26
|
"@ai-sdk/ui-utils": "1.2.11",
|
|
27
|
-
"@elizaos/core": "^1.
|
|
27
|
+
"@elizaos/core": "^1.5.7",
|
|
28
28
|
"@openrouter/ai-sdk-provider": "^0.4.5",
|
|
29
29
|
"ai": "^4.3.15",
|
|
30
30
|
"undici": "^7.9.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
+
"@types/bun": "^1.1.14",
|
|
33
34
|
"@types/node": "^20.0.0",
|
|
35
|
+
"dotenv": "^16.5.0",
|
|
34
36
|
"prettier": "3.5.3",
|
|
35
37
|
"tsup": "8.4.0",
|
|
36
|
-
"typescript": "5.8.3"
|
|
37
|
-
"vitest": "3.1.3",
|
|
38
|
-
"dotenv": "^16.5.0"
|
|
38
|
+
"typescript": "5.8.3"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsup",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json tsconfig.tsbuildinfo",
|
|
45
45
|
"format": "prettier --write ./src",
|
|
46
46
|
"format:check": "prettier --check ./src",
|
|
47
|
-
"test": "
|
|
48
|
-
"test:watch": "
|
|
47
|
+
"test": "bun test",
|
|
48
|
+
"test:watch": "bun test --watch"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"type": "string",
|
|
84
84
|
"description": "Overrides the default large language model used for text/object generation.",
|
|
85
85
|
"required": false,
|
|
86
|
-
"default": "google/gemini-2.5-flash
|
|
86
|
+
"default": "google/gemini-2.5-flash",
|
|
87
87
|
"sensitive": false
|
|
88
88
|
},
|
|
89
89
|
"SMALL_MODEL": {
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"type": "string",
|
|
98
98
|
"description": "General fallback environment variable for the large model name when OPENROUTER_LARGE_MODEL is not set.",
|
|
99
99
|
"required": false,
|
|
100
|
-
"default": "google/gemini-2.5-flash
|
|
100
|
+
"default": "google/gemini-2.5-flash",
|
|
101
101
|
"sensitive": false
|
|
102
102
|
},
|
|
103
103
|
"IMAGE_MODEL": {
|
|
@@ -106,6 +106,27 @@
|
|
|
106
106
|
"required": false,
|
|
107
107
|
"default": "x-ai/grok-2-vision-1212",
|
|
108
108
|
"sensitive": false
|
|
109
|
+
},
|
|
110
|
+
"OPENROUTER_IMAGE_GENERATION_MODEL": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"description": "Overrides the default image generation model used by the OpenRouter plugin.",
|
|
113
|
+
"required": false,
|
|
114
|
+
"default": "google/gemini-2.5-flash-image-preview",
|
|
115
|
+
"sensitive": false
|
|
116
|
+
},
|
|
117
|
+
"IMAGE_GENERATION_MODEL": {
|
|
118
|
+
"type": "string",
|
|
119
|
+
"description": "General fallback environment variable for the image generation model name when OPENROUTER_IMAGE_GENERATION_MODEL is not set.",
|
|
120
|
+
"required": false,
|
|
121
|
+
"default": "google/gemini-2.5-flash-image-preview",
|
|
122
|
+
"sensitive": false
|
|
123
|
+
},
|
|
124
|
+
"OPENROUTER_AUTO_CLEANUP_IMAGES": {
|
|
125
|
+
"type": "boolean",
|
|
126
|
+
"description": "Whether to automatically cleanup generated images after a short delay.",
|
|
127
|
+
"required": false,
|
|
128
|
+
"default": false,
|
|
129
|
+
"sensitive": false
|
|
109
130
|
}
|
|
110
131
|
}
|
|
111
132
|
}
|