@elizaos/plugin-elizacloud 2.0.0-alpha.4 → 2.0.0-alpha.537
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 +185 -0
- package/dist/actions/check-credits.d.ts.map +1 -1
- package/dist/actions/confirmation.d.ts +7 -0
- package/dist/actions/confirmation.d.ts.map +1 -0
- package/dist/actions/freeze-agent.d.ts.map +1 -1
- package/dist/actions/provision-agent.d.ts.map +1 -1
- package/dist/actions/resume-agent.d.ts.map +1 -1
- package/dist/browser/index.browser.js +22 -19
- package/dist/browser/index.browser.js.map +36 -27
- package/dist/cjs/index.node.cjs +1710 -406
- package/dist/cjs/index.node.js.map +36 -27
- package/dist/cloud-providers/credit-balance.d.ts +1 -3
- package/dist/cloud-providers/credit-balance.d.ts.map +1 -1
- package/dist/cloud-providers/model-registry.d.ts +4 -0
- package/dist/cloud-providers/model-registry.d.ts.map +1 -0
- package/dist/index.browser.d.ts +2 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.node.d.ts +2 -1
- package/dist/index.node.d.ts.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/models/embeddings.d.ts.map +1 -1
- package/dist/models/image.d.ts.map +1 -1
- package/dist/models/index.d.ts +2 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/object.d.ts.map +1 -1
- package/dist/models/research.d.ts +4 -0
- package/dist/models/research.d.ts.map +1 -0
- package/dist/models/speech.d.ts.map +1 -1
- package/dist/models/text.d.ts +5 -0
- package/dist/models/text.d.ts.map +1 -1
- package/dist/models/transcription.d.ts.map +1 -1
- package/dist/node/index.node.js +1710 -396
- package/dist/node/index.node.js.map +36 -27
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/services/cloud-auth.d.ts +140 -4
- package/dist/services/cloud-auth.d.ts.map +1 -1
- package/dist/services/cloud-bootstrap.d.ts +38 -0
- package/dist/services/cloud-bootstrap.d.ts.map +1 -0
- package/dist/services/cloud-bridge.d.ts +1 -1
- package/dist/services/cloud-managed-gateway-relay.d.ts +38 -0
- package/dist/services/cloud-managed-gateway-relay.d.ts.map +1 -0
- package/dist/services/cloud-model-registry.d.ts +28 -0
- package/dist/services/cloud-model-registry.d.ts.map +1 -0
- package/dist/types/cloud.d.ts +41 -19
- package/dist/types/cloud.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/cloud-api.d.ts +2 -27
- package/dist/utils/cloud-api.d.ts.map +1 -1
- package/dist/utils/config.d.ts +9 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/events.d.ts.map +1 -1
- package/dist/utils/forwarded-settings.d.ts +1 -1
- package/dist/utils/forwarded-settings.d.ts.map +1 -1
- package/dist/utils/responses-output.d.ts +6 -0
- package/dist/utils/responses-output.d.ts.map +1 -0
- package/dist/utils/sdk-client.d.ts +5 -0
- package/dist/utils/sdk-client.d.ts.map +1 -0
- package/package.json +84 -16
- package/types/cloud.ts +54 -41
- package/types/index.ts +6 -0
- package/dist/actions/index.d.ts +0 -5
- package/dist/actions/index.d.ts.map +0 -1
- package/dist/build.d.ts +0 -3
- package/dist/build.d.ts.map +0 -1
- package/dist/cloud-providers/index.d.ts +0 -4
- package/dist/cloud-providers/index.d.ts.map +0 -1
- package/dist/generated/specs/specs.d.ts +0 -55
- package/dist/generated/specs/specs.d.ts.map +0 -1
- package/dist/services/index.d.ts +0 -5
- package/dist/services/index.d.ts.map +0 -1
package/dist/node/index.node.js
CHANGED
|
@@ -2,13 +2,14 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// index.ts
|
|
5
|
-
import { logger as
|
|
5
|
+
import { logger as logger19, ModelType as ModelType6 } from "@elizaos/core";
|
|
6
6
|
|
|
7
7
|
// actions/check-credits.ts
|
|
8
8
|
var DAILY_COST_PER_CONTAINER = 0.67;
|
|
9
9
|
var checkCloudCreditsAction = {
|
|
10
10
|
name: "CHECK_CLOUD_CREDITS",
|
|
11
11
|
description: "Check ElizaCloud credit balance, container costs, and estimated remaining runtime.",
|
|
12
|
+
descriptionCompressed: "Check ElizaCloud credits, container costs, remaining runtime.",
|
|
12
13
|
similes: ["check credits", "check balance", "how much credit", "cloud billing"],
|
|
13
14
|
tags: ["cloud", "billing"],
|
|
14
15
|
parameters: [
|
|
@@ -19,8 +20,29 @@ var checkCloudCreditsAction = {
|
|
|
19
20
|
schema: { type: "boolean" }
|
|
20
21
|
}
|
|
21
22
|
],
|
|
22
|
-
async
|
|
23
|
-
|
|
23
|
+
validate: async (runtime, message, state, options) => {
|
|
24
|
+
const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
|
|
25
|
+
const __avText = __avTextRaw.toLowerCase();
|
|
26
|
+
const __avKeywords = ["check", "cloud", "credits"];
|
|
27
|
+
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
|
|
28
|
+
const __avRegex = /\b(?:check|cloud|credits)\b/i;
|
|
29
|
+
const __avRegexOk = Boolean(__avText.match(__avRegex));
|
|
30
|
+
const __avSource = String(message?.content?.source ?? "");
|
|
31
|
+
const __avExpectedSource = "";
|
|
32
|
+
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
|
|
33
|
+
const __avOptions = options && typeof options === "object" ? options : {};
|
|
34
|
+
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
|
|
35
|
+
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const __avLegacyValidate = async (runtime2) => {
|
|
39
|
+
return !!runtime2.getService("CLOUD_AUTH")?.isAuthenticated();
|
|
40
|
+
};
|
|
41
|
+
try {
|
|
42
|
+
return Boolean(await __avLegacyValidate(runtime));
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
24
46
|
},
|
|
25
47
|
async handler(runtime, message, _state, options, callback) {
|
|
26
48
|
const auth = runtime.getService("CLOUD_AUTH");
|
|
@@ -62,16 +84,36 @@ var checkCloudCreditsAction = {
|
|
|
62
84
|
}
|
|
63
85
|
};
|
|
64
86
|
|
|
87
|
+
// actions/confirmation.ts
|
|
88
|
+
function mergedOptions(options) {
|
|
89
|
+
const direct = options ?? {};
|
|
90
|
+
const parameters = direct.parameters && typeof direct.parameters === "object" ? direct.parameters : {};
|
|
91
|
+
return { ...direct, ...parameters };
|
|
92
|
+
}
|
|
93
|
+
function isConfirmed(options) {
|
|
94
|
+
const raw = mergedOptions(options).confirmed;
|
|
95
|
+
return raw === true || raw === "true";
|
|
96
|
+
}
|
|
97
|
+
function confirmationRequired(preview, data) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
text: preview,
|
|
101
|
+
data: { requiresConfirmation: true, preview, ...data }
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
65
105
|
// actions/freeze-agent.ts
|
|
66
106
|
function getContainerId(message, options) {
|
|
67
|
-
|
|
68
|
-
|
|
107
|
+
const params = mergedOptions(options);
|
|
108
|
+
if (params.containerId)
|
|
109
|
+
return String(params.containerId);
|
|
69
110
|
const meta = message.metadata?.actionParams;
|
|
70
111
|
return meta?.containerId ? String(meta.containerId) : null;
|
|
71
112
|
}
|
|
72
113
|
var freezeCloudAgentAction = {
|
|
73
114
|
name: "FREEZE_CLOUD_AGENT",
|
|
74
115
|
description: "Freeze a cloud agent: snapshot state, disconnect bridge, stop container.",
|
|
116
|
+
descriptionCompressed: "Freeze cloud agent: snapshot, disconnect, stop container.",
|
|
75
117
|
similes: ["freeze agent", "hibernate agent", "pause agent", "stop cloud agent"],
|
|
76
118
|
tags: ["cloud", "container", "backup"],
|
|
77
119
|
parameters: [
|
|
@@ -80,10 +122,37 @@ var freezeCloudAgentAction = {
|
|
|
80
122
|
description: "ID of the container to freeze",
|
|
81
123
|
required: true,
|
|
82
124
|
schema: { type: "string" }
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "confirmed",
|
|
128
|
+
description: "Must be true to freeze the cloud agent after preview.",
|
|
129
|
+
required: false,
|
|
130
|
+
schema: { type: "boolean", default: false }
|
|
83
131
|
}
|
|
84
132
|
],
|
|
85
|
-
async
|
|
86
|
-
|
|
133
|
+
validate: async (runtime, message, state, options) => {
|
|
134
|
+
const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
|
|
135
|
+
const __avText = __avTextRaw.toLowerCase();
|
|
136
|
+
const __avKeywords = ["freeze", "cloud"];
|
|
137
|
+
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
|
|
138
|
+
const __avRegex = /\b(?:freeze|cloud)\b/i;
|
|
139
|
+
const __avRegexOk = Boolean(__avText.match(__avRegex));
|
|
140
|
+
const __avSource = String(message?.content?.source ?? "");
|
|
141
|
+
const __avExpectedSource = "";
|
|
142
|
+
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
|
|
143
|
+
const __avOptions = options && typeof options === "object" ? options : {};
|
|
144
|
+
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
|
|
145
|
+
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const __avLegacyValidate = async (runtime2) => {
|
|
149
|
+
return !!runtime2.getService("CLOUD_AUTH")?.isAuthenticated();
|
|
150
|
+
};
|
|
151
|
+
try {
|
|
152
|
+
return Boolean(await __avLegacyValidate(runtime));
|
|
153
|
+
} catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
87
156
|
},
|
|
88
157
|
async handler(runtime, message, _state, options, callback) {
|
|
89
158
|
const containers = runtime.getService("CLOUD_CONTAINER");
|
|
@@ -99,6 +168,20 @@ var freezeCloudAgentAction = {
|
|
|
99
168
|
error: `Container not running (status: ${container.status})`
|
|
100
169
|
};
|
|
101
170
|
}
|
|
171
|
+
const preview = [
|
|
172
|
+
"Confirmation required before freezing Eliza Cloud agent:",
|
|
173
|
+
`Container: ${container.name}`,
|
|
174
|
+
`ID: ${containerId}`,
|
|
175
|
+
"Effects: create snapshot, disconnect bridge, stop container."
|
|
176
|
+
].join(`
|
|
177
|
+
`);
|
|
178
|
+
if (!isConfirmed(options)) {
|
|
179
|
+
await callback?.({ text: preview, actions: ["FREEZE_CLOUD_AGENT"] });
|
|
180
|
+
return confirmationRequired(preview, {
|
|
181
|
+
containerId,
|
|
182
|
+
containerName: container.name
|
|
183
|
+
});
|
|
184
|
+
}
|
|
102
185
|
const notify = async (text) => {
|
|
103
186
|
if (callback)
|
|
104
187
|
await callback({ text, actions: ["FREEZE_CLOUD_AGENT"] });
|
|
@@ -129,6 +212,10 @@ var freezeCloudAgentAction = {
|
|
|
129
212
|
import { logger } from "@elizaos/core";
|
|
130
213
|
|
|
131
214
|
// types/cloud.ts
|
|
215
|
+
import {
|
|
216
|
+
CloudApiError,
|
|
217
|
+
InsufficientCreditsError
|
|
218
|
+
} from "@elizaos/cloud-sdk";
|
|
132
219
|
var DEFAULT_CLOUD_CONFIG = {
|
|
133
220
|
enabled: false,
|
|
134
221
|
baseUrl: "https://www.elizacloud.ai/api/v1",
|
|
@@ -152,36 +239,32 @@ var DEFAULT_CLOUD_CONFIG = {
|
|
|
152
239
|
}
|
|
153
240
|
};
|
|
154
241
|
|
|
155
|
-
class CloudApiError extends Error {
|
|
156
|
-
statusCode;
|
|
157
|
-
errorBody;
|
|
158
|
-
constructor(statusCode, body) {
|
|
159
|
-
super(body.error);
|
|
160
|
-
this.name = "CloudApiError";
|
|
161
|
-
this.statusCode = statusCode;
|
|
162
|
-
this.errorBody = body;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
class InsufficientCreditsError extends CloudApiError {
|
|
167
|
-
requiredCredits;
|
|
168
|
-
constructor(body) {
|
|
169
|
-
super(402, body);
|
|
170
|
-
this.name = "InsufficientCreditsError";
|
|
171
|
-
this.requiredCredits = body.requiredCredits ?? 0;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
242
|
// utils/forwarded-settings.ts
|
|
176
243
|
var FORWARDED_SETTINGS = [
|
|
177
244
|
"OPENAI_API_KEY",
|
|
178
245
|
"ANTHROPIC_API_KEY",
|
|
179
246
|
"GROQ_API_KEY",
|
|
180
247
|
"ELIZAOS_CLOUD_API_KEY",
|
|
248
|
+
"NANO_MODEL",
|
|
249
|
+
"MEDIUM_MODEL",
|
|
181
250
|
"SMALL_MODEL",
|
|
182
251
|
"LARGE_MODEL",
|
|
252
|
+
"MEGA_MODEL",
|
|
253
|
+
"RESPONSE_HANDLER_MODEL",
|
|
254
|
+
"ACTION_PLANNER_MODEL",
|
|
255
|
+
"SHOULD_RESPOND_MODEL",
|
|
256
|
+
"PLANNER_MODEL",
|
|
257
|
+
"RESPONSE_MODEL",
|
|
183
258
|
"ELIZAOS_CLOUD_SMALL_MODEL",
|
|
184
|
-
"
|
|
259
|
+
"ELIZAOS_CLOUD_NANO_MODEL",
|
|
260
|
+
"ELIZAOS_CLOUD_MEDIUM_MODEL",
|
|
261
|
+
"ELIZAOS_CLOUD_LARGE_MODEL",
|
|
262
|
+
"ELIZAOS_CLOUD_MEGA_MODEL",
|
|
263
|
+
"ELIZAOS_CLOUD_RESPONSE_HANDLER_MODEL",
|
|
264
|
+
"ELIZAOS_CLOUD_ACTION_PLANNER_MODEL",
|
|
265
|
+
"ELIZAOS_CLOUD_SHOULD_RESPOND_MODEL",
|
|
266
|
+
"ELIZAOS_CLOUD_PLANNER_MODEL",
|
|
267
|
+
"ELIZAOS_CLOUD_RESPONSE_MODEL"
|
|
185
268
|
];
|
|
186
269
|
function collectEnvVars(runtime) {
|
|
187
270
|
const vars = {};
|
|
@@ -195,8 +278,9 @@ function collectEnvVars(runtime) {
|
|
|
195
278
|
|
|
196
279
|
// actions/provision-agent.ts
|
|
197
280
|
function extractParams(message, options) {
|
|
198
|
-
|
|
199
|
-
|
|
281
|
+
const params = mergedOptions(options);
|
|
282
|
+
if (Object.keys(params).length > 0)
|
|
283
|
+
return params;
|
|
200
284
|
const meta = message.metadata;
|
|
201
285
|
if (meta?.actionParams)
|
|
202
286
|
return meta.actionParams;
|
|
@@ -208,6 +292,7 @@ function extractParams(message, options) {
|
|
|
208
292
|
var provisionCloudAgentAction = {
|
|
209
293
|
name: "PROVISION_CLOUD_AGENT",
|
|
210
294
|
description: "Deploy an ElizaOS agent to ElizaCloud. Provisions a container, waits for deployment, connects the bridge, and starts auto-backup.",
|
|
295
|
+
descriptionCompressed: "Deploy agent to ElizaCloud. Provisions container, connects bridge, starts backup.",
|
|
211
296
|
similes: [
|
|
212
297
|
"deploy agent to cloud",
|
|
213
298
|
"launch cloud agent",
|
|
@@ -245,11 +330,38 @@ var provisionCloudAgentAction = {
|
|
|
245
330
|
description: "Enable periodic auto-backup (default: true)",
|
|
246
331
|
required: false,
|
|
247
332
|
schema: { type: "boolean" }
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
name: "confirmed",
|
|
336
|
+
description: "Must be true to provision the cloud agent after preview.",
|
|
337
|
+
required: false,
|
|
338
|
+
schema: { type: "boolean", default: false }
|
|
248
339
|
}
|
|
249
340
|
],
|
|
250
|
-
async
|
|
251
|
-
const
|
|
252
|
-
|
|
341
|
+
validate: async (runtime, message, state, options) => {
|
|
342
|
+
const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
|
|
343
|
+
const __avText = __avTextRaw.toLowerCase();
|
|
344
|
+
const __avKeywords = ["provision", "cloud"];
|
|
345
|
+
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
|
|
346
|
+
const __avRegex = /\b(?:provision|cloud)\b/i;
|
|
347
|
+
const __avRegexOk = Boolean(__avText.match(__avRegex));
|
|
348
|
+
const __avSource = String(message?.content?.source ?? "");
|
|
349
|
+
const __avExpectedSource = "";
|
|
350
|
+
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
|
|
351
|
+
const __avOptions = options && typeof options === "object" ? options : {};
|
|
352
|
+
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
|
|
353
|
+
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
const __avLegacyValidate = async (runtime2) => {
|
|
357
|
+
const auth = runtime2.getService("CLOUD_AUTH");
|
|
358
|
+
return !!auth?.isAuthenticated();
|
|
359
|
+
};
|
|
360
|
+
try {
|
|
361
|
+
return Boolean(await __avLegacyValidate(runtime));
|
|
362
|
+
} catch {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
253
365
|
},
|
|
254
366
|
async handler(runtime, message, _state, options, callback) {
|
|
255
367
|
const auth = runtime.getService("CLOUD_AUTH");
|
|
@@ -269,6 +381,22 @@ var provisionCloudAgentAction = {
|
|
|
269
381
|
error: "Missing required parameters: name and project_name"
|
|
270
382
|
};
|
|
271
383
|
}
|
|
384
|
+
const autoBackup = params.auto_backup !== false;
|
|
385
|
+
const preview = [
|
|
386
|
+
"Confirmation required before provisioning Eliza Cloud agent:",
|
|
387
|
+
`Name: ${String(params.name)}`,
|
|
388
|
+
`Project: ${String(params.project_name)}`,
|
|
389
|
+
`Auto-backup: ${autoBackup ? "enabled" : "disabled"}`
|
|
390
|
+
].join(`
|
|
391
|
+
`);
|
|
392
|
+
if (!isConfirmed(options)) {
|
|
393
|
+
await callback?.({ text: preview, actions: ["PROVISION_CLOUD_AGENT"] });
|
|
394
|
+
return confirmationRequired(preview, {
|
|
395
|
+
name: String(params.name),
|
|
396
|
+
project_name: String(params.project_name),
|
|
397
|
+
auto_backup: autoBackup
|
|
398
|
+
});
|
|
399
|
+
}
|
|
272
400
|
const notify = async (text) => {
|
|
273
401
|
if (callback)
|
|
274
402
|
await callback({ text, actions: ["PROVISION_CLOUD_AGENT"] });
|
|
@@ -299,7 +427,6 @@ var provisionCloudAgentAction = {
|
|
|
299
427
|
await bridge.connect(id);
|
|
300
428
|
logger.info(`[PROVISION] Bridge connected to ${id}`);
|
|
301
429
|
}
|
|
302
|
-
const autoBackup = params.auto_backup !== false;
|
|
303
430
|
if (autoBackup && backup)
|
|
304
431
|
backup.scheduleAutoBackup(id);
|
|
305
432
|
await notify(`Agent "${params.name}" deployed.${autoBackup ? " Auto-backup enabled." : ""}`);
|
|
@@ -321,8 +448,9 @@ var provisionCloudAgentAction = {
|
|
|
321
448
|
|
|
322
449
|
// actions/resume-agent.ts
|
|
323
450
|
function extractParams2(message, options) {
|
|
324
|
-
|
|
325
|
-
|
|
451
|
+
const params = mergedOptions(options);
|
|
452
|
+
if (Object.keys(params).length > 0)
|
|
453
|
+
return params;
|
|
326
454
|
const meta = message.metadata;
|
|
327
455
|
return meta?.actionParams ?? {};
|
|
328
456
|
}
|
|
@@ -339,6 +467,7 @@ async function findLatestProjectSnapshot(backup, containers, projectName) {
|
|
|
339
467
|
var resumeCloudAgentAction = {
|
|
340
468
|
name: "RESUME_CLOUD_AGENT",
|
|
341
469
|
description: "Resume a frozen cloud agent from snapshot. Re-provisions, restores state, reconnects bridge.",
|
|
470
|
+
descriptionCompressed: "Resume frozen cloud agent from snapshot.",
|
|
342
471
|
similes: ["resume agent", "unfreeze agent", "restart cloud agent", "restore agent"],
|
|
343
472
|
tags: ["cloud", "container", "restore"],
|
|
344
473
|
parameters: [
|
|
@@ -365,10 +494,37 @@ var resumeCloudAgentAction = {
|
|
|
365
494
|
description: "Additional environment variables",
|
|
366
495
|
required: false,
|
|
367
496
|
schema: { type: "object" }
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
name: "confirmed",
|
|
500
|
+
description: "Must be true to resume the cloud agent after preview.",
|
|
501
|
+
required: false,
|
|
502
|
+
schema: { type: "boolean", default: false }
|
|
368
503
|
}
|
|
369
504
|
],
|
|
370
|
-
async
|
|
371
|
-
|
|
505
|
+
validate: async (runtime, message, state, options) => {
|
|
506
|
+
const __avTextRaw = typeof message?.content?.text === "string" ? message.content.text : "";
|
|
507
|
+
const __avText = __avTextRaw.toLowerCase();
|
|
508
|
+
const __avKeywords = ["resume", "cloud"];
|
|
509
|
+
const __avKeywordOk = __avKeywords.length > 0 && __avKeywords.some((kw) => kw.length > 0 && __avText.includes(kw));
|
|
510
|
+
const __avRegex = /\b(?:resume|cloud)\b/i;
|
|
511
|
+
const __avRegexOk = Boolean(__avText.match(__avRegex));
|
|
512
|
+
const __avSource = String(message?.content?.source ?? "");
|
|
513
|
+
const __avExpectedSource = "";
|
|
514
|
+
const __avSourceOk = __avExpectedSource ? __avSource === __avExpectedSource : Boolean(__avSource || state || runtime?.agentId || runtime?.getService);
|
|
515
|
+
const __avOptions = options && typeof options === "object" ? options : {};
|
|
516
|
+
const __avInputOk = __avText.trim().length > 0 || Object.keys(__avOptions).length > 0 || Boolean(message?.content && typeof message.content === "object");
|
|
517
|
+
if (!(__avKeywordOk && __avRegexOk && __avSourceOk && __avInputOk)) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
const __avLegacyValidate = async (runtime2) => {
|
|
521
|
+
return !!runtime2.getService("CLOUD_AUTH")?.isAuthenticated();
|
|
522
|
+
};
|
|
523
|
+
try {
|
|
524
|
+
return Boolean(await __avLegacyValidate(runtime));
|
|
525
|
+
} catch {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
372
528
|
},
|
|
373
529
|
async handler(runtime, message, _state, options, callback) {
|
|
374
530
|
const containerSvc = runtime.getService("CLOUD_CONTAINER");
|
|
@@ -381,6 +537,22 @@ var resumeCloudAgentAction = {
|
|
|
381
537
|
error: "Missing required parameters: name and project_name"
|
|
382
538
|
};
|
|
383
539
|
}
|
|
540
|
+
const explicitSnapshot = typeof params.snapshotId === "string" && params.snapshotId.length > 0 ? params.snapshotId : null;
|
|
541
|
+
const preview = [
|
|
542
|
+
"Confirmation required before resuming Eliza Cloud agent:",
|
|
543
|
+
`Name: ${String(params.name)}`,
|
|
544
|
+
`Project: ${String(params.project_name)}`,
|
|
545
|
+
`Snapshot: ${explicitSnapshot ?? "latest available"}`
|
|
546
|
+
].join(`
|
|
547
|
+
`);
|
|
548
|
+
if (!isConfirmed(options)) {
|
|
549
|
+
await callback?.({ text: preview, actions: ["RESUME_CLOUD_AGENT"] });
|
|
550
|
+
return confirmationRequired(preview, {
|
|
551
|
+
name: String(params.name),
|
|
552
|
+
project_name: String(params.project_name),
|
|
553
|
+
snapshotId: explicitSnapshot
|
|
554
|
+
});
|
|
555
|
+
}
|
|
384
556
|
const notify = async (text) => {
|
|
385
557
|
if (callback)
|
|
386
558
|
await callback({ text, actions: ["RESUME_CLOUD_AGENT"] });
|
|
@@ -407,7 +579,7 @@ var resumeCloudAgentAction = {
|
|
|
407
579
|
const running = await containerSvc.waitForDeployment(id);
|
|
408
580
|
let restoredId = null;
|
|
409
581
|
if (backup) {
|
|
410
|
-
const explicit =
|
|
582
|
+
const explicit = explicitSnapshot ?? undefined;
|
|
411
583
|
if (explicit) {
|
|
412
584
|
await backup.restoreSnapshot(id, explicit);
|
|
413
585
|
restoredId = explicit;
|
|
@@ -441,6 +613,7 @@ var resumeCloudAgentAction = {
|
|
|
441
613
|
var cloudStatusProvider = {
|
|
442
614
|
name: "elizacloud_status",
|
|
443
615
|
description: "ElizaCloud container and connection status",
|
|
616
|
+
descriptionCompressed: "ElizaCloud container/connection status.",
|
|
444
617
|
dynamic: true,
|
|
445
618
|
position: 90,
|
|
446
619
|
async get(runtime, _message, _state) {
|
|
@@ -487,6 +660,7 @@ var cloudStatusProvider = {
|
|
|
487
660
|
var containerHealthProvider = {
|
|
488
661
|
name: "elizacloud_health",
|
|
489
662
|
description: "ElizaCloud container health",
|
|
663
|
+
descriptionCompressed: "ElizaCloud container health.",
|
|
490
664
|
dynamic: true,
|
|
491
665
|
position: 92,
|
|
492
666
|
private: true,
|
|
@@ -527,24 +701,36 @@ var containerHealthProvider = {
|
|
|
527
701
|
|
|
528
702
|
// cloud-providers/credit-balance.ts
|
|
529
703
|
import { logger as logger2 } from "@elizaos/core";
|
|
530
|
-
var
|
|
704
|
+
var TOP_UP_URL = "https://www.elizacloud.ai/dashboard/settings?tab=billing";
|
|
705
|
+
var creditCaches = new WeakMap;
|
|
531
706
|
var TTL = 60000;
|
|
532
707
|
var creditBalanceProvider = {
|
|
533
708
|
name: "elizacloud_credits",
|
|
534
709
|
description: "ElizaCloud credit balance",
|
|
710
|
+
descriptionCompressed: "ElizaCloud credit balance.",
|
|
535
711
|
dynamic: true,
|
|
536
712
|
position: 91,
|
|
537
713
|
async get(runtime, _message, _state) {
|
|
538
714
|
const auth = runtime.getService("CLOUD_AUTH");
|
|
539
715
|
if (!auth?.isAuthenticated())
|
|
540
716
|
return { text: "" };
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
717
|
+
const cached = creditCaches.get(runtime);
|
|
718
|
+
if (cached && Date.now() - cached.at < TTL)
|
|
719
|
+
return format(cached.value);
|
|
720
|
+
let balance;
|
|
721
|
+
try {
|
|
722
|
+
const { data } = await auth.getClient().get("/credits/balance");
|
|
723
|
+
balance = data.balance;
|
|
724
|
+
} catch (err) {
|
|
725
|
+
logger2.warn(`[CloudCredits] Failed to fetch balance: ${err instanceof Error ? err.message : err}`);
|
|
726
|
+
if (cached)
|
|
727
|
+
return format(cached.value);
|
|
728
|
+
return { text: "" };
|
|
729
|
+
}
|
|
730
|
+
creditCaches.set(runtime, { value: balance, at: Date.now() });
|
|
731
|
+
if (balance < 1)
|
|
732
|
+
logger2.warn(`[CloudCredits] Low balance: $${balance.toFixed(2)}`);
|
|
733
|
+
return format(balance);
|
|
548
734
|
}
|
|
549
735
|
};
|
|
550
736
|
function format(balance) {
|
|
@@ -552,15 +738,53 @@ function format(balance) {
|
|
|
552
738
|
const critical = balance < 0.5;
|
|
553
739
|
let text = `ElizaCloud credits: $${balance.toFixed(2)}`;
|
|
554
740
|
if (critical)
|
|
555
|
-
text +=
|
|
741
|
+
text += ` (CRITICAL — top up at ${TOP_UP_URL})`;
|
|
556
742
|
else if (low)
|
|
557
|
-
text +=
|
|
743
|
+
text += ` (LOW — top up at ${TOP_UP_URL})`;
|
|
558
744
|
return {
|
|
559
745
|
text,
|
|
560
746
|
values: {
|
|
561
747
|
cloudCredits: balance,
|
|
562
748
|
cloudCreditsLow: low,
|
|
563
|
-
cloudCreditsCritical: critical
|
|
749
|
+
cloudCreditsCritical: critical,
|
|
750
|
+
cloudTopUpUrl: TOP_UP_URL
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// cloud-providers/model-registry.ts
|
|
756
|
+
var TTL2 = 300000;
|
|
757
|
+
var runtimeCaches = new WeakMap;
|
|
758
|
+
var modelRegistryProvider = {
|
|
759
|
+
name: "elizacloud_models",
|
|
760
|
+
description: "Available AI models from ElizaCloud grouped by provider",
|
|
761
|
+
descriptionCompressed: "Available AI models from ElizaCloud by provider.",
|
|
762
|
+
dynamic: true,
|
|
763
|
+
position: 92,
|
|
764
|
+
async get(runtime, _message, _state) {
|
|
765
|
+
const registry = runtime.getService("CLOUD_MODEL_REGISTRY");
|
|
766
|
+
if (!registry)
|
|
767
|
+
return { text: "" };
|
|
768
|
+
const cached = runtimeCaches.get(runtime);
|
|
769
|
+
if (cached && Date.now() - cached.at < TTL2) {
|
|
770
|
+
return formatModels(cached.value);
|
|
771
|
+
}
|
|
772
|
+
const byProvider = await registry.getModelsByProvider();
|
|
773
|
+
if (Object.keys(byProvider).length === 0) {
|
|
774
|
+
return { text: "" };
|
|
775
|
+
}
|
|
776
|
+
runtimeCaches.set(runtime, { value: byProvider, at: Date.now() });
|
|
777
|
+
return formatModels(byProvider);
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
function formatModels(byProvider) {
|
|
781
|
+
const providers = Object.keys(byProvider).sort();
|
|
782
|
+
const total = Object.values(byProvider).reduce((n, m) => n + m.length, 0);
|
|
783
|
+
return {
|
|
784
|
+
text: `ElizaCloud: ${total} models (${providers.join(", ")})`,
|
|
785
|
+
values: {
|
|
786
|
+
cloudModelProviders: providers.join(","),
|
|
787
|
+
cloudModelCount: total
|
|
564
788
|
}
|
|
565
789
|
};
|
|
566
790
|
}
|
|
@@ -590,12 +814,6 @@ function isBrowser() {
|
|
|
590
814
|
function isProxyMode(runtime) {
|
|
591
815
|
return isBrowser() && !!getSetting(runtime, "ELIZAOS_CLOUD_BROWSER_BASE_URL");
|
|
592
816
|
}
|
|
593
|
-
function getAuthHeader(runtime, forEmbedding = false) {
|
|
594
|
-
if (isBrowser())
|
|
595
|
-
return {};
|
|
596
|
-
const key = forEmbedding ? getEmbeddingApiKey(runtime) : getApiKey(runtime);
|
|
597
|
-
return key ? { Authorization: `Bearer ${key}` } : {};
|
|
598
|
-
}
|
|
599
817
|
function getBaseURL(runtime) {
|
|
600
818
|
const browserURL = getSetting(runtime, "ELIZAOS_CLOUD_BROWSER_BASE_URL");
|
|
601
819
|
const baseURL = isBrowser() && browserURL ? browserURL : getSetting(runtime, "ELIZAOS_CLOUD_BASE_URL", "https://www.elizacloud.ai/api/v1");
|
|
@@ -623,22 +841,67 @@ function getEmbeddingApiKey(runtime) {
|
|
|
623
841
|
return getApiKey(runtime);
|
|
624
842
|
}
|
|
625
843
|
function getSmallModel(runtime) {
|
|
626
|
-
return getSetting(runtime, "ELIZAOS_CLOUD_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", "gpt-5-mini");
|
|
844
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL", "openai/gpt-5.4-mini");
|
|
845
|
+
}
|
|
846
|
+
function getNanoModel(runtime) {
|
|
847
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_NANO_MODEL") ?? getSetting(runtime, "NANO_MODEL") ?? getSmallModel(runtime);
|
|
848
|
+
}
|
|
849
|
+
function getMediumModel(runtime) {
|
|
850
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_MEDIUM_MODEL") ?? getSetting(runtime, "MEDIUM_MODEL") ?? getSmallModel(runtime);
|
|
627
851
|
}
|
|
628
852
|
function getLargeModel(runtime) {
|
|
629
|
-
return getSetting(runtime, "ELIZAOS_CLOUD_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", "
|
|
853
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL", "anthropic/claude-sonnet-4.6");
|
|
854
|
+
}
|
|
855
|
+
function getMegaModel(runtime) {
|
|
856
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_MEGA_MODEL") ?? getSetting(runtime, "MEGA_MODEL") ?? getLargeModel(runtime);
|
|
857
|
+
}
|
|
858
|
+
function getResponseHandlerModel(runtime) {
|
|
859
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "ELIZAOS_CLOUD_SHOULD_RESPOND_MODEL") ?? getSetting(runtime, "RESPONSE_HANDLER_MODEL") ?? getSetting(runtime, "SHOULD_RESPOND_MODEL") ?? getNanoModel(runtime);
|
|
860
|
+
}
|
|
861
|
+
function getActionPlannerModel(runtime) {
|
|
862
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_ACTION_PLANNER_MODEL") ?? getSetting(runtime, "ELIZAOS_CLOUD_PLANNER_MODEL") ?? getSetting(runtime, "ACTION_PLANNER_MODEL") ?? getSetting(runtime, "PLANNER_MODEL") ?? getMediumModel(runtime);
|
|
630
863
|
}
|
|
631
864
|
function getImageDescriptionModel(runtime) {
|
|
632
|
-
return getSetting(runtime, "ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MODEL", "gpt-5-mini")
|
|
865
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MODEL", "gpt-5.4-mini");
|
|
633
866
|
}
|
|
634
867
|
function getImageGenerationModel(runtime) {
|
|
635
868
|
return getSetting(runtime, "ELIZAOS_CLOUD_IMAGE_GENERATION_MODEL", "google/gemini-2.5-flash-image") ?? "google/gemini-2.5-flash-image";
|
|
636
869
|
}
|
|
870
|
+
function getResearchModel(runtime) {
|
|
871
|
+
return getSetting(runtime, "ELIZAOS_CLOUD_RESEARCH_MODEL") ?? getSetting(runtime, "RESEARCH_MODEL", "o3-deep-research");
|
|
872
|
+
}
|
|
637
873
|
function getExperimentalTelemetry(runtime) {
|
|
638
874
|
const setting = getSetting(runtime, "ELIZAOS_CLOUD_EXPERIMENTAL_TELEMETRY", "false");
|
|
639
875
|
return String(setting).toLowerCase() === "true";
|
|
640
876
|
}
|
|
641
877
|
|
|
878
|
+
// utils/sdk-client.ts
|
|
879
|
+
import { CloudApiClient, ElizaCloudClient } from "@elizaos/cloud-sdk";
|
|
880
|
+
function trimTrailingSlash(value) {
|
|
881
|
+
return value.replace(/\/+$/, "");
|
|
882
|
+
}
|
|
883
|
+
function apiBaseToSiteBaseUrl(apiBaseUrl) {
|
|
884
|
+
const trimmed = trimTrailingSlash(apiBaseUrl);
|
|
885
|
+
return trimmed.endsWith("/api/v1") ? trimmed.slice(0, -"/api/v1".length) : trimmed;
|
|
886
|
+
}
|
|
887
|
+
function apiKeyForRuntime(runtime, embedding = false) {
|
|
888
|
+
if (isBrowser())
|
|
889
|
+
return;
|
|
890
|
+
return embedding ? getEmbeddingApiKey(runtime) : getApiKey(runtime);
|
|
891
|
+
}
|
|
892
|
+
function createCloudApiClient(runtime, embedding = false) {
|
|
893
|
+
const baseUrl = embedding ? getEmbeddingBaseURL(runtime) : getBaseURL(runtime);
|
|
894
|
+
return new CloudApiClient(trimTrailingSlash(baseUrl), apiKeyForRuntime(runtime, embedding));
|
|
895
|
+
}
|
|
896
|
+
function createElizaCloudClient(runtime) {
|
|
897
|
+
const apiBaseUrl = trimTrailingSlash(getBaseURL(runtime));
|
|
898
|
+
return new ElizaCloudClient({
|
|
899
|
+
apiBaseUrl,
|
|
900
|
+
baseUrl: apiBaseToSiteBaseUrl(apiBaseUrl),
|
|
901
|
+
apiKey: apiKeyForRuntime(runtime)
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
|
|
642
905
|
// init.ts
|
|
643
906
|
function initializeOpenAI(_config, runtime) {
|
|
644
907
|
(async () => {
|
|
@@ -649,20 +912,11 @@ function initializeOpenAI(_config, runtime) {
|
|
|
649
912
|
return;
|
|
650
913
|
}
|
|
651
914
|
try {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
headers: { ...getAuthHeader(runtime) }
|
|
655
|
-
});
|
|
656
|
-
if (!response.ok) {
|
|
657
|
-
logger4.warn(`ElizaOS Cloud API key validation failed: ${response.statusText}`);
|
|
658
|
-
logger4.warn("ElizaOS Cloud functionality will be limited until a valid API key is provided");
|
|
659
|
-
logger4.info("Get your API key from https://www.elizacloud.ai/dashboard/api-keys");
|
|
660
|
-
} else {
|
|
661
|
-
logger4.log("ElizaOS Cloud API key validated successfully");
|
|
662
|
-
}
|
|
915
|
+
await createCloudApiClient(runtime).get("/models");
|
|
916
|
+
logger4.log("ElizaOS Cloud API key validated successfully");
|
|
663
917
|
} catch (fetchError) {
|
|
664
918
|
const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
665
|
-
logger4.warn(`
|
|
919
|
+
logger4.warn(`ElizaOS Cloud API key validation failed: ${message}`);
|
|
666
920
|
logger4.warn("ElizaOS Cloud functionality will be limited until a valid API key is provided");
|
|
667
921
|
}
|
|
668
922
|
} catch (error) {
|
|
@@ -677,12 +931,14 @@ function initializeOpenAI(_config, runtime) {
|
|
|
677
931
|
import { logger as logger5, ModelType, VECTOR_DIMS } from "@elizaos/core";
|
|
678
932
|
|
|
679
933
|
// utils/events.ts
|
|
680
|
-
import {
|
|
934
|
+
import {
|
|
935
|
+
EventType
|
|
936
|
+
} from "@elizaos/core";
|
|
681
937
|
function emitModelUsageEvent(runtime, type, _prompt, usage) {
|
|
682
938
|
const inputTokens = Number(usage.inputTokens || 0);
|
|
683
939
|
const outputTokens = Number(usage.outputTokens || 0);
|
|
684
940
|
const totalTokens = Number(usage.totalTokens != null ? usage.totalTokens : inputTokens + outputTokens);
|
|
685
|
-
|
|
941
|
+
const payload = {
|
|
686
942
|
runtime,
|
|
687
943
|
source: "elizacloud",
|
|
688
944
|
type,
|
|
@@ -691,7 +947,8 @@ function emitModelUsageEvent(runtime, type, _prompt, usage) {
|
|
|
691
947
|
completion: outputTokens,
|
|
692
948
|
total: totalTokens
|
|
693
949
|
}
|
|
694
|
-
}
|
|
950
|
+
};
|
|
951
|
+
runtime.emitEvent(EventType.MODEL_USED, payload);
|
|
695
952
|
}
|
|
696
953
|
|
|
697
954
|
// models/embeddings.ts
|
|
@@ -746,7 +1003,7 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
746
1003
|
}
|
|
747
1004
|
async function handleBatchTextEmbedding(runtime, texts) {
|
|
748
1005
|
const { embeddingModelName, embeddingDimension } = getEmbeddingConfig(runtime);
|
|
749
|
-
const
|
|
1006
|
+
const client = createCloudApiClient(runtime, true);
|
|
750
1007
|
if (!texts || texts.length === 0) {
|
|
751
1008
|
logger5.warn("[BatchEmbeddings] Empty texts array");
|
|
752
1009
|
return [];
|
|
@@ -771,16 +1028,11 @@ async function handleBatchTextEmbedding(runtime, texts) {
|
|
|
771
1028
|
const batchTexts = batch.map((b) => b.text);
|
|
772
1029
|
logger5.info(`[BatchEmbeddings] Processing batch ${Math.floor(batchStart / MAX_BATCH_SIZE) + 1}/${Math.ceil(validTexts.length / MAX_BATCH_SIZE)}: ${batch.length} texts`);
|
|
773
1030
|
try {
|
|
774
|
-
const response = await
|
|
775
|
-
|
|
776
|
-
headers: {
|
|
777
|
-
...getAuthHeader(runtime, true),
|
|
778
|
-
"Content-Type": "application/json"
|
|
779
|
-
},
|
|
780
|
-
body: JSON.stringify({
|
|
1031
|
+
const response = await client.requestRaw("POST", "/embeddings", {
|
|
1032
|
+
json: {
|
|
781
1033
|
model: embeddingModelName,
|
|
782
1034
|
input: batchTexts
|
|
783
|
-
}
|
|
1035
|
+
}
|
|
784
1036
|
});
|
|
785
1037
|
const rateLimitInfo = extractRateLimitInfo(response);
|
|
786
1038
|
if (rateLimitInfo.remainingRequests !== undefined && rateLimitInfo.remainingRequests < 50) {
|
|
@@ -790,16 +1042,11 @@ async function handleBatchTextEmbedding(runtime, texts) {
|
|
|
790
1042
|
const retryAfter = rateLimitInfo.retryAfter || 30;
|
|
791
1043
|
logger5.warn(`[BatchEmbeddings] Rate limited, waiting ${retryAfter}s...`);
|
|
792
1044
|
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
|
|
793
|
-
const retryResponse = await
|
|
794
|
-
|
|
795
|
-
headers: {
|
|
796
|
-
...getAuthHeader(runtime, true),
|
|
797
|
-
"Content-Type": "application/json"
|
|
798
|
-
},
|
|
799
|
-
body: JSON.stringify({
|
|
1045
|
+
const retryResponse = await client.requestRaw("POST", "/embeddings", {
|
|
1046
|
+
json: {
|
|
800
1047
|
model: embeddingModelName,
|
|
801
1048
|
input: batchTexts
|
|
802
|
-
}
|
|
1049
|
+
}
|
|
803
1050
|
});
|
|
804
1051
|
if (!retryResponse.ok) {
|
|
805
1052
|
logger5.error(`[BatchEmbeddings] Retry failed: ${retryResponse.status}`);
|
|
@@ -919,7 +1166,6 @@ async function handleImageGeneration(runtime, params) {
|
|
|
919
1166
|
const prompt = params.prompt;
|
|
920
1167
|
const modelName = getImageGenerationModel(runtime);
|
|
921
1168
|
logger7.log(`[ELIZAOS_CLOUD] Using IMAGE model: ${modelName}`);
|
|
922
|
-
const baseURL = getBaseURL(runtime);
|
|
923
1169
|
const aspectRatioMap = {
|
|
924
1170
|
"1024x1024": "1:1",
|
|
925
1171
|
"1792x1024": "16:9",
|
|
@@ -927,27 +1173,13 @@ async function handleImageGeneration(runtime, params) {
|
|
|
927
1173
|
};
|
|
928
1174
|
const aspectRatio = aspectRatioMap[size] || "1:1";
|
|
929
1175
|
try {
|
|
930
|
-
const requestUrl = `${baseURL}/generate-image`;
|
|
931
1176
|
const requestBody = {
|
|
932
1177
|
prompt,
|
|
933
1178
|
numImages,
|
|
934
1179
|
aspectRatio,
|
|
935
1180
|
model: modelName
|
|
936
1181
|
};
|
|
937
|
-
const
|
|
938
|
-
method: "POST",
|
|
939
|
-
headers: {
|
|
940
|
-
...getAuthHeader(runtime),
|
|
941
|
-
"Content-Type": "application/json"
|
|
942
|
-
},
|
|
943
|
-
body: JSON.stringify(requestBody)
|
|
944
|
-
});
|
|
945
|
-
if (!response.ok) {
|
|
946
|
-
const errorText = await response.text();
|
|
947
|
-
throw new Error(`Failed to generate image: ${response.status} ${errorText}`);
|
|
948
|
-
}
|
|
949
|
-
const data = await response.json();
|
|
950
|
-
const typedData = data;
|
|
1182
|
+
const typedData = await createElizaCloudClient(runtime).generateImage(requestBody);
|
|
951
1183
|
const result = typedData.images.map((img) => ({
|
|
952
1184
|
url: img.url || img.image
|
|
953
1185
|
}));
|
|
@@ -980,23 +1212,32 @@ async function handleImageDescription(runtime, params) {
|
|
|
980
1212
|
]
|
|
981
1213
|
}
|
|
982
1214
|
];
|
|
983
|
-
const
|
|
1215
|
+
const client = createElizaCloudClient(runtime);
|
|
984
1216
|
try {
|
|
985
1217
|
const requestBody = {
|
|
986
1218
|
model: modelName,
|
|
987
1219
|
messages,
|
|
988
1220
|
max_tokens: maxTokens
|
|
989
1221
|
};
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1222
|
+
let response = null;
|
|
1223
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
1224
|
+
response = await client.routes.postApiV1ChatCompletionsRaw({
|
|
1225
|
+
json: requestBody
|
|
1226
|
+
});
|
|
1227
|
+
if (response.status === 429 && attempt < 2) {
|
|
1228
|
+
const wait = (attempt + 1) * 2000;
|
|
1229
|
+
logger7.warn(`[ELIZAOS_CLOUD] Image analysis rate-limited (429), retrying in ${wait / 1000}s...`);
|
|
1230
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
break;
|
|
1234
|
+
}
|
|
1235
|
+
if (!response?.ok) {
|
|
1236
|
+
const status = response?.status ?? 0;
|
|
1237
|
+
if (status === 402) {
|
|
1238
|
+
throw new Error("Eliza Cloud credits exhausted — top up at https://www.elizacloud.ai/dashboard/settings?tab=billing");
|
|
1239
|
+
}
|
|
1240
|
+
throw new Error(`ElizaOS Cloud API error: ${status}`);
|
|
1000
1241
|
}
|
|
1001
1242
|
const typedResult = await response.json();
|
|
1002
1243
|
const content = typedResult.choices?.[0]?.message?.content;
|
|
@@ -1025,62 +1266,179 @@ async function handleImageDescription(runtime, params) {
|
|
|
1025
1266
|
}
|
|
1026
1267
|
// models/object.ts
|
|
1027
1268
|
import { logger as logger8, ModelType as ModelType3 } from "@elizaos/core";
|
|
1028
|
-
import { generateObject, JSONParseError as JSONParseError2 } from "ai";
|
|
1029
1269
|
|
|
1030
|
-
//
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
return
|
|
1270
|
+
// utils/responses-output.ts
|
|
1271
|
+
function asRecord(value) {
|
|
1272
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1273
|
+
return null;
|
|
1274
|
+
}
|
|
1275
|
+
return value;
|
|
1276
|
+
}
|
|
1277
|
+
function normalizeContentItems(value) {
|
|
1278
|
+
if (Array.isArray(value))
|
|
1279
|
+
return value;
|
|
1280
|
+
if (typeof value === "string")
|
|
1281
|
+
return [{ type: "text", text: value }];
|
|
1282
|
+
return value && typeof value === "object" ? [value] : [];
|
|
1283
|
+
}
|
|
1284
|
+
function extractTextFromContentItem(value) {
|
|
1285
|
+
if (typeof value === "string") {
|
|
1286
|
+
return [value];
|
|
1287
|
+
}
|
|
1288
|
+
const record = asRecord(value);
|
|
1289
|
+
if (!record)
|
|
1290
|
+
return [];
|
|
1291
|
+
const text = typeof record.text === "string" ? record.text : typeof record.output_text === "string" ? record.output_text : typeof record.content === "string" ? record.content : "";
|
|
1292
|
+
const type = typeof record.type === "string" ? record.type : undefined;
|
|
1293
|
+
if (text && (!type || type === "output_text" || type === "text")) {
|
|
1294
|
+
return [text];
|
|
1295
|
+
}
|
|
1296
|
+
return [];
|
|
1297
|
+
}
|
|
1298
|
+
function extractTextFromOutputItem(value) {
|
|
1299
|
+
const record = asRecord(value);
|
|
1300
|
+
if (!record)
|
|
1301
|
+
return [];
|
|
1302
|
+
const directContent = normalizeContentItems(record.content);
|
|
1303
|
+
if (directContent.length > 0) {
|
|
1304
|
+
return directContent.flatMap(extractTextFromContentItem);
|
|
1305
|
+
}
|
|
1306
|
+
const nestedMessage = asRecord(record.message);
|
|
1307
|
+
if (nestedMessage) {
|
|
1308
|
+
return normalizeContentItems(nestedMessage.content).flatMap(extractTextFromContentItem);
|
|
1309
|
+
}
|
|
1310
|
+
const type = typeof record.type === "string" ? record.type : undefined;
|
|
1311
|
+
const text = typeof record.text === "string" ? record.text : typeof record.output_text === "string" ? record.output_text : "";
|
|
1312
|
+
if (text && (type === "output_text" || type === "text")) {
|
|
1313
|
+
return [text];
|
|
1314
|
+
}
|
|
1315
|
+
return [];
|
|
1316
|
+
}
|
|
1317
|
+
function extractTextFromChoice(value) {
|
|
1318
|
+
const record = asRecord(value);
|
|
1319
|
+
if (!record)
|
|
1320
|
+
return [];
|
|
1321
|
+
if (typeof record.text === "string" && record.text) {
|
|
1322
|
+
return [record.text];
|
|
1323
|
+
}
|
|
1324
|
+
const message = asRecord(record.message);
|
|
1325
|
+
if (!message) {
|
|
1326
|
+
return [];
|
|
1327
|
+
}
|
|
1328
|
+
return normalizeContentItems(message.content).flatMap(extractTextFromContentItem);
|
|
1329
|
+
}
|
|
1330
|
+
function extractResponsesOutputText(data) {
|
|
1331
|
+
const record = asRecord(data);
|
|
1332
|
+
if (!record)
|
|
1333
|
+
return "";
|
|
1334
|
+
const segments = [];
|
|
1335
|
+
if (typeof record.output_text === "string" && record.output_text) {
|
|
1336
|
+
segments.push(record.output_text);
|
|
1337
|
+
}
|
|
1338
|
+
if (Array.isArray(record.output)) {
|
|
1339
|
+
segments.push(...record.output.flatMap(extractTextFromOutputItem));
|
|
1340
|
+
}
|
|
1341
|
+
if (Array.isArray(record.choices)) {
|
|
1342
|
+
segments.push(...record.choices.flatMap(extractTextFromChoice));
|
|
1343
|
+
}
|
|
1344
|
+
return segments.join("");
|
|
1036
1345
|
}
|
|
1037
1346
|
|
|
1038
1347
|
// models/object.ts
|
|
1348
|
+
var REASONING_MODEL_PATTERNS = [
|
|
1349
|
+
"o1",
|
|
1350
|
+
"o3",
|
|
1351
|
+
"o4",
|
|
1352
|
+
"deepseek-r1",
|
|
1353
|
+
"deepseek-reasoner",
|
|
1354
|
+
"claude-opus-4.7",
|
|
1355
|
+
"claude-opus-4-7",
|
|
1356
|
+
"gpt-5"
|
|
1357
|
+
];
|
|
1358
|
+
function isReasoningModel(modelName) {
|
|
1359
|
+
const lower = modelName.toLowerCase();
|
|
1360
|
+
return REASONING_MODEL_PATTERNS.some((pattern) => lower.includes(pattern));
|
|
1361
|
+
}
|
|
1039
1362
|
async function generateObjectByModelType(runtime, params, modelType, getModelFn) {
|
|
1040
|
-
const openai = createOpenAIClient(runtime);
|
|
1041
1363
|
const modelName = getModelFn(runtime);
|
|
1042
1364
|
logger8.log(`[ELIZAOS_CLOUD] Using ${modelType} model: ${modelName}`);
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
prompt: params.prompt,
|
|
1050
|
-
temperature,
|
|
1051
|
-
experimental_repairText: getJsonRepairFunction()
|
|
1365
|
+
const reasoning = isReasoningModel(modelName);
|
|
1366
|
+
const input = [];
|
|
1367
|
+
if (runtime.character.system) {
|
|
1368
|
+
input.push({
|
|
1369
|
+
role: "system",
|
|
1370
|
+
content: [{ type: "input_text", text: runtime.character.system }]
|
|
1052
1371
|
});
|
|
1053
|
-
|
|
1054
|
-
|
|
1372
|
+
}
|
|
1373
|
+
input.push({
|
|
1374
|
+
role: "user",
|
|
1375
|
+
content: [{ type: "input_text", text: params.prompt }]
|
|
1376
|
+
});
|
|
1377
|
+
const requestBody = {
|
|
1378
|
+
model: modelName,
|
|
1379
|
+
input,
|
|
1380
|
+
max_output_tokens: params.maxTokens ?? 8192,
|
|
1381
|
+
text: { format: { type: "json_object" } }
|
|
1382
|
+
};
|
|
1383
|
+
if (!reasoning && typeof params.temperature === "number") {
|
|
1384
|
+
requestBody.temperature = params.temperature;
|
|
1385
|
+
}
|
|
1386
|
+
const response = await createCloudApiClient(runtime).requestRaw("POST", "/responses", {
|
|
1387
|
+
json: requestBody
|
|
1388
|
+
});
|
|
1389
|
+
const responseText = await response.text();
|
|
1390
|
+
let data = {};
|
|
1391
|
+
if (responseText) {
|
|
1392
|
+
try {
|
|
1393
|
+
data = JSON.parse(responseText);
|
|
1394
|
+
} catch (parseErr) {
|
|
1395
|
+
logger8.error(`[generateObject] Failed to parse Eliza Cloud JSON: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
|
|
1055
1396
|
}
|
|
1056
|
-
|
|
1397
|
+
}
|
|
1398
|
+
if (!response.ok) {
|
|
1399
|
+
const errorBody = typeof data === "object" && data ? data.error : undefined;
|
|
1400
|
+
const errorMessage = typeof errorBody?.message === "string" && errorBody.message.trim() ? errorBody.message.trim() : `elizaOS Cloud error ${response.status}`;
|
|
1401
|
+
const requestError = new Error(errorMessage);
|
|
1402
|
+
requestError.status = response.status;
|
|
1403
|
+
if (errorBody) {
|
|
1404
|
+
requestError.error = errorBody;
|
|
1405
|
+
}
|
|
1406
|
+
throw requestError;
|
|
1407
|
+
}
|
|
1408
|
+
if (data.usage) {
|
|
1409
|
+
emitModelUsageEvent(runtime, modelType, params.prompt, {
|
|
1410
|
+
inputTokens: data.usage.input_tokens ?? 0,
|
|
1411
|
+
outputTokens: data.usage.output_tokens ?? 0,
|
|
1412
|
+
totalTokens: data.usage.total_tokens ?? 0
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
let jsonText = extractResponsesOutputText(data);
|
|
1416
|
+
if (!jsonText.trim()) {
|
|
1417
|
+
throw new Error("Object generation returned empty response");
|
|
1418
|
+
}
|
|
1419
|
+
jsonText = jsonText.replace(/^[\s]*```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
|
|
1420
|
+
try {
|
|
1421
|
+
return JSON.parse(jsonText);
|
|
1057
1422
|
} catch (error) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
logger8.error(`[generateObject] Failed to parse repaired JSON: ${message}`);
|
|
1073
|
-
throw repairParseError;
|
|
1074
|
-
}
|
|
1075
|
-
} else {
|
|
1076
|
-
logger8.error("[generateObject] JSON repair failed.");
|
|
1077
|
-
throw error;
|
|
1423
|
+
const repairFunction = getJsonRepairFunction();
|
|
1424
|
+
const repairedJsonString = await repairFunction({
|
|
1425
|
+
text: jsonText,
|
|
1426
|
+
error
|
|
1427
|
+
});
|
|
1428
|
+
if (repairedJsonString) {
|
|
1429
|
+
try {
|
|
1430
|
+
const repairedObject = JSON.parse(repairedJsonString);
|
|
1431
|
+
logger8.info("[generateObject] Successfully repaired JSON.");
|
|
1432
|
+
return repairedObject;
|
|
1433
|
+
} catch (repairParseError) {
|
|
1434
|
+
const message2 = repairParseError instanceof Error ? repairParseError.message : String(repairParseError);
|
|
1435
|
+
logger8.error(`[generateObject] Failed to parse repaired JSON: ${message2}`);
|
|
1436
|
+
throw repairParseError;
|
|
1078
1437
|
}
|
|
1079
|
-
} else {
|
|
1080
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1081
|
-
logger8.error(`[generateObject] Error: ${message}`);
|
|
1082
|
-
throw error;
|
|
1083
1438
|
}
|
|
1439
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1440
|
+
logger8.error(`[generateObject] Failed to parse JSON: ${message}`);
|
|
1441
|
+
throw error;
|
|
1084
1442
|
}
|
|
1085
1443
|
}
|
|
1086
1444
|
async function handleObjectSmall(runtime, params) {
|
|
@@ -1089,32 +1447,185 @@ async function handleObjectSmall(runtime, params) {
|
|
|
1089
1447
|
async function handleObjectLarge(runtime, params) {
|
|
1090
1448
|
return generateObjectByModelType(runtime, params, ModelType3.OBJECT_LARGE, getLargeModel);
|
|
1091
1449
|
}
|
|
1450
|
+
// models/research.ts
|
|
1451
|
+
import { logger as logger9, ModelType as ModelType4 } from "@elizaos/core";
|
|
1452
|
+
function normalizeInput(input) {
|
|
1453
|
+
if (typeof input !== "string") {
|
|
1454
|
+
return input;
|
|
1455
|
+
}
|
|
1456
|
+
return [
|
|
1457
|
+
{
|
|
1458
|
+
role: "user",
|
|
1459
|
+
content: [
|
|
1460
|
+
{
|
|
1461
|
+
type: "input_text",
|
|
1462
|
+
text: input
|
|
1463
|
+
}
|
|
1464
|
+
]
|
|
1465
|
+
}
|
|
1466
|
+
];
|
|
1467
|
+
}
|
|
1468
|
+
function buildResearchApiError(status, errorText) {
|
|
1469
|
+
try {
|
|
1470
|
+
const parsed = JSON.parse(errorText);
|
|
1471
|
+
const message = parsed.error?.message;
|
|
1472
|
+
const param = parsed.error?.param;
|
|
1473
|
+
if (param === "tools.0.type" && message?.includes('expected "function"')) {
|
|
1474
|
+
return new Error(`Research API error: ${status} Eliza Cloud /responses rejected deep-research tool types; the provider currently only accepts function tools on this route`);
|
|
1475
|
+
}
|
|
1476
|
+
} catch {}
|
|
1477
|
+
return new Error(`Research API error: ${status} ${errorText}`);
|
|
1478
|
+
}
|
|
1479
|
+
function parseAnnotations(raw) {
|
|
1480
|
+
return raw.filter((a) => a.url !== undefined).map((a) => ({
|
|
1481
|
+
url: a.url,
|
|
1482
|
+
title: a.title ?? "",
|
|
1483
|
+
startIndex: a.start_index ?? 0,
|
|
1484
|
+
endIndex: a.end_index ?? 0
|
|
1485
|
+
}));
|
|
1486
|
+
}
|
|
1487
|
+
function parseOutputItems(raw) {
|
|
1488
|
+
const items = [];
|
|
1489
|
+
for (const item of raw) {
|
|
1490
|
+
switch (item.type) {
|
|
1491
|
+
case "web_search_call":
|
|
1492
|
+
items.push({
|
|
1493
|
+
id: item.id ?? "",
|
|
1494
|
+
type: "web_search_call",
|
|
1495
|
+
status: item.status ?? "completed",
|
|
1496
|
+
action: {
|
|
1497
|
+
type: item.action?.type ?? "search",
|
|
1498
|
+
query: item.action?.query,
|
|
1499
|
+
url: item.action?.url
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
break;
|
|
1503
|
+
case "file_search_call":
|
|
1504
|
+
items.push({
|
|
1505
|
+
id: item.id ?? "",
|
|
1506
|
+
type: "file_search_call",
|
|
1507
|
+
status: item.status ?? "completed",
|
|
1508
|
+
query: item.query ?? "",
|
|
1509
|
+
results: item.results?.map((r) => ({
|
|
1510
|
+
fileId: r.file_id,
|
|
1511
|
+
fileName: r.file_name,
|
|
1512
|
+
score: r.score
|
|
1513
|
+
}))
|
|
1514
|
+
});
|
|
1515
|
+
break;
|
|
1516
|
+
case "code_interpreter_call":
|
|
1517
|
+
items.push({
|
|
1518
|
+
id: item.id ?? "",
|
|
1519
|
+
type: "code_interpreter_call",
|
|
1520
|
+
status: item.status ?? "completed",
|
|
1521
|
+
code: item.code ?? "",
|
|
1522
|
+
output: item.output
|
|
1523
|
+
});
|
|
1524
|
+
break;
|
|
1525
|
+
case "mcp_tool_call":
|
|
1526
|
+
items.push({
|
|
1527
|
+
id: item.id ?? "",
|
|
1528
|
+
type: "mcp_tool_call",
|
|
1529
|
+
status: item.status ?? "completed",
|
|
1530
|
+
serverLabel: item.server_label ?? "",
|
|
1531
|
+
toolName: item.tool_name ?? "",
|
|
1532
|
+
arguments: item.arguments ?? {},
|
|
1533
|
+
result: item.result
|
|
1534
|
+
});
|
|
1535
|
+
break;
|
|
1536
|
+
case "message": {
|
|
1537
|
+
const content = item.content ?? [];
|
|
1538
|
+
items.push({
|
|
1539
|
+
type: "message",
|
|
1540
|
+
content: content.filter((c) => c.type === "output_text").map((c) => ({
|
|
1541
|
+
type: "output_text",
|
|
1542
|
+
text: c.text ?? "",
|
|
1543
|
+
annotations: parseAnnotations(c.annotations ?? [])
|
|
1544
|
+
}))
|
|
1545
|
+
});
|
|
1546
|
+
break;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return items;
|
|
1551
|
+
}
|
|
1552
|
+
async function handleResearch(runtime, params) {
|
|
1553
|
+
const modelName = params.model ?? getResearchModel(runtime);
|
|
1554
|
+
logger9.log(`[ELIZAOS_CLOUD] Using RESEARCH model: ${modelName}`);
|
|
1555
|
+
const tools = params.tools ?? [{ type: "web_search_preview" }];
|
|
1556
|
+
const requestBody = {
|
|
1557
|
+
model: modelName,
|
|
1558
|
+
input: normalizeInput(params.input),
|
|
1559
|
+
tools
|
|
1560
|
+
};
|
|
1561
|
+
if (params.instructions) {
|
|
1562
|
+
requestBody.instructions = params.instructions;
|
|
1563
|
+
}
|
|
1564
|
+
if (params.background !== undefined) {
|
|
1565
|
+
requestBody.background = params.background;
|
|
1566
|
+
}
|
|
1567
|
+
if (params.maxToolCalls !== undefined) {
|
|
1568
|
+
requestBody.max_tool_calls = params.maxToolCalls;
|
|
1569
|
+
}
|
|
1570
|
+
if (params.reasoningSummary) {
|
|
1571
|
+
requestBody.reasoning = { summary: params.reasoningSummary };
|
|
1572
|
+
}
|
|
1573
|
+
const response = await createCloudApiClient(runtime).requestRaw("POST", "/responses", {
|
|
1574
|
+
json: requestBody
|
|
1575
|
+
});
|
|
1576
|
+
if (!response.ok) {
|
|
1577
|
+
const errorText = await response.text();
|
|
1578
|
+
throw buildResearchApiError(response.status, errorText);
|
|
1579
|
+
}
|
|
1580
|
+
const data = await response.json();
|
|
1581
|
+
if (data.usage) {
|
|
1582
|
+
emitModelUsageEvent(runtime, ModelType4.RESEARCH, params.input, {
|
|
1583
|
+
inputTokens: data.usage.input_tokens,
|
|
1584
|
+
outputTokens: data.usage.output_tokens,
|
|
1585
|
+
totalTokens: data.usage.total_tokens
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
const outputItems = parseOutputItems(data.output);
|
|
1589
|
+
let text = "";
|
|
1590
|
+
const annotations = [];
|
|
1591
|
+
for (const item of outputItems) {
|
|
1592
|
+
if (item.type === "message") {
|
|
1593
|
+
for (const content of item.content) {
|
|
1594
|
+
if (content.type === "output_text") {
|
|
1595
|
+
text += content.text;
|
|
1596
|
+
annotations.push(...content.annotations);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
return {
|
|
1602
|
+
id: data.id,
|
|
1603
|
+
text,
|
|
1604
|
+
annotations,
|
|
1605
|
+
outputItems,
|
|
1606
|
+
status: data.status
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1092
1609
|
// models/speech.ts
|
|
1093
|
-
import { logger as
|
|
1610
|
+
import { logger as logger10 } from "@elizaos/core";
|
|
1094
1611
|
async function fetchTextToSpeech(runtime, options) {
|
|
1095
1612
|
const defaultModel = getSetting(runtime, "ELIZAOS_CLOUD_TTS_MODEL", "gpt-5-mini-tts");
|
|
1096
1613
|
const defaultVoice = getSetting(runtime, "ELIZAOS_CLOUD_TTS_VOICE", "nova");
|
|
1097
|
-
const defaultInstructions = getSetting(runtime, "ELIZAOS_CLOUD_TTS_INSTRUCTIONS", "");
|
|
1098
|
-
const baseURL = getBaseURL(runtime);
|
|
1099
1614
|
const model = options.model || defaultModel;
|
|
1100
1615
|
const voice = options.voice || defaultVoice;
|
|
1101
|
-
const instructions = options.instructions ?? defaultInstructions;
|
|
1102
1616
|
const format2 = options.format || "mp3";
|
|
1617
|
+
const modelId = model.startsWith("elevenlabs/") ? model.split("/").slice(1).join("/") : model.startsWith("eleven_") ? model : undefined;
|
|
1618
|
+
const voiceId = voice && voice !== "nova" ? voice : undefined;
|
|
1103
1619
|
try {
|
|
1104
|
-
const res = await
|
|
1105
|
-
method: "POST",
|
|
1620
|
+
const res = await createElizaCloudClient(runtime).routes.postApiV1VoiceTts({
|
|
1106
1621
|
headers: {
|
|
1107
|
-
...getAuthHeader(runtime),
|
|
1108
|
-
"Content-Type": "application/json",
|
|
1109
1622
|
...format2 === "mp3" ? { Accept: "audio/mpeg" } : {}
|
|
1110
1623
|
},
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
...instructions && { instructions }
|
|
1117
|
-
})
|
|
1624
|
+
json: {
|
|
1625
|
+
text: options.text,
|
|
1626
|
+
...voiceId ? { voiceId } : {},
|
|
1627
|
+
...modelId ? { modelId } : {}
|
|
1628
|
+
}
|
|
1118
1629
|
});
|
|
1119
1630
|
if (!res.ok) {
|
|
1120
1631
|
const err = await res.text();
|
|
@@ -1133,151 +1644,214 @@ async function fetchTextToSpeech(runtime, options) {
|
|
|
1133
1644
|
}
|
|
1134
1645
|
}
|
|
1135
1646
|
// models/text.ts
|
|
1136
|
-
import { logger as
|
|
1137
|
-
|
|
1647
|
+
import { logger as logger11, ModelType as ModelType5 } from "@elizaos/core";
|
|
1648
|
+
|
|
1649
|
+
// providers/openai.ts
|
|
1650
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
1651
|
+
function createOpenAIClient(runtime) {
|
|
1652
|
+
const baseURL = getBaseURL(runtime);
|
|
1653
|
+
const apiKey = getApiKey(runtime) ?? (isProxyMode(runtime) ? "eliza-proxy" : undefined);
|
|
1654
|
+
return createOpenAI({
|
|
1655
|
+
apiKey: apiKey ?? "",
|
|
1656
|
+
baseURL
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
// models/text.ts
|
|
1661
|
+
var TEXT_NANO_MODEL_TYPE = ModelType5.TEXT_NANO ?? "TEXT_NANO";
|
|
1662
|
+
var TEXT_MEDIUM_MODEL_TYPE = ModelType5.TEXT_MEDIUM ?? "TEXT_MEDIUM";
|
|
1663
|
+
var TEXT_SMALL_MODEL_TYPE = ModelType5.TEXT_SMALL;
|
|
1664
|
+
var TEXT_LARGE_MODEL_TYPE = ModelType5.TEXT_LARGE;
|
|
1665
|
+
var TEXT_MEGA_MODEL_TYPE = ModelType5.TEXT_MEGA ?? "TEXT_MEGA";
|
|
1666
|
+
var RESPONSE_HANDLER_MODEL_TYPE = ModelType5.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
|
|
1667
|
+
var ACTION_PLANNER_MODEL_TYPE = ModelType5.ACTION_PLANNER ?? "ACTION_PLANNER";
|
|
1668
|
+
var REASONING_MODEL_PATTERNS2 = [
|
|
1669
|
+
"o1",
|
|
1670
|
+
"o3",
|
|
1671
|
+
"o4",
|
|
1672
|
+
"deepseek-r1",
|
|
1673
|
+
"deepseek-reasoner",
|
|
1674
|
+
"claude-opus-4.7",
|
|
1675
|
+
"claude-opus-4-7",
|
|
1676
|
+
"gpt-5"
|
|
1677
|
+
];
|
|
1678
|
+
var RESPONSES_ROUTED_PREFIXES = ["openai/", "anthropic/"];
|
|
1679
|
+
function buildUserContent(params) {
|
|
1680
|
+
const content = [{ type: "text", text: params.prompt }];
|
|
1681
|
+
for (const attachment of params.attachments ?? []) {
|
|
1682
|
+
content.push({
|
|
1683
|
+
type: "file",
|
|
1684
|
+
data: attachment.data,
|
|
1685
|
+
mediaType: attachment.mediaType,
|
|
1686
|
+
...attachment.filename ? { filename: attachment.filename } : {}
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
return content;
|
|
1690
|
+
}
|
|
1691
|
+
function isReasoningModel2(modelName) {
|
|
1692
|
+
const lower = modelName.toLowerCase();
|
|
1693
|
+
return REASONING_MODEL_PATTERNS2.some((pattern) => lower.includes(pattern));
|
|
1694
|
+
}
|
|
1695
|
+
function supportsStopSequences(modelName) {
|
|
1696
|
+
const lower = modelName.toLowerCase();
|
|
1697
|
+
return !RESPONSES_ROUTED_PREFIXES.some((prefix) => lower.startsWith(prefix));
|
|
1698
|
+
}
|
|
1699
|
+
function getPurposeForModelType(modelType) {
|
|
1700
|
+
switch (modelType) {
|
|
1701
|
+
case RESPONSE_HANDLER_MODEL_TYPE:
|
|
1702
|
+
return "should_respond";
|
|
1703
|
+
case ACTION_PLANNER_MODEL_TYPE:
|
|
1704
|
+
return "action_planner";
|
|
1705
|
+
default:
|
|
1706
|
+
return "response";
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
function getModelNameForType(runtime, modelType) {
|
|
1710
|
+
switch (modelType) {
|
|
1711
|
+
case TEXT_NANO_MODEL_TYPE:
|
|
1712
|
+
return getNanoModel(runtime);
|
|
1713
|
+
case TEXT_MEDIUM_MODEL_TYPE:
|
|
1714
|
+
return getMediumModel(runtime);
|
|
1715
|
+
case TEXT_SMALL_MODEL_TYPE:
|
|
1716
|
+
return getSmallModel(runtime);
|
|
1717
|
+
case TEXT_LARGE_MODEL_TYPE:
|
|
1718
|
+
return getLargeModel(runtime);
|
|
1719
|
+
case TEXT_MEGA_MODEL_TYPE:
|
|
1720
|
+
return getMegaModel(runtime);
|
|
1721
|
+
case RESPONSE_HANDLER_MODEL_TYPE:
|
|
1722
|
+
return getResponseHandlerModel(runtime);
|
|
1723
|
+
case ACTION_PLANNER_MODEL_TYPE:
|
|
1724
|
+
return getActionPlannerModel(runtime);
|
|
1725
|
+
default:
|
|
1726
|
+
return getLargeModel(runtime);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1138
1729
|
function buildGenerateParams(runtime, modelType, params) {
|
|
1139
|
-
const
|
|
1140
|
-
const
|
|
1141
|
-
const frequencyPenalty = params.frequencyPenalty ?? 0.7;
|
|
1142
|
-
const presencePenalty = params.presencePenalty ?? 0.7;
|
|
1730
|
+
const paramsWithAttachments = params;
|
|
1731
|
+
const { prompt } = params;
|
|
1143
1732
|
const maxTokens = params.maxTokens ?? 8192;
|
|
1144
1733
|
const openai = createOpenAIClient(runtime);
|
|
1145
|
-
const modelName =
|
|
1146
|
-
const modelLabel = modelType === ModelType4.TEXT_SMALL ? "TEXT_SMALL" : "TEXT_LARGE";
|
|
1734
|
+
const modelName = getModelNameForType(runtime, modelType);
|
|
1147
1735
|
const experimentalTelemetry = getExperimentalTelemetry(runtime);
|
|
1148
|
-
const
|
|
1736
|
+
const userContent = (paramsWithAttachments.attachments?.length ?? 0) > 0 ? buildUserContent(paramsWithAttachments) : undefined;
|
|
1737
|
+
const model = openai.chat(modelName);
|
|
1738
|
+
const reasoning = isReasoningModel2(modelName);
|
|
1739
|
+
const stopSequences = !reasoning && supportsStopSequences(modelName) && Array.isArray(params.stopSequences) && params.stopSequences.length > 0 ? params.stopSequences : undefined;
|
|
1149
1740
|
const generateParams = {
|
|
1150
1741
|
model,
|
|
1151
|
-
prompt,
|
|
1742
|
+
...userContent ? { messages: [{ role: "user", content: userContent }] } : { prompt },
|
|
1152
1743
|
system: runtime.character.system ?? undefined,
|
|
1153
|
-
|
|
1744
|
+
...stopSequences ? { stopSequences } : {},
|
|
1154
1745
|
maxOutputTokens: maxTokens,
|
|
1155
|
-
frequencyPenalty,
|
|
1156
|
-
presencePenalty,
|
|
1157
|
-
stopSequences,
|
|
1158
1746
|
experimental_telemetry: {
|
|
1159
1747
|
isEnabled: experimentalTelemetry
|
|
1160
1748
|
}
|
|
1161
1749
|
};
|
|
1162
|
-
return { generateParams, modelName,
|
|
1163
|
-
}
|
|
1164
|
-
function handleStreamingGeneration(runtime, modelType, generateParams, prompt, modelLabel) {
|
|
1165
|
-
logger10.debug(`[ELIZAOS_CLOUD] Streaming text with ${modelLabel} model`);
|
|
1166
|
-
const streamResult = streamText(generateParams);
|
|
1167
|
-
return {
|
|
1168
|
-
textStream: streamResult.textStream,
|
|
1169
|
-
text: Promise.resolve(streamResult.text),
|
|
1170
|
-
usage: Promise.resolve(streamResult.usage).then((usage) => {
|
|
1171
|
-
if (usage) {
|
|
1172
|
-
emitModelUsageEvent(runtime, modelType, prompt, usage);
|
|
1173
|
-
const inputTokens = usage.inputTokens ?? 0;
|
|
1174
|
-
const outputTokens = usage.outputTokens ?? 0;
|
|
1175
|
-
return {
|
|
1176
|
-
promptTokens: inputTokens,
|
|
1177
|
-
completionTokens: outputTokens,
|
|
1178
|
-
totalTokens: inputTokens + outputTokens
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
return;
|
|
1182
|
-
}),
|
|
1183
|
-
finishReason: Promise.resolve(streamResult.finishReason)
|
|
1184
|
-
};
|
|
1750
|
+
return { generateParams, modelName, modelType, prompt };
|
|
1185
1751
|
}
|
|
1186
1752
|
async function generateTextWithModel(runtime, modelType, params) {
|
|
1187
|
-
const {
|
|
1188
|
-
|
|
1753
|
+
const { modelName, prompt } = buildGenerateParams(runtime, modelType, params);
|
|
1754
|
+
logger11.debug(`[ELIZAOS_CLOUD] Generating text with ${modelType} model: ${modelName}`);
|
|
1189
1755
|
if (params.stream) {
|
|
1190
|
-
|
|
1756
|
+
logger11.debug("[ELIZAOS_CLOUD] Streaming text disabled for responses compatibility; falling back to buffered response.");
|
|
1757
|
+
}
|
|
1758
|
+
logger11.log(`[ELIZAOS_CLOUD] Using ${modelType} model: ${modelName}`);
|
|
1759
|
+
logger11.log(prompt);
|
|
1760
|
+
const reasoning = isReasoningModel2(modelName);
|
|
1761
|
+
const input = [];
|
|
1762
|
+
if (runtime.character.system) {
|
|
1763
|
+
input.push({
|
|
1764
|
+
role: "system",
|
|
1765
|
+
content: [{ type: "input_text", text: runtime.character.system }]
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
input.push({
|
|
1769
|
+
role: "user",
|
|
1770
|
+
content: [{ type: "input_text", text: prompt }]
|
|
1771
|
+
});
|
|
1772
|
+
const requestBody = {
|
|
1773
|
+
model: modelName,
|
|
1774
|
+
input,
|
|
1775
|
+
max_output_tokens: params.maxTokens ?? 8192
|
|
1776
|
+
};
|
|
1777
|
+
if (!reasoning && typeof params.temperature === "number") {
|
|
1778
|
+
requestBody.temperature = params.temperature;
|
|
1779
|
+
}
|
|
1780
|
+
const response = await createCloudApiClient(runtime).requestRaw("POST", "/responses", {
|
|
1781
|
+
headers: {
|
|
1782
|
+
"X-Eliza-Llm-Purpose": getPurposeForModelType(modelType),
|
|
1783
|
+
"X-Eliza-Model-Type": modelType
|
|
1784
|
+
},
|
|
1785
|
+
json: requestBody
|
|
1786
|
+
});
|
|
1787
|
+
const responseText = await response.text();
|
|
1788
|
+
let data = {};
|
|
1789
|
+
if (responseText) {
|
|
1790
|
+
try {
|
|
1791
|
+
data = JSON.parse(responseText);
|
|
1792
|
+
} catch (parseErr) {
|
|
1793
|
+
logger11.error(`[ELIZAOS_CLOUD] Failed to parse responses JSON: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
if (!response.ok) {
|
|
1797
|
+
const errorBody = typeof data === "object" && data ? data.error : undefined;
|
|
1798
|
+
const errorMessage = typeof errorBody?.message === "string" && errorBody.message.trim() ? errorBody.message.trim() : `elizaOS Cloud error ${response.status}`;
|
|
1799
|
+
const requestError = new Error(errorMessage);
|
|
1800
|
+
requestError.status = response.status;
|
|
1801
|
+
if (errorBody) {
|
|
1802
|
+
requestError.error = errorBody;
|
|
1803
|
+
}
|
|
1804
|
+
throw requestError;
|
|
1805
|
+
}
|
|
1806
|
+
if (data.usage) {
|
|
1807
|
+
emitModelUsageEvent(runtime, modelType, prompt, {
|
|
1808
|
+
inputTokens: data.usage.input_tokens ?? 0,
|
|
1809
|
+
outputTokens: data.usage.output_tokens ?? 0,
|
|
1810
|
+
totalTokens: data.usage.total_tokens ?? 0
|
|
1811
|
+
});
|
|
1191
1812
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
if (response.usage) {
|
|
1196
|
-
emitModelUsageEvent(runtime, modelType, prompt, response.usage);
|
|
1813
|
+
const text = extractResponsesOutputText(data);
|
|
1814
|
+
if (!text.trim()) {
|
|
1815
|
+
throw new Error("elizaOS Cloud returned no text response");
|
|
1197
1816
|
}
|
|
1198
|
-
return
|
|
1817
|
+
return text;
|
|
1199
1818
|
}
|
|
1200
1819
|
async function handleTextSmall(runtime, params) {
|
|
1201
|
-
return generateTextWithModel(runtime,
|
|
1820
|
+
return generateTextWithModel(runtime, TEXT_SMALL_MODEL_TYPE, params);
|
|
1821
|
+
}
|
|
1822
|
+
async function handleTextNano(runtime, params) {
|
|
1823
|
+
return generateTextWithModel(runtime, TEXT_NANO_MODEL_TYPE, params);
|
|
1824
|
+
}
|
|
1825
|
+
async function handleTextMedium(runtime, params) {
|
|
1826
|
+
return generateTextWithModel(runtime, TEXT_MEDIUM_MODEL_TYPE, params);
|
|
1202
1827
|
}
|
|
1203
1828
|
async function handleTextLarge(runtime, params) {
|
|
1204
|
-
return generateTextWithModel(runtime,
|
|
1829
|
+
return generateTextWithModel(runtime, TEXT_LARGE_MODEL_TYPE, params);
|
|
1830
|
+
}
|
|
1831
|
+
async function handleTextMega(runtime, params) {
|
|
1832
|
+
return generateTextWithModel(runtime, TEXT_MEGA_MODEL_TYPE, params);
|
|
1833
|
+
}
|
|
1834
|
+
async function handleResponseHandler(runtime, params) {
|
|
1835
|
+
return generateTextWithModel(runtime, RESPONSE_HANDLER_MODEL_TYPE, params);
|
|
1836
|
+
}
|
|
1837
|
+
async function handleActionPlanner(runtime, params) {
|
|
1838
|
+
return generateTextWithModel(runtime, ACTION_PLANNER_MODEL_TYPE, params);
|
|
1205
1839
|
}
|
|
1206
1840
|
// services/cloud-auth.ts
|
|
1207
1841
|
import { logger as logger12, Service } from "@elizaos/core";
|
|
1842
|
+
import {
|
|
1843
|
+
resolveApiSecurityConfig,
|
|
1844
|
+
resolveDesktopApiPort
|
|
1845
|
+
} from "@elizaos/shared";
|
|
1846
|
+
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
1208
1847
|
|
|
1209
1848
|
// utils/cloud-api.ts
|
|
1210
|
-
import {
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
this.apiKey = apiKey;
|
|
1217
|
-
}
|
|
1218
|
-
setApiKey(key) {
|
|
1219
|
-
this.apiKey = key;
|
|
1220
|
-
}
|
|
1221
|
-
setBaseUrl(url) {
|
|
1222
|
-
this.baseUrl = url.replace(/\/+$/, "");
|
|
1223
|
-
}
|
|
1224
|
-
getBaseUrl() {
|
|
1225
|
-
return this.baseUrl;
|
|
1226
|
-
}
|
|
1227
|
-
getApiKey() {
|
|
1228
|
-
return this.apiKey;
|
|
1229
|
-
}
|
|
1230
|
-
buildWsUrl(path) {
|
|
1231
|
-
return `${this.baseUrl.replace(/^http/, "ws")}${path}`;
|
|
1232
|
-
}
|
|
1233
|
-
async get(path) {
|
|
1234
|
-
return this.request("GET", path);
|
|
1235
|
-
}
|
|
1236
|
-
async post(path, body) {
|
|
1237
|
-
return this.request("POST", path, body);
|
|
1238
|
-
}
|
|
1239
|
-
async delete(path) {
|
|
1240
|
-
return this.request("DELETE", path);
|
|
1241
|
-
}
|
|
1242
|
-
async postUnauthenticated(path, body) {
|
|
1243
|
-
return this.request("POST", path, body, true);
|
|
1244
|
-
}
|
|
1245
|
-
async request(method, path, body, skipAuth = false) {
|
|
1246
|
-
const url = `${this.baseUrl}${path}`;
|
|
1247
|
-
logger11.debug(`[CloudAPI] ${method} ${url}`);
|
|
1248
|
-
const headers = {
|
|
1249
|
-
"Content-Type": "application/json",
|
|
1250
|
-
Accept: "application/json"
|
|
1251
|
-
};
|
|
1252
|
-
if (!skipAuth && this.apiKey) {
|
|
1253
|
-
headers.Authorization = `Bearer ${this.apiKey}`;
|
|
1254
|
-
}
|
|
1255
|
-
const response = await fetch(url, {
|
|
1256
|
-
method,
|
|
1257
|
-
headers,
|
|
1258
|
-
...body ? { body: JSON.stringify(body) } : {}
|
|
1259
|
-
});
|
|
1260
|
-
return this.handleResponse(response);
|
|
1261
|
-
}
|
|
1262
|
-
async handleResponse(response) {
|
|
1263
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
1264
|
-
if (!contentType.includes("application/json")) {
|
|
1265
|
-
if (!response.ok) {
|
|
1266
|
-
throw new CloudApiError(response.status, {
|
|
1267
|
-
success: false,
|
|
1268
|
-
error: `HTTP ${response.status}: ${response.statusText}`
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
|
-
return { success: true };
|
|
1272
|
-
}
|
|
1273
|
-
const body = await response.json();
|
|
1274
|
-
if (!response.ok) {
|
|
1275
|
-
const err = body;
|
|
1276
|
-
throw response.status === 402 ? new InsufficientCreditsError(err) : new CloudApiError(response.status, err);
|
|
1277
|
-
}
|
|
1278
|
-
return body;
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1849
|
+
import {
|
|
1850
|
+
CloudApiClient as CloudApiClient2,
|
|
1851
|
+
CloudApiError as CloudApiError2,
|
|
1852
|
+
ElizaCloudHttpClient,
|
|
1853
|
+
InsufficientCreditsError as InsufficientCreditsError2
|
|
1854
|
+
} from "@elizaos/cloud-sdk";
|
|
1281
1855
|
|
|
1282
1856
|
// services/cloud-auth.ts
|
|
1283
1857
|
async function deriveDeviceId() {
|
|
@@ -1304,15 +1878,14 @@ function detectPlatform() {
|
|
|
1304
1878
|
};
|
|
1305
1879
|
return map[process.platform] ?? "linux";
|
|
1306
1880
|
}
|
|
1307
|
-
|
|
1308
1881
|
class CloudAuthService extends Service {
|
|
1309
1882
|
static serviceType = "CLOUD_AUTH";
|
|
1310
|
-
capabilityDescription = "
|
|
1883
|
+
capabilityDescription = "Eliza Cloud device authentication and SSO session helpers";
|
|
1311
1884
|
client;
|
|
1312
1885
|
credentials = null;
|
|
1313
1886
|
constructor(runtime) {
|
|
1314
1887
|
super(runtime);
|
|
1315
|
-
this.client = new
|
|
1888
|
+
this.client = new CloudApiClient2(DEFAULT_CLOUD_CONFIG.baseUrl);
|
|
1316
1889
|
}
|
|
1317
1890
|
static async start(runtime) {
|
|
1318
1891
|
const service = new CloudAuthService(runtime);
|
|
@@ -1329,31 +1902,43 @@ class CloudAuthService extends Service {
|
|
|
1329
1902
|
if (existingKey) {
|
|
1330
1903
|
const key = String(existingKey);
|
|
1331
1904
|
this.client.setApiKey(key);
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
this.
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1905
|
+
this.credentials = {
|
|
1906
|
+
apiKey: key,
|
|
1907
|
+
userId: String(this.runtime.getSetting("ELIZAOS_CLOUD_USER_ID") ?? ""),
|
|
1908
|
+
organizationId: String(this.runtime.getSetting("ELIZAOS_CLOUD_ORG_ID") ?? this.runtime.getSetting("ELIZA_CLOUD_ORGANIZATION_ID") ?? ""),
|
|
1909
|
+
authenticatedAt: Date.now()
|
|
1910
|
+
};
|
|
1911
|
+
logger12.info("[CloudAuth] Authenticated with saved API key");
|
|
1912
|
+
this.validateApiKey(key).then((valid) => {
|
|
1913
|
+
if (!valid) {
|
|
1914
|
+
logger12.warn("[CloudAuth] Saved API key could not be validated (cloud may be unreachable or key revoked) — model calls will use the key anyway");
|
|
1915
|
+
}
|
|
1916
|
+
}).catch(() => {});
|
|
1917
|
+
return;
|
|
1344
1918
|
}
|
|
1345
1919
|
const enabled = this.runtime.getSetting("ELIZAOS_CLOUD_ENABLED");
|
|
1346
1920
|
if (enabled === "true" || enabled === "1") {
|
|
1347
|
-
|
|
1921
|
+
try {
|
|
1922
|
+
await this.authenticateWithDevice();
|
|
1923
|
+
} catch (err) {
|
|
1924
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1925
|
+
logger12.warn(`[CloudAuth] Device auth failed (cloud may be unreachable): ${msg}`);
|
|
1926
|
+
logger12.info("[CloudAuth] Service will start unauthenticated — cloud features disabled until connectivity is restored");
|
|
1927
|
+
}
|
|
1348
1928
|
} else {
|
|
1349
1929
|
logger12.info("[CloudAuth] Cloud not enabled (set ELIZAOS_CLOUD_ENABLED=true)");
|
|
1350
1930
|
}
|
|
1351
1931
|
}
|
|
1352
1932
|
async validateApiKey(key) {
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1933
|
+
try {
|
|
1934
|
+
const validationClient = new CloudApiClient2(this.client.getBaseUrl(), key);
|
|
1935
|
+
await validationClient.get("/models", { timeoutMs: 1e4 });
|
|
1936
|
+
return true;
|
|
1937
|
+
} catch (err) {
|
|
1938
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1939
|
+
logger12.warn(`[CloudAuth] Could not reach cloud API to validate key: ${msg}`);
|
|
1940
|
+
return false;
|
|
1941
|
+
}
|
|
1357
1942
|
}
|
|
1358
1943
|
async authenticateWithDevice() {
|
|
1359
1944
|
const deviceId = await deriveDeviceId();
|
|
@@ -1378,6 +1963,25 @@ class CloudAuthService extends Service {
|
|
|
1378
1963
|
logger12.info(`[CloudAuth] ${action} (credits: $${response.data.credits.toFixed(2)})`);
|
|
1379
1964
|
return this.credentials;
|
|
1380
1965
|
}
|
|
1966
|
+
authenticateWithApiKey(input) {
|
|
1967
|
+
const apiKey = input.apiKey.trim();
|
|
1968
|
+
if (!apiKey) {
|
|
1969
|
+
throw new Error("Eliza Cloud API key is required");
|
|
1970
|
+
}
|
|
1971
|
+
this.client.setApiKey(apiKey);
|
|
1972
|
+
this.credentials = {
|
|
1973
|
+
apiKey,
|
|
1974
|
+
userId: input.userId ?? "",
|
|
1975
|
+
organizationId: input.organizationId ?? "",
|
|
1976
|
+
authenticatedAt: Date.now()
|
|
1977
|
+
};
|
|
1978
|
+
logger12.info("[CloudAuth] Authenticated with API key");
|
|
1979
|
+
return this.credentials;
|
|
1980
|
+
}
|
|
1981
|
+
clearAuth() {
|
|
1982
|
+
this.credentials = null;
|
|
1983
|
+
this.client.setApiKey(undefined);
|
|
1984
|
+
}
|
|
1381
1985
|
isAuthenticated() {
|
|
1382
1986
|
return this.credentials !== null;
|
|
1383
1987
|
}
|
|
@@ -1422,7 +2026,7 @@ class CloudBackupService extends Service2 {
|
|
|
1422
2026
|
async initialize() {
|
|
1423
2027
|
const auth = this.runtime.getService("CLOUD_AUTH");
|
|
1424
2028
|
if (!auth) {
|
|
1425
|
-
logger13.
|
|
2029
|
+
logger13.debug("[CloudBackup] CloudAuthService not available");
|
|
1426
2030
|
return;
|
|
1427
2031
|
}
|
|
1428
2032
|
this.authService = auth;
|
|
@@ -1524,10 +2128,72 @@ function formatBytes(bytes) {
|
|
|
1524
2128
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
1525
2129
|
}
|
|
1526
2130
|
|
|
1527
|
-
// services/cloud-
|
|
2131
|
+
// services/cloud-bootstrap.ts
|
|
1528
2132
|
import { logger as logger14, Service as Service3 } from "@elizaos/core";
|
|
2133
|
+
function readEnv() {
|
|
2134
|
+
if (typeof process === "undefined") {
|
|
2135
|
+
return {};
|
|
2136
|
+
}
|
|
2137
|
+
return process.env;
|
|
2138
|
+
}
|
|
2139
|
+
function readSetting(runtime, key) {
|
|
2140
|
+
if (runtime && typeof runtime.getSetting === "function") {
|
|
2141
|
+
const value = runtime.getSetting(key);
|
|
2142
|
+
if (typeof value === "string" && value.length > 0) {
|
|
2143
|
+
return value;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
const fromEnv = readEnv()[key];
|
|
2147
|
+
if (typeof fromEnv === "string" && fromEnv.length > 0) {
|
|
2148
|
+
return fromEnv;
|
|
2149
|
+
}
|
|
2150
|
+
return null;
|
|
2151
|
+
}
|
|
2152
|
+
function trimTrailingSlash2(input) {
|
|
2153
|
+
let end = input.length;
|
|
2154
|
+
while (end > 0 && input.charCodeAt(end - 1) === 47) {
|
|
2155
|
+
end -= 1;
|
|
2156
|
+
}
|
|
2157
|
+
return end === input.length ? input : input.slice(0, end);
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
class CloudBootstrapServiceImpl extends Service3 {
|
|
2161
|
+
static serviceType = "CLOUD_BOOTSTRAP";
|
|
2162
|
+
capabilityDescription = "Exposes Eliza Cloud bootstrap-token trust anchor (issuer, JWKS URL, revocation list URL, expected container id) to app-core";
|
|
2163
|
+
static async start(runtime) {
|
|
2164
|
+
const service = new CloudBootstrapServiceImpl(runtime);
|
|
2165
|
+
const issuer = readSetting(runtime, "ELIZA_CLOUD_ISSUER");
|
|
2166
|
+
const containerId = readSetting(runtime, "ELIZA_CLOUD_CONTAINER_ID");
|
|
2167
|
+
if (issuer) {
|
|
2168
|
+
logger14.info(`[CloudBootstrap] Trust anchor configured (issuer=${issuer}, containerId=${containerId ?? "<unset>"})`);
|
|
2169
|
+
} else {
|
|
2170
|
+
logger14.debug("[CloudBootstrap] ELIZA_CLOUD_ISSUER unset — bootstrap-token verification will reject until configured");
|
|
2171
|
+
}
|
|
2172
|
+
return service;
|
|
2173
|
+
}
|
|
2174
|
+
async stop() {}
|
|
2175
|
+
getExpectedIssuer() {
|
|
2176
|
+
const issuer = readSetting(this.runtime, "ELIZA_CLOUD_ISSUER");
|
|
2177
|
+
if (!issuer) {
|
|
2178
|
+
throw new Error("ELIZA_CLOUD_ISSUER is not configured — bootstrap-token verification cannot proceed");
|
|
2179
|
+
}
|
|
2180
|
+
return trimTrailingSlash2(issuer);
|
|
2181
|
+
}
|
|
2182
|
+
getJwksUrl() {
|
|
2183
|
+
return `${this.getExpectedIssuer()}/.well-known/jwks.json`;
|
|
2184
|
+
}
|
|
2185
|
+
getRevocationListUrl() {
|
|
2186
|
+
return `${this.getExpectedIssuer()}/.well-known/revocations.json`;
|
|
2187
|
+
}
|
|
2188
|
+
getExpectedContainerId() {
|
|
2189
|
+
return readSetting(this.runtime, "ELIZA_CLOUD_CONTAINER_ID");
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
// services/cloud-bridge.ts
|
|
2194
|
+
import { logger as logger15, Service as Service4 } from "@elizaos/core";
|
|
1529
2195
|
import { WebSocket } from "undici";
|
|
1530
|
-
class CloudBridgeService extends
|
|
2196
|
+
class CloudBridgeService extends Service4 {
|
|
1531
2197
|
static serviceType = "CLOUD_BRIDGE";
|
|
1532
2198
|
capabilityDescription = "WebSocket bridge to cloud-hosted ElizaOS agents";
|
|
1533
2199
|
authService;
|
|
@@ -1542,22 +2208,22 @@ class CloudBridgeService extends Service3 {
|
|
|
1542
2208
|
for (const [containerId] of this.connections) {
|
|
1543
2209
|
await this.disconnect(containerId);
|
|
1544
2210
|
}
|
|
1545
|
-
|
|
2211
|
+
logger15.info("[CloudBridge] Service stopped");
|
|
1546
2212
|
}
|
|
1547
2213
|
async initialize() {
|
|
1548
2214
|
const auth = this.runtime.getService("CLOUD_AUTH");
|
|
1549
2215
|
if (!auth) {
|
|
1550
|
-
|
|
2216
|
+
logger15.debug("[CloudBridge] CloudAuthService not available");
|
|
1551
2217
|
return;
|
|
1552
2218
|
}
|
|
1553
2219
|
this.authService = auth;
|
|
1554
|
-
|
|
2220
|
+
logger15.info("[CloudBridge] Service initialized");
|
|
1555
2221
|
}
|
|
1556
2222
|
async connect(containerId) {
|
|
1557
|
-
|
|
1558
|
-
|
|
2223
|
+
const existing = this.connections.get(containerId);
|
|
2224
|
+
if (existing) {
|
|
1559
2225
|
if (existing.state === "connected" || existing.state === "connecting") {
|
|
1560
|
-
|
|
2226
|
+
logger15.debug(`[CloudBridge] Already connected/connecting to ${containerId}`);
|
|
1561
2227
|
return;
|
|
1562
2228
|
}
|
|
1563
2229
|
}
|
|
@@ -1580,7 +2246,7 @@ class CloudBridgeService extends Service3 {
|
|
|
1580
2246
|
conn.ws.close(1000, "Client disconnect");
|
|
1581
2247
|
}
|
|
1582
2248
|
this.connections.delete(containerId);
|
|
1583
|
-
|
|
2249
|
+
logger15.info(`[CloudBridge] Disconnected from ${containerId}`);
|
|
1584
2250
|
}
|
|
1585
2251
|
async establishConnection(containerId, reconnectAttempts) {
|
|
1586
2252
|
const client = this.authService.getClient();
|
|
@@ -1604,7 +2270,7 @@ class CloudBridgeService extends Service3 {
|
|
|
1604
2270
|
conn.state = "connected";
|
|
1605
2271
|
conn.connectedAt = Date.now();
|
|
1606
2272
|
conn.reconnectAttempts = 0;
|
|
1607
|
-
|
|
2273
|
+
logger15.info(`[CloudBridge] Connected to agent ${containerId}`);
|
|
1608
2274
|
conn.heartbeatTimer = setInterval(() => {
|
|
1609
2275
|
this.sendHeartbeat(containerId);
|
|
1610
2276
|
}, this.bridgeConfig.heartbeatIntervalMs);
|
|
@@ -1639,26 +2305,26 @@ class CloudBridgeService extends Service3 {
|
|
|
1639
2305
|
if (conn.heartbeatTimer)
|
|
1640
2306
|
clearInterval(conn.heartbeatTimer);
|
|
1641
2307
|
if (event.code === 1000) {
|
|
1642
|
-
|
|
2308
|
+
logger15.info(`[CloudBridge] Clean disconnect from ${containerId}`);
|
|
1643
2309
|
return;
|
|
1644
2310
|
}
|
|
1645
|
-
|
|
2311
|
+
logger15.warn(`[CloudBridge] Connection lost to ${containerId} (code=${event.code}, reason=${event.reason})`);
|
|
1646
2312
|
this.scheduleReconnect(containerId, conn.reconnectAttempts + 1);
|
|
1647
2313
|
});
|
|
1648
2314
|
conn.ws.addEventListener("error", () => {
|
|
1649
|
-
|
|
2315
|
+
logger15.error(`[CloudBridge] WebSocket error for ${containerId}`);
|
|
1650
2316
|
});
|
|
1651
2317
|
}
|
|
1652
2318
|
scheduleReconnect(containerId, attempt) {
|
|
1653
2319
|
if (attempt > this.bridgeConfig.maxReconnectAttempts) {
|
|
1654
|
-
|
|
2320
|
+
logger15.error(`[CloudBridge] Max reconnect attempts (${this.bridgeConfig.maxReconnectAttempts}) reached for ${containerId}`);
|
|
1655
2321
|
this.connections.delete(containerId);
|
|
1656
2322
|
return;
|
|
1657
2323
|
}
|
|
1658
2324
|
const base = this.bridgeConfig.reconnectIntervalMs;
|
|
1659
2325
|
const delay = Math.min(base * 2 ** Math.min(attempt, 5), 120000);
|
|
1660
2326
|
const jitter = Math.floor(Math.random() * 1000);
|
|
1661
|
-
|
|
2327
|
+
logger15.info(`[CloudBridge] Reconnecting to ${containerId} in ${Math.round((delay + jitter) / 1000)}s (attempt ${attempt})`);
|
|
1662
2328
|
const conn = this.connections.get(containerId);
|
|
1663
2329
|
if (conn) {
|
|
1664
2330
|
conn.state = "reconnecting";
|
|
@@ -1774,8 +2440,8 @@ class CloudBridgeService extends Service3 {
|
|
|
1774
2440
|
}
|
|
1775
2441
|
|
|
1776
2442
|
// services/cloud-container.ts
|
|
1777
|
-
import { logger as
|
|
1778
|
-
class CloudContainerService extends
|
|
2443
|
+
import { logger as logger16, Service as Service5 } from "@elizaos/core";
|
|
2444
|
+
class CloudContainerService extends Service5 {
|
|
1779
2445
|
static serviceType = "CLOUD_CONTAINER";
|
|
1780
2446
|
capabilityDescription = "ElizaCloud container provisioning and lifecycle management";
|
|
1781
2447
|
authService;
|
|
@@ -1798,7 +2464,7 @@ class CloudContainerService extends Service4 {
|
|
|
1798
2464
|
async initialize() {
|
|
1799
2465
|
const auth = this.runtime.getService("CLOUD_AUTH");
|
|
1800
2466
|
if (!auth) {
|
|
1801
|
-
|
|
2467
|
+
logger16.debug("[CloudContainer] CloudAuthService not available, container operations will fail");
|
|
1802
2468
|
return;
|
|
1803
2469
|
}
|
|
1804
2470
|
this.authService = auth;
|
|
@@ -1817,7 +2483,7 @@ class CloudContainerService extends Service4 {
|
|
|
1817
2483
|
this.startHealthMonitoring(container.id);
|
|
1818
2484
|
}
|
|
1819
2485
|
}
|
|
1820
|
-
|
|
2486
|
+
logger16.info(`[CloudContainer] Loaded ${containers.length} existing container(s)`);
|
|
1821
2487
|
}
|
|
1822
2488
|
}
|
|
1823
2489
|
getClient() {
|
|
@@ -1848,7 +2514,7 @@ class CloudContainerService extends Service4 {
|
|
|
1848
2514
|
healthTimer: null
|
|
1849
2515
|
});
|
|
1850
2516
|
this.startPolling(response.data.id);
|
|
1851
|
-
|
|
2517
|
+
logger16.info(`[CloudContainer] Created container "${request.name}" (id=${response.data.id}, stack=${response.stackName})`);
|
|
1852
2518
|
return response;
|
|
1853
2519
|
}
|
|
1854
2520
|
async listContainers() {
|
|
@@ -1876,7 +2542,7 @@ class CloudContainerService extends Service4 {
|
|
|
1876
2542
|
clearInterval(tracked.healthTimer);
|
|
1877
2543
|
this.tracked.delete(containerId);
|
|
1878
2544
|
}
|
|
1879
|
-
|
|
2545
|
+
logger16.info(`[CloudContainer] Deleted container ${containerId}`);
|
|
1880
2546
|
}
|
|
1881
2547
|
startPolling(containerId) {
|
|
1882
2548
|
const tracked = this.tracked.get(containerId);
|
|
@@ -1889,21 +2555,21 @@ class CloudContainerService extends Service4 {
|
|
|
1889
2555
|
const poll = async () => {
|
|
1890
2556
|
attempt++;
|
|
1891
2557
|
if (attempt > maxAttempts) {
|
|
1892
|
-
|
|
2558
|
+
logger16.error(`[CloudContainer] Polling timed out for container ${containerId} after ${maxAttempts} attempts`);
|
|
1893
2559
|
return;
|
|
1894
2560
|
}
|
|
1895
2561
|
const container = await this.getContainer(containerId);
|
|
1896
2562
|
const status = container.status;
|
|
1897
|
-
|
|
2563
|
+
logger16.debug(`[CloudContainer] Poll #${attempt} for ${containerId}: status=${status}`);
|
|
1898
2564
|
if (status === "running") {
|
|
1899
|
-
|
|
2565
|
+
logger16.info(`[CloudContainer] Container ${containerId} is now running at ${container.load_balancer_url}`);
|
|
1900
2566
|
this.startHealthMonitoring(containerId);
|
|
1901
2567
|
return;
|
|
1902
2568
|
}
|
|
1903
2569
|
if (status === "failed" || status === "stopped" || status === "suspended") {
|
|
1904
|
-
|
|
2570
|
+
logger16.warn(`[CloudContainer] Container ${containerId} reached terminal state: ${status}`);
|
|
1905
2571
|
if (container.error_message) {
|
|
1906
|
-
|
|
2572
|
+
logger16.error(`[CloudContainer] Error: ${container.error_message}`);
|
|
1907
2573
|
}
|
|
1908
2574
|
return;
|
|
1909
2575
|
}
|
|
@@ -1939,10 +2605,10 @@ class CloudContainerService extends Service4 {
|
|
|
1939
2605
|
tracked.healthTimer = setInterval(() => {
|
|
1940
2606
|
this.getContainerHealth(containerId).then((health) => {
|
|
1941
2607
|
if (!health.data.healthy) {
|
|
1942
|
-
|
|
2608
|
+
logger16.warn(`[CloudContainer] Container ${containerId} unhealthy: ${health.data.status}`);
|
|
1943
2609
|
}
|
|
1944
2610
|
}).catch((err) => {
|
|
1945
|
-
|
|
2611
|
+
logger16.error(`[CloudContainer] Health check failed for ${containerId}: ${err.message}`);
|
|
1946
2612
|
});
|
|
1947
2613
|
}, interval);
|
|
1948
2614
|
}
|
|
@@ -1964,7 +2630,622 @@ class CloudContainerService extends Service4 {
|
|
|
1964
2630
|
}
|
|
1965
2631
|
}
|
|
1966
2632
|
|
|
2633
|
+
// services/cloud-managed-gateway-relay.ts
|
|
2634
|
+
import {
|
|
2635
|
+
ChannelType,
|
|
2636
|
+
ContentType,
|
|
2637
|
+
createMessageMemory,
|
|
2638
|
+
createUniqueUuid,
|
|
2639
|
+
logger as logger17,
|
|
2640
|
+
Service as Service6
|
|
2641
|
+
} from "@elizaos/core";
|
|
2642
|
+
var POLL_TIMEOUT_MS = 25000;
|
|
2643
|
+
var REQUEST_TIMEOUT_MS = POLL_TIMEOUT_MS + 5000;
|
|
2644
|
+
var RETRY_DELAY_MS = 2000;
|
|
2645
|
+
var IDLE_DELAY_MS = 250;
|
|
2646
|
+
function sleep(ms) {
|
|
2647
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2648
|
+
}
|
|
2649
|
+
function isRecord(value) {
|
|
2650
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2651
|
+
}
|
|
2652
|
+
function isUuidLike(value) {
|
|
2653
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
2654
|
+
}
|
|
2655
|
+
function asTrimmedString(value) {
|
|
2656
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
2657
|
+
}
|
|
2658
|
+
function resolveChannelType(value) {
|
|
2659
|
+
const candidate = asTrimmedString(value)?.toUpperCase();
|
|
2660
|
+
return candidate && candidate in ChannelType ? ChannelType[candidate] : ChannelType.DM;
|
|
2661
|
+
}
|
|
2662
|
+
function isCloudProvisionedRuntime() {
|
|
2663
|
+
if (typeof process === "undefined") {
|
|
2664
|
+
return false;
|
|
2665
|
+
}
|
|
2666
|
+
return process.env.ELIZA_CLOUD_PROVISIONED === "1";
|
|
2667
|
+
}
|
|
2668
|
+
function isNodeHost() {
|
|
2669
|
+
return typeof process !== "undefined" && typeof process.versions?.node === "string";
|
|
2670
|
+
}
|
|
2671
|
+
function normalizeAttachments(value) {
|
|
2672
|
+
if (!Array.isArray(value)) {
|
|
2673
|
+
return;
|
|
2674
|
+
}
|
|
2675
|
+
const attachments = value.map((entry, index) => {
|
|
2676
|
+
if (!isRecord(entry)) {
|
|
2677
|
+
return null;
|
|
2678
|
+
}
|
|
2679
|
+
const url = asTrimmedString(entry.url);
|
|
2680
|
+
if (!url) {
|
|
2681
|
+
return null;
|
|
2682
|
+
}
|
|
2683
|
+
const type = asTrimmedString(entry.type)?.toLowerCase();
|
|
2684
|
+
return {
|
|
2685
|
+
id: asTrimmedString(entry.id) ?? `${index}:${url}`,
|
|
2686
|
+
url,
|
|
2687
|
+
source: asTrimmedString(entry.source),
|
|
2688
|
+
title: asTrimmedString(entry.title),
|
|
2689
|
+
description: asTrimmedString(entry.description),
|
|
2690
|
+
text: asTrimmedString(entry.text),
|
|
2691
|
+
contentType: type === "image" ? ContentType.IMAGE : type === "video" ? ContentType.VIDEO : type === "audio" ? ContentType.AUDIO : type === "document" ? ContentType.DOCUMENT : undefined
|
|
2692
|
+
};
|
|
2693
|
+
}).filter((entry) => entry !== null);
|
|
2694
|
+
return attachments.length > 0 ? attachments : undefined;
|
|
2695
|
+
}
|
|
2696
|
+
function toJsonRecord(value) {
|
|
2697
|
+
return isRecord(value) ? value : undefined;
|
|
2698
|
+
}
|
|
2699
|
+
function toJsonMetadataRecord(value) {
|
|
2700
|
+
if (!isRecord(value)) {
|
|
2701
|
+
return;
|
|
2702
|
+
}
|
|
2703
|
+
return JSON.parse(JSON.stringify(value));
|
|
2704
|
+
}
|
|
2705
|
+
function buildGatewayMessagePayload(runtime, rpc) {
|
|
2706
|
+
const params = toJsonRecord(rpc.params);
|
|
2707
|
+
const sender = toJsonRecord(params?.sender);
|
|
2708
|
+
const source = asTrimmedString(params?.source) ?? "eliza_cloud_gateway";
|
|
2709
|
+
const text = typeof params?.text === "string" ? params.text : "";
|
|
2710
|
+
const senderId = asTrimmedString(sender?.id) ?? `${source}:anonymous`;
|
|
2711
|
+
const senderUserName = asTrimmedString(sender?.username) ?? senderId;
|
|
2712
|
+
const senderName = asTrimmedString(sender?.displayName) ?? asTrimmedString(sender?.name) ?? senderUserName;
|
|
2713
|
+
const roomKey = asTrimmedString(params?.roomId) ?? `${source}:${senderId}:${String(rpc.id ?? Date.now())}:${runtime.agentId}`;
|
|
2714
|
+
if (!text.trim() && !normalizeAttachments(params?.attachments)?.length) {
|
|
2715
|
+
return null;
|
|
2716
|
+
}
|
|
2717
|
+
return {
|
|
2718
|
+
text: text.trim() || " ",
|
|
2719
|
+
roomKey,
|
|
2720
|
+
channelType: resolveChannelType(params?.channelType),
|
|
2721
|
+
source,
|
|
2722
|
+
senderId,
|
|
2723
|
+
senderUserName,
|
|
2724
|
+
senderName,
|
|
2725
|
+
attachments: normalizeAttachments(params?.attachments),
|
|
2726
|
+
senderMetadata: toJsonRecord(sender?.metadata),
|
|
2727
|
+
transportMetadata: toJsonRecord(params?.metadata)
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
function buildWorldKey(source, metadata, roomKey) {
|
|
2731
|
+
const discord = toJsonRecord(metadata?.discord);
|
|
2732
|
+
const guildId = asTrimmedString(discord?.guildId);
|
|
2733
|
+
if (guildId) {
|
|
2734
|
+
return `gateway:${source}:guild:${guildId}`;
|
|
2735
|
+
}
|
|
2736
|
+
const threadId = asTrimmedString(metadata?.threadId);
|
|
2737
|
+
if (threadId) {
|
|
2738
|
+
return `gateway:${source}:thread:${threadId}`;
|
|
2739
|
+
}
|
|
2740
|
+
return `gateway:${source}:room:${roomKey}`;
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
class SessionMissingError extends Error {
|
|
2744
|
+
constructor() {
|
|
2745
|
+
super("Gateway relay session missing");
|
|
2746
|
+
this.name = "SessionMissingError";
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
class CloudManagedGatewayRelayService extends Service6 {
|
|
2751
|
+
static serviceType = "CLOUD_MANAGED_GATEWAY_RELAY";
|
|
2752
|
+
capabilityDescription = "Registers a local Eliza runtime with the cloud managed gateway and handles inbound relay traffic";
|
|
2753
|
+
authService = null;
|
|
2754
|
+
loopPromise = null;
|
|
2755
|
+
currentSessionId = null;
|
|
2756
|
+
stopping = false;
|
|
2757
|
+
activeAbortController = null;
|
|
2758
|
+
relayStatus = "idle";
|
|
2759
|
+
lastSeenAt = null;
|
|
2760
|
+
static async start(runtime) {
|
|
2761
|
+
const service = new CloudManagedGatewayRelayService(runtime);
|
|
2762
|
+
await service.initialize();
|
|
2763
|
+
return service;
|
|
2764
|
+
}
|
|
2765
|
+
async stop() {
|
|
2766
|
+
this.stopping = true;
|
|
2767
|
+
this.relayStatus = "stopped";
|
|
2768
|
+
this.activeAbortController?.abort();
|
|
2769
|
+
if (this.loopPromise) {
|
|
2770
|
+
await this.loopPromise.catch((error) => {
|
|
2771
|
+
logger17.debug(`[CloudManagedGatewayRelay] Ignoring relay loop shutdown error: ${error instanceof Error ? error.message : String(error)}`);
|
|
2772
|
+
});
|
|
2773
|
+
}
|
|
2774
|
+
const sessionId = this.currentSessionId;
|
|
2775
|
+
this.currentSessionId = null;
|
|
2776
|
+
if (sessionId) {
|
|
2777
|
+
await this.disconnectSession(sessionId);
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
async initialize() {
|
|
2781
|
+
if (!isNodeHost()) {
|
|
2782
|
+
logger17.debug("[CloudManagedGatewayRelay] Skipping gateway relay outside Node.js runtime");
|
|
2783
|
+
this.relayStatus = "stopped";
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
if (isCloudProvisionedRuntime()) {
|
|
2787
|
+
logger17.debug("[CloudManagedGatewayRelay] Skipping local relay inside provisioned cloud runtime");
|
|
2788
|
+
this.relayStatus = "stopped";
|
|
2789
|
+
return;
|
|
2790
|
+
}
|
|
2791
|
+
if (!this.runtime.messageService) {
|
|
2792
|
+
logger17.debug("[CloudManagedGatewayRelay] Skipping gateway relay without message service");
|
|
2793
|
+
this.relayStatus = "idle";
|
|
2794
|
+
return;
|
|
2795
|
+
}
|
|
2796
|
+
const auth = this.runtime.getService("CLOUD_AUTH");
|
|
2797
|
+
if (!auth) {
|
|
2798
|
+
logger17.debug("[CloudManagedGatewayRelay] CloudAuthService not available");
|
|
2799
|
+
this.relayStatus = "idle";
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
this.authService = auth;
|
|
2803
|
+
if (!this.authService.isAuthenticated()) {
|
|
2804
|
+
logger17.debug("[CloudManagedGatewayRelay] Skipping gateway relay while cloud auth is inactive");
|
|
2805
|
+
this.relayStatus = "idle";
|
|
2806
|
+
return;
|
|
2807
|
+
}
|
|
2808
|
+
this.startRelayLoopIfReady();
|
|
2809
|
+
}
|
|
2810
|
+
getSessionInfo() {
|
|
2811
|
+
const auth = this.authService;
|
|
2812
|
+
const status = this.stopping || this.relayStatus === "stopped" ? "stopped" : auth?.isAuthenticated() === false ? "idle" : this.relayStatus;
|
|
2813
|
+
return {
|
|
2814
|
+
sessionId: this.currentSessionId,
|
|
2815
|
+
organizationId: auth?.getOrganizationId() ?? null,
|
|
2816
|
+
userId: auth?.getUserId() ?? null,
|
|
2817
|
+
agentName: this.getAgentName(),
|
|
2818
|
+
platform: "local-runtime",
|
|
2819
|
+
lastSeenAt: this.lastSeenAt,
|
|
2820
|
+
status
|
|
2821
|
+
};
|
|
2822
|
+
}
|
|
2823
|
+
startRelayLoopIfReady() {
|
|
2824
|
+
if (this.loopPromise && !this.stopping) {
|
|
2825
|
+
return true;
|
|
2826
|
+
}
|
|
2827
|
+
const auth = this.authService ?? this.runtime.getService("CLOUD_AUTH");
|
|
2828
|
+
if (!auth?.isAuthenticated() || !this.runtime.messageService) {
|
|
2829
|
+
this.relayStatus = "idle";
|
|
2830
|
+
return false;
|
|
2831
|
+
}
|
|
2832
|
+
this.authService = auth;
|
|
2833
|
+
this.stopping = false;
|
|
2834
|
+
this.relayStatus = "idle";
|
|
2835
|
+
this.loopPromise = this.runLoop();
|
|
2836
|
+
logger17.info("[CloudManagedGatewayRelay] Local gateway relay loop started");
|
|
2837
|
+
return true;
|
|
2838
|
+
}
|
|
2839
|
+
async runLoop() {
|
|
2840
|
+
while (!this.stopping) {
|
|
2841
|
+
try {
|
|
2842
|
+
if (!this.currentSessionId) {
|
|
2843
|
+
this.currentSessionId = await this.registerSession();
|
|
2844
|
+
this.relayStatus = "registered";
|
|
2845
|
+
this.lastSeenAt = new Date().toISOString();
|
|
2846
|
+
continue;
|
|
2847
|
+
}
|
|
2848
|
+
this.relayStatus = "polling";
|
|
2849
|
+
const request = await this.pollNextRequest(this.currentSessionId);
|
|
2850
|
+
this.lastSeenAt = new Date().toISOString();
|
|
2851
|
+
if (!request) {
|
|
2852
|
+
this.relayStatus = "registered";
|
|
2853
|
+
await sleep(IDLE_DELAY_MS);
|
|
2854
|
+
continue;
|
|
2855
|
+
}
|
|
2856
|
+
const response = await this.handleRequest(request.rpc);
|
|
2857
|
+
await this.submitResponse(this.currentSessionId, request.requestId, response);
|
|
2858
|
+
this.relayStatus = "registered";
|
|
2859
|
+
} catch (error) {
|
|
2860
|
+
if (this.stopping) {
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2863
|
+
if (error instanceof SessionMissingError) {
|
|
2864
|
+
this.currentSessionId = null;
|
|
2865
|
+
this.relayStatus = "idle";
|
|
2866
|
+
await sleep(IDLE_DELAY_MS);
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2869
|
+
this.relayStatus = "error";
|
|
2870
|
+
logger17.warn(`[CloudManagedGatewayRelay] Relay loop error: ${error instanceof Error ? error.message : String(error)}`);
|
|
2871
|
+
await sleep(RETRY_DELAY_MS);
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
getAgentName() {
|
|
2876
|
+
return this.runtime.character?.name?.trim() || "Eliza";
|
|
2877
|
+
}
|
|
2878
|
+
getClient() {
|
|
2879
|
+
const client = this.authService?.getClient();
|
|
2880
|
+
if (!client) {
|
|
2881
|
+
throw new Error("Cloud API client is unavailable");
|
|
2882
|
+
}
|
|
2883
|
+
return client;
|
|
2884
|
+
}
|
|
2885
|
+
async requestJson(path, options) {
|
|
2886
|
+
const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
2887
|
+
const controller = new AbortController;
|
|
2888
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
2889
|
+
this.activeAbortController = controller;
|
|
2890
|
+
try {
|
|
2891
|
+
const response = await this.getClient().requestRaw(options.method, path, {
|
|
2892
|
+
headers: {
|
|
2893
|
+
Accept: "application/json"
|
|
2894
|
+
},
|
|
2895
|
+
json: options.json,
|
|
2896
|
+
query: options.query,
|
|
2897
|
+
signal: controller.signal
|
|
2898
|
+
});
|
|
2899
|
+
const body = await response.json().catch(() => ({}));
|
|
2900
|
+
return { status: response.status, body };
|
|
2901
|
+
} finally {
|
|
2902
|
+
clearTimeout(timeoutId);
|
|
2903
|
+
if (this.activeAbortController === controller) {
|
|
2904
|
+
this.activeAbortController = null;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
async registerSession() {
|
|
2909
|
+
const { status, body } = await this.requestJson("/eliza/gateway-relay/sessions", {
|
|
2910
|
+
method: "POST",
|
|
2911
|
+
json: {
|
|
2912
|
+
runtimeAgentId: this.runtime.agentId,
|
|
2913
|
+
agentName: this.getAgentName()
|
|
2914
|
+
}
|
|
2915
|
+
});
|
|
2916
|
+
if (status >= 400 || !body?.success || !body.data?.session?.id) {
|
|
2917
|
+
throw new Error(`Failed to register gateway relay session (status=${status})`);
|
|
2918
|
+
}
|
|
2919
|
+
logger17.info(`[CloudManagedGatewayRelay] Registered local runtime for managed gateway (${body.data.session.id})`);
|
|
2920
|
+
return body.data.session.id;
|
|
2921
|
+
}
|
|
2922
|
+
async disconnectSession(sessionId) {
|
|
2923
|
+
try {
|
|
2924
|
+
await this.requestJson(`/eliza/gateway-relay/sessions/${encodeURIComponent(sessionId)}`, {
|
|
2925
|
+
method: "DELETE",
|
|
2926
|
+
timeoutMs: 1e4
|
|
2927
|
+
});
|
|
2928
|
+
} catch (error) {
|
|
2929
|
+
logger17.debug(`[CloudManagedGatewayRelay] Failed to disconnect relay session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
async pollNextRequest(sessionId) {
|
|
2933
|
+
const { status, body } = await this.requestJson(`/eliza/gateway-relay/sessions/${encodeURIComponent(sessionId)}/next`, {
|
|
2934
|
+
method: "GET",
|
|
2935
|
+
query: { timeoutMs: POLL_TIMEOUT_MS },
|
|
2936
|
+
timeoutMs: POLL_TIMEOUT_MS + 5000
|
|
2937
|
+
});
|
|
2938
|
+
if (status === 404) {
|
|
2939
|
+
throw new SessionMissingError;
|
|
2940
|
+
}
|
|
2941
|
+
if (status >= 400 || !body?.success) {
|
|
2942
|
+
throw new Error(`Failed to poll gateway relay session ${sessionId} (status=${status})`);
|
|
2943
|
+
}
|
|
2944
|
+
return body.data?.request ?? null;
|
|
2945
|
+
}
|
|
2946
|
+
async submitResponse(sessionId, requestId, response) {
|
|
2947
|
+
const { status, body } = await this.requestJson(`/eliza/gateway-relay/sessions/${encodeURIComponent(sessionId)}/responses`, {
|
|
2948
|
+
method: "POST",
|
|
2949
|
+
json: { requestId, response }
|
|
2950
|
+
});
|
|
2951
|
+
if (status === 404) {
|
|
2952
|
+
throw new SessionMissingError;
|
|
2953
|
+
}
|
|
2954
|
+
if (status >= 400 || body?.success === false) {
|
|
2955
|
+
throw new Error(`Failed to submit gateway relay response (status=${status})`);
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
async handleRequest(rpc) {
|
|
2959
|
+
switch (rpc.method) {
|
|
2960
|
+
case "heartbeat":
|
|
2961
|
+
return {
|
|
2962
|
+
jsonrpc: "2.0",
|
|
2963
|
+
id: rpc.id,
|
|
2964
|
+
result: { timestamp: Date.now() }
|
|
2965
|
+
};
|
|
2966
|
+
case "status.get":
|
|
2967
|
+
return {
|
|
2968
|
+
jsonrpc: "2.0",
|
|
2969
|
+
id: rpc.id,
|
|
2970
|
+
result: {
|
|
2971
|
+
status: "running",
|
|
2972
|
+
runtimeAgentId: this.runtime.agentId,
|
|
2973
|
+
agentName: this.getAgentName()
|
|
2974
|
+
}
|
|
2975
|
+
};
|
|
2976
|
+
case "message.send":
|
|
2977
|
+
return this.handleMessageSend(rpc);
|
|
2978
|
+
default:
|
|
2979
|
+
return {
|
|
2980
|
+
jsonrpc: "2.0",
|
|
2981
|
+
id: rpc.id,
|
|
2982
|
+
error: {
|
|
2983
|
+
code: -32601,
|
|
2984
|
+
message: `Unsupported relay method: ${rpc.method}`
|
|
2985
|
+
}
|
|
2986
|
+
};
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
async handleMessageSend(rpc) {
|
|
2990
|
+
if (!this.runtime.messageService) {
|
|
2991
|
+
return {
|
|
2992
|
+
jsonrpc: "2.0",
|
|
2993
|
+
id: rpc.id,
|
|
2994
|
+
error: { code: -32603, message: "Message service is not available" }
|
|
2995
|
+
};
|
|
2996
|
+
}
|
|
2997
|
+
const payload = buildGatewayMessagePayload(this.runtime, rpc);
|
|
2998
|
+
if (!payload) {
|
|
2999
|
+
return {
|
|
3000
|
+
jsonrpc: "2.0",
|
|
3001
|
+
id: rpc.id,
|
|
3002
|
+
error: { code: -32602, message: "Invalid message relay payload" }
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
const roomId = isUuidLike(payload.roomKey) ? payload.roomKey : createUniqueUuid(this.runtime, payload.roomKey);
|
|
3006
|
+
const worldId = createUniqueUuid(this.runtime, buildWorldKey(payload.source, payload.transportMetadata, payload.roomKey));
|
|
3007
|
+
const entityId = createUniqueUuid(this.runtime, `${payload.source}:${payload.senderId}`);
|
|
3008
|
+
const messageServerId = createUniqueUuid(this.runtime, `eliza-cloud-gateway:${payload.source}`);
|
|
3009
|
+
const messageId = createUniqueUuid(this.runtime, `${payload.source}:${payload.roomKey}:${String(rpc.id ?? Date.now())}:inbound`);
|
|
3010
|
+
const transportMetadata = toJsonMetadataRecord(payload.transportMetadata);
|
|
3011
|
+
await this.runtime.ensureConnection({
|
|
3012
|
+
entityId,
|
|
3013
|
+
roomId,
|
|
3014
|
+
roomName: payload.roomKey,
|
|
3015
|
+
worldId,
|
|
3016
|
+
worldName: payload.source,
|
|
3017
|
+
userName: payload.senderUserName,
|
|
3018
|
+
name: payload.senderName,
|
|
3019
|
+
source: payload.source,
|
|
3020
|
+
channelId: payload.roomKey,
|
|
3021
|
+
type: payload.channelType,
|
|
3022
|
+
messageServerId,
|
|
3023
|
+
metadata: transportMetadata
|
|
3024
|
+
});
|
|
3025
|
+
const message = createMessageMemory({
|
|
3026
|
+
id: messageId,
|
|
3027
|
+
entityId,
|
|
3028
|
+
agentId: this.runtime.agentId,
|
|
3029
|
+
roomId,
|
|
3030
|
+
content: {
|
|
3031
|
+
text: payload.text,
|
|
3032
|
+
source: payload.source,
|
|
3033
|
+
channelType: payload.channelType,
|
|
3034
|
+
...payload.attachments ? { attachments: payload.attachments } : {}
|
|
3035
|
+
}
|
|
3036
|
+
});
|
|
3037
|
+
message.metadata = {
|
|
3038
|
+
...message.metadata,
|
|
3039
|
+
entityName: payload.senderName,
|
|
3040
|
+
entityUserName: payload.senderUserName,
|
|
3041
|
+
...payload.senderMetadata ? { gatewaySender: toJsonMetadataRecord(payload.senderMetadata) } : {},
|
|
3042
|
+
...payload.transportMetadata ? { gatewayMetadata: transportMetadata } : {}
|
|
3043
|
+
};
|
|
3044
|
+
const callbackTexts = [];
|
|
3045
|
+
const callback = async (content) => {
|
|
3046
|
+
const responseText = typeof content.text === "string" ? content.text : "";
|
|
3047
|
+
if (responseText.trim()) {
|
|
3048
|
+
callbackTexts.push(responseText);
|
|
3049
|
+
}
|
|
3050
|
+
const responseMemory = createMessageMemory({
|
|
3051
|
+
id: createUniqueUuid(this.runtime, `${payload.source}:${payload.roomKey}:${String(rpc.id ?? Date.now())}:response:${callbackTexts.length}`),
|
|
3052
|
+
entityId: this.runtime.agentId,
|
|
3053
|
+
agentId: this.runtime.agentId,
|
|
3054
|
+
roomId,
|
|
3055
|
+
content: {
|
|
3056
|
+
...content,
|
|
3057
|
+
text: responseText,
|
|
3058
|
+
source: payload.source,
|
|
3059
|
+
channelType: payload.channelType
|
|
3060
|
+
}
|
|
3061
|
+
});
|
|
3062
|
+
await this.runtime.createMemory(responseMemory, "messages");
|
|
3063
|
+
return [responseMemory];
|
|
3064
|
+
};
|
|
3065
|
+
try {
|
|
3066
|
+
const result = await this.runtime.messageService.handleMessage(this.runtime, message, callback);
|
|
3067
|
+
const replyText = callbackTexts[callbackTexts.length - 1] ?? (typeof result.responseContent?.text === "string" ? result.responseContent.text : undefined);
|
|
3068
|
+
return {
|
|
3069
|
+
jsonrpc: "2.0",
|
|
3070
|
+
id: rpc.id,
|
|
3071
|
+
result: {
|
|
3072
|
+
didRespond: result.didRespond,
|
|
3073
|
+
...replyText ? { text: replyText } : {},
|
|
3074
|
+
runtimeAgentId: this.runtime.agentId
|
|
3075
|
+
}
|
|
3076
|
+
};
|
|
3077
|
+
} catch (error) {
|
|
3078
|
+
return {
|
|
3079
|
+
jsonrpc: "2.0",
|
|
3080
|
+
id: rpc.id,
|
|
3081
|
+
error: {
|
|
3082
|
+
code: -32603,
|
|
3083
|
+
message: error instanceof Error ? error.message : String(error)
|
|
3084
|
+
}
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
// services/cloud-model-registry.ts
|
|
3091
|
+
import { logger as logger18, Service as Service7 } from "@elizaos/core";
|
|
3092
|
+
var CACHE_TTL_MS = 30 * 60 * 1000;
|
|
3093
|
+
var PROVIDER_PREFIXES = [
|
|
3094
|
+
["gpt-", "openai"],
|
|
3095
|
+
["o1", "openai"],
|
|
3096
|
+
["o3", "openai"],
|
|
3097
|
+
["o4", "openai"],
|
|
3098
|
+
["dall-e", "openai"],
|
|
3099
|
+
["whisper", "openai"],
|
|
3100
|
+
["tts", "openai"],
|
|
3101
|
+
["claude-", "anthropic"],
|
|
3102
|
+
["gemini-", "google"],
|
|
3103
|
+
["llama", "meta"],
|
|
3104
|
+
["deepseek", "deepseek"],
|
|
3105
|
+
["grok", "xai"],
|
|
3106
|
+
["kimi", "moonshot"]
|
|
3107
|
+
];
|
|
3108
|
+
function extractProvider(modelId) {
|
|
3109
|
+
if (modelId.includes("/"))
|
|
3110
|
+
return modelId.split("/")[0];
|
|
3111
|
+
const lower = modelId.toLowerCase();
|
|
3112
|
+
for (const [prefix, provider] of PROVIDER_PREFIXES) {
|
|
3113
|
+
if (lower.startsWith(prefix))
|
|
3114
|
+
return provider;
|
|
3115
|
+
}
|
|
3116
|
+
return "unknown";
|
|
3117
|
+
}
|
|
3118
|
+
function stripProvider(modelId) {
|
|
3119
|
+
if (modelId.includes("/")) {
|
|
3120
|
+
return modelId.split("/").slice(1).join("/");
|
|
3121
|
+
}
|
|
3122
|
+
return modelId;
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
class CloudModelRegistryService extends Service7 {
|
|
3126
|
+
static serviceType = "CLOUD_MODEL_REGISTRY";
|
|
3127
|
+
capabilityDescription = "Discovers and caches available AI models from ElizaCloud";
|
|
3128
|
+
models = [];
|
|
3129
|
+
byProvider = {};
|
|
3130
|
+
lastFetchedAt = 0;
|
|
3131
|
+
fetchPromise = null;
|
|
3132
|
+
static async start(runtime) {
|
|
3133
|
+
const service = new CloudModelRegistryService(runtime);
|
|
3134
|
+
await service.initialize();
|
|
3135
|
+
return service;
|
|
3136
|
+
}
|
|
3137
|
+
async stop() {
|
|
3138
|
+
this.models = [];
|
|
3139
|
+
this.byProvider = {};
|
|
3140
|
+
this.lastFetchedAt = 0;
|
|
3141
|
+
}
|
|
3142
|
+
async initialize() {
|
|
3143
|
+
const auth = this.runtime.getService("CLOUD_AUTH");
|
|
3144
|
+
if (!auth?.isAuthenticated()) {
|
|
3145
|
+
logger18.info("[CloudModelRegistry] Auth not available, will fetch models on first access");
|
|
3146
|
+
return;
|
|
3147
|
+
}
|
|
3148
|
+
await this.fetchModels();
|
|
3149
|
+
this.validateConfiguredModels();
|
|
3150
|
+
}
|
|
3151
|
+
async fetchModels() {
|
|
3152
|
+
if (this.fetchPromise) {
|
|
3153
|
+
await this.fetchPromise;
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
this.fetchPromise = this.doFetchModels();
|
|
3157
|
+
await this.fetchPromise;
|
|
3158
|
+
this.fetchPromise = null;
|
|
3159
|
+
}
|
|
3160
|
+
async doFetchModels() {
|
|
3161
|
+
const auth = this.runtime.getService("CLOUD_AUTH");
|
|
3162
|
+
if (!auth?.isAuthenticated())
|
|
3163
|
+
return;
|
|
3164
|
+
const client = auth.getClient();
|
|
3165
|
+
const response = await client.get("/models");
|
|
3166
|
+
const entries = response.data ?? [];
|
|
3167
|
+
this.models = entries.map((entry) => ({
|
|
3168
|
+
id: entry.id,
|
|
3169
|
+
provider: extractProvider(entry.id),
|
|
3170
|
+
name: stripProvider(entry.id),
|
|
3171
|
+
createdAt: entry.created
|
|
3172
|
+
}));
|
|
3173
|
+
this.byProvider = {};
|
|
3174
|
+
for (const model of this.models) {
|
|
3175
|
+
if (!this.byProvider[model.provider]) {
|
|
3176
|
+
this.byProvider[model.provider] = [];
|
|
3177
|
+
}
|
|
3178
|
+
this.byProvider[model.provider].push(model);
|
|
3179
|
+
}
|
|
3180
|
+
this.lastFetchedAt = Date.now();
|
|
3181
|
+
logger18.info(`[CloudModelRegistry] Loaded ${this.models.length} models from ${Object.keys(this.byProvider).length} providers`);
|
|
3182
|
+
}
|
|
3183
|
+
validateConfiguredModels() {
|
|
3184
|
+
if (this.models.length === 0)
|
|
3185
|
+
return;
|
|
3186
|
+
const modelIds = new Set(this.models.map((m) => m.id));
|
|
3187
|
+
const nameSet = new Set(this.models.map((m) => m.name));
|
|
3188
|
+
const settingsToCheck = [
|
|
3189
|
+
{ key: "ELIZAOS_CLOUD_NANO_MODEL", label: "nano model" },
|
|
3190
|
+
{ key: "ELIZAOS_CLOUD_MEDIUM_MODEL", label: "medium model" },
|
|
3191
|
+
{ key: "ELIZAOS_CLOUD_SMALL_MODEL", label: "small model" },
|
|
3192
|
+
{ key: "ELIZAOS_CLOUD_LARGE_MODEL", label: "large model" },
|
|
3193
|
+
{ key: "ELIZAOS_CLOUD_MEGA_MODEL", label: "mega model" },
|
|
3194
|
+
{
|
|
3195
|
+
key: "ELIZAOS_CLOUD_RESPONSE_HANDLER_MODEL",
|
|
3196
|
+
label: "response handler model"
|
|
3197
|
+
},
|
|
3198
|
+
{
|
|
3199
|
+
key: "ELIZAOS_CLOUD_ACTION_PLANNER_MODEL",
|
|
3200
|
+
label: "action planner model"
|
|
3201
|
+
},
|
|
3202
|
+
{ key: "ELIZAOS_CLOUD_RESPONSE_MODEL", label: "response model" },
|
|
3203
|
+
{ key: "ELIZAOS_CLOUD_RESEARCH_MODEL", label: "research model" },
|
|
3204
|
+
{ key: "ELIZAOS_CLOUD_EMBEDDING_MODEL", label: "embedding model" },
|
|
3205
|
+
{
|
|
3206
|
+
key: "ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MODEL",
|
|
3207
|
+
label: "image description model"
|
|
3208
|
+
},
|
|
3209
|
+
{
|
|
3210
|
+
key: "ELIZAOS_CLOUD_IMAGE_GENERATION_MODEL",
|
|
3211
|
+
label: "image generation model"
|
|
3212
|
+
},
|
|
3213
|
+
{ key: "ELIZAOS_CLOUD_TTS_MODEL", label: "TTS model" },
|
|
3214
|
+
{
|
|
3215
|
+
key: "ELIZAOS_CLOUD_TRANSCRIPTION_MODEL",
|
|
3216
|
+
label: "transcription model"
|
|
3217
|
+
}
|
|
3218
|
+
];
|
|
3219
|
+
for (const { key, label } of settingsToCheck) {
|
|
3220
|
+
const value = this.runtime.getSetting(key);
|
|
3221
|
+
if (value && typeof value === "string") {
|
|
3222
|
+
const found = modelIds.has(value) || nameSet.has(value);
|
|
3223
|
+
if (!found) {
|
|
3224
|
+
logger18.warn(`[CloudModelRegistry] Configured ${label} "${value}" not found in available models. ` + "It may still work if the gateway supports it, but check your configuration.");
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
async getAvailableModels() {
|
|
3230
|
+
if (Date.now() - this.lastFetchedAt > CACHE_TTL_MS) {
|
|
3231
|
+
await this.fetchModels();
|
|
3232
|
+
}
|
|
3233
|
+
return this.models;
|
|
3234
|
+
}
|
|
3235
|
+
async getModelsByProvider() {
|
|
3236
|
+
if (Date.now() - this.lastFetchedAt > CACHE_TTL_MS) {
|
|
3237
|
+
await this.fetchModels();
|
|
3238
|
+
}
|
|
3239
|
+
return this.byProvider;
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
|
|
1967
3243
|
// index.ts
|
|
3244
|
+
var TEXT_NANO_MODEL_TYPE2 = ModelType6.TEXT_NANO ?? "TEXT_NANO";
|
|
3245
|
+
var TEXT_MEDIUM_MODEL_TYPE2 = ModelType6.TEXT_MEDIUM ?? "TEXT_MEDIUM";
|
|
3246
|
+
var TEXT_MEGA_MODEL_TYPE2 = ModelType6.TEXT_MEGA ?? "TEXT_MEGA";
|
|
3247
|
+
var RESPONSE_HANDLER_MODEL_TYPE2 = ModelType6.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
|
|
3248
|
+
var ACTION_PLANNER_MODEL_TYPE2 = ModelType6.ACTION_PLANNER ?? "ACTION_PLANNER";
|
|
1968
3249
|
function getProcessEnv() {
|
|
1969
3250
|
if (typeof process === "undefined") {
|
|
1970
3251
|
return {};
|
|
@@ -1979,38 +3260,77 @@ var elizaOSCloudPlugin = {
|
|
|
1979
3260
|
ELIZAOS_CLOUD_API_KEY: env.ELIZAOS_CLOUD_API_KEY ?? null,
|
|
1980
3261
|
ELIZAOS_CLOUD_BASE_URL: env.ELIZAOS_CLOUD_BASE_URL ?? null,
|
|
1981
3262
|
ELIZAOS_CLOUD_ENABLED: env.ELIZAOS_CLOUD_ENABLED ?? null,
|
|
3263
|
+
ELIZAOS_CLOUD_NANO_MODEL: env.ELIZAOS_CLOUD_NANO_MODEL ?? null,
|
|
3264
|
+
ELIZAOS_CLOUD_MEDIUM_MODEL: env.ELIZAOS_CLOUD_MEDIUM_MODEL ?? null,
|
|
1982
3265
|
ELIZAOS_CLOUD_SMALL_MODEL: env.ELIZAOS_CLOUD_SMALL_MODEL ?? null,
|
|
1983
3266
|
ELIZAOS_CLOUD_LARGE_MODEL: env.ELIZAOS_CLOUD_LARGE_MODEL ?? null,
|
|
3267
|
+
ELIZAOS_CLOUD_MEGA_MODEL: env.ELIZAOS_CLOUD_MEGA_MODEL ?? null,
|
|
3268
|
+
ELIZAOS_CLOUD_RESPONSE_HANDLER_MODEL: env.ELIZAOS_CLOUD_RESPONSE_HANDLER_MODEL ?? null,
|
|
3269
|
+
ELIZAOS_CLOUD_SHOULD_RESPOND_MODEL: env.ELIZAOS_CLOUD_SHOULD_RESPOND_MODEL ?? null,
|
|
3270
|
+
ELIZAOS_CLOUD_ACTION_PLANNER_MODEL: env.ELIZAOS_CLOUD_ACTION_PLANNER_MODEL ?? null,
|
|
3271
|
+
ELIZAOS_CLOUD_PLANNER_MODEL: env.ELIZAOS_CLOUD_PLANNER_MODEL ?? null,
|
|
3272
|
+
ELIZAOS_CLOUD_RESPONSE_MODEL: env.ELIZAOS_CLOUD_RESPONSE_MODEL ?? null,
|
|
3273
|
+
NANO_MODEL: env.NANO_MODEL ?? null,
|
|
3274
|
+
MEDIUM_MODEL: env.MEDIUM_MODEL ?? null,
|
|
1984
3275
|
SMALL_MODEL: env.SMALL_MODEL ?? null,
|
|
1985
3276
|
LARGE_MODEL: env.LARGE_MODEL ?? null,
|
|
3277
|
+
MEGA_MODEL: env.MEGA_MODEL ?? null,
|
|
3278
|
+
RESPONSE_HANDLER_MODEL: env.RESPONSE_HANDLER_MODEL ?? null,
|
|
3279
|
+
SHOULD_RESPOND_MODEL: env.SHOULD_RESPOND_MODEL ?? null,
|
|
3280
|
+
ACTION_PLANNER_MODEL: env.ACTION_PLANNER_MODEL ?? null,
|
|
3281
|
+
PLANNER_MODEL: env.PLANNER_MODEL ?? null,
|
|
3282
|
+
RESPONSE_MODEL: env.RESPONSE_MODEL ?? null,
|
|
3283
|
+
ELIZAOS_CLOUD_RESEARCH_MODEL: env.ELIZAOS_CLOUD_RESEARCH_MODEL ?? null,
|
|
3284
|
+
RESEARCH_MODEL: env.RESEARCH_MODEL ?? null,
|
|
1986
3285
|
ELIZAOS_CLOUD_EMBEDDING_MODEL: env.ELIZAOS_CLOUD_EMBEDDING_MODEL ?? null,
|
|
1987
3286
|
ELIZAOS_CLOUD_EMBEDDING_API_KEY: env.ELIZAOS_CLOUD_EMBEDDING_API_KEY ?? null,
|
|
1988
3287
|
ELIZAOS_CLOUD_EMBEDDING_URL: env.ELIZAOS_CLOUD_EMBEDDING_URL ?? null,
|
|
1989
3288
|
ELIZAOS_CLOUD_EMBEDDING_DIMENSIONS: env.ELIZAOS_CLOUD_EMBEDDING_DIMENSIONS ?? null,
|
|
1990
3289
|
ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MODEL: env.ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MODEL ?? null,
|
|
1991
3290
|
ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MAX_TOKENS: env.ELIZAOS_CLOUD_IMAGE_DESCRIPTION_MAX_TOKENS ?? null,
|
|
1992
|
-
|
|
1993
|
-
|
|
3291
|
+
ELIZAOS_CLOUD_IMAGE_GENERATION_MODEL: env.ELIZAOS_CLOUD_IMAGE_GENERATION_MODEL ?? null,
|
|
3292
|
+
ELIZAOS_CLOUD_TTS_MODEL: env.ELIZAOS_CLOUD_TTS_MODEL ?? null,
|
|
3293
|
+
ELIZAOS_CLOUD_TRANSCRIPTION_MODEL: env.ELIZAOS_CLOUD_TRANSCRIPTION_MODEL ?? null,
|
|
3294
|
+
ELIZAOS_CLOUD_EXPERIMENTAL_TELEMETRY: env.ELIZAOS_CLOUD_EXPERIMENTAL_TELEMETRY ?? null
|
|
1994
3295
|
},
|
|
1995
3296
|
async init(config, runtime) {
|
|
1996
3297
|
initializeOpenAI(config, runtime);
|
|
1997
3298
|
},
|
|
1998
|
-
services: [
|
|
3299
|
+
services: [
|
|
3300
|
+
CloudAuthService,
|
|
3301
|
+
CloudBootstrapServiceImpl,
|
|
3302
|
+
CloudManagedGatewayRelayService,
|
|
3303
|
+
CloudModelRegistryService,
|
|
3304
|
+
CloudContainerService,
|
|
3305
|
+
CloudBridgeService,
|
|
3306
|
+
CloudBackupService
|
|
3307
|
+
],
|
|
1999
3308
|
actions: [
|
|
2000
3309
|
provisionCloudAgentAction,
|
|
2001
3310
|
freezeCloudAgentAction,
|
|
2002
3311
|
resumeCloudAgentAction,
|
|
2003
3312
|
checkCloudCreditsAction
|
|
2004
3313
|
],
|
|
2005
|
-
providers: [
|
|
3314
|
+
providers: [
|
|
3315
|
+
cloudStatusProvider,
|
|
3316
|
+
creditBalanceProvider,
|
|
3317
|
+
containerHealthProvider,
|
|
3318
|
+
modelRegistryProvider
|
|
3319
|
+
],
|
|
2006
3320
|
models: {
|
|
2007
|
-
[
|
|
2008
|
-
[
|
|
2009
|
-
[
|
|
2010
|
-
[
|
|
2011
|
-
[
|
|
2012
|
-
[
|
|
2013
|
-
[
|
|
3321
|
+
[ModelType6.TEXT_EMBEDDING]: handleTextEmbedding,
|
|
3322
|
+
[TEXT_NANO_MODEL_TYPE2]: handleTextNano,
|
|
3323
|
+
[TEXT_MEDIUM_MODEL_TYPE2]: handleTextMedium,
|
|
3324
|
+
[ModelType6.TEXT_SMALL]: handleTextSmall,
|
|
3325
|
+
[ModelType6.TEXT_LARGE]: handleTextLarge,
|
|
3326
|
+
[TEXT_MEGA_MODEL_TYPE2]: handleTextMega,
|
|
3327
|
+
[RESPONSE_HANDLER_MODEL_TYPE2]: handleResponseHandler,
|
|
3328
|
+
[ACTION_PLANNER_MODEL_TYPE2]: handleActionPlanner,
|
|
3329
|
+
[ModelType6.RESEARCH]: handleResearch,
|
|
3330
|
+
[ModelType6.IMAGE]: handleImageGeneration,
|
|
3331
|
+
[ModelType6.IMAGE_DESCRIPTION]: handleImageDescription,
|
|
3332
|
+
[ModelType6.OBJECT_SMALL]: handleObjectSmall,
|
|
3333
|
+
[ModelType6.OBJECT_LARGE]: handleObjectLarge
|
|
2014
3334
|
},
|
|
2015
3335
|
tests: [
|
|
2016
3336
|
{
|
|
@@ -2019,118 +3339,109 @@ var elizaOSCloudPlugin = {
|
|
|
2019
3339
|
{
|
|
2020
3340
|
name: "ELIZAOS_CLOUD_test_url_and_api_key_validation",
|
|
2021
3341
|
fn: async (runtime) => {
|
|
2022
|
-
const
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
Authorization: `Bearer ${getApiKey(runtime)}`
|
|
2026
|
-
}
|
|
2027
|
-
});
|
|
2028
|
-
const data = await response.json();
|
|
2029
|
-
logger16.log({
|
|
2030
|
-
data: data?.data?.length ?? "N/A"
|
|
3342
|
+
const data = await createCloudApiClient(runtime).get("/models");
|
|
3343
|
+
logger19.log({
|
|
3344
|
+
data: data.data?.length ?? "N/A"
|
|
2031
3345
|
}, "Models Available");
|
|
2032
|
-
if (!response.ok) {
|
|
2033
|
-
throw new Error(`Failed to validate OpenAI API key: ${response.statusText}`);
|
|
2034
|
-
}
|
|
2035
3346
|
}
|
|
2036
3347
|
},
|
|
2037
3348
|
{
|
|
2038
3349
|
name: "ELIZAOS_CLOUD_test_text_embedding",
|
|
2039
3350
|
fn: async (runtime) => {
|
|
2040
|
-
const embedding = await runtime.useModel(
|
|
3351
|
+
const embedding = await runtime.useModel(ModelType6.TEXT_EMBEDDING, {
|
|
2041
3352
|
text: "Hello, world!"
|
|
2042
3353
|
});
|
|
2043
|
-
|
|
3354
|
+
logger19.log({ embedding }, "embedding");
|
|
2044
3355
|
}
|
|
2045
3356
|
},
|
|
2046
3357
|
{
|
|
2047
3358
|
name: "ELIZAOS_CLOUD_test_text_large",
|
|
2048
3359
|
fn: async (runtime) => {
|
|
2049
|
-
const text = await runtime.useModel(
|
|
3360
|
+
const text = await runtime.useModel(ModelType6.TEXT_LARGE, {
|
|
2050
3361
|
prompt: "What is the nature of reality in 10 words?"
|
|
2051
3362
|
});
|
|
2052
3363
|
if (text.length === 0) {
|
|
2053
3364
|
throw new Error("Failed to generate text");
|
|
2054
3365
|
}
|
|
2055
|
-
|
|
3366
|
+
logger19.log({ text }, "generated with test_text_large");
|
|
2056
3367
|
}
|
|
2057
3368
|
},
|
|
2058
3369
|
{
|
|
2059
3370
|
name: "ELIZAOS_CLOUD_test_text_small",
|
|
2060
3371
|
fn: async (runtime) => {
|
|
2061
|
-
const text = await runtime.useModel(
|
|
3372
|
+
const text = await runtime.useModel(ModelType6.TEXT_SMALL, {
|
|
2062
3373
|
prompt: "What is the nature of reality in 10 words?"
|
|
2063
3374
|
});
|
|
2064
3375
|
if (text.length === 0) {
|
|
2065
3376
|
throw new Error("Failed to generate text");
|
|
2066
3377
|
}
|
|
2067
|
-
|
|
3378
|
+
logger19.log({ text }, "generated with test_text_small");
|
|
2068
3379
|
}
|
|
2069
3380
|
},
|
|
2070
3381
|
{
|
|
2071
3382
|
name: "ELIZAOS_CLOUD_test_image_generation",
|
|
2072
3383
|
fn: async (runtime) => {
|
|
2073
|
-
|
|
2074
|
-
const image = await runtime.useModel(
|
|
3384
|
+
logger19.log("ELIZAOS_CLOUD_test_image_generation");
|
|
3385
|
+
const image = await runtime.useModel(ModelType6.IMAGE, {
|
|
2075
3386
|
prompt: "A beautiful sunset over a calm ocean",
|
|
2076
3387
|
count: 1,
|
|
2077
3388
|
size: "1024x1024"
|
|
2078
3389
|
});
|
|
2079
|
-
|
|
3390
|
+
logger19.log({ image }, "generated with test_image_generation");
|
|
2080
3391
|
}
|
|
2081
3392
|
},
|
|
2082
3393
|
{
|
|
2083
3394
|
name: "image-description",
|
|
2084
3395
|
fn: async (runtime) => {
|
|
2085
|
-
|
|
2086
|
-
const result = await runtime.useModel(
|
|
3396
|
+
logger19.log("ELIZAOS_CLOUD_test_image_description");
|
|
3397
|
+
const result = await runtime.useModel(ModelType6.IMAGE_DESCRIPTION, "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg/537px-Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg");
|
|
2087
3398
|
if (result && typeof result === "object" && "title" in result && "description" in result) {
|
|
2088
|
-
|
|
3399
|
+
logger19.log({ result }, "Image description");
|
|
2089
3400
|
} else {
|
|
2090
|
-
|
|
3401
|
+
logger19.error(`Invalid image description result format: ${JSON.stringify(result)}`);
|
|
2091
3402
|
}
|
|
2092
3403
|
}
|
|
2093
3404
|
},
|
|
2094
3405
|
{
|
|
2095
3406
|
name: "ELIZAOS_CLOUD_test_transcription",
|
|
2096
3407
|
fn: async (runtime) => {
|
|
2097
|
-
|
|
3408
|
+
logger19.log("ELIZAOS_CLOUD_test_transcription");
|
|
2098
3409
|
const response = await fetch("https://upload.wikimedia.org/wikipedia/en/4/40/Chris_Benoit_Voice_Message.ogg");
|
|
2099
3410
|
const arrayBuffer = await response.arrayBuffer();
|
|
2100
|
-
const transcription = await runtime.useModel(
|
|
2101
|
-
|
|
3411
|
+
const transcription = await runtime.useModel(ModelType6.TRANSCRIPTION, Buffer.from(new Uint8Array(arrayBuffer)));
|
|
3412
|
+
logger19.log({ transcription }, "generated with test_transcription");
|
|
2102
3413
|
}
|
|
2103
3414
|
},
|
|
2104
3415
|
{
|
|
2105
3416
|
name: "ELIZAOS_CLOUD_test_text_tokenizer_encode",
|
|
2106
3417
|
fn: async (runtime) => {
|
|
2107
3418
|
const prompt = "Hello tokenizer encode!";
|
|
2108
|
-
const tokens = await runtime.useModel(
|
|
3419
|
+
const tokens = await runtime.useModel(ModelType6.TEXT_TOKENIZER_ENCODE, {
|
|
2109
3420
|
prompt,
|
|
2110
|
-
modelType:
|
|
3421
|
+
modelType: ModelType6.TEXT_SMALL
|
|
2111
3422
|
});
|
|
2112
3423
|
if (!Array.isArray(tokens) || tokens.length === 0) {
|
|
2113
3424
|
throw new Error("Failed to tokenize text: expected non-empty array of tokens");
|
|
2114
3425
|
}
|
|
2115
|
-
|
|
3426
|
+
logger19.log({ tokens }, "Tokenized output");
|
|
2116
3427
|
}
|
|
2117
3428
|
},
|
|
2118
3429
|
{
|
|
2119
3430
|
name: "ELIZAOS_CLOUD_test_text_tokenizer_decode",
|
|
2120
3431
|
fn: async (runtime) => {
|
|
2121
3432
|
const prompt = "Hello tokenizer decode!";
|
|
2122
|
-
const tokens = await runtime.useModel(
|
|
3433
|
+
const tokens = await runtime.useModel(ModelType6.TEXT_TOKENIZER_ENCODE, {
|
|
2123
3434
|
prompt,
|
|
2124
|
-
modelType:
|
|
3435
|
+
modelType: ModelType6.TEXT_SMALL
|
|
2125
3436
|
});
|
|
2126
|
-
const decodedText = await runtime.useModel(
|
|
3437
|
+
const decodedText = await runtime.useModel(ModelType6.TEXT_TOKENIZER_DECODE, {
|
|
2127
3438
|
tokens,
|
|
2128
|
-
modelType:
|
|
3439
|
+
modelType: ModelType6.TEXT_SMALL
|
|
2129
3440
|
});
|
|
2130
3441
|
if (decodedText !== prompt) {
|
|
2131
3442
|
throw new Error(`Decoded text does not match original. Expected "${prompt}", got "${decodedText}"`);
|
|
2132
3443
|
}
|
|
2133
|
-
|
|
3444
|
+
logger19.log({ decodedText }, "Decoded text");
|
|
2134
3445
|
}
|
|
2135
3446
|
},
|
|
2136
3447
|
{
|
|
@@ -2142,17 +3453,20 @@ var elizaOSCloudPlugin = {
|
|
|
2142
3453
|
if (!response) {
|
|
2143
3454
|
throw new Error("Failed to generate speech");
|
|
2144
3455
|
}
|
|
2145
|
-
|
|
3456
|
+
logger19.log("Generated speech successfully");
|
|
2146
3457
|
}
|
|
2147
3458
|
}
|
|
2148
3459
|
]
|
|
2149
3460
|
}
|
|
2150
3461
|
]
|
|
2151
3462
|
};
|
|
2152
|
-
var
|
|
3463
|
+
var plugin_elizacloud_default = elizaOSCloudPlugin;
|
|
3464
|
+
|
|
3465
|
+
// index.node.ts
|
|
3466
|
+
var index_node_default = plugin_elizacloud_default;
|
|
2153
3467
|
export {
|
|
2154
3468
|
elizaOSCloudPlugin,
|
|
2155
|
-
|
|
3469
|
+
index_node_default as default
|
|
2156
3470
|
};
|
|
2157
3471
|
|
|
2158
|
-
//# debugId=
|
|
3472
|
+
//# debugId=6243C8A3ED6780E664756E2164756E21
|