@elizaos/plugin-openrouter 2.0.0-alpha.8 → 2.0.0-beta.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/LICENSE +21 -0
- package/README.md +125 -0
- package/auto-enable.ts +17 -0
- package/dist/browser/index.browser.js +333 -137
- package/dist/browser/index.browser.js.map +10 -11
- package/dist/cjs/index.node.cjs +334 -134
- package/dist/cjs/index.node.cjs.map +10 -11
- package/dist/node/index.node.js +333 -137
- package/dist/node/index.node.js.map +10 -11
- package/package.json +29 -13
package/dist/node/index.node.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// plugin.ts
|
|
2
2
|
import {
|
|
3
|
-
logger as
|
|
4
|
-
ModelType as
|
|
3
|
+
logger as logger4,
|
|
4
|
+
ModelType as ModelType4
|
|
5
5
|
} from "@elizaos/core";
|
|
6
6
|
|
|
7
7
|
// init.ts
|
|
@@ -42,9 +42,24 @@ function getApiKey(runtime) {
|
|
|
42
42
|
function getSmallModel(runtime) {
|
|
43
43
|
return getSetting(runtime, "OPENROUTER_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", DEFAULT_SMALL_MODEL) ?? DEFAULT_SMALL_MODEL;
|
|
44
44
|
}
|
|
45
|
+
function getNanoModel(runtime) {
|
|
46
|
+
return getSetting(runtime, "OPENROUTER_NANO_MODEL") ?? getSetting(runtime, "NANO_MODEL") ?? getSmallModel(runtime);
|
|
47
|
+
}
|
|
48
|
+
function getMediumModel(runtime) {
|
|
49
|
+
return getSetting(runtime, "OPENROUTER_MEDIUM_MODEL") ?? getSetting(runtime, "MEDIUM_MODEL") ?? getSmallModel(runtime);
|
|
50
|
+
}
|
|
45
51
|
function getLargeModel(runtime) {
|
|
46
52
|
return getSetting(runtime, "OPENROUTER_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", DEFAULT_LARGE_MODEL) ?? DEFAULT_LARGE_MODEL;
|
|
47
53
|
}
|
|
54
|
+
function getMegaModel(runtime) {
|
|
55
|
+
return getSetting(runtime, "OPENROUTER_MEGA_MODEL") ?? getSetting(runtime, "MEGA_MODEL") ?? getLargeModel(runtime);
|
|
56
|
+
}
|
|
57
|
+
function getResponseHandlerModel(runtime) {
|
|
58
|
+
return getSetting(runtime, "OPENROUTER_RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "OPENROUTER_SHOULD_RESPOND_MODEL") ?? getSetting(runtime, "RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "SHOULD_RESPOND_MODEL") ?? getNanoModel(runtime);
|
|
59
|
+
}
|
|
60
|
+
function getActionPlannerModel(runtime) {
|
|
61
|
+
return getSetting(runtime, "OPENROUTER_ACTION_PLANNER_MODEL") ?? getSetting(runtime, "OPENROUTER_PLANNER_MODEL") ?? getSetting(runtime, "ACTION_PLANNER_MODEL") ?? getSetting(runtime, "PLANNER_MODEL") ?? getMediumModel(runtime);
|
|
62
|
+
}
|
|
48
63
|
function getImageModel(runtime) {
|
|
49
64
|
return getSetting(runtime, "OPENROUTER_IMAGE_MODEL") ?? getSetting(runtime, "IMAGE_MODEL", DEFAULT_IMAGE_MODEL) ?? DEFAULT_IMAGE_MODEL;
|
|
50
65
|
}
|
|
@@ -93,26 +108,34 @@ function initializeOpenRouter(_config, runtime) {
|
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
// models/embedding.ts
|
|
96
|
-
import { logger as
|
|
111
|
+
import { logger as logger2, ModelType, VECTOR_DIMS } from "@elizaos/core";
|
|
97
112
|
|
|
98
113
|
// utils/events.ts
|
|
99
|
-
import {
|
|
100
|
-
function emitModelUsageEvent(
|
|
114
|
+
import { EventType } from "@elizaos/core";
|
|
115
|
+
function emitModelUsageEvent(runtime, modelType, _prompt, usage, modelName, modelLabel) {
|
|
101
116
|
const inputTokens = usage.inputTokens ?? usage.promptTokens ?? 0;
|
|
102
117
|
const outputTokens = usage.outputTokens ?? usage.completionTokens ?? 0;
|
|
103
118
|
const totalTokens = usage.totalTokens ?? inputTokens + outputTokens;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
119
|
+
const model = modelName?.trim() || modelLabel?.trim() || String(modelType);
|
|
120
|
+
runtime.emitEvent(EventType.MODEL_USED, {
|
|
121
|
+
runtime,
|
|
122
|
+
source: "openrouter",
|
|
107
123
|
provider: "openrouter",
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
type: modelType,
|
|
125
|
+
model,
|
|
126
|
+
modelName: model,
|
|
127
|
+
modelLabel: modelLabel ?? String(modelType),
|
|
128
|
+
tokens: {
|
|
129
|
+
prompt: inputTokens,
|
|
130
|
+
completion: outputTokens,
|
|
131
|
+
total: totalTokens
|
|
132
|
+
}
|
|
115
133
|
});
|
|
134
|
+
return {
|
|
135
|
+
promptTokens: inputTokens,
|
|
136
|
+
completionTokens: outputTokens,
|
|
137
|
+
totalTokens
|
|
138
|
+
};
|
|
116
139
|
}
|
|
117
140
|
|
|
118
141
|
// models/embedding.ts
|
|
@@ -121,7 +144,7 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
121
144
|
const embeddingDimension = Number.parseInt(getSetting(runtime, "OPENROUTER_EMBEDDING_DIMENSIONS") ?? getSetting(runtime, "EMBEDDING_DIMENSIONS") ?? "1536", 10);
|
|
122
145
|
if (!Object.values(VECTOR_DIMS).includes(embeddingDimension)) {
|
|
123
146
|
const errorMsg = `Invalid embedding dimension: ${embeddingDimension}. Must be one of: ${Object.values(VECTOR_DIMS).join(", ")}`;
|
|
124
|
-
|
|
147
|
+
logger2.error(errorMsg);
|
|
125
148
|
throw new Error(errorMsg);
|
|
126
149
|
}
|
|
127
150
|
if (params === null) {
|
|
@@ -136,27 +159,27 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
136
159
|
text = params.text;
|
|
137
160
|
} else {
|
|
138
161
|
const errorMsg = "Invalid input format for embedding";
|
|
139
|
-
|
|
162
|
+
logger2.warn(errorMsg);
|
|
140
163
|
const fallbackVector = Array(embeddingDimension).fill(0);
|
|
141
164
|
fallbackVector[0] = 0.2;
|
|
142
165
|
return fallbackVector;
|
|
143
166
|
}
|
|
144
167
|
if (!text.trim()) {
|
|
145
168
|
const errorMsg = "Empty text for embedding";
|
|
146
|
-
|
|
169
|
+
logger2.warn(errorMsg);
|
|
147
170
|
const fallbackVector = Array(embeddingDimension).fill(0);
|
|
148
171
|
fallbackVector[0] = 0.3;
|
|
149
172
|
return fallbackVector;
|
|
150
173
|
}
|
|
151
174
|
const maxChars = 8000 * 4;
|
|
152
175
|
if (text.length > maxChars) {
|
|
153
|
-
|
|
176
|
+
logger2.warn(`[OpenRouter] Embedding input too long (~${Math.ceil(text.length / 4)} tokens), truncating to ~8000 tokens`);
|
|
154
177
|
text = text.slice(0, maxChars);
|
|
155
178
|
}
|
|
156
179
|
const apiKey = getApiKey(runtime);
|
|
157
180
|
if (!apiKey) {
|
|
158
181
|
const errorMsg = "OPENROUTER_API_KEY is not set";
|
|
159
|
-
|
|
182
|
+
logger2.error(errorMsg);
|
|
160
183
|
throw new Error(errorMsg);
|
|
161
184
|
}
|
|
162
185
|
const baseURL = getBaseURL(runtime);
|
|
@@ -175,18 +198,18 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
175
198
|
})
|
|
176
199
|
});
|
|
177
200
|
if (!response.ok) {
|
|
178
|
-
|
|
201
|
+
logger2.error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
|
|
179
202
|
throw new Error(`OpenRouter API error: ${response.status} - ${response.statusText}`);
|
|
180
203
|
}
|
|
181
204
|
const data = await response.json();
|
|
182
205
|
if (!data?.data?.[0]?.embedding) {
|
|
183
|
-
|
|
206
|
+
logger2.error("API returned invalid structure");
|
|
184
207
|
throw new Error("API returned invalid structure");
|
|
185
208
|
}
|
|
186
209
|
const embedding = data.data[0].embedding;
|
|
187
210
|
if (!Array.isArray(embedding) || embedding.length !== embeddingDimension) {
|
|
188
211
|
const errorMsg = `Embedding length ${embedding?.length ?? 0} does not match configured dimension ${embeddingDimension}`;
|
|
189
|
-
|
|
212
|
+
logger2.error(errorMsg);
|
|
190
213
|
const fallbackVector = Array(embeddingDimension).fill(0);
|
|
191
214
|
fallbackVector[0] = 0.4;
|
|
192
215
|
return fallbackVector;
|
|
@@ -197,18 +220,18 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
197
220
|
outputTokens: 0,
|
|
198
221
|
totalTokens: data.usage.total_tokens
|
|
199
222
|
};
|
|
200
|
-
emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage);
|
|
223
|
+
emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, text, usage, embeddingModelName);
|
|
201
224
|
}
|
|
202
225
|
return embedding;
|
|
203
226
|
} catch (error) {
|
|
204
227
|
const message = error instanceof Error ? error.message : String(error);
|
|
205
|
-
|
|
228
|
+
logger2.error(`Error generating embedding: ${message}`);
|
|
206
229
|
throw error instanceof Error ? error : new Error(message);
|
|
207
230
|
}
|
|
208
231
|
}
|
|
209
232
|
|
|
210
233
|
// models/image.ts
|
|
211
|
-
import { logger as
|
|
234
|
+
import { logger as logger3, ModelType as ModelType2 } from "@elizaos/core";
|
|
212
235
|
import { generateText } from "ai";
|
|
213
236
|
|
|
214
237
|
// providers/openrouter.ts
|
|
@@ -243,12 +266,12 @@ async function handleImageDescription(runtime, params) {
|
|
|
243
266
|
};
|
|
244
267
|
const response = await generateText(generateParams);
|
|
245
268
|
if (response.usage) {
|
|
246
|
-
emitModelUsageEvent(runtime, ModelType2.IMAGE_DESCRIPTION, prompt, response.usage);
|
|
269
|
+
emitModelUsageEvent(runtime, ModelType2.IMAGE_DESCRIPTION, prompt, response.usage, modelName);
|
|
247
270
|
}
|
|
248
271
|
return response.text;
|
|
249
272
|
} catch (error) {
|
|
250
273
|
const message = error instanceof Error ? error.message : String(error);
|
|
251
|
-
|
|
274
|
+
logger3.error(`Error describing image: ${message}`);
|
|
252
275
|
throw error instanceof Error ? error : new Error(message);
|
|
253
276
|
}
|
|
254
277
|
}
|
|
@@ -262,7 +285,7 @@ async function handleImageGeneration(runtime, params) {
|
|
|
262
285
|
};
|
|
263
286
|
const response = await generateText(generateParams);
|
|
264
287
|
if (response.usage) {
|
|
265
|
-
emitModelUsageEvent(runtime, ModelType2.IMAGE, params.prompt, response.usage);
|
|
288
|
+
emitModelUsageEvent(runtime, ModelType2.IMAGE, params.prompt, response.usage, modelName);
|
|
266
289
|
}
|
|
267
290
|
return {
|
|
268
291
|
imageUrl: response.text,
|
|
@@ -270,64 +293,41 @@ async function handleImageGeneration(runtime, params) {
|
|
|
270
293
|
};
|
|
271
294
|
} catch (error) {
|
|
272
295
|
const message = error instanceof Error ? error.message : String(error);
|
|
273
|
-
|
|
296
|
+
logger3.error(`Error generating image: ${message}`);
|
|
274
297
|
throw error instanceof Error ? error : new Error(message);
|
|
275
298
|
}
|
|
276
299
|
}
|
|
277
300
|
|
|
278
|
-
// models/
|
|
301
|
+
// models/text.ts
|
|
279
302
|
import {
|
|
280
|
-
|
|
303
|
+
buildCanonicalSystemPrompt,
|
|
304
|
+
dropDuplicateLeadingSystemMessage,
|
|
305
|
+
ModelType as ModelType3,
|
|
306
|
+
resolveEffectiveSystemPrompt
|
|
281
307
|
} from "@elizaos/core";
|
|
282
|
-
import {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
schema: jsonSchema(params.schema),
|
|
302
|
-
output: "object",
|
|
303
|
-
prompt: params.prompt,
|
|
304
|
-
temperature
|
|
305
|
-
}) : await generateObject({
|
|
306
|
-
model,
|
|
307
|
-
output: "no-schema",
|
|
308
|
-
prompt: params.prompt,
|
|
309
|
-
temperature
|
|
308
|
+
import {
|
|
309
|
+
generateText as generateText2,
|
|
310
|
+
streamText
|
|
311
|
+
} from "ai";
|
|
312
|
+
var RESPONSES_ROUTED_PREFIXES = ["openai/", "anthropic/"];
|
|
313
|
+
var NO_SAMPLING_MODEL_PATTERNS = ["o1", "o3", "o4", "gpt-5", "gpt-5-mini"];
|
|
314
|
+
var TEXT_NANO_MODEL_TYPE = ModelType3.TEXT_NANO ?? "TEXT_NANO";
|
|
315
|
+
var TEXT_MEDIUM_MODEL_TYPE = ModelType3.TEXT_MEDIUM ?? "TEXT_MEDIUM";
|
|
316
|
+
var TEXT_MEGA_MODEL_TYPE = ModelType3.TEXT_MEGA ?? "TEXT_MEGA";
|
|
317
|
+
var RESPONSE_HANDLER_MODEL_TYPE = ModelType3.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
|
|
318
|
+
var ACTION_PLANNER_MODEL_TYPE = ModelType3.ACTION_PLANNER ?? "ACTION_PLANNER";
|
|
319
|
+
function buildUserContent(params) {
|
|
320
|
+
const content = [{ type: "text", text: params.prompt }];
|
|
321
|
+
for (const attachment of params.attachments ?? []) {
|
|
322
|
+
content.push({
|
|
323
|
+
type: "file",
|
|
324
|
+
data: attachment.data,
|
|
325
|
+
mediaType: attachment.mediaType,
|
|
326
|
+
...attachment.filename ? { filename: attachment.filename } : {}
|
|
310
327
|
});
|
|
311
|
-
if (usage) {
|
|
312
|
-
emitModelUsageEvent(runtime, modelType, params.prompt, usage);
|
|
313
|
-
}
|
|
314
|
-
return object;
|
|
315
|
-
} catch (error) {
|
|
316
|
-
return handleObjectGenerationError(error);
|
|
317
328
|
}
|
|
329
|
+
return content;
|
|
318
330
|
}
|
|
319
|
-
async function handleObjectSmall(runtime, params) {
|
|
320
|
-
return generateObjectWithModel(runtime, ModelType3.OBJECT_SMALL, params);
|
|
321
|
-
}
|
|
322
|
-
async function handleObjectLarge(runtime, params) {
|
|
323
|
-
return generateObjectWithModel(runtime, ModelType3.OBJECT_LARGE, params);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// models/text.ts
|
|
327
|
-
import { ModelType as ModelType4 } from "@elizaos/core";
|
|
328
|
-
import { generateText as generateText2, streamText } from "ai";
|
|
329
|
-
var RESPONSES_ROUTED_PREFIXES = ["openai/", "anthropic/"];
|
|
330
|
-
var NO_SAMPLING_MODEL_PATTERNS = ["o1", "o3", "o4", "gpt-5", "gpt-5-mini"];
|
|
331
331
|
function supportsSamplingParameters(modelName) {
|
|
332
332
|
const lowerModelName = modelName.toLowerCase();
|
|
333
333
|
if (RESPONSES_ROUTED_PREFIXES.some((prefix) => lowerModelName.startsWith(prefix))) {
|
|
@@ -335,74 +335,222 @@ function supportsSamplingParameters(modelName) {
|
|
|
335
335
|
}
|
|
336
336
|
return !NO_SAMPLING_MODEL_PATTERNS.some((pattern) => lowerModelName.includes(pattern));
|
|
337
337
|
}
|
|
338
|
+
function buildStructuredOutput(responseSchema) {
|
|
339
|
+
if (responseSchema && typeof responseSchema === "object" && "responseFormat" in responseSchema && "parseCompleteOutput" in responseSchema) {
|
|
340
|
+
return responseSchema;
|
|
341
|
+
}
|
|
342
|
+
const schemaOptions = responseSchema && typeof responseSchema === "object" && "schema" in responseSchema ? responseSchema : { schema: responseSchema };
|
|
343
|
+
return {
|
|
344
|
+
name: "object",
|
|
345
|
+
responseFormat: Promise.resolve({
|
|
346
|
+
type: "json",
|
|
347
|
+
schema: schemaOptions.schema,
|
|
348
|
+
...schemaOptions.name ? { name: schemaOptions.name } : {},
|
|
349
|
+
...schemaOptions.description ? { description: schemaOptions.description } : {}
|
|
350
|
+
}),
|
|
351
|
+
async parseCompleteOutput({ text }) {
|
|
352
|
+
return JSON.parse(text);
|
|
353
|
+
},
|
|
354
|
+
async parsePartialOutput() {
|
|
355
|
+
return;
|
|
356
|
+
},
|
|
357
|
+
createElementStreamTransform() {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function usesNativeTextResult(params) {
|
|
363
|
+
return Boolean(params.messages || params.tools || params.toolChoice || params.responseSchema);
|
|
364
|
+
}
|
|
365
|
+
function getModelNameForType(runtime, modelType) {
|
|
366
|
+
switch (modelType) {
|
|
367
|
+
case TEXT_NANO_MODEL_TYPE:
|
|
368
|
+
return getNanoModel(runtime);
|
|
369
|
+
case TEXT_MEDIUM_MODEL_TYPE:
|
|
370
|
+
return getMediumModel(runtime);
|
|
371
|
+
case ModelType3.TEXT_SMALL:
|
|
372
|
+
return getSmallModel(runtime);
|
|
373
|
+
case ModelType3.TEXT_LARGE:
|
|
374
|
+
return getLargeModel(runtime);
|
|
375
|
+
case TEXT_MEGA_MODEL_TYPE:
|
|
376
|
+
return getMegaModel(runtime);
|
|
377
|
+
case RESPONSE_HANDLER_MODEL_TYPE:
|
|
378
|
+
return getResponseHandlerModel(runtime);
|
|
379
|
+
case ACTION_PLANNER_MODEL_TYPE:
|
|
380
|
+
return getActionPlannerModel(runtime);
|
|
381
|
+
default:
|
|
382
|
+
return getLargeModel(runtime);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function getModelLabelForType(modelType) {
|
|
386
|
+
switch (modelType) {
|
|
387
|
+
case TEXT_NANO_MODEL_TYPE:
|
|
388
|
+
return "TEXT_NANO";
|
|
389
|
+
case TEXT_MEDIUM_MODEL_TYPE:
|
|
390
|
+
return "TEXT_MEDIUM";
|
|
391
|
+
case ModelType3.TEXT_SMALL:
|
|
392
|
+
return "TEXT_SMALL";
|
|
393
|
+
case ModelType3.TEXT_LARGE:
|
|
394
|
+
return "TEXT_LARGE";
|
|
395
|
+
case TEXT_MEGA_MODEL_TYPE:
|
|
396
|
+
return "TEXT_MEGA";
|
|
397
|
+
case RESPONSE_HANDLER_MODEL_TYPE:
|
|
398
|
+
return "RESPONSE_HANDLER";
|
|
399
|
+
case ACTION_PLANNER_MODEL_TYPE:
|
|
400
|
+
return "ACTION_PLANNER";
|
|
401
|
+
default:
|
|
402
|
+
return String(modelType);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
338
405
|
function buildGenerateParams(runtime, modelType, params) {
|
|
406
|
+
const paramsWithAttachments = params;
|
|
339
407
|
const { prompt } = params;
|
|
340
408
|
const paramsWithMax = params;
|
|
341
409
|
const resolvedMaxOutput = paramsWithMax.maxOutputTokens ?? paramsWithMax.maxTokens ?? 8192;
|
|
342
410
|
const openrouter = createOpenRouterProvider(runtime);
|
|
343
|
-
const modelName =
|
|
344
|
-
const modelLabel = modelType
|
|
411
|
+
const modelName = getModelNameForType(runtime, modelType);
|
|
412
|
+
const modelLabel = getModelLabelForType(modelType);
|
|
345
413
|
const supportsSampling = supportsSamplingParameters(modelName);
|
|
346
414
|
const stopSequences = Array.isArray(params.stopSequences) && params.stopSequences.length > 0 ? params.stopSequences : undefined;
|
|
415
|
+
const userContent = (paramsWithAttachments.attachments?.length ?? 0) > 0 ? buildUserContent(paramsWithAttachments) : undefined;
|
|
347
416
|
const temperature = params.temperature ?? 0.7;
|
|
348
417
|
const frequencyPenalty = params.frequencyPenalty ?? 0.7;
|
|
349
418
|
const presencePenalty = params.presencePenalty ?? 0.7;
|
|
419
|
+
const systemPrompt = resolveEffectiveSystemPrompt({
|
|
420
|
+
params: paramsWithAttachments,
|
|
421
|
+
fallback: buildCanonicalSystemPrompt({ character: runtime.character })
|
|
422
|
+
});
|
|
423
|
+
const wireMessages = dropDuplicateLeadingSystemMessage(paramsWithAttachments.messages, systemPrompt);
|
|
424
|
+
const promptOrMessages = paramsWithAttachments.messages ? wireMessages && wireMessages.length > 0 ? { messages: wireMessages } : userContent ? { messages: [{ role: "user", content: userContent }] } : { prompt } : userContent ? { messages: [{ role: "user", content: userContent }] } : { prompt };
|
|
425
|
+
const rawProviderOptions = paramsWithAttachments.providerOptions;
|
|
426
|
+
const { openrouter: rawOpenrouterOptions, ...restProviderOptions } = rawProviderOptions ?? {};
|
|
427
|
+
const openrouterOptions = {
|
|
428
|
+
...rawOpenrouterOptions ?? {}
|
|
429
|
+
};
|
|
430
|
+
const mergedProviderOptions = {
|
|
431
|
+
...restProviderOptions,
|
|
432
|
+
...Object.keys(openrouterOptions).length > 0 ? { openrouter: openrouterOptions } : {}
|
|
433
|
+
};
|
|
434
|
+
const resolvedProviderOptions = Object.keys(mergedProviderOptions).length > 0 ? mergedProviderOptions : undefined;
|
|
350
435
|
const generateParams = {
|
|
351
436
|
model: openrouter.chat(modelName),
|
|
352
|
-
|
|
353
|
-
system:
|
|
437
|
+
...promptOrMessages,
|
|
438
|
+
system: systemPrompt,
|
|
354
439
|
...supportsSampling ? {
|
|
355
440
|
temperature,
|
|
356
441
|
frequencyPenalty,
|
|
357
442
|
presencePenalty,
|
|
358
443
|
...stopSequences ? { stopSequences } : {}
|
|
359
444
|
} : {},
|
|
360
|
-
maxOutputTokens: resolvedMaxOutput
|
|
445
|
+
maxOutputTokens: resolvedMaxOutput,
|
|
446
|
+
...paramsWithAttachments.tools ? { tools: paramsWithAttachments.tools } : {},
|
|
447
|
+
...paramsWithAttachments.toolChoice ? { toolChoice: paramsWithAttachments.toolChoice } : {},
|
|
448
|
+
...paramsWithAttachments.responseSchema ? { output: buildStructuredOutput(paramsWithAttachments.responseSchema) } : {},
|
|
449
|
+
...resolvedProviderOptions ? { providerOptions: resolvedProviderOptions } : {}
|
|
450
|
+
};
|
|
451
|
+
return {
|
|
452
|
+
generateParams,
|
|
453
|
+
modelName,
|
|
454
|
+
modelLabel,
|
|
455
|
+
prompt,
|
|
456
|
+
shouldReturnNativeResult: usesNativeTextResult(paramsWithAttachments)
|
|
361
457
|
};
|
|
362
|
-
return { generateParams, modelName, modelLabel, prompt };
|
|
363
458
|
}
|
|
364
|
-
function handleStreamingGeneration(runtime, modelType, generateParams, prompt,
|
|
459
|
+
function handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelName, modelLabel, shouldReturnNativeResult) {
|
|
365
460
|
const streamResult = streamText(generateParams);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
text: Promise.resolve(streamResult.text),
|
|
369
|
-
usage: Promise.resolve(streamResult.usage).then((usage) => {
|
|
370
|
-
if (usage) {
|
|
371
|
-
emitModelUsageEvent(runtime, modelType, prompt, usage);
|
|
372
|
-
const inputTokens = usage.inputTokens ?? 0;
|
|
373
|
-
const outputTokens = usage.outputTokens ?? 0;
|
|
374
|
-
return {
|
|
375
|
-
promptTokens: inputTokens,
|
|
376
|
-
completionTokens: outputTokens,
|
|
377
|
-
totalTokens: inputTokens + outputTokens
|
|
378
|
-
};
|
|
379
|
-
}
|
|
461
|
+
const usagePromise = Promise.resolve(streamResult.usage).then((usage) => {
|
|
462
|
+
if (!usage) {
|
|
380
463
|
return;
|
|
464
|
+
}
|
|
465
|
+
return emitModelUsageEvent(runtime, modelType, prompt, usage, modelName, modelLabel);
|
|
466
|
+
});
|
|
467
|
+
const ignoreUsageError = () => {
|
|
468
|
+
return;
|
|
469
|
+
};
|
|
470
|
+
async function* textStreamWithUsage() {
|
|
471
|
+
let completed = false;
|
|
472
|
+
try {
|
|
473
|
+
for await (const chunk of streamResult.textStream) {
|
|
474
|
+
yield chunk;
|
|
475
|
+
}
|
|
476
|
+
completed = true;
|
|
477
|
+
} finally {
|
|
478
|
+
if (completed) {
|
|
479
|
+
await usagePromise.catch(ignoreUsageError);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return {
|
|
484
|
+
textStream: textStreamWithUsage(),
|
|
485
|
+
text: Promise.resolve(streamResult.text).then(async (text) => {
|
|
486
|
+
await usagePromise.catch(ignoreUsageError);
|
|
487
|
+
return text;
|
|
381
488
|
}),
|
|
489
|
+
...shouldReturnNativeResult ? { toolCalls: Promise.resolve(streamResult.toolCalls) } : {},
|
|
490
|
+
usage: usagePromise,
|
|
382
491
|
finishReason: Promise.resolve(streamResult.finishReason)
|
|
383
492
|
};
|
|
384
493
|
}
|
|
494
|
+
function buildNativeTextResult(result) {
|
|
495
|
+
const inputTokens = result.usage?.inputTokens ?? result.usage?.promptTokens ?? 0;
|
|
496
|
+
const outputTokens = result.usage?.outputTokens ?? result.usage?.completionTokens ?? 0;
|
|
497
|
+
if (!result.usage) {
|
|
498
|
+
return {
|
|
499
|
+
text: result.text,
|
|
500
|
+
toolCalls: result.toolCalls ?? [],
|
|
501
|
+
finishReason: result.finishReason
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
const cacheRead = result.usage.cacheReadInputTokens ?? result.usage.cachedInputTokens;
|
|
505
|
+
const cacheCreation = result.usage.cacheCreationInputTokens;
|
|
506
|
+
const usage = {
|
|
507
|
+
promptTokens: inputTokens,
|
|
508
|
+
completionTokens: outputTokens,
|
|
509
|
+
totalTokens: result.usage.totalTokens ?? inputTokens + outputTokens,
|
|
510
|
+
...typeof cacheRead === "number" ? { cacheReadInputTokens: cacheRead } : {},
|
|
511
|
+
...typeof cacheCreation === "number" ? { cacheCreationInputTokens: cacheCreation } : {}
|
|
512
|
+
};
|
|
513
|
+
return {
|
|
514
|
+
text: result.text,
|
|
515
|
+
toolCalls: result.toolCalls ?? [],
|
|
516
|
+
finishReason: result.finishReason,
|
|
517
|
+
usage
|
|
518
|
+
};
|
|
519
|
+
}
|
|
385
520
|
async function generateTextWithModel(runtime, modelType, params) {
|
|
386
|
-
const {
|
|
387
|
-
generateParams,
|
|
388
|
-
modelName: _modelName,
|
|
389
|
-
modelLabel,
|
|
390
|
-
prompt
|
|
391
|
-
} = buildGenerateParams(runtime, modelType, params);
|
|
521
|
+
const { generateParams, modelName, modelLabel, prompt, shouldReturnNativeResult } = buildGenerateParams(runtime, modelType, params);
|
|
392
522
|
if (params.stream) {
|
|
393
|
-
return handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelLabel);
|
|
523
|
+
return handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelName, modelLabel, shouldReturnNativeResult);
|
|
394
524
|
}
|
|
395
525
|
const response = await generateText2(generateParams);
|
|
396
526
|
if (response.usage) {
|
|
397
|
-
emitModelUsageEvent(runtime, modelType, prompt, response.usage);
|
|
527
|
+
emitModelUsageEvent(runtime, modelType, prompt, response.usage, modelName, modelLabel);
|
|
528
|
+
}
|
|
529
|
+
if (shouldReturnNativeResult) {
|
|
530
|
+
return buildNativeTextResult(response);
|
|
398
531
|
}
|
|
399
532
|
return response.text;
|
|
400
533
|
}
|
|
401
534
|
async function handleTextSmall(runtime, params) {
|
|
402
|
-
return generateTextWithModel(runtime,
|
|
535
|
+
return generateTextWithModel(runtime, ModelType3.TEXT_SMALL, params);
|
|
536
|
+
}
|
|
537
|
+
async function handleTextNano(runtime, params) {
|
|
538
|
+
return generateTextWithModel(runtime, TEXT_NANO_MODEL_TYPE, params);
|
|
539
|
+
}
|
|
540
|
+
async function handleTextMedium(runtime, params) {
|
|
541
|
+
return generateTextWithModel(runtime, TEXT_MEDIUM_MODEL_TYPE, params);
|
|
403
542
|
}
|
|
404
543
|
async function handleTextLarge(runtime, params) {
|
|
405
|
-
return generateTextWithModel(runtime,
|
|
544
|
+
return generateTextWithModel(runtime, ModelType3.TEXT_LARGE, params);
|
|
545
|
+
}
|
|
546
|
+
async function handleTextMega(runtime, params) {
|
|
547
|
+
return generateTextWithModel(runtime, TEXT_MEGA_MODEL_TYPE, params);
|
|
548
|
+
}
|
|
549
|
+
async function handleResponseHandler(runtime, params) {
|
|
550
|
+
return generateTextWithModel(runtime, RESPONSE_HANDLER_MODEL_TYPE, params);
|
|
551
|
+
}
|
|
552
|
+
async function handleActionPlanner(runtime, params) {
|
|
553
|
+
return generateTextWithModel(runtime, ACTION_PLANNER_MODEL_TYPE, params);
|
|
406
554
|
}
|
|
407
555
|
|
|
408
556
|
// plugin.ts
|
|
@@ -413,21 +561,43 @@ function getProcessEnv() {
|
|
|
413
561
|
return process.env;
|
|
414
562
|
}
|
|
415
563
|
var env = getProcessEnv();
|
|
564
|
+
var TEXT_NANO_MODEL_TYPE2 = ModelType4.TEXT_NANO ?? "TEXT_NANO";
|
|
565
|
+
var TEXT_MEDIUM_MODEL_TYPE2 = ModelType4.TEXT_MEDIUM ?? "TEXT_MEDIUM";
|
|
566
|
+
var TEXT_MEGA_MODEL_TYPE2 = ModelType4.TEXT_MEGA ?? "TEXT_MEGA";
|
|
567
|
+
var RESPONSE_HANDLER_MODEL_TYPE2 = ModelType4.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
|
|
568
|
+
var ACTION_PLANNER_MODEL_TYPE2 = ModelType4.ACTION_PLANNER ?? "ACTION_PLANNER";
|
|
416
569
|
var openrouterPlugin = {
|
|
417
570
|
name: "openrouter",
|
|
418
571
|
description: "OpenRouter multi-model AI gateway plugin",
|
|
572
|
+
autoEnable: {
|
|
573
|
+
envKeys: ["OPENROUTER_API_KEY"]
|
|
574
|
+
},
|
|
419
575
|
config: {
|
|
420
576
|
OPENROUTER_API_KEY: env.OPENROUTER_API_KEY ?? null,
|
|
421
577
|
OPENROUTER_BASE_URL: env.OPENROUTER_BASE_URL ?? null,
|
|
578
|
+
OPENROUTER_NANO_MODEL: env.OPENROUTER_NANO_MODEL ?? null,
|
|
579
|
+
OPENROUTER_MEDIUM_MODEL: env.OPENROUTER_MEDIUM_MODEL ?? null,
|
|
422
580
|
OPENROUTER_SMALL_MODEL: env.OPENROUTER_SMALL_MODEL ?? null,
|
|
423
581
|
OPENROUTER_LARGE_MODEL: env.OPENROUTER_LARGE_MODEL ?? null,
|
|
582
|
+
OPENROUTER_MEGA_MODEL: env.OPENROUTER_MEGA_MODEL ?? null,
|
|
583
|
+
OPENROUTER_RESPONSE_HANDLER_MODEL: env.OPENROUTER_RESPONSE_HANDLER_MODEL ?? null,
|
|
584
|
+
OPENROUTER_SHOULD_RESPOND_MODEL: env.OPENROUTER_SHOULD_RESPOND_MODEL ?? null,
|
|
585
|
+
OPENROUTER_ACTION_PLANNER_MODEL: env.OPENROUTER_ACTION_PLANNER_MODEL ?? null,
|
|
586
|
+
OPENROUTER_PLANNER_MODEL: env.OPENROUTER_PLANNER_MODEL ?? null,
|
|
424
587
|
OPENROUTER_IMAGE_MODEL: env.OPENROUTER_IMAGE_MODEL ?? null,
|
|
425
588
|
OPENROUTER_IMAGE_GENERATION_MODEL: env.OPENROUTER_IMAGE_GENERATION_MODEL ?? null,
|
|
426
589
|
OPENROUTER_EMBEDDING_MODEL: env.OPENROUTER_EMBEDDING_MODEL ?? null,
|
|
427
590
|
OPENROUTER_EMBEDDING_DIMENSIONS: env.OPENROUTER_EMBEDDING_DIMENSIONS ?? null,
|
|
428
591
|
OPENROUTER_AUTO_CLEANUP_IMAGES: env.OPENROUTER_AUTO_CLEANUP_IMAGES ?? null,
|
|
592
|
+
NANO_MODEL: env.NANO_MODEL ?? null,
|
|
593
|
+
MEDIUM_MODEL: env.MEDIUM_MODEL ?? null,
|
|
429
594
|
SMALL_MODEL: env.SMALL_MODEL ?? null,
|
|
430
595
|
LARGE_MODEL: env.LARGE_MODEL ?? null,
|
|
596
|
+
MEGA_MODEL: env.MEGA_MODEL ?? null,
|
|
597
|
+
RESPONSE_HANDLER_MODEL: env.RESPONSE_HANDLER_MODEL ?? null,
|
|
598
|
+
SHOULD_RESPOND_MODEL: env.SHOULD_RESPOND_MODEL ?? null,
|
|
599
|
+
ACTION_PLANNER_MODEL: env.ACTION_PLANNER_MODEL ?? null,
|
|
600
|
+
PLANNER_MODEL: env.PLANNER_MODEL ?? null,
|
|
431
601
|
IMAGE_MODEL: env.IMAGE_MODEL ?? null,
|
|
432
602
|
IMAGE_GENERATION_MODEL: env.IMAGE_GENERATION_MODEL ?? null,
|
|
433
603
|
EMBEDDING_MODEL: env.EMBEDDING_MODEL ?? null,
|
|
@@ -437,27 +607,36 @@ var openrouterPlugin = {
|
|
|
437
607
|
initializeOpenRouter(config, runtime);
|
|
438
608
|
},
|
|
439
609
|
models: {
|
|
440
|
-
[
|
|
610
|
+
[TEXT_NANO_MODEL_TYPE2]: async (runtime, params) => {
|
|
611
|
+
return handleTextNano(runtime, params);
|
|
612
|
+
},
|
|
613
|
+
[ModelType4.TEXT_SMALL]: async (runtime, params) => {
|
|
441
614
|
return handleTextSmall(runtime, params);
|
|
442
615
|
},
|
|
443
|
-
[
|
|
616
|
+
[TEXT_MEDIUM_MODEL_TYPE2]: async (runtime, params) => {
|
|
617
|
+
return handleTextMedium(runtime, params);
|
|
618
|
+
},
|
|
619
|
+
[ModelType4.TEXT_LARGE]: async (runtime, params) => {
|
|
444
620
|
return handleTextLarge(runtime, params);
|
|
445
621
|
},
|
|
446
|
-
[
|
|
447
|
-
return
|
|
622
|
+
[TEXT_MEGA_MODEL_TYPE2]: async (runtime, params) => {
|
|
623
|
+
return handleTextMega(runtime, params);
|
|
448
624
|
},
|
|
449
|
-
[
|
|
450
|
-
return
|
|
625
|
+
[RESPONSE_HANDLER_MODEL_TYPE2]: async (runtime, params) => {
|
|
626
|
+
return handleResponseHandler(runtime, params);
|
|
451
627
|
},
|
|
452
|
-
[
|
|
628
|
+
[ACTION_PLANNER_MODEL_TYPE2]: async (runtime, params) => {
|
|
629
|
+
return handleActionPlanner(runtime, params);
|
|
630
|
+
},
|
|
631
|
+
[ModelType4.IMAGE_DESCRIPTION]: async (runtime, params) => {
|
|
453
632
|
const description = await handleImageDescription(runtime, params);
|
|
454
633
|
return { title: "", description };
|
|
455
634
|
},
|
|
456
|
-
[
|
|
635
|
+
[ModelType4.IMAGE]: async (runtime, params) => {
|
|
457
636
|
const result = await handleImageGeneration(runtime, params);
|
|
458
637
|
return [{ url: result.imageUrl }];
|
|
459
638
|
},
|
|
460
|
-
[
|
|
639
|
+
[ModelType4.TEXT_EMBEDDING]: async (runtime, params) => {
|
|
461
640
|
return handleTextEmbedding(runtime, params);
|
|
462
641
|
}
|
|
463
642
|
},
|
|
@@ -469,16 +648,17 @@ var openrouterPlugin = {
|
|
|
469
648
|
name: "openrouter_test_text_small",
|
|
470
649
|
fn: async (runtime) => {
|
|
471
650
|
try {
|
|
472
|
-
const
|
|
651
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
652
|
+
const text = await runModel(ModelType4.TEXT_SMALL, {
|
|
473
653
|
prompt: "What is the nature of reality in 10 words?"
|
|
474
654
|
});
|
|
475
655
|
if (text.length === 0) {
|
|
476
656
|
throw new Error("Failed to generate text");
|
|
477
657
|
}
|
|
478
|
-
|
|
658
|
+
logger4.log({ text }, "generated with test_text_small");
|
|
479
659
|
} catch (error) {
|
|
480
660
|
const message = error instanceof Error ? error.message : String(error);
|
|
481
|
-
|
|
661
|
+
logger4.error(`Error in test_text_small: ${message}`);
|
|
482
662
|
throw error;
|
|
483
663
|
}
|
|
484
664
|
}
|
|
@@ -487,35 +667,41 @@ var openrouterPlugin = {
|
|
|
487
667
|
name: "openrouter_test_text_large",
|
|
488
668
|
fn: async (runtime) => {
|
|
489
669
|
try {
|
|
490
|
-
const
|
|
670
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
671
|
+
const text = await runModel(ModelType4.TEXT_LARGE, {
|
|
491
672
|
prompt: "What is the nature of reality in 10 words?"
|
|
492
673
|
});
|
|
493
674
|
if (text.length === 0) {
|
|
494
675
|
throw new Error("Failed to generate text");
|
|
495
676
|
}
|
|
496
|
-
|
|
677
|
+
logger4.log({ text }, "generated with test_text_large");
|
|
497
678
|
} catch (error) {
|
|
498
679
|
const message = error instanceof Error ? error.message : String(error);
|
|
499
|
-
|
|
680
|
+
logger4.error(`Error in test_text_large: ${message}`);
|
|
500
681
|
throw error;
|
|
501
682
|
}
|
|
502
683
|
}
|
|
503
684
|
},
|
|
504
685
|
{
|
|
505
|
-
name: "
|
|
686
|
+
name: "openrouter_test_structured_output_via_text_large",
|
|
506
687
|
fn: async (runtime) => {
|
|
507
688
|
try {
|
|
508
|
-
const
|
|
689
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
690
|
+
const result = await runModel(ModelType4.TEXT_LARGE, {
|
|
509
691
|
prompt: "Create a simple JSON object with a message field saying hello",
|
|
510
|
-
|
|
692
|
+
responseSchema: {
|
|
693
|
+
type: "object",
|
|
694
|
+
properties: { message: { type: "string" } },
|
|
695
|
+
required: ["message"]
|
|
696
|
+
}
|
|
511
697
|
});
|
|
512
|
-
|
|
513
|
-
if (!result
|
|
514
|
-
throw new Error("Failed to generate
|
|
698
|
+
logger4.log({ result }, "Generated structured output via TEXT_LARGE");
|
|
699
|
+
if (!result) {
|
|
700
|
+
throw new Error("Failed to generate structured output");
|
|
515
701
|
}
|
|
516
702
|
} catch (error) {
|
|
517
703
|
const message = error instanceof Error ? error.message : String(error);
|
|
518
|
-
|
|
704
|
+
logger4.error(`Error in test_structured_output_via_text_large: ${message}`);
|
|
519
705
|
throw error;
|
|
520
706
|
}
|
|
521
707
|
}
|
|
@@ -524,13 +710,14 @@ var openrouterPlugin = {
|
|
|
524
710
|
name: "openrouter_test_text_embedding",
|
|
525
711
|
fn: async (runtime) => {
|
|
526
712
|
try {
|
|
527
|
-
const
|
|
713
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
714
|
+
const embedding = await runModel(ModelType4.TEXT_EMBEDDING, {
|
|
528
715
|
text: "Hello, world!"
|
|
529
716
|
});
|
|
530
|
-
|
|
717
|
+
logger4.log({ embedding }, "embedding");
|
|
531
718
|
} catch (error) {
|
|
532
719
|
const message = error instanceof Error ? error.message : String(error);
|
|
533
|
-
|
|
720
|
+
logger4.error(`Error in test_text_embedding: ${message}`);
|
|
534
721
|
throw error;
|
|
535
722
|
}
|
|
536
723
|
}
|
|
@@ -539,11 +726,19 @@ var openrouterPlugin = {
|
|
|
539
726
|
}
|
|
540
727
|
]
|
|
541
728
|
};
|
|
729
|
+
var plugin_default = openrouterPlugin;
|
|
730
|
+
|
|
731
|
+
// index.ts
|
|
732
|
+
var openrouterPlugin2 = plugin_default;
|
|
542
733
|
export {
|
|
543
734
|
shouldAutoCleanupImages,
|
|
544
|
-
openrouterPlugin,
|
|
735
|
+
openrouterPlugin2 as openrouterPlugin,
|
|
545
736
|
getSmallModel,
|
|
546
737
|
getSetting,
|
|
738
|
+
getResponseHandlerModel,
|
|
739
|
+
getNanoModel,
|
|
740
|
+
getMegaModel,
|
|
741
|
+
getMediumModel,
|
|
547
742
|
getLargeModel,
|
|
548
743
|
getImageModel,
|
|
549
744
|
getImageGenerationModel,
|
|
@@ -551,7 +746,8 @@ export {
|
|
|
551
746
|
getEmbeddingDimensions,
|
|
552
747
|
getBaseURL,
|
|
553
748
|
getApiKey,
|
|
554
|
-
|
|
749
|
+
getActionPlannerModel,
|
|
750
|
+
openrouterPlugin2 as default,
|
|
555
751
|
DEFAULT_SMALL_MODEL,
|
|
556
752
|
DEFAULT_LARGE_MODEL,
|
|
557
753
|
DEFAULT_IMAGE_MODEL,
|
|
@@ -561,5 +757,5 @@ export {
|
|
|
561
757
|
DEFAULT_BASE_URL
|
|
562
758
|
};
|
|
563
759
|
|
|
564
|
-
//# debugId=
|
|
760
|
+
//# debugId=778917F34416E3C764756E2164756E21
|
|
565
761
|
//# sourceMappingURL=index.node.js.map
|