@elizaos/ui 2.0.0-alpha.528 → 2.0.0-alpha.529
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/package.json +1 -1
- package/packages/agent/src/actions/browser-autofill-login.d.ts +36 -0
- package/packages/agent/src/actions/browser-autofill-login.d.ts.map +1 -0
- package/packages/agent/src/actions/browser-autofill-login.js +347 -0
- package/packages/agent/src/api/experience-routes.d.ts.map +1 -1
- package/packages/agent/src/api/experience-routes.js +40 -2
- package/packages/agent/src/api/static-file-server.d.ts +2 -2
- package/packages/agent/src/api/static-file-server.d.ts.map +1 -1
- package/packages/agent/src/api/static-file-server.js +4 -2
- package/packages/agent/src/runtime/agent-wallets.d.ts +103 -0
- package/packages/agent/src/runtime/agent-wallets.d.ts.map +1 -0
- package/packages/agent/src/runtime/agent-wallets.js +244 -0
- package/packages/agent/src/runtime/eliza-plugin.d.ts.map +1 -1
- package/packages/agent/src/runtime/eliza-plugin.js +2 -0
- package/packages/agent/src/runtime/eliza.d.ts.map +1 -1
- package/packages/agent/src/runtime/eliza.js +67 -1
- package/packages/agent/src/runtime/operations/index.d.ts +1 -1
- package/packages/agent/src/runtime/operations/index.d.ts.map +1 -1
- package/packages/agent/src/runtime/operations/index.js +1 -1
- package/packages/agent/src/runtime/operations/vault-bridge.d.ts +22 -1
- package/packages/agent/src/runtime/operations/vault-bridge.d.ts.map +1 -1
- package/packages/agent/src/runtime/operations/vault-bridge.js +53 -0
- package/packages/agent/src/runtime/plugin-lifecycle.js +1 -1
- package/packages/agent/src/runtime/vault-profile-resolver.d.ts +37 -0
- package/packages/agent/src/runtime/vault-profile-resolver.d.ts.map +1 -0
- package/packages/agent/src/runtime/vault-profile-resolver.js +75 -0
- package/packages/app-core/src/api/client-agent.d.ts +1 -0
- package/packages/app-core/src/api/client-agent.d.ts.map +1 -1
- package/packages/app-core/src/api/client-base.d.ts.map +1 -1
- package/packages/app-core/src/api/client-base.js +11 -2
- package/packages/app-core/src/api/client-vault.d.ts +53 -0
- package/packages/app-core/src/api/client-vault.d.ts.map +1 -0
- package/packages/app-core/src/api/client-vault.js +48 -0
- package/packages/app-core/src/api/client.d.ts +1 -0
- package/packages/app-core/src/api/client.d.ts.map +1 -1
- package/packages/app-core/src/api/client.js +1 -0
- package/packages/app-core/src/registry/index.d.ts +7 -0
- package/packages/app-core/src/registry/index.d.ts.map +1 -0
- package/packages/app-core/src/registry/index.js +43 -0
- package/packages/app-core/src/registry/legacy-adapter.d.ts +32 -0
- package/packages/app-core/src/registry/legacy-adapter.d.ts.map +1 -0
- package/packages/app-core/src/registry/legacy-adapter.js +101 -0
- package/packages/app-core/src/registry/loader.d.ts +27 -0
- package/packages/app-core/src/registry/loader.d.ts.map +1 -0
- package/packages/app-core/src/registry/loader.js +111 -0
- package/packages/app-core/src/registry/schema.d.ts +986 -0
- package/packages/app-core/src/registry/schema.d.ts.map +1 -0
- package/packages/app-core/src/registry/schema.js +250 -0
- package/packages/app-core/src/services/vault-bootstrap.d.ts +31 -0
- package/packages/app-core/src/services/vault-bootstrap.d.ts.map +1 -0
- package/packages/app-core/src/services/vault-bootstrap.js +245 -0
- package/packages/app-core/src/services/vault-mirror.d.ts +44 -0
- package/packages/app-core/src/services/vault-mirror.d.ts.map +1 -0
- package/packages/app-core/src/services/vault-mirror.js +80 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent wallet keys, stored in the Eliza vault.
|
|
3
|
+
*
|
|
4
|
+
* This module is the bridge between agent identity and the vault. Each
|
|
5
|
+
* agent gets its own EVM and Solana keypair, stored under
|
|
6
|
+
* `agent.<agentId>.wallet.<chain>` as a JSON record. Private keys are
|
|
7
|
+
* sensitive and AES-GCM encrypted at rest by the vault; the vault's
|
|
8
|
+
* master key lives in the OS keychain.
|
|
9
|
+
*
|
|
10
|
+
* The runtime-wide single wallet (process.env.EVM_PRIVATE_KEY etc.) is
|
|
11
|
+
* the *user* wallet, hydrated from the OS secure store via
|
|
12
|
+
* `hydrateWalletKeysFromNodePlatformSecureStore`. Per-agent wallets are
|
|
13
|
+
* stored *inside* the vault (encrypted file), enumerable and easy to
|
|
14
|
+
* surface in the UI alongside saved logins.
|
|
15
|
+
*
|
|
16
|
+
* This module does not generate or store keys on its own; callers
|
|
17
|
+
* supply a `Vault` instance. Agent-creation lifecycle code wires this
|
|
18
|
+
* up — see `runtime/eliza.ts`.
|
|
19
|
+
*/
|
|
20
|
+
import { removeEntryMeta, setEntryMeta } from "@elizaos/vault";
|
|
21
|
+
import { deriveEvmAddress, generateWalletForChain } from "../api/wallet.js";
|
|
22
|
+
const PREFIX = "agent";
|
|
23
|
+
const SEGMENT = "wallet";
|
|
24
|
+
function encodeAgentSegment(agentId) {
|
|
25
|
+
if (typeof agentId !== "string" || agentId.trim().length === 0) {
|
|
26
|
+
throw new TypeError("agent-wallets: agentId must be a non-empty string");
|
|
27
|
+
}
|
|
28
|
+
// encodeURIComponent leaves `.` alone, but our vault keys split on `.`
|
|
29
|
+
// — escape it explicitly so an agent ID like "alice.bob" doesn't bleed
|
|
30
|
+
// into the layout (`agent.alice.bob.wallet.evm` has five parts, not four).
|
|
31
|
+
return encodeURIComponent(agentId.trim()).replace(/\./g, "%2E");
|
|
32
|
+
}
|
|
33
|
+
function decodeAgentSegment(segment) {
|
|
34
|
+
return decodeURIComponent(segment);
|
|
35
|
+
}
|
|
36
|
+
function walletKey(agentId, chain) {
|
|
37
|
+
return `${PREFIX}.${encodeAgentSegment(agentId)}.${SEGMENT}.${chain}`;
|
|
38
|
+
}
|
|
39
|
+
function agentPrefix(agentId) {
|
|
40
|
+
return `${PREFIX}.${encodeAgentSegment(agentId)}.${SEGMENT}`;
|
|
41
|
+
}
|
|
42
|
+
function parseAgentWalletKey(key) {
|
|
43
|
+
// Layout: agent.<encodedId>.wallet.<chain>
|
|
44
|
+
const parts = key.split(".");
|
|
45
|
+
if (parts.length !== 4)
|
|
46
|
+
return null;
|
|
47
|
+
if (parts[0] !== PREFIX || parts[2] !== SEGMENT)
|
|
48
|
+
return null;
|
|
49
|
+
const chain = parts[3];
|
|
50
|
+
if (chain !== "evm" && chain !== "solana")
|
|
51
|
+
return null;
|
|
52
|
+
return { agentId: decodeAgentSegment(parts[1]), chain };
|
|
53
|
+
}
|
|
54
|
+
function parseStored(raw) {
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
if ((parsed.chain !== "evm" && parsed.chain !== "solana") ||
|
|
57
|
+
typeof parsed.address !== "string" ||
|
|
58
|
+
typeof parsed.privateKey !== "string" ||
|
|
59
|
+
typeof parsed.lastModified !== "number") {
|
|
60
|
+
throw new Error("agent-wallets: stored entry malformed (expected chain/address/privateKey/lastModified)");
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
chain: parsed.chain,
|
|
64
|
+
address: parsed.address,
|
|
65
|
+
privateKey: parsed.privateKey,
|
|
66
|
+
lastModified: parsed.lastModified,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Derive the public address from a stored private key. EVM uses the
|
|
71
|
+
* existing helper; Solana stores the public key alongside the secret in
|
|
72
|
+
* `generateWalletForChain`, so the stored `address` is authoritative
|
|
73
|
+
* and we trust it for the read path.
|
|
74
|
+
*/
|
|
75
|
+
function deriveAddressFor(chain, privateKey) {
|
|
76
|
+
if (chain === "evm")
|
|
77
|
+
return deriveEvmAddress(privateKey);
|
|
78
|
+
// For Solana the keypair format already includes the public key; the
|
|
79
|
+
// caller is expected to have stored the public key as `address` at
|
|
80
|
+
// write time. Re-derivation would require @solana/web3.js, which we
|
|
81
|
+
// avoid pulling in here.
|
|
82
|
+
throw new Error("agent-wallets: deriveAddressFor only supports EVM; Solana addresses must be supplied at write time");
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Read the public descriptor for an agent's wallet. Returns null when
|
|
86
|
+
* the agent has no wallet for that chain. Does NOT reveal the private
|
|
87
|
+
* key.
|
|
88
|
+
*/
|
|
89
|
+
export async function getAgentWalletDescriptor(vault, agentId, chain) {
|
|
90
|
+
const key = walletKey(agentId, chain);
|
|
91
|
+
if (!(await vault.has(key)))
|
|
92
|
+
return null;
|
|
93
|
+
const raw = await vault.get(key);
|
|
94
|
+
const stored = parseStored(raw);
|
|
95
|
+
return {
|
|
96
|
+
agentId,
|
|
97
|
+
chain,
|
|
98
|
+
address: stored.address,
|
|
99
|
+
lastModified: stored.lastModified,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reveal the private key. Audit-logged via the vault. Use only for
|
|
104
|
+
* signing flows.
|
|
105
|
+
*/
|
|
106
|
+
export async function revealAgentWalletPrivateKey(vault, agentId, chain, caller) {
|
|
107
|
+
const key = walletKey(agentId, chain);
|
|
108
|
+
const raw = await vault.reveal(key, caller);
|
|
109
|
+
return parseStored(raw).privateKey;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Existence check. Does not reveal the key.
|
|
113
|
+
*/
|
|
114
|
+
export async function hasAgentWallet(vault, agentId, chain) {
|
|
115
|
+
return vault.has(walletKey(agentId, chain));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* List every wallet descriptor for an agent (typically [evm, solana]).
|
|
119
|
+
*/
|
|
120
|
+
export async function listAgentWallets(vault, agentId) {
|
|
121
|
+
const keys = await vault.list(agentPrefix(agentId));
|
|
122
|
+
const out = [];
|
|
123
|
+
for (const key of keys) {
|
|
124
|
+
const parsed = parseAgentWalletKey(key);
|
|
125
|
+
if (!parsed)
|
|
126
|
+
continue;
|
|
127
|
+
const raw = await vault.get(key);
|
|
128
|
+
const stored = parseStored(raw);
|
|
129
|
+
out.push({
|
|
130
|
+
agentId: parsed.agentId,
|
|
131
|
+
chain: parsed.chain,
|
|
132
|
+
address: stored.address,
|
|
133
|
+
lastModified: stored.lastModified,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* List every agent that has at least one wallet stored. Returns the
|
|
140
|
+
* agent IDs (decoded). Use for UI surfaces enumerating agent wallets.
|
|
141
|
+
*/
|
|
142
|
+
export async function listAgentsWithWallets(vault) {
|
|
143
|
+
const keys = await vault.list(PREFIX);
|
|
144
|
+
const agents = new Set();
|
|
145
|
+
for (const key of keys) {
|
|
146
|
+
const parsed = parseAgentWalletKey(key);
|
|
147
|
+
if (!parsed)
|
|
148
|
+
continue;
|
|
149
|
+
agents.add(parsed.agentId);
|
|
150
|
+
}
|
|
151
|
+
return [...agents];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Persist a wallet for an agent. Replaces any existing entry for that
|
|
155
|
+
* (agentId, chain). Stamps `lastModified`.
|
|
156
|
+
*
|
|
157
|
+
* Caller is responsible for supplying the matching address — for EVM
|
|
158
|
+
* this can be derived from the private key, for Solana the keypair
|
|
159
|
+
* generator returns it directly.
|
|
160
|
+
*/
|
|
161
|
+
export async function setAgentWallet(vault, agentId, chain, privateKey, address, caller) {
|
|
162
|
+
if (typeof privateKey !== "string" || privateKey.trim().length === 0) {
|
|
163
|
+
throw new TypeError("agent-wallets: privateKey required");
|
|
164
|
+
}
|
|
165
|
+
if (typeof address !== "string" || address.trim().length === 0) {
|
|
166
|
+
throw new TypeError("agent-wallets: address required");
|
|
167
|
+
}
|
|
168
|
+
const stored = {
|
|
169
|
+
chain,
|
|
170
|
+
address,
|
|
171
|
+
privateKey,
|
|
172
|
+
lastModified: Date.now(),
|
|
173
|
+
};
|
|
174
|
+
const key = walletKey(agentId, chain);
|
|
175
|
+
await vault.set(key, JSON.stringify(stored), {
|
|
176
|
+
sensitive: true,
|
|
177
|
+
...(caller ? { caller } : {}),
|
|
178
|
+
});
|
|
179
|
+
// Surface per-agent wallets in Settings → Vault → Secrets under the
|
|
180
|
+
// "Wallet" group. Without explicit meta, the inventory categorizer
|
|
181
|
+
// falls back to "plugin" for the `agent.<id>.wallet.<chain>` shape.
|
|
182
|
+
await setEntryMeta(vault, key, {
|
|
183
|
+
category: "wallet",
|
|
184
|
+
label: `agent ${agentId} (${chain})`,
|
|
185
|
+
});
|
|
186
|
+
return {
|
|
187
|
+
agentId,
|
|
188
|
+
chain,
|
|
189
|
+
address: stored.address,
|
|
190
|
+
lastModified: stored.lastModified,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Generate a fresh wallet for an agent and persist it. Returns the
|
|
195
|
+
* public descriptor. Idempotent: callers should check `hasAgentWallet`
|
|
196
|
+
* first if they want to avoid replacing an existing wallet.
|
|
197
|
+
*/
|
|
198
|
+
export async function generateAgentWallet(vault, agentId, chain, caller) {
|
|
199
|
+
const generated = generateWalletForChain(chain);
|
|
200
|
+
return setAgentWallet(vault, agentId, chain, generated.privateKey, generated.address, caller);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Generate any missing wallets (EVM + Solana) for an agent. Existing
|
|
204
|
+
* wallets are left alone. Returns descriptors for every chain that now
|
|
205
|
+
* has a wallet (whether it was generated this call or was already
|
|
206
|
+
* present).
|
|
207
|
+
*/
|
|
208
|
+
export async function ensureAgentWallets(vault, agentId, caller) {
|
|
209
|
+
const chains = ["evm", "solana"];
|
|
210
|
+
const out = [];
|
|
211
|
+
for (const chain of chains) {
|
|
212
|
+
const existing = await getAgentWalletDescriptor(vault, agentId, chain);
|
|
213
|
+
if (existing) {
|
|
214
|
+
out.push(existing);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
out.push(await generateAgentWallet(vault, agentId, chain, caller));
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Remove an agent's wallet for one chain. Idempotent.
|
|
223
|
+
*/
|
|
224
|
+
export async function removeAgentWallet(vault, agentId, chain) {
|
|
225
|
+
const key = walletKey(agentId, chain);
|
|
226
|
+
await vault.remove(key);
|
|
227
|
+
await removeEntryMeta(vault, key);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Remove every wallet for an agent. Use during agent deletion.
|
|
231
|
+
*/
|
|
232
|
+
export async function removeAllAgentWallets(vault, agentId) {
|
|
233
|
+
const wallets = await listAgentWallets(vault, agentId);
|
|
234
|
+
for (const w of wallets) {
|
|
235
|
+
await removeAgentWallet(vault, agentId, w.chain);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Internal helpers — exported for tests only.
|
|
239
|
+
export const __test__ = {
|
|
240
|
+
walletKey,
|
|
241
|
+
agentPrefix,
|
|
242
|
+
parseAgentWalletKey,
|
|
243
|
+
deriveAddressFor,
|
|
244
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eliza-plugin.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/runtime/eliza-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAiB,MAAM,EAAgB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"eliza-plugin.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/runtime/eliza-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAiB,MAAM,EAAgB,MAAM,eAAe,CAAC;AAmHzE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,CA2MpE"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* Memory search/get actions are superseded by plugin-clipboard.
|
|
7
7
|
*/
|
|
8
8
|
import { AgentEventService } from "@elizaos/core";
|
|
9
|
+
import { browserAutofillLoginAction } from "../actions/browser-autofill-login.js";
|
|
9
10
|
import { browserSessionAction } from "../actions/browser-session.js";
|
|
10
11
|
import { disconnectConnectorAction, listConnectorsAction, saveConnectorConfigAction, toggleConnectorAction, } from "../actions/connector-control.js";
|
|
11
12
|
import { executeDatabaseQueryAction, getTableDataAction, listDatabaseTablesAction, searchVectorsAction, } from "../actions/database.js";
|
|
@@ -186,6 +187,7 @@ export function createElizaPlugin(config) {
|
|
|
186
187
|
webSearchAction,
|
|
187
188
|
extractPageAction,
|
|
188
189
|
browserSessionAction,
|
|
190
|
+
browserAutofillLoginAction,
|
|
189
191
|
launchpadLaunchAction,
|
|
190
192
|
readChannelAction,
|
|
191
193
|
searchConversationsAction,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eliza.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/runtime/eliza.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eliza.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/runtime/eliza.ts"],"names":[],"mappings":"AA+BA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,yBAAyB,EACzB,iCAAiC,EACjC,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,+BAA+B,GAChC,MAAM,mBAAmB,CAAC;AAiB3B,OAAO,EACL,YAAY,EASZ,KAAK,QAAQ,EAIb,KAAK,MAAM,EAKZ,MAAM,eAAe,CAAC;AA2BvB,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,qBAAqB,CAAC;AAuB7B,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAqQxE,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,WAAW,GACnB,IAAI,CA2IN;AAgPD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EACxC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAgBhE;AAgMD,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,CAAC;AA4B/C;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA+BjE;AAunBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMzD;AA8KD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAO/D;AA8MD,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CA6NxE;AA0YD;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,WAAW,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,SAAS,CAKpB;AA0DD,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE,uBAA4B,GACjC,OAAO,CAAC,YAAY,CAAC,CAYvB;AAcD,eAAO,MAAM,iBAAiB,GAAI,OAAO,QAAQ,SAiChD,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAwiDnC;AASD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CA8FnC"}
|
|
@@ -20,6 +20,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
20
20
|
// Extracted modules — re-exported for backward compatibility
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
import { runFirstTimeSetup } from "./first-time-setup.js";
|
|
23
|
+
import { resolveConfigEnvForProcess } from "./operations/vault-bridge.js";
|
|
23
24
|
import { resolvePlugins } from "./plugin-resolver.js";
|
|
24
25
|
import { CUSTOM_PLUGINS_DIRNAME as CUSTOM_RUNTIME_PLUGINS_DIRNAME, STATIC_ELIZA_PLUGINS, } from "./plugin-types.js";
|
|
25
26
|
export { CHANNEL_PLUGIN_MAP, collectPluginNames, OPTIONAL_PLUGIN_MAP, PROVIDER_PLUGIN_MAP, } from "./plugin-collector.js";
|
|
@@ -2217,7 +2218,35 @@ export async function startEliza(opts) {
|
|
|
2217
2218
|
applyX402ConfigToEnv(config);
|
|
2218
2219
|
// 2d. Propagate database config into process.env for plugin-sql
|
|
2219
2220
|
applyDatabaseConfigToEnv(config);
|
|
2220
|
-
// 2e.
|
|
2221
|
+
// 2e. Boot-time vault hydration. Migrate plaintext sensitive values from
|
|
2222
|
+
// milady.json + config.env + sensitive process.env keys into the OS-keychain
|
|
2223
|
+
// vault, then resolve any vault://KEY sentinels in `config.env` so the
|
|
2224
|
+
// legacy hydration loop below sees real values.
|
|
2225
|
+
{
|
|
2226
|
+
const { runVaultBootstrap } = await import("@elizaos/app-core/services/vault-bootstrap");
|
|
2227
|
+
const { sharedVault } = await import("@elizaos/app-core/services/vault-mirror");
|
|
2228
|
+
const bootResult = await runVaultBootstrap();
|
|
2229
|
+
logger.info(`[vault-bootstrap] migrated=${bootResult.migrated} already-hydrated=${bootResult.alreadyHydrated} failed=${bootResult.failed.length}`);
|
|
2230
|
+
const { resolved, missing } = await resolveConfigEnvForProcess(config.env, sharedVault());
|
|
2231
|
+
if (missing.length > 0) {
|
|
2232
|
+
logger.warn(`[vault-bootstrap] sentinel(s) without vault entry: ${missing.join(", ")}`);
|
|
2233
|
+
}
|
|
2234
|
+
if (config.env &&
|
|
2235
|
+
typeof config.env === "object" &&
|
|
2236
|
+
!Array.isArray(config.env)) {
|
|
2237
|
+
for (const [key, value] of Object.entries(resolved)) {
|
|
2238
|
+
config.env[key] = value;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
const varsBag = config.env?.vars;
|
|
2242
|
+
if (varsBag && typeof varsBag === "object" && !Array.isArray(varsBag)) {
|
|
2243
|
+
const varsResult = await resolveConfigEnvForProcess(varsBag, sharedVault());
|
|
2244
|
+
for (const [key, value] of Object.entries(varsResult.resolved)) {
|
|
2245
|
+
varsBag[key] = value;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
// 2f. Propagate arbitrary env vars from config.env into process.env.
|
|
2221
2250
|
// Eliza stores user-defined env vars (plugin settings, API URLs, etc.)
|
|
2222
2251
|
// in config.env; elizaOS plugins read them via process.env / getSetting.
|
|
2223
2252
|
// Skip ELIZAOS_CLOUD_* — applyCloudConfigToEnv() owns those; otherwise a
|
|
@@ -2338,6 +2367,43 @@ export async function startEliza(opts) {
|
|
|
2338
2367
|
});
|
|
2339
2368
|
// 5. Create the Eliza bridge plugin (workspace context + session keys + compaction)
|
|
2340
2369
|
const agentId = character.name?.toLowerCase().replace(/\s+/g, "-") ?? "main";
|
|
2370
|
+
// 5-pre0. Apply per-agent vault profile overrides to process.env.
|
|
2371
|
+
//
|
|
2372
|
+
// Vault keys with multiple named profiles (work / personal / throwaway)
|
|
2373
|
+
// resolve the active profile for THIS agent through the vault's
|
|
2374
|
+
// routing layer, then write the resolved value into process.env so
|
|
2375
|
+
// the synchronous runtime.getSetting fast path picks it up. Idempotent;
|
|
2376
|
+
// safe to run multiple times. Opt-out via
|
|
2377
|
+
// MILADY_DISABLE_VAULT_PROFILE_RESOLVER=1.
|
|
2378
|
+
if (process.env.MILADY_DISABLE_VAULT_PROFILE_RESOLVER !== "1") {
|
|
2379
|
+
try {
|
|
2380
|
+
const { sharedVault } = await import("@elizaos/app-core/services/vault-mirror");
|
|
2381
|
+
const { applyVaultProfilesForAgent } = await import("./vault-profile-resolver.js");
|
|
2382
|
+
await applyVaultProfilesForAgent(sharedVault(), agentId);
|
|
2383
|
+
}
|
|
2384
|
+
catch (err) {
|
|
2385
|
+
logger.warn(`[vault-profile-resolver] boot-time apply failed agent="${agentId}": ${err instanceof Error ? err.message : String(err)}`);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
// 5-pre. Ensure each agent has its own EVM + Solana keypair in the vault.
|
|
2389
|
+
// The runtime-wide EVM_PRIVATE_KEY / SOLANA_PRIVATE_KEY (process.env) is
|
|
2390
|
+
// the *user* wallet; per-agent wallets live inside the encrypted vault and
|
|
2391
|
+
// are surfaced separately in the in-app browser. Idempotent — existing
|
|
2392
|
+
// wallets are preserved. Opt-out via MILADY_DISABLE_AGENT_WALLET_BOOTSTRAP=1.
|
|
2393
|
+
if (process.env.MILADY_DISABLE_AGENT_WALLET_BOOTSTRAP !== "1") {
|
|
2394
|
+
try {
|
|
2395
|
+
const { sharedVault } = await import("@elizaos/app-core/services/vault-mirror");
|
|
2396
|
+
const { ensureAgentWallets } = await import("./agent-wallets.js");
|
|
2397
|
+
const descriptors = await ensureAgentWallets(sharedVault(), agentId, "agent-bootstrap");
|
|
2398
|
+
const summary = descriptors
|
|
2399
|
+
.map((d) => `${d.chain}:${d.address}`)
|
|
2400
|
+
.join(" ");
|
|
2401
|
+
logger.info(`[agent-wallets] agent="${agentId}" wallets ready (${summary})`);
|
|
2402
|
+
}
|
|
2403
|
+
catch (err) {
|
|
2404
|
+
logger.warn(`[agent-wallets] failed to ensure wallets for agent="${agentId}": ${err instanceof Error ? err.message : String(err)}`);
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2341
2407
|
// 5a. If cloud is configured and no local GitHub token, try fetching from cloud
|
|
2342
2408
|
await autoFetchCloudGithubToken(config.cloud?.agentId?.trim() || agentId);
|
|
2343
2409
|
// 5b. Pump N8N_HOST + N8N_API_KEY into process.env for
|
|
@@ -13,5 +13,5 @@ export { DefaultRuntimeOperationManager, type DefaultRuntimeOperationManagerOpti
|
|
|
13
13
|
export { createHotStrategy, type HotStrategyDeps } from "./reload-hot.js";
|
|
14
14
|
export { FilesystemRuntimeOperationRepository, getDefaultRepository, } from "./repository.js";
|
|
15
15
|
export * from "./types.js";
|
|
16
|
-
export { _resetDefaultSecretsManagerForTesting, defaultSecretsManager, persistProviderApiKey, resolveProviderApiKey, vaultKeyForProviderApiKey, } from "./vault-bridge.js";
|
|
16
|
+
export { _resetDefaultSecretsManagerForTesting, defaultSecretsManager, formatVaultRef, isVaultRef, parseVaultRef, persistProviderApiKey, resolveConfigEnvForProcess, resolveProviderApiKey, type VaultLike, vaultKeyForProviderApiKey, } from "./vault-bridge.js";
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../agent/src/runtime/operations/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,eAAe,EACpB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,8BAA8B,EAC9B,KAAK,qCAAqC,EAC1C,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EACL,oCAAoC,EACpC,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,qCAAqC,EACrC,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../agent/src/runtime/operations/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,eAAe,EACpB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,8BAA8B,EAC9B,KAAK,qCAAqC,EAC1C,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EACL,oCAAoC,EACpC,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,qCAAqC,EACrC,qBAAqB,EACrB,cAAc,EACd,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,SAAS,EACd,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC"}
|
|
@@ -12,4 +12,4 @@ export { DefaultRuntimeOperationManager, } from "./manager.js";
|
|
|
12
12
|
export { createHotStrategy } from "./reload-hot.js";
|
|
13
13
|
export { FilesystemRuntimeOperationRepository, getDefaultRepository, } from "./repository.js";
|
|
14
14
|
export * from "./types.js";
|
|
15
|
-
export { _resetDefaultSecretsManagerForTesting, defaultSecretsManager, persistProviderApiKey, resolveProviderApiKey, vaultKeyForProviderApiKey, } from "./vault-bridge.js";
|
|
15
|
+
export { _resetDefaultSecretsManagerForTesting, defaultSecretsManager, formatVaultRef, isVaultRef, parseVaultRef, persistProviderApiKey, resolveConfigEnvForProcess, resolveProviderApiKey, vaultKeyForProviderApiKey, } from "./vault-bridge.js";
|
|
@@ -13,12 +13,33 @@
|
|
|
13
13
|
* SecretsManager (tests), or call `defaultSecretsManager()` (production)
|
|
14
14
|
* which constructs a fresh manager backed by the OS-keychain vault.
|
|
15
15
|
*/
|
|
16
|
-
import { type SecretsManager } from "@elizaos/vault";
|
|
16
|
+
import { type SecretsManager, type Vault } from "@elizaos/vault";
|
|
17
17
|
import type { OperationErrorCode } from "./types.js";
|
|
18
18
|
export declare class VaultResolveError extends Error {
|
|
19
19
|
readonly code: OperationErrorCode;
|
|
20
20
|
constructor(apiKeyRef: string, cause: unknown);
|
|
21
21
|
}
|
|
22
|
+
/** Format a stable vault key into the `vault://<key>` sentinel form. */
|
|
23
|
+
export declare function formatVaultRef(key: string): string;
|
|
24
|
+
/** Type guard: true when `value` is a `vault://<key>` sentinel string. */
|
|
25
|
+
export declare function isVaultRef(value: unknown): value is string;
|
|
26
|
+
/** Extract the underlying vault key from a sentinel; null if malformed. */
|
|
27
|
+
export declare function parseVaultRef(value: string): string | null;
|
|
28
|
+
/** Narrow surface of `Vault` used by the boot resolver — easier to stub. */
|
|
29
|
+
export type VaultLike = Pick<Vault, "get" | "has">;
|
|
30
|
+
/**
|
|
31
|
+
* Walk an env-shaped record and replace `vault://<key>` sentinels with the
|
|
32
|
+
* resolved vault values. Non-sentinel strings are passed through unchanged;
|
|
33
|
+
* non-string values are dropped (process.env only accepts strings).
|
|
34
|
+
*
|
|
35
|
+
* Returns `missing` for sentinel keys the vault does not contain — callers
|
|
36
|
+
* should warn but continue (the legacy hydrate-from-config-env path will run
|
|
37
|
+
* next and may still backfill from non-sentinel sources).
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveConfigEnvForProcess(envBag: Record<string, unknown> | undefined, vault: VaultLike): Promise<{
|
|
40
|
+
resolved: Record<string, string>;
|
|
41
|
+
missing: string[];
|
|
42
|
+
}>;
|
|
22
43
|
/** Stable vault key for a provider API key. */
|
|
23
44
|
export declare function vaultKeyForProviderApiKey(normalizedProvider: string): string;
|
|
24
45
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-bridge.d.ts","sourceRoot":"","sources":["../../../../../../../agent/src/runtime/operations/vault-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"vault-bridge.d.ts","sourceRoot":"","sources":["../../../../../../../agent/src/runtime/operations/vault-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAiB,KAAK,cAAc,EAAE,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAA0B;gBAE/C,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAQ9C;AAKD,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAM1D;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG1D;AAED,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;AAEnD;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,KAAK,EAAE,SAAS,GACf,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAqBlE;AAED,+CAA+C;AAC/C,wBAAgB,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAO5E;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,OAAO,EAAE,cAAc,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAOlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,OAAO,EAAE,cAAc,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO9B;AAID;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,cAAc,CAGtD;AAED,0CAA0C;AAC1C,wBAAgB,qCAAqC,IAAI,IAAI,CAE5D"}
|
|
@@ -21,6 +21,59 @@ export class VaultResolveError extends Error {
|
|
|
21
21
|
this.name = "VaultResolveError";
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
/** Sentinel prefix marking a config value that resolves through the vault. */
|
|
25
|
+
const VAULT_REF_PREFIX = "vault://";
|
|
26
|
+
/** Format a stable vault key into the `vault://<key>` sentinel form. */
|
|
27
|
+
export function formatVaultRef(key) {
|
|
28
|
+
if (typeof key !== "string" || key.length === 0) {
|
|
29
|
+
throw new TypeError(`[runtime-ops:vault] formatVaultRef requires a non-empty key`);
|
|
30
|
+
}
|
|
31
|
+
return `${VAULT_REF_PREFIX}${key}`;
|
|
32
|
+
}
|
|
33
|
+
/** Type guard: true when `value` is a `vault://<key>` sentinel string. */
|
|
34
|
+
export function isVaultRef(value) {
|
|
35
|
+
return (typeof value === "string" &&
|
|
36
|
+
value.startsWith(VAULT_REF_PREFIX) &&
|
|
37
|
+
value.length > VAULT_REF_PREFIX.length);
|
|
38
|
+
}
|
|
39
|
+
/** Extract the underlying vault key from a sentinel; null if malformed. */
|
|
40
|
+
export function parseVaultRef(value) {
|
|
41
|
+
if (!isVaultRef(value))
|
|
42
|
+
return null;
|
|
43
|
+
return value.slice(VAULT_REF_PREFIX.length);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Walk an env-shaped record and replace `vault://<key>` sentinels with the
|
|
47
|
+
* resolved vault values. Non-sentinel strings are passed through unchanged;
|
|
48
|
+
* non-string values are dropped (process.env only accepts strings).
|
|
49
|
+
*
|
|
50
|
+
* Returns `missing` for sentinel keys the vault does not contain — callers
|
|
51
|
+
* should warn but continue (the legacy hydrate-from-config-env path will run
|
|
52
|
+
* next and may still backfill from non-sentinel sources).
|
|
53
|
+
*/
|
|
54
|
+
export async function resolveConfigEnvForProcess(envBag, vault) {
|
|
55
|
+
const resolved = {};
|
|
56
|
+
const missing = [];
|
|
57
|
+
if (!envBag)
|
|
58
|
+
return { resolved, missing };
|
|
59
|
+
for (const [envKey, value] of Object.entries(envBag)) {
|
|
60
|
+
if (typeof value !== "string")
|
|
61
|
+
continue;
|
|
62
|
+
if (!isVaultRef(value)) {
|
|
63
|
+
resolved[envKey] = value;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const vaultKey = parseVaultRef(value);
|
|
67
|
+
if (!vaultKey)
|
|
68
|
+
continue;
|
|
69
|
+
if (!(await vault.has(vaultKey))) {
|
|
70
|
+
missing.push(vaultKey);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
resolved[envKey] = await vault.get(vaultKey);
|
|
74
|
+
}
|
|
75
|
+
return { resolved, missing };
|
|
76
|
+
}
|
|
24
77
|
/** Stable vault key for a provider API key. */
|
|
25
78
|
export function vaultKeyForProviderApiKey(normalizedProvider) {
|
|
26
79
|
if (!normalizedProvider || normalizedProvider.includes(".")) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { resolveActionContexts, resolveProviderContexts, } from "
|
|
2
|
+
import { resolveActionContexts, resolveProviderContexts, } from "@elizaos/core";
|
|
3
3
|
const pluginRegistrationContext = new AsyncLocalStorage();
|
|
4
4
|
const pluginServiceStartContext = new AsyncLocalStorage();
|
|
5
5
|
const serviceClassOwners = new WeakMap();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent vault profile resolver.
|
|
3
|
+
*
|
|
4
|
+
* Walks every vault entry that has profile metadata, asks the vault's
|
|
5
|
+
* routing layer which profile applies for the current agent, and pumps
|
|
6
|
+
* the resolved value into `process.env[KEY]`. Runtime hot paths read
|
|
7
|
+
* env vars synchronously (`process.env.OPENROUTER_API_KEY`, etc.), so
|
|
8
|
+
* we resolve once at agent boot rather than instrumenting every call
|
|
9
|
+
* site.
|
|
10
|
+
*
|
|
11
|
+
* Scope: this is the minimum-viable wiring per the spec —
|
|
12
|
+
* - Only `agent` scope rules apply; the runtime knows agentId.
|
|
13
|
+
* - `app` and `skill` scope rules are persisted but not yet
|
|
14
|
+
* resolved here (no call site has the context).
|
|
15
|
+
*
|
|
16
|
+
* Idempotent: re-running for the same agent overwrites with the same
|
|
17
|
+
* value. Opt-out via `MILADY_DISABLE_VAULT_PROFILE_RESOLVER=1`.
|
|
18
|
+
*/
|
|
19
|
+
import { type Vault } from "@elizaos/vault";
|
|
20
|
+
export interface ResolveProfilesResult {
|
|
21
|
+
/** Number of keys whose env value was overridden. */
|
|
22
|
+
readonly overridden: number;
|
|
23
|
+
/** Keys that had profiles but every candidate profile was empty. */
|
|
24
|
+
readonly skipped: ReadonlyArray<string>;
|
|
25
|
+
/** Keys where resolution failed (vault read error). */
|
|
26
|
+
readonly failed: ReadonlyArray<string>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* For each inventory entry that has `hasProfiles === true`, resolve
|
|
30
|
+
* the active value for `agentId` and write it into `process.env[KEY]`.
|
|
31
|
+
*
|
|
32
|
+
* Keys without profiles are left alone — `process.env` already holds
|
|
33
|
+
* whatever the legacy hydration path put there (config.env, milady.json,
|
|
34
|
+
* direct env). This resolver is purely additive.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyVaultProfilesForAgent(vault: Vault, agentId: string): Promise<ResolveProfilesResult>;
|
|
37
|
+
//# sourceMappingURL=vault-profile-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault-profile-resolver.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/runtime/vault-profile-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAGL,KAAK,KAAK,EAEX,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,qBAAqB;IACpC,qDAAqD;IACrD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,CAAC,CAsDhC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent vault profile resolver.
|
|
3
|
+
*
|
|
4
|
+
* Walks every vault entry that has profile metadata, asks the vault's
|
|
5
|
+
* routing layer which profile applies for the current agent, and pumps
|
|
6
|
+
* the resolved value into `process.env[KEY]`. Runtime hot paths read
|
|
7
|
+
* env vars synchronously (`process.env.OPENROUTER_API_KEY`, etc.), so
|
|
8
|
+
* we resolve once at agent boot rather than instrumenting every call
|
|
9
|
+
* site.
|
|
10
|
+
*
|
|
11
|
+
* Scope: this is the minimum-viable wiring per the spec —
|
|
12
|
+
* - Only `agent` scope rules apply; the runtime knows agentId.
|
|
13
|
+
* - `app` and `skill` scope rules are persisted but not yet
|
|
14
|
+
* resolved here (no call site has the context).
|
|
15
|
+
*
|
|
16
|
+
* Idempotent: re-running for the same agent overwrites with the same
|
|
17
|
+
* value. Opt-out via `MILADY_DISABLE_VAULT_PROFILE_RESOLVER=1`.
|
|
18
|
+
*/
|
|
19
|
+
import { logger } from "@elizaos/core";
|
|
20
|
+
import { listVaultInventory, resolveActiveValue, } from "@elizaos/vault";
|
|
21
|
+
/**
|
|
22
|
+
* For each inventory entry that has `hasProfiles === true`, resolve
|
|
23
|
+
* the active value for `agentId` and write it into `process.env[KEY]`.
|
|
24
|
+
*
|
|
25
|
+
* Keys without profiles are left alone — `process.env` already holds
|
|
26
|
+
* whatever the legacy hydration path put there (config.env, milady.json,
|
|
27
|
+
* direct env). This resolver is purely additive.
|
|
28
|
+
*/
|
|
29
|
+
export async function applyVaultProfilesForAgent(vault, agentId) {
|
|
30
|
+
if (process.env.MILADY_DISABLE_VAULT_PROFILE_RESOLVER === "1") {
|
|
31
|
+
return { overridden: 0, skipped: [], failed: [] };
|
|
32
|
+
}
|
|
33
|
+
let entries;
|
|
34
|
+
try {
|
|
35
|
+
entries = await listVaultInventory(vault);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
logger.warn(`[vault-profile-resolver] inventory listing failed for agent="${agentId}": ${err instanceof Error ? err.message : String(err)}`);
|
|
39
|
+
return { overridden: 0, skipped: [], failed: [] };
|
|
40
|
+
}
|
|
41
|
+
let overridden = 0;
|
|
42
|
+
const skipped = [];
|
|
43
|
+
const failed = [];
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (!entry.hasProfiles)
|
|
46
|
+
continue;
|
|
47
|
+
if (entry.kind === "reference") {
|
|
48
|
+
// Reference entries resolve through their backing password
|
|
49
|
+
// manager, not through profiles. Skip — but only after auditing
|
|
50
|
+
// we'd actually have a profile blob to read.
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const value = await resolveActiveValue(vault, entry.key, { agentId });
|
|
55
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
56
|
+
skipped.push(entry.key);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
process.env[entry.key] = value;
|
|
60
|
+
overridden += 1;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
// resolveActiveValue throws when no profile and no bare value
|
|
64
|
+
// resolves. Don't try to fall back to legacy env — the user
|
|
65
|
+
// explicitly declared profiles for this key, so an unresolvable
|
|
66
|
+
// active profile is a real failure they should see.
|
|
67
|
+
failed.push(entry.key);
|
|
68
|
+
logger.warn(`[vault-profile-resolver] failed to resolve agent="${agentId}" key="${entry.key}": ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (overridden > 0 || failed.length > 0) {
|
|
72
|
+
logger.info(`[vault-profile-resolver] agent="${agentId}" overridden=${overridden} skipped=${skipped.length} failed=${failed.length}`);
|
|
73
|
+
}
|
|
74
|
+
return { overridden, skipped: Object.freeze(skipped), failed: Object.freeze(failed) };
|
|
75
|
+
}
|