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