miladyai 2.0.0-alpha.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +7 -0
- package/dist/actions/emote.js +64 -0
- package/dist/actions/restart.js +81 -0
- package/dist/actions/send-message.js +152 -0
- package/dist/agent-admin-routes.js +82 -0
- package/dist/agent-lifecycle-routes.js +79 -0
- package/dist/agent-transfer-routes.js +102 -0
- package/dist/api/agent-admin-routes.js +82 -0
- package/dist/api/agent-lifecycle-routes.js +79 -0
- package/dist/api/agent-transfer-routes.js +102 -0
- package/dist/api/apps-hyperscape-routes.js +58 -0
- package/dist/api/apps-routes.js +114 -0
- package/dist/api/auth-routes.js +56 -0
- package/dist/api/autonomy-routes.js +44 -0
- package/dist/api/bug-report-routes.js +111 -0
- package/dist/api/character-routes.js +195 -0
- package/dist/api/cloud-routes.js +330 -0
- package/dist/api/cloud-status-routes.js +155 -0
- package/dist/api/compat-utils.js +111 -0
- package/dist/api/database.js +735 -0
- package/dist/api/diagnostics-routes.js +205 -0
- package/dist/api/drop-service.js +134 -0
- package/dist/api/early-logs.js +86 -0
- package/dist/api/http-helpers.js +131 -0
- package/dist/api/knowledge-routes.js +534 -0
- package/dist/api/memory-bounds.js +71 -0
- package/dist/api/models-routes.js +28 -0
- package/dist/api/og-tracker.js +36 -0
- package/dist/api/permissions-routes.js +109 -0
- package/dist/api/plugin-validation.js +198 -0
- package/dist/api/provider-switch-config.js +41 -0
- package/dist/api/registry-routes.js +86 -0
- package/dist/api/registry-service.js +164 -0
- package/dist/api/sandbox-routes.js +1112 -0
- package/dist/api/server.js +7949 -0
- package/dist/api/subscription-routes.js +172 -0
- package/dist/api/terminal-run-limits.js +24 -0
- package/dist/api/training-routes.js +158 -0
- package/dist/api/trajectory-routes.js +300 -0
- package/dist/api/trigger-routes.js +246 -0
- package/dist/api/twitter-verify.js +134 -0
- package/dist/api/tx-service.js +108 -0
- package/dist/api/wallet-routes.js +266 -0
- package/dist/api/wallet.js +568 -0
- package/dist/api/whatsapp-routes.js +182 -0
- package/dist/api/zip-utils.js +109 -0
- package/dist/apps-hyperscape-routes.js +58 -0
- package/dist/apps-routes.js +114 -0
- package/dist/ascii.js +20 -0
- package/dist/auth/anthropic.js +44 -0
- package/dist/auth/apply-stealth.js +41 -0
- package/dist/auth/claude-code-stealth.js +78 -0
- package/dist/auth/credentials.js +156 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/openai-codex.js +66 -0
- package/dist/auth/types.js +9 -0
- package/dist/auth-routes.js +56 -0
- package/dist/autonomy-routes.js +44 -0
- package/dist/bug-report-routes.js +111 -0
- package/dist/build-info.json +6 -0
- package/dist/character-routes.js +195 -0
- package/dist/cli/argv.js +63 -0
- package/dist/cli/banner.js +34 -0
- package/dist/cli/cli-name.js +21 -0
- package/dist/cli/cli-utils.js +16 -0
- package/dist/cli/git-commit.js +78 -0
- package/dist/cli/parse-duration.js +15 -0
- package/dist/cli/plugins-cli.js +590 -0
- package/dist/cli/profile-utils.js +9 -0
- package/dist/cli/profile.js +95 -0
- package/dist/cli/program/build-program.js +17 -0
- package/dist/cli/program/command-registry.js +23 -0
- package/dist/cli/program/help.js +47 -0
- package/dist/cli/program/preaction.js +33 -0
- package/dist/cli/program/register.config.js +106 -0
- package/dist/cli/program/register.configure.js +20 -0
- package/dist/cli/program/register.dashboard.js +124 -0
- package/dist/cli/program/register.models.js +23 -0
- package/dist/cli/program/register.setup.js +36 -0
- package/dist/cli/program/register.start.js +22 -0
- package/dist/cli/program/register.subclis.js +70 -0
- package/dist/cli/program/register.tui.js +163 -0
- package/dist/cli/program/register.update.js +154 -0
- package/dist/cli/program.js +3 -0
- package/dist/cli/run-main.js +37 -0
- package/dist/cli/version.js +7 -0
- package/dist/cloud/validate-url.js +93 -0
- package/dist/cloud-routes.js +330 -0
- package/dist/cloud-status-routes.js +155 -0
- package/dist/compat-utils.js +111 -0
- package/dist/config/config.js +69 -0
- package/dist/config/env-vars.js +19 -0
- package/dist/config/includes.js +121 -0
- package/dist/config/object-utils.js +7 -0
- package/dist/config/paths.js +38 -0
- package/dist/config/plugin-auto-enable.js +231 -0
- package/dist/config/schema.js +864 -0
- package/dist/config/telegram-custom-commands.js +76 -0
- package/dist/config/zod-schema.agent-runtime.js +519 -0
- package/dist/config/zod-schema.core.js +538 -0
- package/dist/config/zod-schema.hooks.js +103 -0
- package/dist/config/zod-schema.js +488 -0
- package/dist/config/zod-schema.providers-core.js +785 -0
- package/dist/config/zod-schema.session.js +73 -0
- package/dist/core-plugins.js +37 -0
- package/dist/custom-actions.js +250 -0
- package/dist/database.js +735 -0
- package/dist/diagnostics/integration-observability.js +57 -0
- package/dist/diagnostics-routes.js +205 -0
- package/dist/drop-service.js +134 -0
- package/dist/early-logs.js +24 -0
- package/dist/eliza.js +2061 -0
- package/dist/emotes/catalog.js +271 -0
- package/dist/entry.js +40 -0
- package/dist/hooks/discovery.js +167 -0
- package/dist/hooks/eligibility.js +64 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/loader.js +147 -0
- package/dist/hooks/registry.js +55 -0
- package/dist/http-helpers.js +131 -0
- package/dist/index.js +49 -0
- package/dist/knowledge-routes.js +534 -0
- package/dist/memory-bounds.js +71 -0
- package/dist/milady-plugin.js +90 -0
- package/dist/models-routes.js +28 -0
- package/dist/onboarding-names.js +78 -0
- package/dist/onboarding-presets.js +922 -0
- package/dist/package.json +1 -0
- package/dist/permissions-routes.js +109 -0
- package/dist/plugin-validation.js +107 -0
- package/dist/plugins/whatsapp/actions.js +91 -0
- package/dist/plugins/whatsapp/index.js +16 -0
- package/dist/plugins/whatsapp/service.js +270 -0
- package/dist/provider-switch-config.js +41 -0
- package/dist/providers/admin-trust.js +46 -0
- package/dist/providers/autonomous-state.js +101 -0
- package/dist/providers/session-bridge.js +86 -0
- package/dist/providers/session-utils.js +36 -0
- package/dist/providers/simple-mode.js +50 -0
- package/dist/providers/ui-catalog.js +15 -0
- package/dist/providers/workspace-provider.js +93 -0
- package/dist/providers/workspace.js +348 -0
- package/dist/registry-routes.js +86 -0
- package/dist/registry-service.js +164 -0
- package/dist/restart.js +40 -0
- package/dist/runtime/core-plugins.js +37 -0
- package/dist/runtime/custom-actions.js +250 -0
- package/dist/runtime/eliza.js +2061 -0
- package/dist/runtime/embedding-manager-support.js +185 -0
- package/dist/runtime/embedding-manager.js +193 -0
- package/dist/runtime/embedding-presets.js +54 -0
- package/dist/runtime/embedding-state.js +8 -0
- package/dist/runtime/milady-plugin.js +90 -0
- package/dist/runtime/onboarding-names.js +78 -0
- package/dist/runtime/restart.js +40 -0
- package/dist/runtime/version.js +7 -0
- package/dist/sandbox-routes.js +1112 -0
- package/dist/security/audit-log.js +149 -0
- package/dist/security/network-policy.js +70 -0
- package/dist/server.js +7949 -0
- package/dist/services/agent-export.js +559 -0
- package/dist/services/app-manager.js +389 -0
- package/dist/services/browser-capture.js +86 -0
- package/dist/services/fallback-training-service.js +128 -0
- package/dist/services/mcp-marketplace.js +134 -0
- package/dist/services/plugin-installer.js +396 -0
- package/dist/services/plugin-manager-types.js +15 -0
- package/dist/services/registry-client-app-meta.js +144 -0
- package/dist/services/registry-client-endpoints.js +166 -0
- package/dist/services/registry-client-local.js +271 -0
- package/dist/services/registry-client-network.js +93 -0
- package/dist/services/registry-client-queries.js +70 -0
- package/dist/services/registry-client.js +157 -0
- package/dist/services/sandbox-engine.js +511 -0
- package/dist/services/sandbox-manager.js +297 -0
- package/dist/services/self-updater.js +175 -0
- package/dist/services/skill-catalog-client.js +119 -0
- package/dist/services/skill-marketplace.js +521 -0
- package/dist/services/stream-manager.js +236 -0
- package/dist/services/update-checker.js +121 -0
- package/dist/services/update-notifier.js +29 -0
- package/dist/services/version-compat.js +78 -0
- package/dist/services/whatsapp-pairing.js +196 -0
- package/dist/shared/ui-catalog-prompt.js +728 -0
- package/dist/subscription-routes.js +172 -0
- package/dist/terminal/links.js +19 -0
- package/dist/terminal/palette.js +14 -0
- package/dist/terminal/theme.js +25 -0
- package/dist/terminal-run-limits.js +24 -0
- package/dist/training-routes.js +158 -0
- package/dist/trajectory-routes.js +300 -0
- package/dist/trigger-routes.js +246 -0
- package/dist/triggers/action.js +218 -0
- package/dist/triggers/runtime.js +281 -0
- package/dist/triggers/scheduling.js +295 -0
- package/dist/triggers/types.js +5 -0
- package/dist/tui/components/assistant-message.js +76 -0
- package/dist/tui/components/chat-editor.js +34 -0
- package/dist/tui/components/embeddings-overlay.js +46 -0
- package/dist/tui/components/footer.js +60 -0
- package/dist/tui/components/index.js +15 -0
- package/dist/tui/components/modal-frame.js +45 -0
- package/dist/tui/components/modal-style.js +15 -0
- package/dist/tui/components/model-selector.js +70 -0
- package/dist/tui/components/pinned-chat-layout.js +46 -0
- package/dist/tui/components/plugins-endpoints-tab.js +196 -0
- package/dist/tui/components/plugins-installed-tab-view.js +69 -0
- package/dist/tui/components/plugins-installed-tab.js +319 -0
- package/dist/tui/components/plugins-overlay-catalog.js +81 -0
- package/dist/tui/components/plugins-overlay-data-api.js +21 -0
- package/dist/tui/components/plugins-overlay-data-shared.js +20 -0
- package/dist/tui/components/plugins-overlay-data.js +323 -0
- package/dist/tui/components/plugins-overlay.js +117 -0
- package/dist/tui/components/plugins-store-tab.js +148 -0
- package/dist/tui/components/settings-overlay.js +61 -0
- package/dist/tui/components/status-bar.js +64 -0
- package/dist/tui/components/tool-execution.js +68 -0
- package/dist/tui/components/user-message.js +22 -0
- package/dist/tui/eliza-tui-bridge.js +606 -0
- package/dist/tui/index.js +370 -0
- package/dist/tui/modal-presets.js +33 -0
- package/dist/tui/model-spec.js +46 -0
- package/dist/tui/sse-parser.js +78 -0
- package/dist/tui/theme.js +110 -0
- package/dist/tui/titlebar-spinner.js +62 -0
- package/dist/tui/tui-app.js +311 -0
- package/dist/tui/ws-client.js +215 -0
- package/dist/twitter-verify.js +134 -0
- package/dist/tx-service.js +108 -0
- package/dist/utils/exec-safety.js +17 -0
- package/dist/utils/globals.js +20 -0
- package/dist/utils/milady-root.js +61 -0
- package/dist/utils/number-parsing.js +37 -0
- package/dist/version-resolver.js +37 -0
- package/dist/version.js +7 -0
- package/dist/wallet-routes.js +266 -0
- package/dist/wallet.js +568 -0
- package/dist/whatsapp-routes.js +182 -0
- package/dist/zip-utils.js +109 -0
- package/milady.mjs +14 -0
- package/package.json +111 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
import { logger } from "@elizaos/core";
|
|
2
|
+
import * as crypto$1 from "node:crypto";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
import { createGunzip, gzipSync } from "node:zlib";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/services/agent-export.ts
|
|
8
|
+
/**
|
|
9
|
+
* Agent Export/Import Service
|
|
10
|
+
*
|
|
11
|
+
* Provides encrypted, portable agent archives for migrating agents between
|
|
12
|
+
* machines. Captures all database state (character, memories, entities,
|
|
13
|
+
* relationships, rooms, participants, worlds, tasks, and optionally logs)
|
|
14
|
+
* into a single password-encrypted binary file (.eliza-agent).
|
|
15
|
+
*
|
|
16
|
+
* Encryption: PBKDF2-SHA256 key derivation + AES-256-GCM
|
|
17
|
+
* Compression: gzip
|
|
18
|
+
*
|
|
19
|
+
* File format (binary):
|
|
20
|
+
* ELIZA_AGENT_V1\n (15 bytes magic header)
|
|
21
|
+
* iterations (4 bytes uint32 BE — PBKDF2 iteration count)
|
|
22
|
+
* salt (32 bytes — PBKDF2 salt)
|
|
23
|
+
* iv (12 bytes — AES-256-GCM nonce)
|
|
24
|
+
* tag (16 bytes — AES-GCM authentication tag)
|
|
25
|
+
* ciphertext (variable — gzip-compressed JSON, encrypted)
|
|
26
|
+
*/
|
|
27
|
+
const MAGIC_BYTES = Buffer.from("ELIZA_AGENT_V1\n", "utf-8");
|
|
28
|
+
const PBKDF2_ITERATIONS = 6e5;
|
|
29
|
+
const MAX_PBKDF2_ITERATIONS = 12e5;
|
|
30
|
+
const SALT_LEN = 32;
|
|
31
|
+
const IV_LEN = 12;
|
|
32
|
+
const TAG_LEN = 16;
|
|
33
|
+
const KEY_LEN = 32;
|
|
34
|
+
const MIN_PASSWORD_LENGTH = 4;
|
|
35
|
+
const HEADER_SIZE = MAGIC_BYTES.length + 4 + SALT_LEN + IV_LEN + TAG_LEN;
|
|
36
|
+
const EXPORT_VERSION = 1;
|
|
37
|
+
const MAX_IMPORT_DECOMPRESSED_BYTES = 16 * 1024 * 1024;
|
|
38
|
+
const MEMORY_TABLES = [
|
|
39
|
+
"messages",
|
|
40
|
+
"facts",
|
|
41
|
+
"documents",
|
|
42
|
+
"fragments",
|
|
43
|
+
"descriptions",
|
|
44
|
+
"character_modifications",
|
|
45
|
+
"custom"
|
|
46
|
+
];
|
|
47
|
+
const IdRecord = z.record(z.string(), z.unknown()).and(z.object({ id: z.string() }));
|
|
48
|
+
const IdRecordArray = z.array(IdRecord);
|
|
49
|
+
const LooseRecordArray = z.array(z.record(z.string(), z.unknown()));
|
|
50
|
+
const PayloadSchema = z.object({
|
|
51
|
+
version: z.number().int().min(1),
|
|
52
|
+
exportedAt: z.string(),
|
|
53
|
+
sourceAgentId: z.string(),
|
|
54
|
+
agent: z.record(z.string(), z.unknown()),
|
|
55
|
+
characterConfig: z.record(z.string(), z.unknown()).optional(),
|
|
56
|
+
entities: IdRecordArray,
|
|
57
|
+
memories: IdRecordArray,
|
|
58
|
+
components: IdRecordArray,
|
|
59
|
+
rooms: IdRecordArray,
|
|
60
|
+
participants: z.array(z.object({
|
|
61
|
+
entityId: z.string(),
|
|
62
|
+
roomId: z.string(),
|
|
63
|
+
userState: z.string().nullable()
|
|
64
|
+
})),
|
|
65
|
+
relationships: IdRecordArray,
|
|
66
|
+
worlds: IdRecordArray,
|
|
67
|
+
tasks: IdRecordArray,
|
|
68
|
+
logs: LooseRecordArray
|
|
69
|
+
});
|
|
70
|
+
function deriveKey(password, salt, iterations) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
crypto$1.pbkdf2(password, salt, iterations, KEY_LEN, "sha256", (err, key) => {
|
|
73
|
+
if (err) reject(err);
|
|
74
|
+
else resolve(key);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async function encrypt(plaintext, password) {
|
|
79
|
+
const salt = crypto$1.randomBytes(SALT_LEN);
|
|
80
|
+
const iv = crypto$1.randomBytes(IV_LEN);
|
|
81
|
+
const key = await deriveKey(password, salt, PBKDF2_ITERATIONS);
|
|
82
|
+
const cipher = crypto$1.createCipheriv("aes-256-gcm", key, iv);
|
|
83
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
84
|
+
return {
|
|
85
|
+
salt,
|
|
86
|
+
iv,
|
|
87
|
+
tag: cipher.getAuthTag(),
|
|
88
|
+
ciphertext,
|
|
89
|
+
iterations: PBKDF2_ITERATIONS
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function decrypt(ciphertext, password, salt, iv, tag, iterations) {
|
|
93
|
+
const key = await deriveKey(password, salt, iterations);
|
|
94
|
+
const decipher = crypto$1.createDecipheriv("aes-256-gcm", key, iv);
|
|
95
|
+
decipher.setAuthTag(tag);
|
|
96
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
97
|
+
}
|
|
98
|
+
function packFile(encrypted) {
|
|
99
|
+
const iterBuf = Buffer.alloc(4);
|
|
100
|
+
iterBuf.writeUInt32BE(encrypted.iterations, 0);
|
|
101
|
+
return Buffer.concat([
|
|
102
|
+
MAGIC_BYTES,
|
|
103
|
+
iterBuf,
|
|
104
|
+
encrypted.salt,
|
|
105
|
+
encrypted.iv,
|
|
106
|
+
encrypted.tag,
|
|
107
|
+
encrypted.ciphertext
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
function unpackFile(fileBuffer) {
|
|
111
|
+
if (fileBuffer.length < HEADER_SIZE) throw new AgentExportError("File is too small to be a valid .eliza-agent export.");
|
|
112
|
+
if (!fileBuffer.subarray(0, MAGIC_BYTES.length).equals(MAGIC_BYTES)) throw new AgentExportError("Invalid file format — this does not appear to be an .eliza-agent export file.");
|
|
113
|
+
let offset = MAGIC_BYTES.length;
|
|
114
|
+
const iterations = fileBuffer.readUInt32BE(offset);
|
|
115
|
+
offset += 4;
|
|
116
|
+
if (iterations < 1 || iterations > MAX_PBKDF2_ITERATIONS) throw new AgentExportError(`Invalid PBKDF2 iteration count (${iterations}). Expected between 1 and ${MAX_PBKDF2_ITERATIONS.toLocaleString()}.`);
|
|
117
|
+
const salt = fileBuffer.subarray(offset, offset + SALT_LEN);
|
|
118
|
+
offset += SALT_LEN;
|
|
119
|
+
const iv = fileBuffer.subarray(offset, offset + IV_LEN);
|
|
120
|
+
offset += IV_LEN;
|
|
121
|
+
const tag = fileBuffer.subarray(offset, offset + TAG_LEN);
|
|
122
|
+
offset += TAG_LEN;
|
|
123
|
+
const ciphertext = fileBuffer.subarray(offset);
|
|
124
|
+
if (ciphertext.length === 0) throw new AgentExportError("Export file contains no encrypted data.");
|
|
125
|
+
return {
|
|
126
|
+
salt,
|
|
127
|
+
iv,
|
|
128
|
+
tag,
|
|
129
|
+
ciphertext,
|
|
130
|
+
iterations
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
var AgentExportError = class extends Error {
|
|
134
|
+
constructor(message) {
|
|
135
|
+
super(message);
|
|
136
|
+
this.name = "AgentExportError";
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
async function gunzipWithSizeLimit(compressed, maxBytes = MAX_IMPORT_DECOMPRESSED_BYTES) {
|
|
140
|
+
const source = Readable.from([compressed]);
|
|
141
|
+
const gunzip = createGunzip();
|
|
142
|
+
const chunks = [];
|
|
143
|
+
let total = 0;
|
|
144
|
+
source.pipe(gunzip);
|
|
145
|
+
for await (const chunk of gunzip) {
|
|
146
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
147
|
+
total += buf.length;
|
|
148
|
+
if (total > maxBytes) {
|
|
149
|
+
source.destroy();
|
|
150
|
+
gunzip.destroy();
|
|
151
|
+
throw new AgentExportError(`Decompressed payload exceeds import limit (${maxBytes} bytes).`);
|
|
152
|
+
}
|
|
153
|
+
chunks.push(buf);
|
|
154
|
+
}
|
|
155
|
+
return Buffer.concat(chunks, total);
|
|
156
|
+
}
|
|
157
|
+
/** Read agentId from a Task, accounting for proto vs DB naming. */
|
|
158
|
+
function taskAgentId(t) {
|
|
159
|
+
const rec = t;
|
|
160
|
+
return rec.agentId ?? rec.agent_id;
|
|
161
|
+
}
|
|
162
|
+
async function extractAgentData(runtime, options) {
|
|
163
|
+
const db = runtime.adapter;
|
|
164
|
+
const agentId = runtime.agentId;
|
|
165
|
+
logger.info(`[agent-export] Extracting data for agent ${agentId}`);
|
|
166
|
+
const agent = await db.getAgent(agentId);
|
|
167
|
+
if (!agent) throw new AgentExportError(`Agent ${agentId} not found in database.`);
|
|
168
|
+
const agentWorlds = (await db.getAllWorlds()).filter((w) => w.agentId === agentId);
|
|
169
|
+
logger.info(`[agent-export] Found ${agentWorlds.length} worlds`);
|
|
170
|
+
const roomMap = /* @__PURE__ */ new Map();
|
|
171
|
+
for (const world of agentWorlds) {
|
|
172
|
+
if (!world.id) continue;
|
|
173
|
+
const worldRooms = await db.getRoomsByWorld(world.id);
|
|
174
|
+
for (const room of worldRooms) if (room.id) roomMap.set(room.id, room);
|
|
175
|
+
}
|
|
176
|
+
const participantRoomIds = await db.getRoomsForParticipant(agentId);
|
|
177
|
+
if (participantRoomIds.length > 0) {
|
|
178
|
+
const participantRooms = await db.getRoomsByIds(participantRoomIds);
|
|
179
|
+
if (participantRooms) {
|
|
180
|
+
for (const room of participantRooms) if (room.id) roomMap.set(room.id, room);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const rooms = Array.from(roomMap.values());
|
|
184
|
+
logger.info(`[agent-export] Found ${rooms.length} rooms`);
|
|
185
|
+
const entityMap = /* @__PURE__ */ new Map();
|
|
186
|
+
const participantRecords = [];
|
|
187
|
+
for (const room of rooms) {
|
|
188
|
+
if (!room.id) continue;
|
|
189
|
+
const roomEntities = await db.getEntitiesForRoom(room.id, true);
|
|
190
|
+
for (const entity of roomEntities) if (entity.id) entityMap.set(entity.id, entity);
|
|
191
|
+
const participantIds = await db.getParticipantsForRoom(room.id);
|
|
192
|
+
for (const entityId of participantIds) {
|
|
193
|
+
const userState = await db.getParticipantUserState(room.id, entityId);
|
|
194
|
+
participantRecords.push({
|
|
195
|
+
entityId,
|
|
196
|
+
roomId: room.id,
|
|
197
|
+
userState
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const entities = Array.from(entityMap.values());
|
|
202
|
+
logger.info(`[agent-export] Found ${entities.length} entities, ${participantRecords.length} participant records`);
|
|
203
|
+
const componentIds = /* @__PURE__ */ new Set();
|
|
204
|
+
const allComponents = [];
|
|
205
|
+
const addComponent = (c) => {
|
|
206
|
+
if (c.id && !componentIds.has(c.id)) {
|
|
207
|
+
componentIds.add(c.id);
|
|
208
|
+
allComponents.push(c);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
for (const entity of entities) {
|
|
212
|
+
if (!entity.id) continue;
|
|
213
|
+
for (const c of await db.getComponents(entity.id)) addComponent(c);
|
|
214
|
+
for (const world of agentWorlds) {
|
|
215
|
+
if (!world.id) continue;
|
|
216
|
+
for (const c of await db.getComponents(entity.id, world.id)) addComponent(c);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
logger.info(`[agent-export] Found ${allComponents.length} components`);
|
|
220
|
+
const allMemories = [];
|
|
221
|
+
const memoryIdSet = /* @__PURE__ */ new Set();
|
|
222
|
+
for (const tableName of MEMORY_TABLES) {
|
|
223
|
+
const memories = await db.getMemories({
|
|
224
|
+
agentId,
|
|
225
|
+
tableName,
|
|
226
|
+
count: Number.MAX_SAFE_INTEGER
|
|
227
|
+
});
|
|
228
|
+
for (const mem of memories) if (mem.id && !memoryIdSet.has(mem.id)) {
|
|
229
|
+
memoryIdSet.add(mem.id);
|
|
230
|
+
allMemories.push({
|
|
231
|
+
...mem,
|
|
232
|
+
embedding: void 0
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
for (const world of agentWorlds) {
|
|
237
|
+
if (!world.id) continue;
|
|
238
|
+
for (const tableName of MEMORY_TABLES) {
|
|
239
|
+
const worldMemories = await db.getMemoriesByWorldId({
|
|
240
|
+
worldId: world.id,
|
|
241
|
+
count: Number.MAX_SAFE_INTEGER,
|
|
242
|
+
tableName
|
|
243
|
+
});
|
|
244
|
+
for (const mem of worldMemories) if (mem.id && !memoryIdSet.has(mem.id)) {
|
|
245
|
+
memoryIdSet.add(mem.id);
|
|
246
|
+
allMemories.push({
|
|
247
|
+
...mem,
|
|
248
|
+
embedding: void 0
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
logger.info(`[agent-export] Found ${allMemories.length} memories`);
|
|
254
|
+
const relationships = await db.getRelationships({ entityId: agentId });
|
|
255
|
+
logger.info(`[agent-export] Found ${relationships.length} relationships`);
|
|
256
|
+
const agentTasks = (await db.getTasks({})).filter((t) => taskAgentId(t) === agentId);
|
|
257
|
+
logger.info(`[agent-export] Found ${agentTasks.length} tasks`);
|
|
258
|
+
let logs = [];
|
|
259
|
+
if (options.includeLogs) {
|
|
260
|
+
logs = await db.getLogs({ count: Number.MAX_SAFE_INTEGER });
|
|
261
|
+
logger.info(`[agent-export] Found ${logs.length} logs`);
|
|
262
|
+
}
|
|
263
|
+
let characterConfig;
|
|
264
|
+
if (runtime.character) {
|
|
265
|
+
const { secrets, ...safeChar } = runtime.character;
|
|
266
|
+
characterConfig = safeChar;
|
|
267
|
+
logger.info(`[agent-export] Captured runtime character config (${Object.keys(safeChar).length} fields)`);
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
version: EXPORT_VERSION,
|
|
271
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
272
|
+
sourceAgentId: agentId,
|
|
273
|
+
agent,
|
|
274
|
+
characterConfig,
|
|
275
|
+
entities,
|
|
276
|
+
memories: allMemories,
|
|
277
|
+
components: allComponents,
|
|
278
|
+
rooms,
|
|
279
|
+
participants: participantRecords,
|
|
280
|
+
relationships,
|
|
281
|
+
worlds: agentWorlds,
|
|
282
|
+
tasks: agentTasks,
|
|
283
|
+
logs
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function createIdRemapper(fixed) {
|
|
287
|
+
const map = new Map(fixed);
|
|
288
|
+
return (oldId) => {
|
|
289
|
+
if (!oldId) return oldId;
|
|
290
|
+
const existing = map.get(oldId);
|
|
291
|
+
if (existing) return existing;
|
|
292
|
+
const newId = crypto$1.randomUUID();
|
|
293
|
+
map.set(oldId, newId);
|
|
294
|
+
return newId;
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
async function restoreAgentData(runtime, payload) {
|
|
298
|
+
const db = runtime.adapter;
|
|
299
|
+
const newAgentId = crypto$1.randomUUID();
|
|
300
|
+
const remap = createIdRemapper(new Map([[payload.sourceAgentId, newAgentId]]));
|
|
301
|
+
logger.info(`[agent-import] Importing agent "${payload.agent.name}" as ${newAgentId}`);
|
|
302
|
+
const charBase = payload.characterConfig ? { ...payload.characterConfig } : {};
|
|
303
|
+
delete charBase.secrets;
|
|
304
|
+
const agentData = {
|
|
305
|
+
...charBase,
|
|
306
|
+
...payload.agent
|
|
307
|
+
};
|
|
308
|
+
agentData.id = newAgentId;
|
|
309
|
+
agentData.enabled = true;
|
|
310
|
+
agentData.createdAt = Date.now();
|
|
311
|
+
agentData.updatedAt = Date.now();
|
|
312
|
+
if (!await db.createAgent(agentData)) throw new AgentExportError("Failed to create agent in database.");
|
|
313
|
+
logger.info(`[agent-import] Created agent record${payload.characterConfig ? " (merged with characterConfig)" : ""}`);
|
|
314
|
+
let worldsImported = 0;
|
|
315
|
+
for (const world of payload.worlds) {
|
|
316
|
+
const newWorld = {
|
|
317
|
+
...world,
|
|
318
|
+
id: remap(world.id ?? ""),
|
|
319
|
+
agentId: newAgentId
|
|
320
|
+
};
|
|
321
|
+
await db.createWorld(newWorld);
|
|
322
|
+
worldsImported++;
|
|
323
|
+
}
|
|
324
|
+
logger.info(`[agent-import] Imported ${worldsImported} worlds`);
|
|
325
|
+
let roomsImported = 0;
|
|
326
|
+
const roomBatch = [];
|
|
327
|
+
for (const room of payload.rooms) {
|
|
328
|
+
const newRoom = {
|
|
329
|
+
...room,
|
|
330
|
+
id: remap(room.id ?? ""),
|
|
331
|
+
agentId: newAgentId,
|
|
332
|
+
worldId: room.worldId ? remap(room.worldId) : void 0
|
|
333
|
+
};
|
|
334
|
+
roomBatch.push(newRoom);
|
|
335
|
+
}
|
|
336
|
+
if (roomBatch.length > 0) {
|
|
337
|
+
await db.createRooms(roomBatch);
|
|
338
|
+
roomsImported = roomBatch.length;
|
|
339
|
+
}
|
|
340
|
+
logger.info(`[agent-import] Imported ${roomsImported} rooms`);
|
|
341
|
+
let entitiesImported = 0;
|
|
342
|
+
const entityBatch = [];
|
|
343
|
+
for (const entity of payload.entities) {
|
|
344
|
+
const newEntity = {
|
|
345
|
+
...entity,
|
|
346
|
+
id: remap(entity.id ?? ""),
|
|
347
|
+
agentId: newAgentId,
|
|
348
|
+
components: void 0
|
|
349
|
+
};
|
|
350
|
+
entityBatch.push(newEntity);
|
|
351
|
+
}
|
|
352
|
+
if (entityBatch.length > 0) {
|
|
353
|
+
await db.createEntities(entityBatch);
|
|
354
|
+
entitiesImported = entityBatch.length;
|
|
355
|
+
}
|
|
356
|
+
logger.info(`[agent-import] Imported ${entitiesImported} entities`);
|
|
357
|
+
let participantsImported = 0;
|
|
358
|
+
for (const p of payload.participants) {
|
|
359
|
+
const newEntityId = remap(p.entityId);
|
|
360
|
+
const newRoomId = remap(p.roomId);
|
|
361
|
+
await db.addParticipantsRoom([newEntityId], newRoomId);
|
|
362
|
+
if (p.userState === "FOLLOWED" || p.userState === "MUTED") await db.setParticipantUserState(newRoomId, newEntityId, p.userState);
|
|
363
|
+
participantsImported++;
|
|
364
|
+
}
|
|
365
|
+
logger.info(`[agent-import] Imported ${participantsImported} participants`);
|
|
366
|
+
let componentsImported = 0;
|
|
367
|
+
for (const comp of payload.components) {
|
|
368
|
+
const newComp = {
|
|
369
|
+
...comp,
|
|
370
|
+
id: remap(comp.id ?? ""),
|
|
371
|
+
...comp.entityId ? { entityId: remap(comp.entityId) } : {},
|
|
372
|
+
...comp.agentId ? { agentId: newAgentId } : {},
|
|
373
|
+
...comp.roomId ? { roomId: remap(comp.roomId) } : {},
|
|
374
|
+
...comp.worldId ? { worldId: remap(comp.worldId) } : {},
|
|
375
|
+
...comp.sourceEntityId ? { sourceEntityId: remap(comp.sourceEntityId) } : {}
|
|
376
|
+
};
|
|
377
|
+
await db.createComponent(newComp);
|
|
378
|
+
componentsImported++;
|
|
379
|
+
}
|
|
380
|
+
logger.info(`[agent-import] Imported ${componentsImported} components`);
|
|
381
|
+
let memoriesImported = 0;
|
|
382
|
+
for (const mem of payload.memories) {
|
|
383
|
+
const tableName = resolveMemoryTableName(mem);
|
|
384
|
+
const newMem = {
|
|
385
|
+
...mem,
|
|
386
|
+
id: remap(mem.id ?? ""),
|
|
387
|
+
agentId: newAgentId,
|
|
388
|
+
...mem.entityId ? { entityId: remap(mem.entityId) } : {},
|
|
389
|
+
...mem.roomId ? { roomId: remap(mem.roomId) } : {},
|
|
390
|
+
...mem.worldId ? { worldId: remap(mem.worldId) } : {},
|
|
391
|
+
embedding: void 0
|
|
392
|
+
};
|
|
393
|
+
await db.createMemory(newMem, tableName);
|
|
394
|
+
memoriesImported++;
|
|
395
|
+
}
|
|
396
|
+
logger.info(`[agent-import] Imported ${memoriesImported} memories`);
|
|
397
|
+
let relationshipsImported = 0;
|
|
398
|
+
for (const rel of payload.relationships) {
|
|
399
|
+
await db.createRelationship({
|
|
400
|
+
sourceEntityId: remap(rel.sourceEntityId ?? ""),
|
|
401
|
+
targetEntityId: remap(rel.targetEntityId ?? ""),
|
|
402
|
+
tags: rel.tags,
|
|
403
|
+
metadata: rel.metadata
|
|
404
|
+
});
|
|
405
|
+
relationshipsImported++;
|
|
406
|
+
}
|
|
407
|
+
logger.info(`[agent-import] Imported ${relationshipsImported} relationships`);
|
|
408
|
+
let tasksImported = 0;
|
|
409
|
+
for (const task of payload.tasks) {
|
|
410
|
+
const newTask = {
|
|
411
|
+
...task,
|
|
412
|
+
id: remap(task.id ?? ""),
|
|
413
|
+
agentId: newAgentId,
|
|
414
|
+
roomId: task.roomId ? remap(task.roomId) : void 0,
|
|
415
|
+
worldId: task.worldId ? remap(task.worldId) : void 0,
|
|
416
|
+
entityId: task.entityId ? remap(task.entityId) : void 0
|
|
417
|
+
};
|
|
418
|
+
await db.createTask(newTask);
|
|
419
|
+
tasksImported++;
|
|
420
|
+
}
|
|
421
|
+
logger.info(`[agent-import] Imported ${tasksImported} tasks`);
|
|
422
|
+
let logsImported = 0;
|
|
423
|
+
for (const logEntry of payload.logs) {
|
|
424
|
+
await db.log({
|
|
425
|
+
body: logEntry.body,
|
|
426
|
+
entityId: logEntry.entityId ? remap(logEntry.entityId) : logEntry.entityId,
|
|
427
|
+
roomId: logEntry.roomId ? remap(logEntry.roomId) : newAgentId,
|
|
428
|
+
type: logEntry.type ?? "action"
|
|
429
|
+
});
|
|
430
|
+
logsImported++;
|
|
431
|
+
}
|
|
432
|
+
logger.info(`[agent-import] Imported ${logsImported} logs`);
|
|
433
|
+
return {
|
|
434
|
+
success: true,
|
|
435
|
+
agentId: newAgentId,
|
|
436
|
+
agentName: payload.agent.name ?? "Unknown",
|
|
437
|
+
counts: {
|
|
438
|
+
memories: memoriesImported,
|
|
439
|
+
entities: entitiesImported,
|
|
440
|
+
components: componentsImported,
|
|
441
|
+
rooms: roomsImported,
|
|
442
|
+
participants: participantsImported,
|
|
443
|
+
relationships: relationshipsImported,
|
|
444
|
+
worlds: worldsImported,
|
|
445
|
+
tasks: tasksImported,
|
|
446
|
+
logs: logsImported
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Resolve the memory table name from a memory record's metadata.
|
|
452
|
+
* The ElizaOS adapter requires a tableName for createMemory.
|
|
453
|
+
*/
|
|
454
|
+
function resolveMemoryTableName(mem) {
|
|
455
|
+
const metaType = mem.metadata?.type;
|
|
456
|
+
if (metaType === "message") return "messages";
|
|
457
|
+
if (metaType === "document") return "documents";
|
|
458
|
+
if (metaType === "fragment") return "fragments";
|
|
459
|
+
if (metaType === "description") return "descriptions";
|
|
460
|
+
if (metaType === "custom") return "custom";
|
|
461
|
+
const memType = mem.type;
|
|
462
|
+
if (typeof memType === "string" && memType.length > 0) return memType;
|
|
463
|
+
return "messages";
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Export the current agent's full state as a password-encrypted binary file.
|
|
467
|
+
*
|
|
468
|
+
* @param runtime - The running AgentRuntime with an active database adapter
|
|
469
|
+
* @param password - User-provided password for encryption
|
|
470
|
+
* @param options - Export options (e.g., whether to include logs)
|
|
471
|
+
* @returns A Buffer containing the encrypted .eliza-agent file
|
|
472
|
+
*/
|
|
473
|
+
async function exportAgent(runtime, password, options = {}) {
|
|
474
|
+
if (!password || password.length < MIN_PASSWORD_LENGTH) throw new AgentExportError(`A password of at least ${MIN_PASSWORD_LENGTH} characters is required to encrypt the export.`);
|
|
475
|
+
if (!runtime.adapter) throw new AgentExportError("No database adapter available on the runtime.");
|
|
476
|
+
const payload = await extractAgentData(runtime, { includeLogs: options.includeLogs ?? false });
|
|
477
|
+
const jsonString = JSON.stringify(payload);
|
|
478
|
+
const compressed = gzipSync(Buffer.from(jsonString, "utf-8"));
|
|
479
|
+
logger.info(`[agent-export] Payload: ${jsonString.length} bytes JSON → ${compressed.length} bytes compressed`);
|
|
480
|
+
const fileBuffer = packFile(await encrypt(compressed, password));
|
|
481
|
+
logger.info(`[agent-export] Final file size: ${fileBuffer.length} bytes`);
|
|
482
|
+
return fileBuffer;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Import an agent from a password-encrypted .eliza-agent file.
|
|
486
|
+
*
|
|
487
|
+
* @param runtime - An AgentRuntime with an active database adapter (the agent
|
|
488
|
+
* will be created in this database, not overwriting the current agent)
|
|
489
|
+
* @param fileBuffer - The raw bytes of the .eliza-agent file
|
|
490
|
+
* @param password - The password used when the file was exported
|
|
491
|
+
* @returns An ImportResult describing what was imported
|
|
492
|
+
*/
|
|
493
|
+
async function importAgent(runtime, fileBuffer, password) {
|
|
494
|
+
if (!password || password.length < MIN_PASSWORD_LENGTH) throw new AgentExportError(`A password of at least ${MIN_PASSWORD_LENGTH} characters is required to decrypt the import.`);
|
|
495
|
+
if (!runtime.adapter) throw new AgentExportError("No database adapter available on the runtime.");
|
|
496
|
+
const { salt, iv, tag, ciphertext, iterations } = unpackFile(fileBuffer);
|
|
497
|
+
let compressed;
|
|
498
|
+
try {
|
|
499
|
+
compressed = await decrypt(ciphertext, password, salt, iv, tag, iterations);
|
|
500
|
+
} catch (err) {
|
|
501
|
+
if (err instanceof Error && (err.message.includes("Unsupported state") || err.message.includes("unable to authenticate") || err.message.includes("auth"))) throw new AgentExportError("Incorrect password — decryption failed. Please check your password and try again.");
|
|
502
|
+
throw new AgentExportError(`Decryption failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
503
|
+
}
|
|
504
|
+
let jsonString;
|
|
505
|
+
try {
|
|
506
|
+
jsonString = (await gunzipWithSizeLimit(compressed)).toString("utf-8");
|
|
507
|
+
} catch (err) {
|
|
508
|
+
if (err instanceof AgentExportError) throw err;
|
|
509
|
+
throw new AgentExportError(`Decompression failed — the file may be corrupt: ${err instanceof Error ? err.message : String(err)}`);
|
|
510
|
+
}
|
|
511
|
+
let rawPayload;
|
|
512
|
+
try {
|
|
513
|
+
rawPayload = JSON.parse(jsonString);
|
|
514
|
+
} catch (err) {
|
|
515
|
+
throw new AgentExportError(`JSON parse failed — the export data is malformed: ${err instanceof Error ? err.message : String(err)}`);
|
|
516
|
+
}
|
|
517
|
+
const parseResult = PayloadSchema.safeParse(rawPayload);
|
|
518
|
+
if (!parseResult.success) throw new AgentExportError(`Export file schema validation failed: ${parseResult.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
|
|
519
|
+
const payload = rawPayload;
|
|
520
|
+
if (payload.version > EXPORT_VERSION) throw new AgentExportError(`Unsupported export version ${payload.version}. This build supports up to version ${EXPORT_VERSION}. Please update your software to import this file.`);
|
|
521
|
+
logger.info(`[agent-import] Importing agent "${payload.agent.name}" exported at ${payload.exportedAt}`);
|
|
522
|
+
return restoreAgentData(runtime, payload);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Estimate the size of an agent export without actually creating it.
|
|
526
|
+
* Useful for showing the user how large the export will be.
|
|
527
|
+
*/
|
|
528
|
+
async function estimateExportSize(runtime) {
|
|
529
|
+
const db = runtime.adapter;
|
|
530
|
+
const agentId = runtime.agentId;
|
|
531
|
+
let memoriesCount = 0;
|
|
532
|
+
for (const tableName of MEMORY_TABLES) {
|
|
533
|
+
const mems = await db.getMemories({
|
|
534
|
+
agentId,
|
|
535
|
+
tableName,
|
|
536
|
+
count: Number.MAX_SAFE_INTEGER
|
|
537
|
+
});
|
|
538
|
+
memoriesCount += mems.length;
|
|
539
|
+
}
|
|
540
|
+
const agentWorlds = (await db.getAllWorlds()).filter((w) => w.agentId === agentId);
|
|
541
|
+
const roomIds = await db.getRoomsForParticipant(agentId);
|
|
542
|
+
const entityIdSet = /* @__PURE__ */ new Set();
|
|
543
|
+
for (const roomId of roomIds) {
|
|
544
|
+
const roomEntities = await db.getEntitiesForRoom(roomId);
|
|
545
|
+
for (const e of roomEntities) if (e.id) entityIdSet.add(e.id);
|
|
546
|
+
}
|
|
547
|
+
const agentTasks = (await db.getTasks({})).filter((t) => taskAgentId(t) === agentId);
|
|
548
|
+
return {
|
|
549
|
+
estimatedBytes: memoriesCount * 500 + entityIdSet.size * 200 + roomIds.length * 300 + agentWorlds.length * 200 + agentTasks.length * 400 + 2e3,
|
|
550
|
+
memoriesCount,
|
|
551
|
+
entitiesCount: entityIdSet.size,
|
|
552
|
+
roomsCount: roomIds.length,
|
|
553
|
+
worldsCount: agentWorlds.length,
|
|
554
|
+
tasksCount: agentTasks.length
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
//#endregion
|
|
559
|
+
export { AgentExportError, estimateExportSize, exportAgent, importAgent };
|