@aomi-labs/client 0.1.2 → 0.1.6
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/README.md +3 -1
- package/dist/cli.js +240 -103
- package/dist/index.cjs +76 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -10
- package/dist/index.d.ts +16 -10
- package/dist/index.js +76 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/aomi-transact/SKILL.md +13 -6
package/README.md
CHANGED
|
@@ -169,7 +169,7 @@ before sending the message and updates that persisted state as well.
|
|
|
169
169
|
The backend builds transactions; the CLI persists and signs them:
|
|
170
170
|
|
|
171
171
|
```
|
|
172
|
-
$ npx @aomi-labs/client chat "swap 1 ETH for USDC on Uniswap" --public-key 0xYourAddr
|
|
172
|
+
$ npx @aomi-labs/client chat "swap 1 ETH for USDC on Uniswap" --public-key 0xYourAddr --chain 1
|
|
173
173
|
⚡ Wallet request queued: tx-1
|
|
174
174
|
to: 0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD
|
|
175
175
|
value: 1000000000000000000
|
|
@@ -257,6 +257,7 @@ All config can be passed as flags (which take priority over env vars):
|
|
|
257
257
|
| `--public-key` | `AOMI_PUBLIC_KEY` | — | Wallet address (tells agent your wallet) |
|
|
258
258
|
| `--private-key` | `PRIVATE_KEY` | — | Hex private key for `aomi sign` |
|
|
259
259
|
| `--rpc-url` | `CHAIN_RPC_URL` | — | RPC URL for transaction submission |
|
|
260
|
+
| `--chain` | `AOMI_CHAIN_ID` | `1` | Chain ID (1, 137, 42161, 8453, 10, 11155111) |
|
|
260
261
|
| `--verbose`, `-v` | — | — | Stream tool calls and agent responses live |
|
|
261
262
|
|
|
262
263
|
```bash
|
|
@@ -285,6 +286,7 @@ persists a small JSON file to `$TMPDIR/aomi-session.json`:
|
|
|
285
286
|
| `sessionId` | Which conversation to continue |
|
|
286
287
|
| `model` | Last successfully applied model for the session |
|
|
287
288
|
| `publicKey` | Wallet address (from `--public-key`) |
|
|
289
|
+
| `chainId` | Active chain ID (from `--chain`) |
|
|
288
290
|
| `pendingTxs` | Unsigned transactions waiting for `aomi sign <id>` |
|
|
289
291
|
| `signedTxs` | Completed transactions with hashes/signatures |
|
|
290
292
|
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,54 @@ var __spreadValues = (a, b) => {
|
|
|
19
19
|
};
|
|
20
20
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
21
|
|
|
22
|
+
// src/cli/errors.ts
|
|
23
|
+
var CliExit = class extends Error {
|
|
24
|
+
constructor(code) {
|
|
25
|
+
super();
|
|
26
|
+
this.code = code;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
function fatal(message) {
|
|
30
|
+
const RED = "\x1B[31m";
|
|
31
|
+
const DIM3 = "\x1B[2m";
|
|
32
|
+
const RESET3 = "\x1B[0m";
|
|
33
|
+
const lines = message.split("\n");
|
|
34
|
+
const [headline, ...details] = lines;
|
|
35
|
+
console.error(`${RED}\u274C ${headline}${RESET3}`);
|
|
36
|
+
for (const detail of details) {
|
|
37
|
+
if (!detail.trim()) {
|
|
38
|
+
console.error("");
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
console.error(`${DIM3}${detail}${RESET3}`);
|
|
42
|
+
}
|
|
43
|
+
throw new CliExit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
22
46
|
// src/cli/args.ts
|
|
47
|
+
var SUPPORTED_CHAIN_IDS = [1, 137, 42161, 8453, 10, 11155111];
|
|
48
|
+
var CHAIN_NAMES = {
|
|
49
|
+
1: "Ethereum",
|
|
50
|
+
137: "Polygon",
|
|
51
|
+
42161: "Arbitrum One",
|
|
52
|
+
8453: "Base",
|
|
53
|
+
10: "Optimism",
|
|
54
|
+
11155111: "Sepolia"
|
|
55
|
+
};
|
|
56
|
+
function parseChainId(value) {
|
|
57
|
+
if (value === void 0) return void 0;
|
|
58
|
+
const n = parseInt(value, 10);
|
|
59
|
+
if (Number.isNaN(n)) return void 0;
|
|
60
|
+
if (!SUPPORTED_CHAIN_IDS.includes(n)) {
|
|
61
|
+
const list = SUPPORTED_CHAIN_IDS.map(
|
|
62
|
+
(id) => ` ${id} (${CHAIN_NAMES[id]})`
|
|
63
|
+
).join("\n");
|
|
64
|
+
fatal(`Unsupported chain ID: ${n}
|
|
65
|
+
Supported chains:
|
|
66
|
+
${list}`);
|
|
67
|
+
}
|
|
68
|
+
return n;
|
|
69
|
+
}
|
|
23
70
|
function parseArgs(argv) {
|
|
24
71
|
const raw = argv.slice(2);
|
|
25
72
|
const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : void 0;
|
|
@@ -49,15 +96,16 @@ function parseArgs(argv) {
|
|
|
49
96
|
return { command, positional, flags };
|
|
50
97
|
}
|
|
51
98
|
function getConfig(parsed) {
|
|
52
|
-
var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
99
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
53
100
|
return {
|
|
54
101
|
baseUrl: (_b = (_a3 = parsed.flags["backend-url"]) != null ? _a3 : process.env.AOMI_BASE_URL) != null ? _b : "https://api.aomi.dev",
|
|
55
102
|
apiKey: (_c = parsed.flags["api-key"]) != null ? _c : process.env.AOMI_API_KEY,
|
|
56
|
-
|
|
103
|
+
app: (_e = (_d = parsed.flags["app"]) != null ? _d : process.env.AOMI_APP) != null ? _e : "default",
|
|
57
104
|
model: (_f = parsed.flags["model"]) != null ? _f : process.env.AOMI_MODEL,
|
|
58
105
|
publicKey: (_g = parsed.flags["public-key"]) != null ? _g : process.env.AOMI_PUBLIC_KEY,
|
|
59
106
|
privateKey: (_h = parsed.flags["private-key"]) != null ? _h : process.env.PRIVATE_KEY,
|
|
60
|
-
chainRpcUrl: (_i = parsed.flags["rpc-url"]) != null ? _i : process.env.CHAIN_RPC_URL
|
|
107
|
+
chainRpcUrl: (_i = parsed.flags["rpc-url"]) != null ? _i : process.env.CHAIN_RPC_URL,
|
|
108
|
+
chain: parseChainId((_j = parsed.flags["chain"]) != null ? _j : process.env.AOMI_CHAIN_ID)
|
|
61
109
|
};
|
|
62
110
|
}
|
|
63
111
|
function createRuntime(argv) {
|
|
@@ -106,10 +154,11 @@ function toCliSessionState(stored) {
|
|
|
106
154
|
return {
|
|
107
155
|
sessionId: stored.sessionId,
|
|
108
156
|
baseUrl: stored.baseUrl,
|
|
109
|
-
|
|
157
|
+
app: stored.app,
|
|
110
158
|
model: stored.model,
|
|
111
159
|
apiKey: stored.apiKey,
|
|
112
160
|
publicKey: stored.publicKey,
|
|
161
|
+
chainId: stored.chainId,
|
|
113
162
|
pendingTxs: stored.pendingTxs,
|
|
114
163
|
signedTxs: stored.signedTxs
|
|
115
164
|
};
|
|
@@ -126,10 +175,11 @@ function readStoredSession(path) {
|
|
|
126
175
|
return {
|
|
127
176
|
sessionId: parsed.sessionId,
|
|
128
177
|
baseUrl: parsed.baseUrl,
|
|
129
|
-
|
|
178
|
+
app: parsed.app,
|
|
130
179
|
model: parsed.model,
|
|
131
180
|
apiKey: parsed.apiKey,
|
|
132
181
|
publicKey: parsed.publicKey,
|
|
182
|
+
chainId: parsed.chainId,
|
|
133
183
|
pendingTxs: parsed.pendingTxs,
|
|
134
184
|
signedTxs: parsed.signedTxs,
|
|
135
185
|
localId: typeof parsed.localId === "number" && parsed.localId > 0 ? parsed.localId : fallbackLocalId,
|
|
@@ -699,9 +749,9 @@ var AomiClient = class {
|
|
|
699
749
|
*/
|
|
700
750
|
async sendMessage(sessionId, message, options) {
|
|
701
751
|
var _a3, _b;
|
|
702
|
-
const
|
|
752
|
+
const app = (_a3 = options == null ? void 0 : options.app) != null ? _a3 : "default";
|
|
703
753
|
const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : this.apiKey;
|
|
704
|
-
const payload = { message,
|
|
754
|
+
const payload = { message, app };
|
|
705
755
|
if (options == null ? void 0 : options.publicKey) {
|
|
706
756
|
payload.public_key = options.publicKey;
|
|
707
757
|
}
|
|
@@ -874,11 +924,11 @@ var AomiClient = class {
|
|
|
874
924
|
// Control API
|
|
875
925
|
// ===========================================================================
|
|
876
926
|
/**
|
|
877
|
-
* Get available
|
|
927
|
+
* Get available apps.
|
|
878
928
|
*/
|
|
879
|
-
async
|
|
929
|
+
async getApps(sessionId, options) {
|
|
880
930
|
var _a3;
|
|
881
|
-
const url = new URL("/api/control/
|
|
931
|
+
const url = new URL("/api/control/apps", this.baseUrl);
|
|
882
932
|
if (options == null ? void 0 : options.publicKey) {
|
|
883
933
|
url.searchParams.set("public_key", options.publicKey);
|
|
884
934
|
}
|
|
@@ -889,7 +939,7 @@ var AomiClient = class {
|
|
|
889
939
|
}
|
|
890
940
|
const response = await fetch(url.toString(), { headers });
|
|
891
941
|
if (!response.ok) {
|
|
892
|
-
throw new Error(`Failed to get
|
|
942
|
+
throw new Error(`Failed to get apps: HTTP ${response.status}`);
|
|
893
943
|
}
|
|
894
944
|
return await response.json();
|
|
895
945
|
}
|
|
@@ -919,8 +969,8 @@ var AomiClient = class {
|
|
|
919
969
|
var _a3;
|
|
920
970
|
const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
|
|
921
971
|
const payload = { rig };
|
|
922
|
-
if (options == null ? void 0 : options.
|
|
923
|
-
payload.
|
|
972
|
+
if (options == null ? void 0 : options.app) {
|
|
973
|
+
payload.app = options.app;
|
|
924
974
|
}
|
|
925
975
|
return postState(this.baseUrl, "/api/control/model", payload, sessionId, apiKey);
|
|
926
976
|
}
|
|
@@ -1054,7 +1104,7 @@ function getToolArgs(payload) {
|
|
|
1054
1104
|
const nestedArgs = asRecord(root == null ? void 0 : root.args);
|
|
1055
1105
|
return (_a3 = nestedArgs != null ? nestedArgs : root) != null ? _a3 : {};
|
|
1056
1106
|
}
|
|
1057
|
-
function
|
|
1107
|
+
function parseChainId2(value) {
|
|
1058
1108
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1059
1109
|
if (typeof value !== "string") return void 0;
|
|
1060
1110
|
const trimmed = value.trim();
|
|
@@ -1076,7 +1126,7 @@ function normalizeTxPayload(payload) {
|
|
|
1076
1126
|
const valueRaw = args.value;
|
|
1077
1127
|
const value = typeof valueRaw === "string" ? valueRaw : typeof valueRaw === "number" && Number.isFinite(valueRaw) ? String(Math.trunc(valueRaw)) : void 0;
|
|
1078
1128
|
const data = typeof args.data === "string" ? args.data : void 0;
|
|
1079
|
-
const chainId = (_c = (_b = (_a3 =
|
|
1129
|
+
const chainId = (_c = (_b = (_a3 = parseChainId2(args.chainId)) != null ? _a3 : parseChainId2(args.chain_id)) != null ? _b : parseChainId2(ctx == null ? void 0 : ctx.user_chain_id)) != null ? _c : parseChainId2(ctx == null ? void 0 : ctx.userChainId);
|
|
1080
1130
|
return { to, value, data, chainId };
|
|
1081
1131
|
}
|
|
1082
1132
|
function normalizeEip712Payload(payload) {
|
|
@@ -1101,7 +1151,38 @@ function normalizeEip712Payload(payload) {
|
|
|
1101
1151
|
}
|
|
1102
1152
|
|
|
1103
1153
|
// src/session.ts
|
|
1104
|
-
|
|
1154
|
+
function sortJson(value) {
|
|
1155
|
+
if (Array.isArray(value)) {
|
|
1156
|
+
return value.map((entry) => sortJson(entry));
|
|
1157
|
+
}
|
|
1158
|
+
if (value && typeof value === "object") {
|
|
1159
|
+
return Object.keys(value).sort().reduce((acc, key) => {
|
|
1160
|
+
acc[key] = sortJson(value[key]);
|
|
1161
|
+
return acc;
|
|
1162
|
+
}, {});
|
|
1163
|
+
}
|
|
1164
|
+
return value;
|
|
1165
|
+
}
|
|
1166
|
+
function isSubsetMatch(expected, actual) {
|
|
1167
|
+
if (Array.isArray(expected)) {
|
|
1168
|
+
if (!Array.isArray(actual) || expected.length !== actual.length) {
|
|
1169
|
+
return false;
|
|
1170
|
+
}
|
|
1171
|
+
return expected.every(
|
|
1172
|
+
(entry, index) => isSubsetMatch(entry, actual[index])
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
if (expected && typeof expected === "object") {
|
|
1176
|
+
if (!actual || typeof actual !== "object" || Array.isArray(actual)) {
|
|
1177
|
+
return false;
|
|
1178
|
+
}
|
|
1179
|
+
return Object.entries(expected).every(
|
|
1180
|
+
([key, value]) => isSubsetMatch(value, actual[key])
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
return expected === actual;
|
|
1184
|
+
}
|
|
1185
|
+
var ClientSession = class extends TypedEventEmitter {
|
|
1105
1186
|
constructor(clientOrOptions, sessionOptions) {
|
|
1106
1187
|
var _a3, _b, _c;
|
|
1107
1188
|
super();
|
|
@@ -1117,7 +1198,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
1117
1198
|
this.pendingResolve = null;
|
|
1118
1199
|
this.client = clientOrOptions instanceof AomiClient ? clientOrOptions : new AomiClient(clientOrOptions);
|
|
1119
1200
|
this.sessionId = (_a3 = sessionOptions == null ? void 0 : sessionOptions.sessionId) != null ? _a3 : crypto.randomUUID();
|
|
1120
|
-
this.
|
|
1201
|
+
this.app = (_b = sessionOptions == null ? void 0 : sessionOptions.app) != null ? _b : "default";
|
|
1121
1202
|
this.publicKey = sessionOptions == null ? void 0 : sessionOptions.publicKey;
|
|
1122
1203
|
this.apiKey = sessionOptions == null ? void 0 : sessionOptions.apiKey;
|
|
1123
1204
|
this.userState = sessionOptions == null ? void 0 : sessionOptions.userState;
|
|
@@ -1143,11 +1224,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
1143
1224
|
async send(message) {
|
|
1144
1225
|
this.assertOpen();
|
|
1145
1226
|
const response = await this.client.sendMessage(this.sessionId, message, {
|
|
1146
|
-
|
|
1227
|
+
app: this.app,
|
|
1147
1228
|
publicKey: this.publicKey,
|
|
1148
1229
|
apiKey: this.apiKey,
|
|
1149
1230
|
userState: this.userState
|
|
1150
1231
|
});
|
|
1232
|
+
this.assertUserStateAligned(response.user_state);
|
|
1151
1233
|
this.applyState(response);
|
|
1152
1234
|
if (!response.is_processing && this.walletRequests.length === 0) {
|
|
1153
1235
|
return { messages: this._messages, title: this._title };
|
|
@@ -1166,11 +1248,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
1166
1248
|
async sendAsync(message) {
|
|
1167
1249
|
this.assertOpen();
|
|
1168
1250
|
const response = await this.client.sendMessage(this.sessionId, message, {
|
|
1169
|
-
|
|
1251
|
+
app: this.app,
|
|
1170
1252
|
publicKey: this.publicKey,
|
|
1171
1253
|
apiKey: this.apiKey,
|
|
1172
1254
|
userState: this.userState
|
|
1173
1255
|
});
|
|
1256
|
+
this.assertUserStateAligned(response.user_state);
|
|
1174
1257
|
this.applyState(response);
|
|
1175
1258
|
if (response.is_processing) {
|
|
1176
1259
|
this._isProcessing = true;
|
|
@@ -1283,6 +1366,23 @@ var Session = class extends TypedEventEmitter {
|
|
|
1283
1366
|
getIsProcessing() {
|
|
1284
1367
|
return this._isProcessing;
|
|
1285
1368
|
}
|
|
1369
|
+
resolveUserState(userState) {
|
|
1370
|
+
this.userState = userState;
|
|
1371
|
+
const address = userState["address"];
|
|
1372
|
+
if (typeof address === "string" && address.length > 0) {
|
|
1373
|
+
this.publicKey = address;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
resolveWallet(address, chainId) {
|
|
1377
|
+
this.resolveUserState({ address, chainId: chainId != null ? chainId : 1, isConnected: true });
|
|
1378
|
+
}
|
|
1379
|
+
async syncUserState() {
|
|
1380
|
+
this.assertOpen();
|
|
1381
|
+
const state = await this.client.fetchState(this.sessionId, this.userState);
|
|
1382
|
+
this.assertUserStateAligned(state.user_state);
|
|
1383
|
+
this.applyState(state);
|
|
1384
|
+
return state;
|
|
1385
|
+
}
|
|
1286
1386
|
// ===========================================================================
|
|
1287
1387
|
// Internal — Polling (ported from PollingController)
|
|
1288
1388
|
// ===========================================================================
|
|
@@ -1311,6 +1411,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
1311
1411
|
this.userState
|
|
1312
1412
|
);
|
|
1313
1413
|
if (!this.pollTimer) return;
|
|
1414
|
+
this.assertUserStateAligned(state.user_state);
|
|
1314
1415
|
this.applyState(state);
|
|
1315
1416
|
if (!state.is_processing && this.walletRequests.length === 0) {
|
|
1316
1417
|
this.stopPolling();
|
|
@@ -1412,6 +1513,18 @@ var Session = class extends TypedEventEmitter {
|
|
|
1412
1513
|
throw new Error("Session is closed");
|
|
1413
1514
|
}
|
|
1414
1515
|
}
|
|
1516
|
+
assertUserStateAligned(actualUserState) {
|
|
1517
|
+
if (!this.userState || !actualUserState) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
if (!isSubsetMatch(this.userState, actualUserState)) {
|
|
1521
|
+
const expected = JSON.stringify(sortJson(this.userState));
|
|
1522
|
+
const actual = JSON.stringify(sortJson(actualUserState));
|
|
1523
|
+
throw new Error(
|
|
1524
|
+
`Backend user_state mismatch. expected subset=${expected} actual=${actual}`
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1415
1528
|
};
|
|
1416
1529
|
|
|
1417
1530
|
// src/cli/context.ts
|
|
@@ -1422,9 +1535,10 @@ function getOrCreateSession(runtime) {
|
|
|
1422
1535
|
state = {
|
|
1423
1536
|
sessionId: crypto.randomUUID(),
|
|
1424
1537
|
baseUrl: config.baseUrl,
|
|
1425
|
-
|
|
1538
|
+
app: config.app,
|
|
1426
1539
|
apiKey: config.apiKey,
|
|
1427
|
-
publicKey: config.publicKey
|
|
1540
|
+
publicKey: config.publicKey,
|
|
1541
|
+
chainId: config.chain
|
|
1428
1542
|
};
|
|
1429
1543
|
writeState(state);
|
|
1430
1544
|
} else {
|
|
@@ -1433,8 +1547,8 @@ function getOrCreateSession(runtime) {
|
|
|
1433
1547
|
state.baseUrl = config.baseUrl;
|
|
1434
1548
|
changed = true;
|
|
1435
1549
|
}
|
|
1436
|
-
if (config.
|
|
1437
|
-
state.
|
|
1550
|
+
if (config.app !== state.app) {
|
|
1551
|
+
state.app = config.app;
|
|
1438
1552
|
changed = true;
|
|
1439
1553
|
}
|
|
1440
1554
|
if (config.apiKey !== void 0 && config.apiKey !== state.apiKey) {
|
|
@@ -1445,22 +1559,24 @@ function getOrCreateSession(runtime) {
|
|
|
1445
1559
|
state.publicKey = config.publicKey;
|
|
1446
1560
|
changed = true;
|
|
1447
1561
|
}
|
|
1562
|
+
if (config.chain !== void 0 && config.chain !== state.chainId) {
|
|
1563
|
+
state.chainId = config.chain;
|
|
1564
|
+
changed = true;
|
|
1565
|
+
}
|
|
1448
1566
|
if (changed) writeState(state);
|
|
1449
1567
|
}
|
|
1450
|
-
const session = new
|
|
1568
|
+
const session = new ClientSession(
|
|
1451
1569
|
{ baseUrl: state.baseUrl, apiKey: state.apiKey },
|
|
1452
1570
|
{
|
|
1453
1571
|
sessionId: state.sessionId,
|
|
1454
|
-
|
|
1572
|
+
app: state.app,
|
|
1455
1573
|
apiKey: state.apiKey,
|
|
1456
|
-
publicKey: state.publicKey
|
|
1457
|
-
userState: state.publicKey ? {
|
|
1458
|
-
address: state.publicKey,
|
|
1459
|
-
chainId: 1,
|
|
1460
|
-
isConnected: true
|
|
1461
|
-
} : void 0
|
|
1574
|
+
publicKey: state.publicKey
|
|
1462
1575
|
}
|
|
1463
1576
|
);
|
|
1577
|
+
if (state.publicKey) {
|
|
1578
|
+
session.resolveWallet(state.publicKey, state.chainId);
|
|
1579
|
+
}
|
|
1464
1580
|
return { session, state };
|
|
1465
1581
|
}
|
|
1466
1582
|
function createControlClient(runtime) {
|
|
@@ -1471,7 +1587,7 @@ function createControlClient(runtime) {
|
|
|
1471
1587
|
}
|
|
1472
1588
|
async function applyModelSelection(session, state, model) {
|
|
1473
1589
|
await session.client.setModel(state.sessionId, model, {
|
|
1474
|
-
|
|
1590
|
+
app: state.app,
|
|
1475
1591
|
apiKey: state.apiKey
|
|
1476
1592
|
});
|
|
1477
1593
|
state.model = model;
|
|
@@ -1485,30 +1601,6 @@ async function applyRequestedModelIfPresent(runtime, session, state) {
|
|
|
1485
1601
|
await applyModelSelection(session, state, requestedModel);
|
|
1486
1602
|
}
|
|
1487
1603
|
|
|
1488
|
-
// src/cli/errors.ts
|
|
1489
|
-
var CliExit = class extends Error {
|
|
1490
|
-
constructor(code) {
|
|
1491
|
-
super();
|
|
1492
|
-
this.code = code;
|
|
1493
|
-
}
|
|
1494
|
-
};
|
|
1495
|
-
function fatal(message) {
|
|
1496
|
-
const RED = "\x1B[31m";
|
|
1497
|
-
const DIM3 = "\x1B[2m";
|
|
1498
|
-
const RESET3 = "\x1B[0m";
|
|
1499
|
-
const lines = message.split("\n");
|
|
1500
|
-
const [headline, ...details] = lines;
|
|
1501
|
-
console.error(`${RED}\u274C ${headline}${RESET3}`);
|
|
1502
|
-
for (const detail of details) {
|
|
1503
|
-
if (!detail.trim()) {
|
|
1504
|
-
console.error("");
|
|
1505
|
-
continue;
|
|
1506
|
-
}
|
|
1507
|
-
console.error(`${DIM3}${detail}${RESET3}`);
|
|
1508
|
-
}
|
|
1509
|
-
throw new CliExit(1);
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
1604
|
// src/cli/transactions.ts
|
|
1513
1605
|
function walletRequestToPendingTx(request) {
|
|
1514
1606
|
if (request.kind === "transaction") {
|
|
@@ -1558,17 +1650,7 @@ async function chatCommand(runtime) {
|
|
|
1558
1650
|
try {
|
|
1559
1651
|
await applyRequestedModelIfPresent(runtime, session, state);
|
|
1560
1652
|
if (state.publicKey) {
|
|
1561
|
-
|
|
1562
|
-
session.sessionId,
|
|
1563
|
-
JSON.stringify({
|
|
1564
|
-
type: "wallet:state_changed",
|
|
1565
|
-
payload: {
|
|
1566
|
-
address: state.publicKey,
|
|
1567
|
-
chainId: 1,
|
|
1568
|
-
isConnected: true
|
|
1569
|
-
}
|
|
1570
|
-
})
|
|
1571
|
-
);
|
|
1653
|
+
session.resolveWallet(state.publicKey, state.chainId);
|
|
1572
1654
|
}
|
|
1573
1655
|
const capturedRequests = [];
|
|
1574
1656
|
let printedAgentCount = 0;
|
|
@@ -1716,7 +1798,7 @@ async function statusCommand(runtime) {
|
|
|
1716
1798
|
{
|
|
1717
1799
|
sessionId: state.sessionId,
|
|
1718
1800
|
baseUrl: state.baseUrl,
|
|
1719
|
-
|
|
1801
|
+
app: state.app,
|
|
1720
1802
|
model: (_a3 = state.model) != null ? _a3 : null,
|
|
1721
1803
|
isProcessing: (_b = apiState.is_processing) != null ? _b : false,
|
|
1722
1804
|
messageCount: (_d = (_c = apiState.messages) == null ? void 0 : _c.length) != null ? _d : 0,
|
|
@@ -2154,8 +2236,51 @@ Run \`aomi tx\` to see available IDs.`
|
|
|
2154
2236
|
}
|
|
2155
2237
|
return pendingTx;
|
|
2156
2238
|
}
|
|
2239
|
+
function rewriteSessionState(runtime, state) {
|
|
2240
|
+
let changed = false;
|
|
2241
|
+
if (runtime.config.baseUrl !== state.baseUrl) {
|
|
2242
|
+
state.baseUrl = runtime.config.baseUrl;
|
|
2243
|
+
changed = true;
|
|
2244
|
+
}
|
|
2245
|
+
if (runtime.config.app !== state.app) {
|
|
2246
|
+
state.app = runtime.config.app;
|
|
2247
|
+
changed = true;
|
|
2248
|
+
}
|
|
2249
|
+
if (runtime.config.apiKey !== void 0 && runtime.config.apiKey !== state.apiKey) {
|
|
2250
|
+
state.apiKey = runtime.config.apiKey;
|
|
2251
|
+
changed = true;
|
|
2252
|
+
}
|
|
2253
|
+
if (runtime.config.chain !== void 0 && runtime.config.chain !== state.chainId) {
|
|
2254
|
+
state.chainId = runtime.config.chain;
|
|
2255
|
+
changed = true;
|
|
2256
|
+
}
|
|
2257
|
+
if (changed) {
|
|
2258
|
+
writeState(state);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
function createSessionFromState(state) {
|
|
2262
|
+
const session = new ClientSession(
|
|
2263
|
+
{ baseUrl: state.baseUrl, apiKey: state.apiKey },
|
|
2264
|
+
{
|
|
2265
|
+
sessionId: state.sessionId,
|
|
2266
|
+
app: state.app,
|
|
2267
|
+
apiKey: state.apiKey,
|
|
2268
|
+
publicKey: state.publicKey
|
|
2269
|
+
}
|
|
2270
|
+
);
|
|
2271
|
+
if (state.publicKey) {
|
|
2272
|
+
session.resolveWallet(state.publicKey, state.chainId);
|
|
2273
|
+
}
|
|
2274
|
+
return session;
|
|
2275
|
+
}
|
|
2276
|
+
async function persistResolvedSignerState(session, state, address, chainId) {
|
|
2277
|
+
state.publicKey = address;
|
|
2278
|
+
writeState(state);
|
|
2279
|
+
session.resolveWallet(address, chainId);
|
|
2280
|
+
await session.syncUserState();
|
|
2281
|
+
}
|
|
2157
2282
|
async function signCommand(runtime) {
|
|
2158
|
-
var _a3, _b, _c;
|
|
2283
|
+
var _a3, _b, _c, _d;
|
|
2159
2284
|
const txId = runtime.parsed.positional[0];
|
|
2160
2285
|
if (!txId) {
|
|
2161
2286
|
fatal(
|
|
@@ -2177,15 +2302,22 @@ async function signCommand(runtime) {
|
|
|
2177
2302
|
if (!state) {
|
|
2178
2303
|
fatal("No active session. Run `aomi chat` first.");
|
|
2179
2304
|
}
|
|
2305
|
+
rewriteSessionState(runtime, state);
|
|
2180
2306
|
const pendingTx = requirePendingTx(state, txId);
|
|
2181
|
-
const
|
|
2307
|
+
const session = createSessionFromState(state);
|
|
2182
2308
|
try {
|
|
2183
2309
|
const account = privateKeyToAccount(privateKey);
|
|
2310
|
+
if (state.publicKey && account.address.toLowerCase() !== state.publicKey.toLowerCase()) {
|
|
2311
|
+
console.log(
|
|
2312
|
+
`\u26A0\uFE0F Signer ${account.address} differs from session public key ${state.publicKey}`
|
|
2313
|
+
);
|
|
2314
|
+
console.log(" Updating session to match the signing key...");
|
|
2315
|
+
}
|
|
2184
2316
|
const rpcUrl = runtime.config.chainRpcUrl;
|
|
2185
|
-
const targetChainId = (_a3 = pendingTx.chainId) != null ? _a3 : 1;
|
|
2186
|
-
const chain = (
|
|
2317
|
+
const targetChainId = (_b = (_a3 = pendingTx.chainId) != null ? _a3 : state.chainId) != null ? _b : 1;
|
|
2318
|
+
const chain = (_c = Object.values(viemChains).find(
|
|
2187
2319
|
(candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === targetChainId
|
|
2188
|
-
)) != null ?
|
|
2320
|
+
)) != null ? _c : {
|
|
2189
2321
|
id: targetChainId,
|
|
2190
2322
|
name: `Chain ${targetChainId}`,
|
|
2191
2323
|
nativeCurrency: {
|
|
@@ -2207,6 +2339,8 @@ async function signCommand(runtime) {
|
|
|
2207
2339
|
console.log(`Signer: ${account.address}`);
|
|
2208
2340
|
console.log(`ID: ${pendingTx.id}`);
|
|
2209
2341
|
console.log(`Kind: ${pendingTx.kind}`);
|
|
2342
|
+
let signedRecord;
|
|
2343
|
+
let backendNotification;
|
|
2210
2344
|
if (pendingTx.kind === "transaction") {
|
|
2211
2345
|
console.log(`To: ${pendingTx.to}`);
|
|
2212
2346
|
if (pendingTx.value) console.log(`Value: ${pendingTx.value}`);
|
|
@@ -2218,12 +2352,10 @@ async function signCommand(runtime) {
|
|
|
2218
2352
|
const hash = await walletClient.sendTransaction({
|
|
2219
2353
|
to: pendingTx.to,
|
|
2220
2354
|
value: pendingTx.value ? BigInt(pendingTx.value) : /* @__PURE__ */ BigInt("0"),
|
|
2221
|
-
data: (
|
|
2355
|
+
data: (_d = pendingTx.data) != null ? _d : void 0
|
|
2222
2356
|
});
|
|
2223
2357
|
console.log(`\u2705 Sent! Hash: ${hash}`);
|
|
2224
|
-
|
|
2225
|
-
const freshState = readState();
|
|
2226
|
-
addSignedTx(freshState, {
|
|
2358
|
+
signedRecord = {
|
|
2227
2359
|
id: txId,
|
|
2228
2360
|
kind: "transaction",
|
|
2229
2361
|
txHash: hash,
|
|
@@ -2232,14 +2364,11 @@ async function signCommand(runtime) {
|
|
|
2232
2364
|
value: pendingTx.value,
|
|
2233
2365
|
chainId: pendingTx.chainId,
|
|
2234
2366
|
timestamp: Date.now()
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
payload: { txHash: hash, status: "success" }
|
|
2241
|
-
})
|
|
2242
|
-
);
|
|
2367
|
+
};
|
|
2368
|
+
backendNotification = {
|
|
2369
|
+
type: "wallet:tx_complete",
|
|
2370
|
+
payload: { txHash: hash, status: "success" }
|
|
2371
|
+
};
|
|
2243
2372
|
} else {
|
|
2244
2373
|
const typedData = pendingTx.payload.typed_data;
|
|
2245
2374
|
if (!typedData) {
|
|
@@ -2262,28 +2391,36 @@ async function signCommand(runtime) {
|
|
|
2262
2391
|
message
|
|
2263
2392
|
});
|
|
2264
2393
|
console.log(`\u2705 Signed! Signature: ${signature.slice(0, 20)}...`);
|
|
2265
|
-
|
|
2266
|
-
const freshState = readState();
|
|
2267
|
-
addSignedTx(freshState, {
|
|
2394
|
+
signedRecord = {
|
|
2268
2395
|
id: txId,
|
|
2269
2396
|
kind: "eip712_sign",
|
|
2270
2397
|
signature,
|
|
2271
2398
|
from: account.address,
|
|
2272
2399
|
description: pendingTx.description,
|
|
2273
2400
|
timestamp: Date.now()
|
|
2274
|
-
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
}
|
|
2284
|
-
})
|
|
2285
|
-
);
|
|
2401
|
+
};
|
|
2402
|
+
backendNotification = {
|
|
2403
|
+
type: "wallet_eip712_response",
|
|
2404
|
+
payload: {
|
|
2405
|
+
status: "success",
|
|
2406
|
+
signature,
|
|
2407
|
+
description: pendingTx.description
|
|
2408
|
+
}
|
|
2409
|
+
};
|
|
2286
2410
|
}
|
|
2411
|
+
await persistResolvedSignerState(
|
|
2412
|
+
session,
|
|
2413
|
+
state,
|
|
2414
|
+
account.address,
|
|
2415
|
+
targetChainId
|
|
2416
|
+
);
|
|
2417
|
+
removePendingTx(state, txId);
|
|
2418
|
+
const freshState = readState();
|
|
2419
|
+
addSignedTx(freshState, signedRecord);
|
|
2420
|
+
await session.client.sendSystemMessage(
|
|
2421
|
+
state.sessionId,
|
|
2422
|
+
JSON.stringify(backendNotification)
|
|
2423
|
+
);
|
|
2287
2424
|
console.log("Backend notified.");
|
|
2288
2425
|
} catch (err) {
|
|
2289
2426
|
if (err instanceof CliExit) throw err;
|
|
@@ -2320,8 +2457,8 @@ Usage:
|
|
|
2320
2457
|
|
|
2321
2458
|
Options:
|
|
2322
2459
|
--backend-url <url> Backend URL (default: https://api.aomi.dev)
|
|
2323
|
-
--api-key <key> API key for non-default
|
|
2324
|
-
--
|
|
2460
|
+
--api-key <key> API key for non-default apps
|
|
2461
|
+
--app <name> App (default: "default")
|
|
2325
2462
|
--model <rig> Set the active model for this session
|
|
2326
2463
|
--public-key <addr> Wallet address (so the agent knows your wallet)
|
|
2327
2464
|
--private-key <key> Hex private key for signing
|
|
@@ -2331,7 +2468,7 @@ Options:
|
|
|
2331
2468
|
Environment (overridden by flags):
|
|
2332
2469
|
AOMI_BASE_URL Backend URL
|
|
2333
2470
|
AOMI_API_KEY API key
|
|
2334
|
-
|
|
2471
|
+
AOMI_APP App
|
|
2335
2472
|
AOMI_MODEL Model rig
|
|
2336
2473
|
AOMI_PUBLIC_KEY Wallet address
|
|
2337
2474
|
PRIVATE_KEY Hex private key for signing
|