@aomi-labs/client 0.1.1 → 0.1.5
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 +55 -26
- package/dist/cli.js +1370 -474
- package/dist/index.cjs +84 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -11
- package/dist/index.d.ts +19 -11
- package/dist/index.js +84 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -8
- package/skills/aomi-transact/SKILL.md +12 -12
package/dist/cli.js
CHANGED
|
@@ -19,6 +19,494 @@ 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
|
+
|
|
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
|
+
}
|
|
70
|
+
function parseArgs(argv) {
|
|
71
|
+
const raw = argv.slice(2);
|
|
72
|
+
const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : void 0;
|
|
73
|
+
const rest = command ? raw.slice(1) : raw;
|
|
74
|
+
const positional = [];
|
|
75
|
+
const flags = {};
|
|
76
|
+
for (let i = 0; i < rest.length; i++) {
|
|
77
|
+
const arg = rest[i];
|
|
78
|
+
if (arg.startsWith("--") && arg.includes("=")) {
|
|
79
|
+
const [key, ...val] = arg.slice(2).split("=");
|
|
80
|
+
flags[key] = val.join("=");
|
|
81
|
+
} else if (arg.startsWith("--")) {
|
|
82
|
+
const key = arg.slice(2);
|
|
83
|
+
const next = rest[i + 1];
|
|
84
|
+
if (next && !next.startsWith("-")) {
|
|
85
|
+
flags[key] = next;
|
|
86
|
+
i++;
|
|
87
|
+
} else {
|
|
88
|
+
flags[key] = "true";
|
|
89
|
+
}
|
|
90
|
+
} else if (arg.startsWith("-") && arg.length === 2) {
|
|
91
|
+
flags[arg.slice(1)] = "true";
|
|
92
|
+
} else {
|
|
93
|
+
positional.push(arg);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { command, positional, flags };
|
|
97
|
+
}
|
|
98
|
+
function getConfig(parsed) {
|
|
99
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
100
|
+
return {
|
|
101
|
+
baseUrl: (_b = (_a3 = parsed.flags["backend-url"]) != null ? _a3 : process.env.AOMI_BASE_URL) != null ? _b : "https://api.aomi.dev",
|
|
102
|
+
apiKey: (_c = parsed.flags["api-key"]) != null ? _c : process.env.AOMI_API_KEY,
|
|
103
|
+
app: (_e = (_d = parsed.flags["app"]) != null ? _d : process.env.AOMI_APP) != null ? _e : "default",
|
|
104
|
+
model: (_f = parsed.flags["model"]) != null ? _f : process.env.AOMI_MODEL,
|
|
105
|
+
publicKey: (_g = parsed.flags["public-key"]) != null ? _g : process.env.AOMI_PUBLIC_KEY,
|
|
106
|
+
privateKey: (_h = parsed.flags["private-key"]) != null ? _h : process.env.PRIVATE_KEY,
|
|
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)
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function createRuntime(argv) {
|
|
112
|
+
const parsed = parseArgs(argv);
|
|
113
|
+
return {
|
|
114
|
+
parsed,
|
|
115
|
+
config: getConfig(parsed)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/cli/state.ts
|
|
120
|
+
import {
|
|
121
|
+
existsSync,
|
|
122
|
+
mkdirSync,
|
|
123
|
+
readFileSync,
|
|
124
|
+
readdirSync,
|
|
125
|
+
rmSync,
|
|
126
|
+
writeFileSync
|
|
127
|
+
} from "fs";
|
|
128
|
+
import { basename, join } from "path";
|
|
129
|
+
import { homedir, tmpdir } from "os";
|
|
130
|
+
var SESSION_FILE_PREFIX = "session-";
|
|
131
|
+
var SESSION_FILE_SUFFIX = ".json";
|
|
132
|
+
var _a;
|
|
133
|
+
var LEGACY_STATE_FILE = join(
|
|
134
|
+
(_a = process.env.XDG_RUNTIME_DIR) != null ? _a : tmpdir(),
|
|
135
|
+
"aomi-session.json"
|
|
136
|
+
);
|
|
137
|
+
var _a2;
|
|
138
|
+
var STATE_ROOT_DIR = (_a2 = process.env.AOMI_STATE_DIR) != null ? _a2 : join(homedir(), ".aomi");
|
|
139
|
+
var SESSIONS_DIR = join(STATE_ROOT_DIR, "sessions");
|
|
140
|
+
var ACTIVE_SESSION_FILE = join(STATE_ROOT_DIR, "active-session.txt");
|
|
141
|
+
function ensureStorageDirs() {
|
|
142
|
+
mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
143
|
+
}
|
|
144
|
+
function parseSessionFileLocalId(filename) {
|
|
145
|
+
const match = filename.match(/^session-(\d+)\.json$/);
|
|
146
|
+
if (!match) return null;
|
|
147
|
+
const localId = parseInt(match[1], 10);
|
|
148
|
+
return Number.isNaN(localId) ? null : localId;
|
|
149
|
+
}
|
|
150
|
+
function toSessionFilePath(localId) {
|
|
151
|
+
return join(SESSIONS_DIR, `${SESSION_FILE_PREFIX}${localId}${SESSION_FILE_SUFFIX}`);
|
|
152
|
+
}
|
|
153
|
+
function toCliSessionState(stored) {
|
|
154
|
+
return {
|
|
155
|
+
sessionId: stored.sessionId,
|
|
156
|
+
baseUrl: stored.baseUrl,
|
|
157
|
+
app: stored.app,
|
|
158
|
+
model: stored.model,
|
|
159
|
+
apiKey: stored.apiKey,
|
|
160
|
+
publicKey: stored.publicKey,
|
|
161
|
+
chainId: stored.chainId,
|
|
162
|
+
pendingTxs: stored.pendingTxs,
|
|
163
|
+
signedTxs: stored.signedTxs
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function readStoredSession(path) {
|
|
167
|
+
var _a3;
|
|
168
|
+
try {
|
|
169
|
+
const raw = readFileSync(path, "utf-8");
|
|
170
|
+
const parsed = JSON.parse(raw);
|
|
171
|
+
if (typeof parsed.sessionId !== "string" || typeof parsed.baseUrl !== "string") {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const fallbackLocalId = (_a3 = parseSessionFileLocalId(basename(path))) != null ? _a3 : 0;
|
|
175
|
+
return {
|
|
176
|
+
sessionId: parsed.sessionId,
|
|
177
|
+
baseUrl: parsed.baseUrl,
|
|
178
|
+
app: parsed.app,
|
|
179
|
+
model: parsed.model,
|
|
180
|
+
apiKey: parsed.apiKey,
|
|
181
|
+
publicKey: parsed.publicKey,
|
|
182
|
+
chainId: parsed.chainId,
|
|
183
|
+
pendingTxs: parsed.pendingTxs,
|
|
184
|
+
signedTxs: parsed.signedTxs,
|
|
185
|
+
localId: typeof parsed.localId === "number" && parsed.localId > 0 ? parsed.localId : fallbackLocalId,
|
|
186
|
+
createdAt: typeof parsed.createdAt === "number" && parsed.createdAt > 0 ? parsed.createdAt : Date.now(),
|
|
187
|
+
updatedAt: typeof parsed.updatedAt === "number" && parsed.updatedAt > 0 ? parsed.updatedAt : Date.now()
|
|
188
|
+
};
|
|
189
|
+
} catch (e) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function readActiveLocalId() {
|
|
194
|
+
try {
|
|
195
|
+
if (!existsSync(ACTIVE_SESSION_FILE)) return null;
|
|
196
|
+
const raw = readFileSync(ACTIVE_SESSION_FILE, "utf-8").trim();
|
|
197
|
+
if (!raw) return null;
|
|
198
|
+
const parsed = parseInt(raw, 10);
|
|
199
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
200
|
+
} catch (e) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function writeActiveLocalId(localId) {
|
|
205
|
+
try {
|
|
206
|
+
if (localId === null) {
|
|
207
|
+
if (existsSync(ACTIVE_SESSION_FILE)) {
|
|
208
|
+
rmSync(ACTIVE_SESSION_FILE);
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
ensureStorageDirs();
|
|
213
|
+
writeFileSync(ACTIVE_SESSION_FILE, String(localId));
|
|
214
|
+
} catch (e) {
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function readAllStoredSessions() {
|
|
218
|
+
try {
|
|
219
|
+
ensureStorageDirs();
|
|
220
|
+
const filenames = readdirSync(SESSIONS_DIR).map((name) => ({ name, localId: parseSessionFileLocalId(name) })).filter(
|
|
221
|
+
(entry) => entry.localId !== null
|
|
222
|
+
).sort((a, b) => a.localId - b.localId);
|
|
223
|
+
const sessions = [];
|
|
224
|
+
for (const entry of filenames) {
|
|
225
|
+
const path = join(SESSIONS_DIR, entry.name);
|
|
226
|
+
const stored = readStoredSession(path);
|
|
227
|
+
if (stored) {
|
|
228
|
+
sessions.push(stored);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return sessions;
|
|
232
|
+
} catch (e) {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function getNextLocalId(sessions) {
|
|
237
|
+
const maxLocalId = sessions.reduce((max, session) => {
|
|
238
|
+
return session.localId > max ? session.localId : max;
|
|
239
|
+
}, 0);
|
|
240
|
+
return maxLocalId + 1;
|
|
241
|
+
}
|
|
242
|
+
var _migrationDone = false;
|
|
243
|
+
function migrateLegacyStateIfNeeded() {
|
|
244
|
+
if (_migrationDone) return;
|
|
245
|
+
_migrationDone = true;
|
|
246
|
+
if (!existsSync(LEGACY_STATE_FILE)) return;
|
|
247
|
+
const existing = readAllStoredSessions();
|
|
248
|
+
if (existing.length > 0) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
const raw = readFileSync(LEGACY_STATE_FILE, "utf-8");
|
|
253
|
+
const legacy = JSON.parse(raw);
|
|
254
|
+
if (!legacy.sessionId || !legacy.baseUrl) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const now = Date.now();
|
|
258
|
+
const migrated = __spreadProps(__spreadValues({}, legacy), {
|
|
259
|
+
localId: 1,
|
|
260
|
+
createdAt: now,
|
|
261
|
+
updatedAt: now
|
|
262
|
+
});
|
|
263
|
+
ensureStorageDirs();
|
|
264
|
+
writeFileSync(toSessionFilePath(1), JSON.stringify(migrated, null, 2));
|
|
265
|
+
writeActiveLocalId(1);
|
|
266
|
+
rmSync(LEGACY_STATE_FILE);
|
|
267
|
+
} catch (e) {
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function resolveStoredSession(selector, sessions) {
|
|
271
|
+
var _a3, _b;
|
|
272
|
+
const trimmed = selector.trim();
|
|
273
|
+
if (!trimmed) return null;
|
|
274
|
+
const localMatch = trimmed.match(/^(?:session-)?(\d+)$/);
|
|
275
|
+
if (localMatch) {
|
|
276
|
+
const localId = parseInt(localMatch[1], 10);
|
|
277
|
+
if (!Number.isNaN(localId)) {
|
|
278
|
+
return (_a3 = sessions.find((session) => session.localId === localId)) != null ? _a3 : null;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return (_b = sessions.find((session) => session.sessionId === trimmed)) != null ? _b : null;
|
|
282
|
+
}
|
|
283
|
+
function toStoredSessionRecord(stored) {
|
|
284
|
+
return {
|
|
285
|
+
localId: stored.localId,
|
|
286
|
+
sessionId: stored.sessionId,
|
|
287
|
+
path: toSessionFilePath(stored.localId),
|
|
288
|
+
createdAt: stored.createdAt,
|
|
289
|
+
updatedAt: stored.updatedAt,
|
|
290
|
+
state: toCliSessionState(stored)
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function getActiveStateFilePath() {
|
|
294
|
+
migrateLegacyStateIfNeeded();
|
|
295
|
+
const sessions = readAllStoredSessions();
|
|
296
|
+
const activeLocalId = readActiveLocalId();
|
|
297
|
+
if (activeLocalId === null) return null;
|
|
298
|
+
const active = sessions.find((session) => session.localId === activeLocalId);
|
|
299
|
+
return active ? toSessionFilePath(active.localId) : null;
|
|
300
|
+
}
|
|
301
|
+
function listStoredSessions() {
|
|
302
|
+
migrateLegacyStateIfNeeded();
|
|
303
|
+
return readAllStoredSessions().map(toStoredSessionRecord);
|
|
304
|
+
}
|
|
305
|
+
function setActiveSession(selector) {
|
|
306
|
+
migrateLegacyStateIfNeeded();
|
|
307
|
+
const sessions = readAllStoredSessions();
|
|
308
|
+
const target = resolveStoredSession(selector, sessions);
|
|
309
|
+
if (!target) return null;
|
|
310
|
+
writeActiveLocalId(target.localId);
|
|
311
|
+
return toStoredSessionRecord(target);
|
|
312
|
+
}
|
|
313
|
+
function deleteStoredSession(selector) {
|
|
314
|
+
var _a3, _b;
|
|
315
|
+
migrateLegacyStateIfNeeded();
|
|
316
|
+
const sessions = readAllStoredSessions();
|
|
317
|
+
const target = resolveStoredSession(selector, sessions);
|
|
318
|
+
if (!target) return null;
|
|
319
|
+
const targetPath = toSessionFilePath(target.localId);
|
|
320
|
+
try {
|
|
321
|
+
if (existsSync(targetPath)) {
|
|
322
|
+
rmSync(targetPath);
|
|
323
|
+
}
|
|
324
|
+
} catch (e) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
const activeLocalId = readActiveLocalId();
|
|
328
|
+
if (activeLocalId === target.localId) {
|
|
329
|
+
const remaining = readAllStoredSessions().sort((a, b) => b.updatedAt - a.updatedAt);
|
|
330
|
+
writeActiveLocalId((_b = (_a3 = remaining[0]) == null ? void 0 : _a3.localId) != null ? _b : null);
|
|
331
|
+
}
|
|
332
|
+
return toStoredSessionRecord(target);
|
|
333
|
+
}
|
|
334
|
+
function readState() {
|
|
335
|
+
var _a3;
|
|
336
|
+
migrateLegacyStateIfNeeded();
|
|
337
|
+
const sessions = readAllStoredSessions();
|
|
338
|
+
if (sessions.length === 0) return null;
|
|
339
|
+
const activeLocalId = readActiveLocalId();
|
|
340
|
+
if (activeLocalId === null) {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
const active = (_a3 = sessions.find((session) => session.localId === activeLocalId)) != null ? _a3 : null;
|
|
344
|
+
if (!active) {
|
|
345
|
+
writeActiveLocalId(null);
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
return toCliSessionState(active);
|
|
349
|
+
}
|
|
350
|
+
function writeState(state) {
|
|
351
|
+
var _a3, _b;
|
|
352
|
+
migrateLegacyStateIfNeeded();
|
|
353
|
+
ensureStorageDirs();
|
|
354
|
+
const sessions = readAllStoredSessions();
|
|
355
|
+
const activeLocalId = readActiveLocalId();
|
|
356
|
+
const existingBySessionId = sessions.find(
|
|
357
|
+
(session) => session.sessionId === state.sessionId
|
|
358
|
+
);
|
|
359
|
+
const existingByActive = activeLocalId !== null ? sessions.find((session) => session.localId === activeLocalId) : void 0;
|
|
360
|
+
const existing = existingBySessionId != null ? existingBySessionId : existingByActive;
|
|
361
|
+
const now = Date.now();
|
|
362
|
+
const localId = (_a3 = existing == null ? void 0 : existing.localId) != null ? _a3 : getNextLocalId(sessions);
|
|
363
|
+
const createdAt = (_b = existing == null ? void 0 : existing.createdAt) != null ? _b : now;
|
|
364
|
+
const payload = __spreadProps(__spreadValues({}, state), {
|
|
365
|
+
localId,
|
|
366
|
+
createdAt,
|
|
367
|
+
updatedAt: now
|
|
368
|
+
});
|
|
369
|
+
writeFileSync(toSessionFilePath(localId), JSON.stringify(payload, null, 2));
|
|
370
|
+
writeActiveLocalId(localId);
|
|
371
|
+
}
|
|
372
|
+
function clearState() {
|
|
373
|
+
migrateLegacyStateIfNeeded();
|
|
374
|
+
writeActiveLocalId(null);
|
|
375
|
+
}
|
|
376
|
+
function getNextTxId(state) {
|
|
377
|
+
var _a3, _b;
|
|
378
|
+
const allIds = [...(_a3 = state.pendingTxs) != null ? _a3 : [], ...(_b = state.signedTxs) != null ? _b : []].map((tx) => {
|
|
379
|
+
const match = tx.id.match(/^tx-(\d+)$/);
|
|
380
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
381
|
+
});
|
|
382
|
+
const max = allIds.length > 0 ? Math.max(...allIds) : 0;
|
|
383
|
+
return `tx-${max + 1}`;
|
|
384
|
+
}
|
|
385
|
+
function addPendingTx(state, tx) {
|
|
386
|
+
if (!state.pendingTxs) state.pendingTxs = [];
|
|
387
|
+
const pending = __spreadProps(__spreadValues({}, tx), {
|
|
388
|
+
id: getNextTxId(state)
|
|
389
|
+
});
|
|
390
|
+
state.pendingTxs.push(pending);
|
|
391
|
+
writeState(state);
|
|
392
|
+
return pending;
|
|
393
|
+
}
|
|
394
|
+
function removePendingTx(state, id) {
|
|
395
|
+
if (!state.pendingTxs) return null;
|
|
396
|
+
const idx = state.pendingTxs.findIndex((tx) => tx.id === id);
|
|
397
|
+
if (idx === -1) return null;
|
|
398
|
+
const [removed] = state.pendingTxs.splice(idx, 1);
|
|
399
|
+
writeState(state);
|
|
400
|
+
return removed;
|
|
401
|
+
}
|
|
402
|
+
function addSignedTx(state, tx) {
|
|
403
|
+
if (!state.signedTxs) state.signedTxs = [];
|
|
404
|
+
state.signedTxs.push(tx);
|
|
405
|
+
writeState(state);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/cli/output.ts
|
|
409
|
+
var DIM = "\x1B[2m";
|
|
410
|
+
var CYAN = "\x1B[36m";
|
|
411
|
+
var YELLOW = "\x1B[33m";
|
|
412
|
+
var GREEN = "\x1B[32m";
|
|
413
|
+
var RESET = "\x1B[0m";
|
|
414
|
+
function printDataFileLocation() {
|
|
415
|
+
const activeFile = getActiveStateFilePath();
|
|
416
|
+
if (activeFile) {
|
|
417
|
+
console.log(`Data stored at ${activeFile} \u{1F4DD}`);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
console.log(`Data stored under ${STATE_ROOT_DIR} \u{1F4DD}`);
|
|
421
|
+
}
|
|
422
|
+
function printToolUpdate(event) {
|
|
423
|
+
var _a3;
|
|
424
|
+
const name = getToolNameFromEvent(event);
|
|
425
|
+
const status = (_a3 = event.status) != null ? _a3 : "running";
|
|
426
|
+
console.log(`${DIM}\u{1F527} [tool] ${name}: ${status}${RESET}`);
|
|
427
|
+
}
|
|
428
|
+
function printToolComplete(event) {
|
|
429
|
+
const name = getToolNameFromEvent(event);
|
|
430
|
+
const result = getToolResultFromEvent(event);
|
|
431
|
+
const line = formatToolResultLine(name, result);
|
|
432
|
+
console.log(line);
|
|
433
|
+
}
|
|
434
|
+
function printToolResultLine(name, result) {
|
|
435
|
+
console.log(formatToolResultLine(name, result));
|
|
436
|
+
}
|
|
437
|
+
function getToolNameFromEvent(event) {
|
|
438
|
+
var _a3, _b;
|
|
439
|
+
return (_b = (_a3 = event.tool_name) != null ? _a3 : event.name) != null ? _b : "unknown";
|
|
440
|
+
}
|
|
441
|
+
function getToolResultFromEvent(event) {
|
|
442
|
+
var _a3;
|
|
443
|
+
return (_a3 = event.result) != null ? _a3 : event.output;
|
|
444
|
+
}
|
|
445
|
+
function toToolResultKey(name, result) {
|
|
446
|
+
return `${name}
|
|
447
|
+
${result != null ? result : ""}`;
|
|
448
|
+
}
|
|
449
|
+
function getMessageToolResults(messages, startAt = 0) {
|
|
450
|
+
const results = [];
|
|
451
|
+
for (let i = startAt; i < messages.length; i++) {
|
|
452
|
+
const toolResult = messages[i].tool_result;
|
|
453
|
+
if (!toolResult) {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
const [name, result] = toolResult;
|
|
457
|
+
if (!name || typeof result !== "string") {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
results.push({ name, result });
|
|
461
|
+
}
|
|
462
|
+
return results;
|
|
463
|
+
}
|
|
464
|
+
function isAlwaysVisibleTool(name) {
|
|
465
|
+
const normalized = name.toLowerCase();
|
|
466
|
+
if (normalized.includes("encode_and_simulate") || normalized.includes("encode-and-simulate") || normalized.includes("encode_and_view") || normalized.includes("encode-and-view")) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
if (normalized.startsWith("simulate ")) {
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
function printNewAgentMessages(messages, lastPrintedCount) {
|
|
475
|
+
const agentMessages = messages.filter(
|
|
476
|
+
(message) => message.sender === "agent" || message.sender === "assistant"
|
|
477
|
+
);
|
|
478
|
+
let handled = lastPrintedCount;
|
|
479
|
+
for (let i = lastPrintedCount; i < agentMessages.length; i++) {
|
|
480
|
+
const message = agentMessages[i];
|
|
481
|
+
if (message.is_streaming) {
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
if (message.content) {
|
|
485
|
+
console.log(`${CYAN}\u{1F916} ${message.content}${RESET}`);
|
|
486
|
+
}
|
|
487
|
+
handled = i + 1;
|
|
488
|
+
}
|
|
489
|
+
return handled;
|
|
490
|
+
}
|
|
491
|
+
function formatLogContent(content) {
|
|
492
|
+
if (!content) return null;
|
|
493
|
+
const trimmed = content.trim();
|
|
494
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
495
|
+
}
|
|
496
|
+
function formatToolResultPreview(result, maxLength = 200) {
|
|
497
|
+
const normalized = result.replace(/\s+/g, " ").trim();
|
|
498
|
+
if (normalized.length <= maxLength) {
|
|
499
|
+
return normalized;
|
|
500
|
+
}
|
|
501
|
+
return `${normalized.slice(0, maxLength)}\u2026`;
|
|
502
|
+
}
|
|
503
|
+
function formatToolResultLine(name, result) {
|
|
504
|
+
if (!result) {
|
|
505
|
+
return `${GREEN}\u2714 [tool] ${name} done${RESET}`;
|
|
506
|
+
}
|
|
507
|
+
return `${GREEN}\u2714 [tool] ${name} \u2192 ${formatToolResultPreview(result, 120)}${RESET}`;
|
|
508
|
+
}
|
|
509
|
+
|
|
22
510
|
// src/sse.ts
|
|
23
511
|
function extractSseData(rawEvent) {
|
|
24
512
|
const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
|
|
@@ -86,13 +574,13 @@ function createSseSubscriber({
|
|
|
86
574
|
stopped: false,
|
|
87
575
|
listeners: /* @__PURE__ */ new Set([listener]),
|
|
88
576
|
stop: (reason) => {
|
|
89
|
-
var
|
|
577
|
+
var _a3;
|
|
90
578
|
subscription.stopped = true;
|
|
91
579
|
if (subscription.retryTimer) {
|
|
92
580
|
clearTimeout(subscription.retryTimer);
|
|
93
581
|
subscription.retryTimer = null;
|
|
94
582
|
}
|
|
95
|
-
(
|
|
583
|
+
(_a3 = subscription.abortController) == null ? void 0 : _a3.abort();
|
|
96
584
|
subscription.abortController = null;
|
|
97
585
|
logger == null ? void 0 : logger.debug("[aomi][sse] stop", {
|
|
98
586
|
sessionId,
|
|
@@ -115,7 +603,7 @@ function createSseSubscriber({
|
|
|
115
603
|
}, delayMs);
|
|
116
604
|
};
|
|
117
605
|
const open = async () => {
|
|
118
|
-
var
|
|
606
|
+
var _a3;
|
|
119
607
|
if (subscription.stopped) return;
|
|
120
608
|
if (subscription.retryTimer) {
|
|
121
609
|
clearTimeout(subscription.retryTimer);
|
|
@@ -139,19 +627,19 @@ function createSseSubscriber({
|
|
|
139
627
|
}
|
|
140
628
|
subscription.retries = 0;
|
|
141
629
|
await readSseStream(response.body, controller.signal, (data) => {
|
|
142
|
-
var
|
|
143
|
-
let
|
|
630
|
+
var _a4, _b;
|
|
631
|
+
let parsed;
|
|
144
632
|
try {
|
|
145
|
-
|
|
633
|
+
parsed = JSON.parse(data);
|
|
146
634
|
} catch (error) {
|
|
147
635
|
for (const item of subscription.listeners) {
|
|
148
|
-
(
|
|
636
|
+
(_a4 = item.onError) == null ? void 0 : _a4.call(item, error);
|
|
149
637
|
}
|
|
150
638
|
return;
|
|
151
639
|
}
|
|
152
640
|
for (const item of subscription.listeners) {
|
|
153
641
|
try {
|
|
154
|
-
item.onUpdate(
|
|
642
|
+
item.onUpdate(parsed);
|
|
155
643
|
} catch (error) {
|
|
156
644
|
(_b = item.onError) == null ? void 0 : _b.call(item, error);
|
|
157
645
|
}
|
|
@@ -166,7 +654,7 @@ function createSseSubscriber({
|
|
|
166
654
|
} catch (error) {
|
|
167
655
|
if (!controller.signal.aborted && !subscription.stopped) {
|
|
168
656
|
for (const item of subscription.listeners) {
|
|
169
|
-
(
|
|
657
|
+
(_a3 = item.onError) == null ? void 0 : _a3.call(item, error);
|
|
170
658
|
}
|
|
171
659
|
}
|
|
172
660
|
}
|
|
@@ -260,10 +748,10 @@ var AomiClient = class {
|
|
|
260
748
|
* Send a chat message and return updated session state.
|
|
261
749
|
*/
|
|
262
750
|
async sendMessage(sessionId, message, options) {
|
|
263
|
-
var
|
|
264
|
-
const
|
|
751
|
+
var _a3, _b;
|
|
752
|
+
const app = (_a3 = options == null ? void 0 : options.app) != null ? _a3 : "default";
|
|
265
753
|
const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : this.apiKey;
|
|
266
|
-
const payload = { message,
|
|
754
|
+
const payload = { message, app };
|
|
267
755
|
if (options == null ? void 0 : options.publicKey) {
|
|
268
756
|
payload.public_key = options.publicKey;
|
|
269
757
|
}
|
|
@@ -436,32 +924,38 @@ var AomiClient = class {
|
|
|
436
924
|
// Control API
|
|
437
925
|
// ===========================================================================
|
|
438
926
|
/**
|
|
439
|
-
* Get available
|
|
927
|
+
* Get available apps.
|
|
440
928
|
*/
|
|
441
|
-
async
|
|
442
|
-
var
|
|
443
|
-
const url = new URL("/api/control/
|
|
929
|
+
async getApps(sessionId, options) {
|
|
930
|
+
var _a3;
|
|
931
|
+
const url = new URL("/api/control/apps", this.baseUrl);
|
|
444
932
|
if (options == null ? void 0 : options.publicKey) {
|
|
445
933
|
url.searchParams.set("public_key", options.publicKey);
|
|
446
934
|
}
|
|
447
|
-
const apiKey = (
|
|
935
|
+
const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
|
|
448
936
|
const headers = new Headers(withSessionHeader(sessionId));
|
|
449
937
|
if (apiKey) {
|
|
450
938
|
headers.set(API_KEY_HEADER, apiKey);
|
|
451
939
|
}
|
|
452
940
|
const response = await fetch(url.toString(), { headers });
|
|
453
941
|
if (!response.ok) {
|
|
454
|
-
throw new Error(`Failed to get
|
|
942
|
+
throw new Error(`Failed to get apps: HTTP ${response.status}`);
|
|
455
943
|
}
|
|
456
944
|
return await response.json();
|
|
457
945
|
}
|
|
458
946
|
/**
|
|
459
947
|
* Get available models.
|
|
460
948
|
*/
|
|
461
|
-
async getModels(sessionId) {
|
|
949
|
+
async getModels(sessionId, options) {
|
|
950
|
+
var _a3;
|
|
462
951
|
const url = new URL("/api/control/models", this.baseUrl);
|
|
952
|
+
const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
|
|
953
|
+
const headers = new Headers(withSessionHeader(sessionId));
|
|
954
|
+
if (apiKey) {
|
|
955
|
+
headers.set(API_KEY_HEADER, apiKey);
|
|
956
|
+
}
|
|
463
957
|
const response = await fetch(url.toString(), {
|
|
464
|
-
headers
|
|
958
|
+
headers
|
|
465
959
|
});
|
|
466
960
|
if (!response.ok) {
|
|
467
961
|
throw new Error(`Failed to get models: HTTP ${response.status}`);
|
|
@@ -472,11 +966,11 @@ var AomiClient = class {
|
|
|
472
966
|
* Set the model for a session.
|
|
473
967
|
*/
|
|
474
968
|
async setModel(sessionId, rig, options) {
|
|
475
|
-
var
|
|
476
|
-
const apiKey = (
|
|
969
|
+
var _a3;
|
|
970
|
+
const apiKey = (_a3 = options == null ? void 0 : options.apiKey) != null ? _a3 : this.apiKey;
|
|
477
971
|
const payload = { rig };
|
|
478
|
-
if (options == null ? void 0 : options.
|
|
479
|
-
payload.
|
|
972
|
+
if (options == null ? void 0 : options.app) {
|
|
973
|
+
payload.app = options.app;
|
|
480
974
|
}
|
|
481
975
|
return postState(this.baseUrl, "/api/control/model", payload, sessionId, apiKey);
|
|
482
976
|
}
|
|
@@ -570,11 +1064,11 @@ function isAsyncCallback(event) {
|
|
|
570
1064
|
|
|
571
1065
|
// src/event-unwrap.ts
|
|
572
1066
|
function unwrapSystemEvent(event) {
|
|
573
|
-
var
|
|
1067
|
+
var _a3;
|
|
574
1068
|
if (isInlineCall(event)) {
|
|
575
1069
|
return {
|
|
576
1070
|
type: event.InlineCall.type,
|
|
577
|
-
payload: (
|
|
1071
|
+
payload: (_a3 = event.InlineCall.payload) != null ? _a3 : event.InlineCall
|
|
578
1072
|
};
|
|
579
1073
|
}
|
|
580
1074
|
if (isSystemNotice(event)) {
|
|
@@ -605,12 +1099,12 @@ function asRecord(value) {
|
|
|
605
1099
|
return value;
|
|
606
1100
|
}
|
|
607
1101
|
function getToolArgs(payload) {
|
|
608
|
-
var
|
|
1102
|
+
var _a3;
|
|
609
1103
|
const root = asRecord(payload);
|
|
610
1104
|
const nestedArgs = asRecord(root == null ? void 0 : root.args);
|
|
611
|
-
return (
|
|
1105
|
+
return (_a3 = nestedArgs != null ? nestedArgs : root) != null ? _a3 : {};
|
|
612
1106
|
}
|
|
613
|
-
function
|
|
1107
|
+
function parseChainId2(value) {
|
|
614
1108
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
615
1109
|
if (typeof value !== "string") return void 0;
|
|
616
1110
|
const trimmed = value.trim();
|
|
@@ -619,11 +1113,11 @@ function parseChainId(value) {
|
|
|
619
1113
|
const parsedHex = Number.parseInt(trimmed.slice(2), 16);
|
|
620
1114
|
return Number.isFinite(parsedHex) ? parsedHex : void 0;
|
|
621
1115
|
}
|
|
622
|
-
const
|
|
623
|
-
return Number.isFinite(
|
|
1116
|
+
const parsed = Number.parseInt(trimmed, 10);
|
|
1117
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
624
1118
|
}
|
|
625
1119
|
function normalizeTxPayload(payload) {
|
|
626
|
-
var
|
|
1120
|
+
var _a3, _b, _c;
|
|
627
1121
|
const root = asRecord(payload);
|
|
628
1122
|
const args = getToolArgs(payload);
|
|
629
1123
|
const ctx = asRecord(root == null ? void 0 : root.ctx);
|
|
@@ -632,19 +1126,19 @@ function normalizeTxPayload(payload) {
|
|
|
632
1126
|
const valueRaw = args.value;
|
|
633
1127
|
const value = typeof valueRaw === "string" ? valueRaw : typeof valueRaw === "number" && Number.isFinite(valueRaw) ? String(Math.trunc(valueRaw)) : void 0;
|
|
634
1128
|
const data = typeof args.data === "string" ? args.data : void 0;
|
|
635
|
-
const chainId = (_c = (_b = (
|
|
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);
|
|
636
1130
|
return { to, value, data, chainId };
|
|
637
1131
|
}
|
|
638
1132
|
function normalizeEip712Payload(payload) {
|
|
639
|
-
var
|
|
1133
|
+
var _a3;
|
|
640
1134
|
const args = getToolArgs(payload);
|
|
641
|
-
const typedDataRaw = (
|
|
1135
|
+
const typedDataRaw = (_a3 = args.typed_data) != null ? _a3 : args.typedData;
|
|
642
1136
|
let typedData;
|
|
643
1137
|
if (typeof typedDataRaw === "string") {
|
|
644
1138
|
try {
|
|
645
|
-
const
|
|
646
|
-
if (
|
|
647
|
-
typedData =
|
|
1139
|
+
const parsed = JSON.parse(typedDataRaw);
|
|
1140
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1141
|
+
typedData = parsed;
|
|
648
1142
|
}
|
|
649
1143
|
} catch (e) {
|
|
650
1144
|
typedData = void 0;
|
|
@@ -657,9 +1151,40 @@ function normalizeEip712Payload(payload) {
|
|
|
657
1151
|
}
|
|
658
1152
|
|
|
659
1153
|
// src/session.ts
|
|
660
|
-
|
|
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 {
|
|
661
1186
|
constructor(clientOrOptions, sessionOptions) {
|
|
662
|
-
var
|
|
1187
|
+
var _a3, _b, _c;
|
|
663
1188
|
super();
|
|
664
1189
|
// Internal state
|
|
665
1190
|
this.pollTimer = null;
|
|
@@ -672,8 +1197,8 @@ var Session = class extends TypedEventEmitter {
|
|
|
672
1197
|
// For send() blocking behavior
|
|
673
1198
|
this.pendingResolve = null;
|
|
674
1199
|
this.client = clientOrOptions instanceof AomiClient ? clientOrOptions : new AomiClient(clientOrOptions);
|
|
675
|
-
this.sessionId = (
|
|
676
|
-
this.
|
|
1200
|
+
this.sessionId = (_a3 = sessionOptions == null ? void 0 : sessionOptions.sessionId) != null ? _a3 : crypto.randomUUID();
|
|
1201
|
+
this.app = (_b = sessionOptions == null ? void 0 : sessionOptions.app) != null ? _b : "default";
|
|
677
1202
|
this.publicKey = sessionOptions == null ? void 0 : sessionOptions.publicKey;
|
|
678
1203
|
this.apiKey = sessionOptions == null ? void 0 : sessionOptions.apiKey;
|
|
679
1204
|
this.userState = sessionOptions == null ? void 0 : sessionOptions.userState;
|
|
@@ -699,11 +1224,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
699
1224
|
async send(message) {
|
|
700
1225
|
this.assertOpen();
|
|
701
1226
|
const response = await this.client.sendMessage(this.sessionId, message, {
|
|
702
|
-
|
|
1227
|
+
app: this.app,
|
|
703
1228
|
publicKey: this.publicKey,
|
|
704
1229
|
apiKey: this.apiKey,
|
|
705
1230
|
userState: this.userState
|
|
706
1231
|
});
|
|
1232
|
+
this.assertUserStateAligned(response.user_state);
|
|
707
1233
|
this.applyState(response);
|
|
708
1234
|
if (!response.is_processing && this.walletRequests.length === 0) {
|
|
709
1235
|
return { messages: this._messages, title: this._title };
|
|
@@ -722,11 +1248,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
722
1248
|
async sendAsync(message) {
|
|
723
1249
|
this.assertOpen();
|
|
724
1250
|
const response = await this.client.sendMessage(this.sessionId, message, {
|
|
725
|
-
|
|
1251
|
+
app: this.app,
|
|
726
1252
|
publicKey: this.publicKey,
|
|
727
1253
|
apiKey: this.apiKey,
|
|
728
1254
|
userState: this.userState
|
|
729
1255
|
});
|
|
1256
|
+
this.assertUserStateAligned(response.user_state);
|
|
730
1257
|
this.applyState(response);
|
|
731
1258
|
if (response.is_processing) {
|
|
732
1259
|
this._isProcessing = true;
|
|
@@ -743,14 +1270,14 @@ var Session = class extends TypedEventEmitter {
|
|
|
743
1270
|
* Sends the result to the backend and resumes polling.
|
|
744
1271
|
*/
|
|
745
1272
|
async resolve(requestId, result) {
|
|
746
|
-
var
|
|
1273
|
+
var _a3;
|
|
747
1274
|
const req = this.removeWalletRequest(requestId);
|
|
748
1275
|
if (!req) {
|
|
749
1276
|
throw new Error(`No pending wallet request with id "${requestId}"`);
|
|
750
1277
|
}
|
|
751
1278
|
if (req.kind === "transaction") {
|
|
752
1279
|
await this.sendSystemEvent("wallet:tx_complete", {
|
|
753
|
-
txHash: (
|
|
1280
|
+
txHash: (_a3 = result.txHash) != null ? _a3 : "",
|
|
754
1281
|
status: "success",
|
|
755
1282
|
amount: result.amount
|
|
756
1283
|
});
|
|
@@ -811,11 +1338,11 @@ var Session = class extends TypedEventEmitter {
|
|
|
811
1338
|
* The session cannot be used after closing.
|
|
812
1339
|
*/
|
|
813
1340
|
close() {
|
|
814
|
-
var
|
|
1341
|
+
var _a3;
|
|
815
1342
|
if (this.closed) return;
|
|
816
1343
|
this.closed = true;
|
|
817
1344
|
this.stopPolling();
|
|
818
|
-
(
|
|
1345
|
+
(_a3 = this.unsubscribeSSE) == null ? void 0 : _a3.call(this);
|
|
819
1346
|
this.unsubscribeSSE = null;
|
|
820
1347
|
this.resolvePending();
|
|
821
1348
|
this.removeAllListeners();
|
|
@@ -839,27 +1366,44 @@ var Session = class extends TypedEventEmitter {
|
|
|
839
1366
|
getIsProcessing() {
|
|
840
1367
|
return this._isProcessing;
|
|
841
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
|
+
}
|
|
842
1386
|
// ===========================================================================
|
|
843
1387
|
// Internal — Polling (ported from PollingController)
|
|
844
1388
|
// ===========================================================================
|
|
845
1389
|
startPolling() {
|
|
846
|
-
var
|
|
1390
|
+
var _a3;
|
|
847
1391
|
if (this.pollTimer || this.closed) return;
|
|
848
|
-
(
|
|
1392
|
+
(_a3 = this.logger) == null ? void 0 : _a3.debug("[session] polling started", this.sessionId);
|
|
849
1393
|
this.pollTimer = setInterval(() => {
|
|
850
1394
|
void this.pollTick();
|
|
851
1395
|
}, this.pollIntervalMs);
|
|
852
1396
|
}
|
|
853
1397
|
stopPolling() {
|
|
854
|
-
var
|
|
1398
|
+
var _a3;
|
|
855
1399
|
if (this.pollTimer) {
|
|
856
1400
|
clearInterval(this.pollTimer);
|
|
857
1401
|
this.pollTimer = null;
|
|
858
|
-
(
|
|
1402
|
+
(_a3 = this.logger) == null ? void 0 : _a3.debug("[session] polling stopped", this.sessionId);
|
|
859
1403
|
}
|
|
860
1404
|
}
|
|
861
1405
|
async pollTick() {
|
|
862
|
-
var
|
|
1406
|
+
var _a3;
|
|
863
1407
|
if (!this.pollTimer) return;
|
|
864
1408
|
try {
|
|
865
1409
|
const state = await this.client.fetchState(
|
|
@@ -867,6 +1411,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
867
1411
|
this.userState
|
|
868
1412
|
);
|
|
869
1413
|
if (!this.pollTimer) return;
|
|
1414
|
+
this.assertUserStateAligned(state.user_state);
|
|
870
1415
|
this.applyState(state);
|
|
871
1416
|
if (!state.is_processing && this.walletRequests.length === 0) {
|
|
872
1417
|
this.stopPolling();
|
|
@@ -875,7 +1420,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
875
1420
|
this.resolvePending();
|
|
876
1421
|
}
|
|
877
1422
|
} catch (error) {
|
|
878
|
-
(
|
|
1423
|
+
(_a3 = this.logger) == null ? void 0 : _a3.debug("[session] poll error", error);
|
|
879
1424
|
this.emit("error", { error });
|
|
880
1425
|
}
|
|
881
1426
|
}
|
|
@@ -883,7 +1428,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
883
1428
|
// Internal — State Application
|
|
884
1429
|
// ===========================================================================
|
|
885
1430
|
applyState(state) {
|
|
886
|
-
var
|
|
1431
|
+
var _a3;
|
|
887
1432
|
if (state.messages) {
|
|
888
1433
|
this._messages = state.messages;
|
|
889
1434
|
this.emit("messages", this._messages);
|
|
@@ -891,12 +1436,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
891
1436
|
if (state.title) {
|
|
892
1437
|
this._title = state.title;
|
|
893
1438
|
}
|
|
894
|
-
if ((
|
|
1439
|
+
if ((_a3 = state.system_events) == null ? void 0 : _a3.length) {
|
|
895
1440
|
this.dispatchSystemEvents(state.system_events);
|
|
896
1441
|
}
|
|
897
1442
|
}
|
|
898
1443
|
dispatchSystemEvents(events) {
|
|
899
|
-
var
|
|
1444
|
+
var _a3;
|
|
900
1445
|
for (const event of events) {
|
|
901
1446
|
const unwrapped = unwrapSystemEvent(event);
|
|
902
1447
|
if (!unwrapped) continue;
|
|
@@ -907,7 +1452,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
907
1452
|
this.emit("wallet_tx_request", req);
|
|
908
1453
|
}
|
|
909
1454
|
} else if (unwrapped.type === "wallet_eip712_request") {
|
|
910
|
-
const payload = normalizeEip712Payload((
|
|
1455
|
+
const payload = normalizeEip712Payload((_a3 = unwrapped.payload) != null ? _a3 : {});
|
|
911
1456
|
const req = this.enqueueWalletRequest("eip712_sign", payload);
|
|
912
1457
|
this.emit("wallet_eip712_request", req);
|
|
913
1458
|
} else if (unwrapped.type === "system_notice" || unwrapped.type === "system_error" || unwrapped.type === "async_callback") {
|
|
@@ -968,289 +1513,170 @@ var Session = class extends TypedEventEmitter {
|
|
|
968
1513
|
throw new Error("Session is closed");
|
|
969
1514
|
}
|
|
970
1515
|
}
|
|
1516
|
+
assertUserStateAligned(actualUserState) {
|
|
1517
|
+
if (!this.userState) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
if (!actualUserState || !isSubsetMatch(this.userState, actualUserState)) {
|
|
1521
|
+
const expected = JSON.stringify(sortJson(this.userState));
|
|
1522
|
+
const actual = JSON.stringify(sortJson(actualUserState != null ? actualUserState : null));
|
|
1523
|
+
throw new Error(
|
|
1524
|
+
`Backend user_state mismatch. expected subset=${expected} actual=${actual}`
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
971
1528
|
};
|
|
972
1529
|
|
|
973
|
-
// src/cli
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
}
|
|
988
|
-
|
|
1530
|
+
// src/cli/context.ts
|
|
1531
|
+
function getOrCreateSession(runtime) {
|
|
1532
|
+
const { config } = runtime;
|
|
1533
|
+
let state = readState();
|
|
1534
|
+
if (!state) {
|
|
1535
|
+
state = {
|
|
1536
|
+
sessionId: crypto.randomUUID(),
|
|
1537
|
+
baseUrl: config.baseUrl,
|
|
1538
|
+
app: config.app,
|
|
1539
|
+
apiKey: config.apiKey,
|
|
1540
|
+
publicKey: config.publicKey,
|
|
1541
|
+
chainId: config.chain
|
|
1542
|
+
};
|
|
1543
|
+
writeState(state);
|
|
1544
|
+
} else {
|
|
1545
|
+
let changed = false;
|
|
1546
|
+
if (config.baseUrl !== state.baseUrl) {
|
|
1547
|
+
state.baseUrl = config.baseUrl;
|
|
1548
|
+
changed = true;
|
|
1549
|
+
}
|
|
1550
|
+
if (config.app !== state.app) {
|
|
1551
|
+
state.app = config.app;
|
|
1552
|
+
changed = true;
|
|
1553
|
+
}
|
|
1554
|
+
if (config.apiKey !== void 0 && config.apiKey !== state.apiKey) {
|
|
1555
|
+
state.apiKey = config.apiKey;
|
|
1556
|
+
changed = true;
|
|
1557
|
+
}
|
|
1558
|
+
if (config.publicKey !== void 0 && config.publicKey !== state.publicKey) {
|
|
1559
|
+
state.publicKey = config.publicKey;
|
|
1560
|
+
changed = true;
|
|
1561
|
+
}
|
|
1562
|
+
if (config.chain !== void 0 && config.chain !== state.chainId) {
|
|
1563
|
+
state.chainId = config.chain;
|
|
1564
|
+
changed = true;
|
|
1565
|
+
}
|
|
1566
|
+
if (changed) writeState(state);
|
|
989
1567
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1568
|
+
const session = new ClientSession(
|
|
1569
|
+
{ baseUrl: state.baseUrl, apiKey: state.apiKey },
|
|
1570
|
+
{
|
|
1571
|
+
sessionId: state.sessionId,
|
|
1572
|
+
app: state.app,
|
|
1573
|
+
apiKey: state.apiKey,
|
|
1574
|
+
publicKey: state.publicKey
|
|
1575
|
+
}
|
|
1576
|
+
);
|
|
1577
|
+
if (state.publicKey) {
|
|
1578
|
+
session.resolveWallet(state.publicKey, state.chainId);
|
|
998
1579
|
}
|
|
1580
|
+
return { session, state };
|
|
999
1581
|
}
|
|
1000
|
-
function
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
...(_b = state.signedTxs) != null ? _b : []
|
|
1005
|
-
].map((t) => {
|
|
1006
|
-
const m = t.id.match(/^tx-(\d+)$/);
|
|
1007
|
-
return m ? parseInt(m[1], 10) : 0;
|
|
1582
|
+
function createControlClient(runtime) {
|
|
1583
|
+
return new AomiClient({
|
|
1584
|
+
baseUrl: runtime.config.baseUrl,
|
|
1585
|
+
apiKey: runtime.config.apiKey
|
|
1008
1586
|
});
|
|
1009
|
-
const max = allIds.length > 0 ? Math.max(...allIds) : 0;
|
|
1010
|
-
return `tx-${max + 1}`;
|
|
1011
1587
|
}
|
|
1012
|
-
function
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1588
|
+
async function applyModelSelection(session, state, model) {
|
|
1589
|
+
await session.client.setModel(state.sessionId, model, {
|
|
1590
|
+
app: state.app,
|
|
1591
|
+
apiKey: state.apiKey
|
|
1016
1592
|
});
|
|
1017
|
-
state.
|
|
1018
|
-
writeState(state);
|
|
1019
|
-
return pending;
|
|
1020
|
-
}
|
|
1021
|
-
function removePendingTx(state, id) {
|
|
1022
|
-
if (!state.pendingTxs) return null;
|
|
1023
|
-
const idx = state.pendingTxs.findIndex((t) => t.id === id);
|
|
1024
|
-
if (idx === -1) return null;
|
|
1025
|
-
const [removed] = state.pendingTxs.splice(idx, 1);
|
|
1026
|
-
writeState(state);
|
|
1027
|
-
return removed;
|
|
1028
|
-
}
|
|
1029
|
-
function addSignedTx(state, tx) {
|
|
1030
|
-
if (!state.signedTxs) state.signedTxs = [];
|
|
1031
|
-
state.signedTxs.push(tx);
|
|
1593
|
+
state.model = model;
|
|
1032
1594
|
writeState(state);
|
|
1033
1595
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
super();
|
|
1039
|
-
this.code = code;
|
|
1040
|
-
}
|
|
1041
|
-
};
|
|
1042
|
-
function fatal(message) {
|
|
1043
|
-
console.error(message);
|
|
1044
|
-
throw new CliExit(1);
|
|
1045
|
-
}
|
|
1046
|
-
function printDataFileLocation() {
|
|
1047
|
-
console.log(`Data stored at ${STATE_FILE} \u{1F4DD}`);
|
|
1048
|
-
}
|
|
1049
|
-
function parseArgs(argv) {
|
|
1050
|
-
const raw = argv.slice(2);
|
|
1051
|
-
const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : void 0;
|
|
1052
|
-
const rest = command ? raw.slice(1) : raw;
|
|
1053
|
-
const positional = [];
|
|
1054
|
-
const flags = {};
|
|
1055
|
-
for (let i = 0; i < rest.length; i++) {
|
|
1056
|
-
const arg = rest[i];
|
|
1057
|
-
if (arg.startsWith("--") && arg.includes("=")) {
|
|
1058
|
-
const [key, ...val] = arg.slice(2).split("=");
|
|
1059
|
-
flags[key] = val.join("=");
|
|
1060
|
-
} else if (arg.startsWith("--")) {
|
|
1061
|
-
const key = arg.slice(2);
|
|
1062
|
-
const next = rest[i + 1];
|
|
1063
|
-
if (next && !next.startsWith("-")) {
|
|
1064
|
-
flags[key] = next;
|
|
1065
|
-
i++;
|
|
1066
|
-
} else {
|
|
1067
|
-
flags[key] = "true";
|
|
1068
|
-
}
|
|
1069
|
-
} else if (arg.startsWith("-") && arg.length === 2) {
|
|
1070
|
-
flags[arg.slice(1)] = "true";
|
|
1071
|
-
} else {
|
|
1072
|
-
positional.push(arg);
|
|
1073
|
-
}
|
|
1596
|
+
async function applyRequestedModelIfPresent(runtime, session, state) {
|
|
1597
|
+
const requestedModel = runtime.config.model;
|
|
1598
|
+
if (!requestedModel || requestedModel === state.model) {
|
|
1599
|
+
return;
|
|
1074
1600
|
}
|
|
1075
|
-
|
|
1076
|
-
}
|
|
1077
|
-
var parsed = parseArgs(process.argv);
|
|
1078
|
-
function getConfig() {
|
|
1079
|
-
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|
1080
|
-
return {
|
|
1081
|
-
baseUrl: (_b = (_a2 = parsed.flags["backend-url"]) != null ? _a2 : process.env.AOMI_BASE_URL) != null ? _b : "https://api.aomi.dev",
|
|
1082
|
-
apiKey: (_c = parsed.flags["api-key"]) != null ? _c : process.env.AOMI_API_KEY,
|
|
1083
|
-
namespace: (_e = (_d = parsed.flags["namespace"]) != null ? _d : process.env.AOMI_NAMESPACE) != null ? _e : "default",
|
|
1084
|
-
publicKey: (_f = parsed.flags["public-key"]) != null ? _f : process.env.AOMI_PUBLIC_KEY,
|
|
1085
|
-
privateKey: (_g = parsed.flags["private-key"]) != null ? _g : process.env.PRIVATE_KEY,
|
|
1086
|
-
chainRpcUrl: (_h = parsed.flags["rpc-url"]) != null ? _h : process.env.CHAIN_RPC_URL
|
|
1087
|
-
};
|
|
1601
|
+
await applyModelSelection(session, state, requestedModel);
|
|
1088
1602
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
if (
|
|
1093
|
-
|
|
1094
|
-
sessionId: crypto.randomUUID(),
|
|
1095
|
-
baseUrl: config.baseUrl,
|
|
1096
|
-
namespace: config.namespace,
|
|
1097
|
-
apiKey: config.apiKey,
|
|
1098
|
-
publicKey: config.publicKey
|
|
1099
|
-
};
|
|
1100
|
-
writeState(state);
|
|
1101
|
-
} else {
|
|
1102
|
-
let changed = false;
|
|
1103
|
-
if (config.baseUrl && config.baseUrl !== state.baseUrl) {
|
|
1104
|
-
state.baseUrl = config.baseUrl;
|
|
1105
|
-
changed = true;
|
|
1106
|
-
}
|
|
1107
|
-
if (config.namespace && config.namespace !== state.namespace) {
|
|
1108
|
-
state.namespace = config.namespace;
|
|
1109
|
-
changed = true;
|
|
1110
|
-
}
|
|
1111
|
-
if (config.apiKey !== void 0 && config.apiKey !== state.apiKey) {
|
|
1112
|
-
state.apiKey = config.apiKey;
|
|
1113
|
-
changed = true;
|
|
1114
|
-
}
|
|
1115
|
-
if (config.publicKey !== void 0 && config.publicKey !== state.publicKey) {
|
|
1116
|
-
state.publicKey = config.publicKey;
|
|
1117
|
-
changed = true;
|
|
1118
|
-
}
|
|
1119
|
-
if (changed) writeState(state);
|
|
1120
|
-
}
|
|
1121
|
-
const session = new Session(
|
|
1122
|
-
{ baseUrl: state.baseUrl, apiKey: state.apiKey },
|
|
1123
|
-
{
|
|
1124
|
-
sessionId: state.sessionId,
|
|
1125
|
-
namespace: state.namespace,
|
|
1126
|
-
apiKey: state.apiKey,
|
|
1127
|
-
publicKey: state.publicKey,
|
|
1128
|
-
userState: state.publicKey ? {
|
|
1129
|
-
address: state.publicKey,
|
|
1130
|
-
chainId: 1,
|
|
1131
|
-
isConnected: true
|
|
1132
|
-
} : void 0
|
|
1133
|
-
}
|
|
1134
|
-
);
|
|
1135
|
-
return { session, state };
|
|
1136
|
-
}
|
|
1137
|
-
function walletRequestToPendingTx(req) {
|
|
1138
|
-
if (req.kind === "transaction") {
|
|
1139
|
-
const p2 = req.payload;
|
|
1603
|
+
|
|
1604
|
+
// src/cli/transactions.ts
|
|
1605
|
+
function walletRequestToPendingTx(request) {
|
|
1606
|
+
if (request.kind === "transaction") {
|
|
1607
|
+
const payload2 = request.payload;
|
|
1140
1608
|
return {
|
|
1141
1609
|
kind: "transaction",
|
|
1142
|
-
to:
|
|
1143
|
-
value:
|
|
1144
|
-
data:
|
|
1145
|
-
chainId:
|
|
1146
|
-
timestamp:
|
|
1147
|
-
payload:
|
|
1610
|
+
to: payload2.to,
|
|
1611
|
+
value: payload2.value,
|
|
1612
|
+
data: payload2.data,
|
|
1613
|
+
chainId: payload2.chainId,
|
|
1614
|
+
timestamp: request.timestamp,
|
|
1615
|
+
payload: request.payload
|
|
1148
1616
|
};
|
|
1149
1617
|
}
|
|
1150
|
-
const
|
|
1618
|
+
const payload = request.payload;
|
|
1151
1619
|
return {
|
|
1152
1620
|
kind: "eip712_sign",
|
|
1153
|
-
description:
|
|
1154
|
-
timestamp:
|
|
1155
|
-
payload:
|
|
1621
|
+
description: payload.description,
|
|
1622
|
+
timestamp: request.timestamp,
|
|
1623
|
+
payload: request.payload
|
|
1156
1624
|
};
|
|
1157
1625
|
}
|
|
1158
1626
|
function formatTxLine(tx, prefix) {
|
|
1159
|
-
var
|
|
1627
|
+
var _a3;
|
|
1160
1628
|
const parts = [`${prefix} ${tx.id}`];
|
|
1161
1629
|
if (tx.kind === "transaction") {
|
|
1162
|
-
parts.push(`to: ${(
|
|
1630
|
+
parts.push(`to: ${(_a3 = tx.to) != null ? _a3 : "?"}`);
|
|
1163
1631
|
if (tx.value) parts.push(`value: ${tx.value}`);
|
|
1164
1632
|
if (tx.chainId) parts.push(`chain: ${tx.chainId}`);
|
|
1165
1633
|
if (tx.data) parts.push(`data: ${tx.data.slice(0, 20)}...`);
|
|
1166
1634
|
} else {
|
|
1167
|
-
parts.push(
|
|
1635
|
+
parts.push("eip712");
|
|
1168
1636
|
if (tx.description) parts.push(tx.description);
|
|
1169
1637
|
}
|
|
1170
1638
|
parts.push(`(${new Date(tx.timestamp).toLocaleTimeString()})`);
|
|
1171
1639
|
return parts.join(" ");
|
|
1172
1640
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
var RESET = "\x1B[0m";
|
|
1178
|
-
function printToolUpdate(event) {
|
|
1179
|
-
var _a2, _b, _c;
|
|
1180
|
-
const name = (_b = (_a2 = event.tool_name) != null ? _a2 : event.name) != null ? _b : "unknown";
|
|
1181
|
-
const status = (_c = event.status) != null ? _c : "running";
|
|
1182
|
-
console.log(`${DIM}\u{1F527} [tool] ${name}: ${status}${RESET}`);
|
|
1183
|
-
}
|
|
1184
|
-
function printToolComplete(event) {
|
|
1185
|
-
var _a2, _b, _c;
|
|
1186
|
-
const name = (_b = (_a2 = event.tool_name) != null ? _a2 : event.name) != null ? _b : "unknown";
|
|
1187
|
-
const result = (_c = event.result) != null ? _c : event.output;
|
|
1188
|
-
const line = result ? `${GREEN}\u2714 [tool] ${name} \u2192 ${result.slice(0, 120)}${result.length > 120 ? "\u2026" : ""}${RESET}` : `${GREEN}\u2714 [tool] ${name} done${RESET}`;
|
|
1189
|
-
console.log(line);
|
|
1190
|
-
}
|
|
1191
|
-
function printNewAgentMessages(messages, lastPrintedCount) {
|
|
1192
|
-
const agentMessages = messages.filter(
|
|
1193
|
-
(m) => m.sender === "agent" || m.sender === "assistant"
|
|
1194
|
-
);
|
|
1195
|
-
let handled = lastPrintedCount;
|
|
1196
|
-
for (let i = lastPrintedCount; i < agentMessages.length; i++) {
|
|
1197
|
-
const msg = agentMessages[i];
|
|
1198
|
-
if (msg.is_streaming) {
|
|
1199
|
-
break;
|
|
1200
|
-
}
|
|
1201
|
-
if (msg.content) {
|
|
1202
|
-
console.log(`${CYAN}\u{1F916} ${msg.content}${RESET}`);
|
|
1203
|
-
}
|
|
1204
|
-
handled = i + 1;
|
|
1205
|
-
}
|
|
1206
|
-
return handled;
|
|
1207
|
-
}
|
|
1208
|
-
async function chatCommand() {
|
|
1209
|
-
const message = parsed.positional.join(" ");
|
|
1641
|
+
|
|
1642
|
+
// src/cli/commands/chat.ts
|
|
1643
|
+
async function chatCommand(runtime) {
|
|
1644
|
+
const message = runtime.parsed.positional.join(" ");
|
|
1210
1645
|
if (!message) {
|
|
1211
1646
|
fatal("Usage: aomi chat <message>");
|
|
1212
1647
|
}
|
|
1213
|
-
const verbose = parsed.flags["verbose"] === "true" || parsed.flags["v"] === "true";
|
|
1214
|
-
const { session, state } = getOrCreateSession();
|
|
1215
|
-
if (state.publicKey) {
|
|
1216
|
-
await session.client.sendSystemMessage(
|
|
1217
|
-
session.sessionId,
|
|
1218
|
-
JSON.stringify({
|
|
1219
|
-
type: "wallet:state_changed",
|
|
1220
|
-
payload: {
|
|
1221
|
-
address: state.publicKey,
|
|
1222
|
-
chainId: 1,
|
|
1223
|
-
isConnected: true
|
|
1224
|
-
}
|
|
1225
|
-
})
|
|
1226
|
-
);
|
|
1227
|
-
}
|
|
1228
|
-
const capturedRequests = [];
|
|
1229
|
-
let printedAgentCount = 0;
|
|
1230
|
-
session.on("wallet_tx_request", (req) => capturedRequests.push(req));
|
|
1231
|
-
session.on("wallet_eip712_request", (req) => capturedRequests.push(req));
|
|
1648
|
+
const verbose = runtime.parsed.flags["verbose"] === "true" || runtime.parsed.flags["v"] === "true";
|
|
1649
|
+
const { session, state } = getOrCreateSession(runtime);
|
|
1232
1650
|
try {
|
|
1233
|
-
await session
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1651
|
+
await applyRequestedModelIfPresent(runtime, session, state);
|
|
1652
|
+
if (state.publicKey) {
|
|
1653
|
+
session.resolveWallet(state.publicKey, state.chainId);
|
|
1654
|
+
}
|
|
1655
|
+
const capturedRequests = [];
|
|
1656
|
+
let printedAgentCount = 0;
|
|
1657
|
+
const seenToolResults = /* @__PURE__ */ new Set();
|
|
1658
|
+
session.on("wallet_tx_request", (request) => capturedRequests.push(request));
|
|
1659
|
+
session.on(
|
|
1660
|
+
"wallet_eip712_request",
|
|
1661
|
+
(request) => capturedRequests.push(request)
|
|
1662
|
+
);
|
|
1663
|
+
session.on("tool_complete", (event) => {
|
|
1664
|
+
const name = getToolNameFromEvent(event);
|
|
1665
|
+
const result = getToolResultFromEvent(event);
|
|
1666
|
+
const key = toToolResultKey(name, result);
|
|
1667
|
+
seenToolResults.add(key);
|
|
1668
|
+
if (verbose || isAlwaysVisibleTool(name)) {
|
|
1669
|
+
printToolComplete(event);
|
|
1240
1670
|
}
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
(
|
|
1244
|
-
|
|
1671
|
+
});
|
|
1672
|
+
session.on("tool_update", (event) => {
|
|
1673
|
+
if (verbose) {
|
|
1674
|
+
printToolUpdate(event);
|
|
1675
|
+
}
|
|
1676
|
+
});
|
|
1245
1677
|
if (verbose) {
|
|
1246
|
-
|
|
1678
|
+
session.on("processing_start", () => {
|
|
1247
1679
|
console.log(`${DIM}\u23F3 Processing\u2026${RESET}`);
|
|
1248
|
-
}
|
|
1249
|
-
printedAgentCount = printNewAgentMessages(allMsgs, printedAgentCount);
|
|
1250
|
-
session.on("tool_update", (event) => printToolUpdate(event));
|
|
1251
|
-
session.on("tool_complete", (event) => printToolComplete(event));
|
|
1252
|
-
session.on("messages", (msgs) => {
|
|
1253
|
-
printedAgentCount = printNewAgentMessages(msgs, printedAgentCount);
|
|
1254
1680
|
});
|
|
1255
1681
|
session.on("system_notice", ({ message: msg }) => {
|
|
1256
1682
|
console.log(`${YELLOW}\u{1F4E2} ${msg}${RESET}`);
|
|
@@ -1259,6 +1685,27 @@ async function chatCommand() {
|
|
|
1259
1685
|
console.log(`\x1B[31m\u274C ${msg}${RESET}`);
|
|
1260
1686
|
});
|
|
1261
1687
|
}
|
|
1688
|
+
await session.sendAsync(message);
|
|
1689
|
+
const allMessages = session.getMessages();
|
|
1690
|
+
let seedIdx = allMessages.length;
|
|
1691
|
+
for (let i = allMessages.length - 1; i >= 0; i--) {
|
|
1692
|
+
if (allMessages[i].sender === "user") {
|
|
1693
|
+
seedIdx = i;
|
|
1694
|
+
break;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
printedAgentCount = allMessages.slice(0, seedIdx).filter(
|
|
1698
|
+
(entry) => entry.sender === "agent" || entry.sender === "assistant"
|
|
1699
|
+
).length;
|
|
1700
|
+
if (verbose) {
|
|
1701
|
+
printedAgentCount = printNewAgentMessages(
|
|
1702
|
+
allMessages,
|
|
1703
|
+
printedAgentCount
|
|
1704
|
+
);
|
|
1705
|
+
session.on("messages", (messages) => {
|
|
1706
|
+
printedAgentCount = printNewAgentMessages(messages, printedAgentCount);
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1262
1709
|
if (session.getIsProcessing()) {
|
|
1263
1710
|
await new Promise((resolve) => {
|
|
1264
1711
|
const checkWallet = () => {
|
|
@@ -1269,27 +1716,54 @@ async function chatCommand() {
|
|
|
1269
1716
|
session.on("processing_end", () => resolve());
|
|
1270
1717
|
});
|
|
1271
1718
|
}
|
|
1719
|
+
const messageToolResults = getMessageToolResults(
|
|
1720
|
+
session.getMessages(),
|
|
1721
|
+
seedIdx + 1
|
|
1722
|
+
);
|
|
1723
|
+
if (verbose) {
|
|
1724
|
+
for (const tool of messageToolResults) {
|
|
1725
|
+
const key = toToolResultKey(tool.name, tool.result);
|
|
1726
|
+
if (seenToolResults.has(key)) {
|
|
1727
|
+
continue;
|
|
1728
|
+
}
|
|
1729
|
+
printToolResultLine(tool.name, tool.result);
|
|
1730
|
+
}
|
|
1731
|
+
} else {
|
|
1732
|
+
for (const tool of messageToolResults) {
|
|
1733
|
+
const key = toToolResultKey(tool.name, tool.result);
|
|
1734
|
+
if (seenToolResults.has(key)) {
|
|
1735
|
+
continue;
|
|
1736
|
+
}
|
|
1737
|
+
if (isAlwaysVisibleTool(tool.name)) {
|
|
1738
|
+
printToolResultLine(tool.name, tool.result);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1272
1742
|
if (verbose) {
|
|
1273
|
-
printNewAgentMessages(
|
|
1743
|
+
printedAgentCount = printNewAgentMessages(
|
|
1744
|
+
session.getMessages(),
|
|
1745
|
+
printedAgentCount
|
|
1746
|
+
);
|
|
1274
1747
|
console.log(`${DIM}\u2705 Done${RESET}`);
|
|
1275
1748
|
}
|
|
1276
|
-
for (const
|
|
1277
|
-
const pending = addPendingTx(state, walletRequestToPendingTx(
|
|
1749
|
+
for (const request of capturedRequests) {
|
|
1750
|
+
const pending = addPendingTx(state, walletRequestToPendingTx(request));
|
|
1278
1751
|
console.log(`\u26A1 Wallet request queued: ${pending.id}`);
|
|
1279
|
-
if (
|
|
1280
|
-
const
|
|
1281
|
-
console.log(` to: ${
|
|
1282
|
-
if (
|
|
1283
|
-
if (
|
|
1752
|
+
if (request.kind === "transaction") {
|
|
1753
|
+
const payload = request.payload;
|
|
1754
|
+
console.log(` to: ${payload.to}`);
|
|
1755
|
+
if (payload.value) console.log(` value: ${payload.value}`);
|
|
1756
|
+
if (payload.chainId) console.log(` chain: ${payload.chainId}`);
|
|
1284
1757
|
} else {
|
|
1285
|
-
const
|
|
1286
|
-
if (
|
|
1758
|
+
const payload = request.payload;
|
|
1759
|
+
if (payload.description) {
|
|
1760
|
+
console.log(` desc: ${payload.description}`);
|
|
1761
|
+
}
|
|
1287
1762
|
}
|
|
1288
1763
|
}
|
|
1289
1764
|
if (!verbose) {
|
|
1290
|
-
const
|
|
1291
|
-
|
|
1292
|
-
(m) => m.sender === "agent" || m.sender === "assistant"
|
|
1765
|
+
const agentMessages = session.getMessages().filter(
|
|
1766
|
+
(entry) => entry.sender === "agent" || entry.sender === "assistant"
|
|
1293
1767
|
);
|
|
1294
1768
|
const last = agentMessages[agentMessages.length - 1];
|
|
1295
1769
|
if (last == null ? void 0 : last.content) {
|
|
@@ -1299,22 +1773,24 @@ async function chatCommand() {
|
|
|
1299
1773
|
}
|
|
1300
1774
|
}
|
|
1301
1775
|
if (capturedRequests.length > 0) {
|
|
1302
|
-
console.log(
|
|
1303
|
-
|
|
1776
|
+
console.log(
|
|
1777
|
+
"\nRun `aomi tx` to see pending transactions, `aomi sign <id>` to sign."
|
|
1778
|
+
);
|
|
1304
1779
|
}
|
|
1305
1780
|
} finally {
|
|
1306
1781
|
session.close();
|
|
1307
1782
|
}
|
|
1308
1783
|
}
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1784
|
+
|
|
1785
|
+
// src/cli/commands/control.ts
|
|
1786
|
+
async function statusCommand(runtime) {
|
|
1787
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1788
|
+
if (!readState()) {
|
|
1313
1789
|
console.log("No active session");
|
|
1314
1790
|
printDataFileLocation();
|
|
1315
1791
|
return;
|
|
1316
1792
|
}
|
|
1317
|
-
const { session } = getOrCreateSession();
|
|
1793
|
+
const { session, state } = getOrCreateSession(runtime);
|
|
1318
1794
|
try {
|
|
1319
1795
|
const apiState = await session.client.fetchState(state.sessionId);
|
|
1320
1796
|
console.log(
|
|
@@ -1322,12 +1798,13 @@ async function statusCommand() {
|
|
|
1322
1798
|
{
|
|
1323
1799
|
sessionId: state.sessionId,
|
|
1324
1800
|
baseUrl: state.baseUrl,
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1801
|
+
app: state.app,
|
|
1802
|
+
model: (_a3 = state.model) != null ? _a3 : null,
|
|
1803
|
+
isProcessing: (_b = apiState.is_processing) != null ? _b : false,
|
|
1804
|
+
messageCount: (_d = (_c = apiState.messages) == null ? void 0 : _c.length) != null ? _d : 0,
|
|
1805
|
+
title: (_e = apiState.title) != null ? _e : null,
|
|
1806
|
+
pendingTxs: (_g = (_f = state.pendingTxs) == null ? void 0 : _f.length) != null ? _g : 0,
|
|
1807
|
+
signedTxs: (_i = (_h = state.signedTxs) == null ? void 0 : _h.length) != null ? _i : 0
|
|
1331
1808
|
},
|
|
1332
1809
|
null,
|
|
1333
1810
|
2
|
|
@@ -1338,13 +1815,12 @@ async function statusCommand() {
|
|
|
1338
1815
|
session.close();
|
|
1339
1816
|
}
|
|
1340
1817
|
}
|
|
1341
|
-
async function eventsCommand() {
|
|
1342
|
-
|
|
1343
|
-
if (!state) {
|
|
1818
|
+
async function eventsCommand(runtime) {
|
|
1819
|
+
if (!readState()) {
|
|
1344
1820
|
console.log("No active session");
|
|
1345
1821
|
return;
|
|
1346
1822
|
}
|
|
1347
|
-
const { session } = getOrCreateSession();
|
|
1823
|
+
const { session, state } = getOrCreateSession(runtime);
|
|
1348
1824
|
try {
|
|
1349
1825
|
const events = await session.client.getSystemEvents(state.sessionId);
|
|
1350
1826
|
console.log(JSON.stringify(events, null, 2));
|
|
@@ -1352,15 +1828,372 @@ async function eventsCommand() {
|
|
|
1352
1828
|
session.close();
|
|
1353
1829
|
}
|
|
1354
1830
|
}
|
|
1831
|
+
async function modelsCommand(runtime) {
|
|
1832
|
+
var _a3, _b;
|
|
1833
|
+
const client = createControlClient(runtime);
|
|
1834
|
+
const state = readState();
|
|
1835
|
+
const sessionId = (_a3 = state == null ? void 0 : state.sessionId) != null ? _a3 : crypto.randomUUID();
|
|
1836
|
+
const models = await client.getModels(sessionId, {
|
|
1837
|
+
apiKey: (_b = runtime.config.apiKey) != null ? _b : state == null ? void 0 : state.apiKey
|
|
1838
|
+
});
|
|
1839
|
+
if (models.length === 0) {
|
|
1840
|
+
console.log("No models available.");
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
for (const model of models) {
|
|
1844
|
+
const marker = (state == null ? void 0 : state.model) === model ? " (current)" : "";
|
|
1845
|
+
console.log(`${model}${marker}`);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
async function modelCommand(runtime) {
|
|
1849
|
+
var _a3;
|
|
1850
|
+
const subcommand = runtime.parsed.positional[0];
|
|
1851
|
+
if (!subcommand || subcommand === "current") {
|
|
1852
|
+
const state2 = readState();
|
|
1853
|
+
if (!state2) {
|
|
1854
|
+
console.log("No active session");
|
|
1855
|
+
printDataFileLocation();
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
console.log((_a3 = state2.model) != null ? _a3 : "(default backend model)");
|
|
1859
|
+
printDataFileLocation();
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
if (subcommand !== "set") {
|
|
1863
|
+
fatal("Usage: aomi model set <rig>\n aomi model current");
|
|
1864
|
+
}
|
|
1865
|
+
const model = runtime.parsed.positional.slice(1).join(" ").trim();
|
|
1866
|
+
if (!model) {
|
|
1867
|
+
fatal("Usage: aomi model set <rig>");
|
|
1868
|
+
}
|
|
1869
|
+
const { session, state } = getOrCreateSession(runtime);
|
|
1870
|
+
try {
|
|
1871
|
+
await applyModelSelection(session, state, model);
|
|
1872
|
+
console.log(`Model set to ${model}`);
|
|
1873
|
+
printDataFileLocation();
|
|
1874
|
+
} finally {
|
|
1875
|
+
session.close();
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
// src/cli/tables.ts
|
|
1880
|
+
var MAX_TABLE_VALUE_WIDTH = 72;
|
|
1881
|
+
var MAX_TX_JSON_WIDTH = 96;
|
|
1882
|
+
var MAX_TX_ROWS = 8;
|
|
1883
|
+
function truncateCell(value, maxWidth) {
|
|
1884
|
+
if (value.length <= maxWidth) return value;
|
|
1885
|
+
return `${value.slice(0, maxWidth - 1)}\u2026`;
|
|
1886
|
+
}
|
|
1887
|
+
function padRight(value, width) {
|
|
1888
|
+
return value.padEnd(width, " ");
|
|
1889
|
+
}
|
|
1890
|
+
function estimateTokenCount(messages) {
|
|
1891
|
+
var _a3;
|
|
1892
|
+
let totalChars = 0;
|
|
1893
|
+
for (const message of messages) {
|
|
1894
|
+
const content = formatLogContent(message.content);
|
|
1895
|
+
if (content) {
|
|
1896
|
+
totalChars += content.length + 1;
|
|
1897
|
+
}
|
|
1898
|
+
if ((_a3 = message.tool_result) == null ? void 0 : _a3[1]) {
|
|
1899
|
+
totalChars += message.tool_result[1].length;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
return Math.round(totalChars / 4);
|
|
1903
|
+
}
|
|
1904
|
+
function toPendingTxMetadata(tx) {
|
|
1905
|
+
var _a3, _b, _c, _d;
|
|
1906
|
+
return {
|
|
1907
|
+
id: tx.id,
|
|
1908
|
+
kind: tx.kind,
|
|
1909
|
+
to: (_a3 = tx.to) != null ? _a3 : null,
|
|
1910
|
+
value: (_b = tx.value) != null ? _b : null,
|
|
1911
|
+
chainId: (_c = tx.chainId) != null ? _c : null,
|
|
1912
|
+
description: (_d = tx.description) != null ? _d : null,
|
|
1913
|
+
timestamp: new Date(tx.timestamp).toISOString()
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
function toSignedTxMetadata(tx) {
|
|
1917
|
+
var _a3, _b, _c, _d, _e, _f, _g;
|
|
1918
|
+
return {
|
|
1919
|
+
id: tx.id,
|
|
1920
|
+
kind: tx.kind,
|
|
1921
|
+
txHash: (_a3 = tx.txHash) != null ? _a3 : null,
|
|
1922
|
+
signature: (_b = tx.signature) != null ? _b : null,
|
|
1923
|
+
from: (_c = tx.from) != null ? _c : null,
|
|
1924
|
+
to: (_d = tx.to) != null ? _d : null,
|
|
1925
|
+
value: (_e = tx.value) != null ? _e : null,
|
|
1926
|
+
chainId: (_f = tx.chainId) != null ? _f : null,
|
|
1927
|
+
description: (_g = tx.description) != null ? _g : null,
|
|
1928
|
+
timestamp: new Date(tx.timestamp).toISOString()
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
function printKeyValueTable(rows, color = CYAN) {
|
|
1932
|
+
const labels = rows.map(([label]) => label);
|
|
1933
|
+
const values = rows.map(
|
|
1934
|
+
([, value]) => truncateCell(value, MAX_TABLE_VALUE_WIDTH)
|
|
1935
|
+
);
|
|
1936
|
+
const keyWidth = Math.max("field".length, ...labels.map((label) => label.length));
|
|
1937
|
+
const valueWidth = Math.max("value".length, ...values.map((value) => value.length));
|
|
1938
|
+
const border = `+${"-".repeat(keyWidth + 2)}+${"-".repeat(valueWidth + 2)}+`;
|
|
1939
|
+
console.log(`${color}${border}${RESET}`);
|
|
1940
|
+
console.log(
|
|
1941
|
+
`${color}| ${padRight("field", keyWidth)} | ${padRight("value", valueWidth)} |${RESET}`
|
|
1942
|
+
);
|
|
1943
|
+
console.log(`${color}${border}${RESET}`);
|
|
1944
|
+
for (let i = 0; i < rows.length; i++) {
|
|
1945
|
+
console.log(
|
|
1946
|
+
`${color}| ${padRight(labels[i], keyWidth)} | ${padRight(values[i], valueWidth)} |${RESET}`
|
|
1947
|
+
);
|
|
1948
|
+
console.log(`${color}${border}${RESET}`);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
function printTransactionTable(pendingTxs, signedTxs, color = GREEN) {
|
|
1952
|
+
const rows = [
|
|
1953
|
+
...pendingTxs.map((tx) => ({
|
|
1954
|
+
status: "pending",
|
|
1955
|
+
metadata: toPendingTxMetadata(tx)
|
|
1956
|
+
})),
|
|
1957
|
+
...signedTxs.map((tx) => ({
|
|
1958
|
+
status: "signed",
|
|
1959
|
+
metadata: toSignedTxMetadata(tx)
|
|
1960
|
+
}))
|
|
1961
|
+
];
|
|
1962
|
+
if (rows.length === 0) {
|
|
1963
|
+
console.log(`${YELLOW}No transactions in local CLI state.${RESET}`);
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
const visibleRows = rows.slice(0, MAX_TX_ROWS);
|
|
1967
|
+
const statusWidth = Math.max(
|
|
1968
|
+
"status".length,
|
|
1969
|
+
...visibleRows.map((row) => row.status.length)
|
|
1970
|
+
);
|
|
1971
|
+
const jsonCells = visibleRows.map(
|
|
1972
|
+
(row) => truncateCell(JSON.stringify(row.metadata), MAX_TX_JSON_WIDTH)
|
|
1973
|
+
);
|
|
1974
|
+
const jsonWidth = Math.max("metadata_json".length, ...jsonCells.map((v) => v.length));
|
|
1975
|
+
const border = `+${"-".repeat(statusWidth + 2)}+${"-".repeat(jsonWidth + 2)}+`;
|
|
1976
|
+
console.log(`${color}${border}${RESET}`);
|
|
1977
|
+
console.log(
|
|
1978
|
+
`${color}| ${padRight("status", statusWidth)} | ${padRight("metadata_json", jsonWidth)} |${RESET}`
|
|
1979
|
+
);
|
|
1980
|
+
console.log(`${color}${border}${RESET}`);
|
|
1981
|
+
for (let i = 0; i < visibleRows.length; i++) {
|
|
1982
|
+
console.log(
|
|
1983
|
+
`${color}| ${padRight(visibleRows[i].status, statusWidth)} | ${padRight(jsonCells[i], jsonWidth)} |${RESET}`
|
|
1984
|
+
);
|
|
1985
|
+
console.log(`${color}${border}${RESET}`);
|
|
1986
|
+
}
|
|
1987
|
+
if (rows.length > MAX_TX_ROWS) {
|
|
1988
|
+
const omitted = rows.length - MAX_TX_ROWS;
|
|
1989
|
+
console.log(`${DIM}${omitted} transaction rows omitted${RESET}`);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
// src/cli/commands/history.ts
|
|
1994
|
+
async function logCommand(runtime) {
|
|
1995
|
+
var _a3, _b, _c, _d, _e;
|
|
1996
|
+
if (!readState()) {
|
|
1997
|
+
console.log("No active session");
|
|
1998
|
+
printDataFileLocation();
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
const { session, state } = getOrCreateSession(runtime);
|
|
2002
|
+
try {
|
|
2003
|
+
const apiState = await session.client.fetchState(state.sessionId);
|
|
2004
|
+
const messages = (_a3 = apiState.messages) != null ? _a3 : [];
|
|
2005
|
+
const pendingTxs = (_b = state.pendingTxs) != null ? _b : [];
|
|
2006
|
+
const signedTxs = (_c = state.signedTxs) != null ? _c : [];
|
|
2007
|
+
const toolCalls = messages.filter((msg) => Boolean(msg.tool_result)).length;
|
|
2008
|
+
const tokenCountEstimate = estimateTokenCount(messages);
|
|
2009
|
+
const topic = (_d = apiState.title) != null ? _d : "Untitled Session";
|
|
2010
|
+
if (messages.length === 0) {
|
|
2011
|
+
console.log("No messages in this session.");
|
|
2012
|
+
printDataFileLocation();
|
|
2013
|
+
return;
|
|
2014
|
+
}
|
|
2015
|
+
console.log(`------ Session id: ${state.sessionId} ------`);
|
|
2016
|
+
printKeyValueTable([
|
|
2017
|
+
["topic", topic],
|
|
2018
|
+
["msg count", String(messages.length)],
|
|
2019
|
+
["token count", `${tokenCountEstimate} (estimated)`],
|
|
2020
|
+
["tool calls", String(toolCalls)],
|
|
2021
|
+
[
|
|
2022
|
+
"transactions",
|
|
2023
|
+
`${pendingTxs.length + signedTxs.length} (${pendingTxs.length} pending, ${signedTxs.length} signed)`
|
|
2024
|
+
]
|
|
2025
|
+
]);
|
|
2026
|
+
console.log("Transactions metadata (JSON):");
|
|
2027
|
+
printTransactionTable(pendingTxs, signedTxs);
|
|
2028
|
+
console.log("-------------------- Messages --------------------");
|
|
2029
|
+
for (const msg of messages) {
|
|
2030
|
+
const content = formatLogContent(msg.content);
|
|
2031
|
+
let time = "";
|
|
2032
|
+
if (msg.timestamp) {
|
|
2033
|
+
const raw = msg.timestamp;
|
|
2034
|
+
const numeric = /^\d+$/.test(raw) ? parseInt(raw, 10) : NaN;
|
|
2035
|
+
const date = !Number.isNaN(numeric) ? new Date(numeric < 1e12 ? numeric * 1e3 : numeric) : new Date(raw);
|
|
2036
|
+
time = Number.isNaN(date.getTime()) ? "" : `${DIM}${date.toLocaleTimeString()}${RESET} `;
|
|
2037
|
+
}
|
|
2038
|
+
const sender = (_e = msg.sender) != null ? _e : "unknown";
|
|
2039
|
+
if (sender === "user") {
|
|
2040
|
+
if (content) {
|
|
2041
|
+
console.log(`${time}${CYAN}\u{1F464} You:${RESET} ${content}`);
|
|
2042
|
+
}
|
|
2043
|
+
} else if (sender === "agent" || sender === "assistant") {
|
|
2044
|
+
if (msg.tool_result) {
|
|
2045
|
+
const [toolName, result] = msg.tool_result;
|
|
2046
|
+
console.log(
|
|
2047
|
+
`${time}${GREEN}\u{1F527} [${toolName}]${RESET} ${formatToolResultPreview(result)}`
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
if (content) {
|
|
2051
|
+
console.log(`${time}${CYAN}\u{1F916} Agent:${RESET} ${content}`);
|
|
2052
|
+
}
|
|
2053
|
+
} else if (sender === "system") {
|
|
2054
|
+
if (content && !content.startsWith("Response of system endpoint:")) {
|
|
2055
|
+
console.log(`${time}${YELLOW}\u2699\uFE0F System:${RESET} ${content}`);
|
|
2056
|
+
}
|
|
2057
|
+
} else {
|
|
2058
|
+
if (content) {
|
|
2059
|
+
console.log(`${time}${DIM}[${sender}]${RESET} ${content}`);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
console.log(`
|
|
2064
|
+
${DIM}\u2014 ${messages.length} messages \u2014${RESET}`);
|
|
2065
|
+
printDataFileLocation();
|
|
2066
|
+
} finally {
|
|
2067
|
+
session.close();
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
function closeCommand(runtime) {
|
|
2071
|
+
if (readState()) {
|
|
2072
|
+
const { session } = getOrCreateSession(runtime);
|
|
2073
|
+
session.close();
|
|
2074
|
+
}
|
|
2075
|
+
clearState();
|
|
2076
|
+
console.log("Session closed");
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// src/cli/commands/sessions.ts
|
|
2080
|
+
async function fetchRemoteSessionStats(record) {
|
|
2081
|
+
var _a3, _b;
|
|
2082
|
+
const client = new AomiClient({
|
|
2083
|
+
baseUrl: record.state.baseUrl,
|
|
2084
|
+
apiKey: record.state.apiKey
|
|
2085
|
+
});
|
|
2086
|
+
try {
|
|
2087
|
+
const apiState = await client.fetchState(record.sessionId);
|
|
2088
|
+
const messages = (_a3 = apiState.messages) != null ? _a3 : [];
|
|
2089
|
+
return {
|
|
2090
|
+
topic: (_b = apiState.title) != null ? _b : "Untitled Session",
|
|
2091
|
+
messageCount: messages.length,
|
|
2092
|
+
tokenCountEstimate: estimateTokenCount(messages),
|
|
2093
|
+
toolCalls: messages.filter((msg) => Boolean(msg.tool_result)).length
|
|
2094
|
+
};
|
|
2095
|
+
} catch (e) {
|
|
2096
|
+
return null;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function printSessionSummary(record, stats, isActive) {
|
|
2100
|
+
var _a3, _b, _c;
|
|
2101
|
+
const pendingTxs = (_a3 = record.state.pendingTxs) != null ? _a3 : [];
|
|
2102
|
+
const signedTxs = (_b = record.state.signedTxs) != null ? _b : [];
|
|
2103
|
+
const header = isActive ? `\u{1F9F5} Session id: ${record.sessionId} (session-${record.localId}, active)` : `\u{1F9F5} Session id: ${record.sessionId} (session-${record.localId})`;
|
|
2104
|
+
console.log(`${YELLOW}------ ${header} ------${RESET}`);
|
|
2105
|
+
printKeyValueTable([
|
|
2106
|
+
["\u{1F9E0} topic", (_c = stats == null ? void 0 : stats.topic) != null ? _c : "Unavailable (fetch failed)"],
|
|
2107
|
+
["\u{1F4AC} msg count", stats ? String(stats.messageCount) : "n/a"],
|
|
2108
|
+
[
|
|
2109
|
+
"\u{1F9EE} token count",
|
|
2110
|
+
stats ? `${stats.tokenCountEstimate} (estimated)` : "n/a"
|
|
2111
|
+
],
|
|
2112
|
+
["\u{1F6E0} tool calls", stats ? String(stats.toolCalls) : "n/a"],
|
|
2113
|
+
[
|
|
2114
|
+
"\u{1F4B8} transactions",
|
|
2115
|
+
`${pendingTxs.length + signedTxs.length} (${pendingTxs.length} pending, ${signedTxs.length} signed)`
|
|
2116
|
+
]
|
|
2117
|
+
]);
|
|
2118
|
+
console.log();
|
|
2119
|
+
console.log(`${YELLOW}\u{1F4BE} Transactions metadata (JSON):${RESET}`);
|
|
2120
|
+
printTransactionTable(pendingTxs, signedTxs);
|
|
2121
|
+
}
|
|
2122
|
+
async function sessionsCommand(_runtime) {
|
|
2123
|
+
var _a3;
|
|
2124
|
+
const sessions = listStoredSessions().sort((a, b) => b.updatedAt - a.updatedAt);
|
|
2125
|
+
if (sessions.length === 0) {
|
|
2126
|
+
console.log("No local sessions.");
|
|
2127
|
+
printDataFileLocation();
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
const activeSessionId = (_a3 = readState()) == null ? void 0 : _a3.sessionId;
|
|
2131
|
+
const statsResults = await Promise.all(
|
|
2132
|
+
sessions.map((record) => fetchRemoteSessionStats(record))
|
|
2133
|
+
);
|
|
2134
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
2135
|
+
printSessionSummary(
|
|
2136
|
+
sessions[i],
|
|
2137
|
+
statsResults[i],
|
|
2138
|
+
sessions[i].sessionId === activeSessionId
|
|
2139
|
+
);
|
|
2140
|
+
if (i < sessions.length - 1) {
|
|
2141
|
+
console.log();
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
printDataFileLocation();
|
|
2145
|
+
}
|
|
2146
|
+
function sessionCommand(runtime) {
|
|
2147
|
+
const subcommand = runtime.parsed.positional[0];
|
|
2148
|
+
const selector = runtime.parsed.positional[1];
|
|
2149
|
+
if (subcommand === "resume") {
|
|
2150
|
+
if (!selector) {
|
|
2151
|
+
fatal("Usage: aomi session resume <session-id|session-N|N>");
|
|
2152
|
+
}
|
|
2153
|
+
const resumed = setActiveSession(selector);
|
|
2154
|
+
if (!resumed) {
|
|
2155
|
+
fatal(`No local session found for selector "${selector}".`);
|
|
2156
|
+
}
|
|
2157
|
+
console.log(`Active session set to ${resumed.sessionId} (session-${resumed.localId}).`);
|
|
2158
|
+
printDataFileLocation();
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
if (subcommand === "delete") {
|
|
2162
|
+
if (!selector) {
|
|
2163
|
+
fatal("Usage: aomi session delete <session-id|session-N|N>");
|
|
2164
|
+
}
|
|
2165
|
+
const deleted = deleteStoredSession(selector);
|
|
2166
|
+
if (!deleted) {
|
|
2167
|
+
fatal(`No local session found for selector "${selector}".`);
|
|
2168
|
+
}
|
|
2169
|
+
console.log(`Deleted local session ${deleted.sessionId} (session-${deleted.localId}).`);
|
|
2170
|
+
const active = readState();
|
|
2171
|
+
if (active) {
|
|
2172
|
+
console.log(`Active session: ${active.sessionId}`);
|
|
2173
|
+
} else {
|
|
2174
|
+
console.log("No active session");
|
|
2175
|
+
}
|
|
2176
|
+
printDataFileLocation();
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
fatal(
|
|
2180
|
+
"Usage: aomi session resume <session-id|session-N|N>\n aomi session delete <session-id|session-N|N>"
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
// src/cli/commands/wallet.ts
|
|
2185
|
+
import { createWalletClient, http } from "viem";
|
|
2186
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
2187
|
+
import * as viemChains from "viem/chains";
|
|
1355
2188
|
function txCommand() {
|
|
1356
|
-
var
|
|
2189
|
+
var _a3, _b, _c;
|
|
1357
2190
|
const state = readState();
|
|
1358
2191
|
if (!state) {
|
|
1359
2192
|
console.log("No active session");
|
|
1360
2193
|
printDataFileLocation();
|
|
1361
2194
|
return;
|
|
1362
2195
|
}
|
|
1363
|
-
const pending = (
|
|
2196
|
+
const pending = (_a3 = state.pendingTxs) != null ? _a3 : [];
|
|
1364
2197
|
const signed = (_b = state.signedTxs) != null ? _b : [];
|
|
1365
2198
|
if (pending.length === 0 && signed.length === 0) {
|
|
1366
2199
|
console.log("No transactions.");
|
|
@@ -1392,48 +2225,112 @@ function txCommand() {
|
|
|
1392
2225
|
}
|
|
1393
2226
|
printDataFileLocation();
|
|
1394
2227
|
}
|
|
1395
|
-
|
|
1396
|
-
var
|
|
1397
|
-
const
|
|
2228
|
+
function requirePendingTx(state, txId) {
|
|
2229
|
+
var _a3;
|
|
2230
|
+
const pendingTx = ((_a3 = state.pendingTxs) != null ? _a3 : []).find((tx) => tx.id === txId);
|
|
2231
|
+
if (!pendingTx) {
|
|
2232
|
+
fatal(
|
|
2233
|
+
`No pending transaction with id "${txId}".
|
|
2234
|
+
Run \`aomi tx\` to see available IDs.`
|
|
2235
|
+
);
|
|
2236
|
+
}
|
|
2237
|
+
return pendingTx;
|
|
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
|
+
}
|
|
2282
|
+
async function signCommand(runtime) {
|
|
2283
|
+
var _a3, _b, _c, _d;
|
|
2284
|
+
const txId = runtime.parsed.positional[0];
|
|
1398
2285
|
if (!txId) {
|
|
1399
|
-
fatal(
|
|
2286
|
+
fatal(
|
|
2287
|
+
"Usage: aomi sign <tx-id>\nRun `aomi tx` to see pending transaction IDs."
|
|
2288
|
+
);
|
|
1400
2289
|
}
|
|
1401
|
-
const
|
|
1402
|
-
const privateKey = config.privateKey;
|
|
2290
|
+
const privateKey = runtime.config.privateKey;
|
|
1403
2291
|
if (!privateKey) {
|
|
1404
|
-
fatal(
|
|
2292
|
+
fatal(
|
|
2293
|
+
[
|
|
2294
|
+
"Private key required for `aomi sign`.",
|
|
2295
|
+
"Pass one of:",
|
|
2296
|
+
" --private-key <hex-key>",
|
|
2297
|
+
" PRIVATE_KEY=<hex-key> aomi sign <tx-id>"
|
|
2298
|
+
].join("\n")
|
|
2299
|
+
);
|
|
1405
2300
|
}
|
|
1406
2301
|
const state = readState();
|
|
1407
2302
|
if (!state) {
|
|
1408
2303
|
fatal("No active session. Run `aomi chat` first.");
|
|
1409
2304
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
Run \`aomi tx\` to see available IDs.`);
|
|
1414
|
-
}
|
|
1415
|
-
const { session } = getOrCreateSession();
|
|
2305
|
+
rewriteSessionState(runtime, state);
|
|
2306
|
+
const pendingTx = requirePendingTx(state, txId);
|
|
2307
|
+
const session = createSessionFromState(state);
|
|
1416
2308
|
try {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
viem = await import("viem");
|
|
1422
|
-
viemAccounts = await import("viem/accounts");
|
|
1423
|
-
viemChains = await import("viem/chains");
|
|
1424
|
-
} catch (e) {
|
|
1425
|
-
fatal(
|
|
1426
|
-
"viem is required for `aomi sign`. Install it:\n npm install viem\n # or: pnpm add viem"
|
|
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}`
|
|
1427
2313
|
);
|
|
2314
|
+
console.log(" Updating session to match the signing key...");
|
|
1428
2315
|
}
|
|
1429
|
-
const
|
|
1430
|
-
const
|
|
1431
|
-
const account = privateKeyToAccount(privateKey);
|
|
1432
|
-
const rpcUrl = config.chainRpcUrl;
|
|
1433
|
-
const targetChainId = (_b = pendingTx.chainId) != null ? _b : 1;
|
|
2316
|
+
const rpcUrl = runtime.config.chainRpcUrl;
|
|
2317
|
+
const targetChainId = (_b = (_a3 = pendingTx.chainId) != null ? _a3 : state.chainId) != null ? _b : 1;
|
|
1434
2318
|
const chain = (_c = Object.values(viemChains).find(
|
|
1435
|
-
(
|
|
1436
|
-
)) != null ? _c : {
|
|
2319
|
+
(candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === targetChainId
|
|
2320
|
+
)) != null ? _c : {
|
|
2321
|
+
id: targetChainId,
|
|
2322
|
+
name: `Chain ${targetChainId}`,
|
|
2323
|
+
nativeCurrency: {
|
|
2324
|
+
name: "ETH",
|
|
2325
|
+
symbol: "ETH",
|
|
2326
|
+
decimals: 18
|
|
2327
|
+
},
|
|
2328
|
+
rpcUrls: {
|
|
2329
|
+
default: {
|
|
2330
|
+
http: [rpcUrl != null ? rpcUrl : ""]
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
};
|
|
1437
2334
|
const walletClient = createWalletClient({
|
|
1438
2335
|
account,
|
|
1439
2336
|
chain,
|
|
@@ -1442,11 +2339,15 @@ Run \`aomi tx\` to see available IDs.`);
|
|
|
1442
2339
|
console.log(`Signer: ${account.address}`);
|
|
1443
2340
|
console.log(`ID: ${pendingTx.id}`);
|
|
1444
2341
|
console.log(`Kind: ${pendingTx.kind}`);
|
|
2342
|
+
let signedRecord;
|
|
2343
|
+
let backendNotification;
|
|
1445
2344
|
if (pendingTx.kind === "transaction") {
|
|
1446
2345
|
console.log(`To: ${pendingTx.to}`);
|
|
1447
2346
|
if (pendingTx.value) console.log(`Value: ${pendingTx.value}`);
|
|
1448
2347
|
if (pendingTx.chainId) console.log(`Chain: ${pendingTx.chainId}`);
|
|
1449
|
-
if (pendingTx.data)
|
|
2348
|
+
if (pendingTx.data) {
|
|
2349
|
+
console.log(`Data: ${pendingTx.data.slice(0, 40)}...`);
|
|
2350
|
+
}
|
|
1450
2351
|
console.log();
|
|
1451
2352
|
const hash = await walletClient.sendTransaction({
|
|
1452
2353
|
to: pendingTx.to,
|
|
@@ -1454,9 +2355,7 @@ Run \`aomi tx\` to see available IDs.`);
|
|
|
1454
2355
|
data: (_d = pendingTx.data) != null ? _d : void 0
|
|
1455
2356
|
});
|
|
1456
2357
|
console.log(`\u2705 Sent! Hash: ${hash}`);
|
|
1457
|
-
|
|
1458
|
-
const freshState = readState();
|
|
1459
|
-
addSignedTx(freshState, {
|
|
2358
|
+
signedRecord = {
|
|
1460
2359
|
id: txId,
|
|
1461
2360
|
kind: "transaction",
|
|
1462
2361
|
txHash: hash,
|
|
@@ -1465,21 +2364,22 @@ Run \`aomi tx\` to see available IDs.`);
|
|
|
1465
2364
|
value: pendingTx.value,
|
|
1466
2365
|
chainId: pendingTx.chainId,
|
|
1467
2366
|
timestamp: Date.now()
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
payload: { txHash: hash, status: "success" }
|
|
1474
|
-
})
|
|
1475
|
-
);
|
|
2367
|
+
};
|
|
2368
|
+
backendNotification = {
|
|
2369
|
+
type: "wallet:tx_complete",
|
|
2370
|
+
payload: { txHash: hash, status: "success" }
|
|
2371
|
+
};
|
|
1476
2372
|
} else {
|
|
1477
2373
|
const typedData = pendingTx.payload.typed_data;
|
|
1478
2374
|
if (!typedData) {
|
|
1479
2375
|
fatal("EIP-712 request is missing typed_data payload.");
|
|
1480
2376
|
}
|
|
1481
|
-
if (pendingTx.description)
|
|
1482
|
-
|
|
2377
|
+
if (pendingTx.description) {
|
|
2378
|
+
console.log(`Desc: ${pendingTx.description}`);
|
|
2379
|
+
}
|
|
2380
|
+
if (typedData.primaryType) {
|
|
2381
|
+
console.log(`Type: ${typedData.primaryType}`);
|
|
2382
|
+
}
|
|
1483
2383
|
console.log();
|
|
1484
2384
|
const { domain, types, primaryType, message } = typedData;
|
|
1485
2385
|
const sigTypes = __spreadValues({}, types);
|
|
@@ -1491,28 +2391,36 @@ Run \`aomi tx\` to see available IDs.`);
|
|
|
1491
2391
|
message
|
|
1492
2392
|
});
|
|
1493
2393
|
console.log(`\u2705 Signed! Signature: ${signature.slice(0, 20)}...`);
|
|
1494
|
-
|
|
1495
|
-
const freshState = readState();
|
|
1496
|
-
addSignedTx(freshState, {
|
|
2394
|
+
signedRecord = {
|
|
1497
2395
|
id: txId,
|
|
1498
2396
|
kind: "eip712_sign",
|
|
1499
2397
|
signature,
|
|
1500
2398
|
from: account.address,
|
|
1501
2399
|
description: pendingTx.description,
|
|
1502
2400
|
timestamp: Date.now()
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
}
|
|
1513
|
-
})
|
|
1514
|
-
);
|
|
2401
|
+
};
|
|
2402
|
+
backendNotification = {
|
|
2403
|
+
type: "wallet_eip712_response",
|
|
2404
|
+
payload: {
|
|
2405
|
+
status: "success",
|
|
2406
|
+
signature,
|
|
2407
|
+
description: pendingTx.description
|
|
2408
|
+
}
|
|
2409
|
+
};
|
|
1515
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
|
+
);
|
|
1516
2424
|
console.log("Backend notified.");
|
|
1517
2425
|
} catch (err) {
|
|
1518
2426
|
if (err instanceof CliExit) throw err;
|
|
@@ -1522,73 +2430,24 @@ Run \`aomi tx\` to see available IDs.`);
|
|
|
1522
2430
|
session.close();
|
|
1523
2431
|
}
|
|
1524
2432
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
const state = readState();
|
|
1528
|
-
if (!state) {
|
|
1529
|
-
console.log("No active session");
|
|
1530
|
-
printDataFileLocation();
|
|
1531
|
-
return;
|
|
1532
|
-
}
|
|
1533
|
-
const { session } = getOrCreateSession();
|
|
1534
|
-
try {
|
|
1535
|
-
const apiState = await session.client.fetchState(state.sessionId);
|
|
1536
|
-
const messages = (_a2 = apiState.messages) != null ? _a2 : [];
|
|
1537
|
-
if (messages.length === 0) {
|
|
1538
|
-
console.log("No messages in this session.");
|
|
1539
|
-
printDataFileLocation();
|
|
1540
|
-
return;
|
|
1541
|
-
}
|
|
1542
|
-
for (const msg of messages) {
|
|
1543
|
-
let time = "";
|
|
1544
|
-
if (msg.timestamp) {
|
|
1545
|
-
const raw = msg.timestamp;
|
|
1546
|
-
const n = /^\d+$/.test(raw) ? parseInt(raw, 10) : NaN;
|
|
1547
|
-
const date = !isNaN(n) ? new Date(n < 1e12 ? n * 1e3 : n) : new Date(raw);
|
|
1548
|
-
time = isNaN(date.getTime()) ? "" : `${DIM}${date.toLocaleTimeString()}${RESET} `;
|
|
1549
|
-
}
|
|
1550
|
-
const sender = (_b = msg.sender) != null ? _b : "unknown";
|
|
1551
|
-
if (sender === "user") {
|
|
1552
|
-
console.log(`${time}${CYAN}\u{1F464} You:${RESET} ${(_c = msg.content) != null ? _c : ""}`);
|
|
1553
|
-
} else if (sender === "agent" || sender === "assistant") {
|
|
1554
|
-
if (msg.tool_result) {
|
|
1555
|
-
const [toolName, result] = msg.tool_result;
|
|
1556
|
-
console.log(
|
|
1557
|
-
`${time}${GREEN}\u{1F527} [${toolName}]${RESET} ${result.slice(0, 200)}${result.length > 200 ? "\u2026" : ""}`
|
|
1558
|
-
);
|
|
1559
|
-
}
|
|
1560
|
-
if (msg.content) {
|
|
1561
|
-
console.log(`${time}${CYAN}\u{1F916} Agent:${RESET} ${msg.content}`);
|
|
1562
|
-
}
|
|
1563
|
-
} else if (sender === "system") {
|
|
1564
|
-
console.log(`${time}${YELLOW}\u2699\uFE0F System:${RESET} ${(_d = msg.content) != null ? _d : ""}`);
|
|
1565
|
-
} else {
|
|
1566
|
-
console.log(`${time}${DIM}[${sender}]${RESET} ${(_e = msg.content) != null ? _e : ""}`);
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
console.log(`
|
|
1570
|
-
${DIM}\u2014 ${messages.length} messages \u2014${RESET}`);
|
|
1571
|
-
printDataFileLocation();
|
|
1572
|
-
} finally {
|
|
1573
|
-
session.close();
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
function closeCommand() {
|
|
1577
|
-
const state = readState();
|
|
1578
|
-
if (state) {
|
|
1579
|
-
const { session } = getOrCreateSession();
|
|
1580
|
-
session.close();
|
|
1581
|
-
}
|
|
1582
|
-
clearState();
|
|
1583
|
-
console.log("Session closed");
|
|
1584
|
-
}
|
|
2433
|
+
|
|
2434
|
+
// src/cli/main.ts
|
|
1585
2435
|
function printUsage() {
|
|
1586
2436
|
console.log(`
|
|
1587
2437
|
aomi \u2014 CLI client for Aomi on-chain agent
|
|
1588
2438
|
|
|
1589
2439
|
Usage:
|
|
1590
2440
|
aomi chat <message> Send a message and print the response
|
|
2441
|
+
aomi chat --model <rig>
|
|
2442
|
+
Set the session model before sending the message
|
|
1591
2443
|
aomi chat --verbose Stream agent responses, tool calls, and events live
|
|
2444
|
+
aomi models List models available to the current backend
|
|
2445
|
+
aomi model set <rig> Set the active model for the current session
|
|
2446
|
+
aomi sessions List local sessions with metadata tables
|
|
2447
|
+
aomi session resume <id>
|
|
2448
|
+
Resume a local session (session-id or session-N)
|
|
2449
|
+
aomi session delete <id>
|
|
2450
|
+
Delete a local session file (session-id or session-N)
|
|
1592
2451
|
aomi log Show full conversation history with tool results
|
|
1593
2452
|
aomi tx List pending and signed transactions
|
|
1594
2453
|
aomi sign <tx-id> Sign and submit a pending transaction
|
|
@@ -1598,8 +2457,9 @@ Usage:
|
|
|
1598
2457
|
|
|
1599
2458
|
Options:
|
|
1600
2459
|
--backend-url <url> Backend URL (default: https://api.aomi.dev)
|
|
1601
|
-
--api-key <key> API key for non-default
|
|
1602
|
-
--
|
|
2460
|
+
--api-key <key> API key for non-default apps
|
|
2461
|
+
--app <name> App (default: "default")
|
|
2462
|
+
--model <rig> Set the active model for this session
|
|
1603
2463
|
--public-key <addr> Wallet address (so the agent knows your wallet)
|
|
1604
2464
|
--private-key <key> Hex private key for signing
|
|
1605
2465
|
--rpc-url <url> RPC URL for transaction submission
|
|
@@ -1608,50 +2468,86 @@ Options:
|
|
|
1608
2468
|
Environment (overridden by flags):
|
|
1609
2469
|
AOMI_BASE_URL Backend URL
|
|
1610
2470
|
AOMI_API_KEY API key
|
|
1611
|
-
|
|
2471
|
+
AOMI_APP App
|
|
2472
|
+
AOMI_MODEL Model rig
|
|
1612
2473
|
AOMI_PUBLIC_KEY Wallet address
|
|
1613
2474
|
PRIVATE_KEY Hex private key for signing
|
|
1614
2475
|
CHAIN_RPC_URL RPC URL for transaction submission
|
|
1615
2476
|
`.trim());
|
|
1616
2477
|
}
|
|
1617
|
-
async function main() {
|
|
1618
|
-
var
|
|
1619
|
-
const
|
|
1620
|
-
switch (
|
|
2478
|
+
async function main(runtime) {
|
|
2479
|
+
var _a3;
|
|
2480
|
+
const command = (_a3 = runtime.parsed.command) != null ? _a3 : runtime.parsed.flags["help"] || runtime.parsed.flags["h"] ? "help" : void 0;
|
|
2481
|
+
switch (command) {
|
|
1621
2482
|
case "chat":
|
|
1622
|
-
await chatCommand();
|
|
2483
|
+
await chatCommand(runtime);
|
|
1623
2484
|
break;
|
|
1624
2485
|
case "log":
|
|
1625
|
-
await logCommand();
|
|
2486
|
+
await logCommand(runtime);
|
|
2487
|
+
break;
|
|
2488
|
+
case "models":
|
|
2489
|
+
await modelsCommand(runtime);
|
|
2490
|
+
break;
|
|
2491
|
+
case "model":
|
|
2492
|
+
await modelCommand(runtime);
|
|
2493
|
+
break;
|
|
2494
|
+
case "sessions":
|
|
2495
|
+
await sessionsCommand(runtime);
|
|
2496
|
+
break;
|
|
2497
|
+
case "session":
|
|
2498
|
+
sessionCommand(runtime);
|
|
1626
2499
|
break;
|
|
1627
2500
|
case "tx":
|
|
1628
2501
|
txCommand();
|
|
1629
2502
|
break;
|
|
1630
2503
|
case "sign":
|
|
1631
|
-
await signCommand();
|
|
2504
|
+
await signCommand(runtime);
|
|
1632
2505
|
break;
|
|
1633
2506
|
case "status":
|
|
1634
|
-
await statusCommand();
|
|
2507
|
+
await statusCommand(runtime);
|
|
1635
2508
|
break;
|
|
1636
2509
|
case "events":
|
|
1637
|
-
await eventsCommand();
|
|
2510
|
+
await eventsCommand(runtime);
|
|
1638
2511
|
break;
|
|
1639
2512
|
case "close":
|
|
1640
|
-
closeCommand();
|
|
2513
|
+
closeCommand(runtime);
|
|
1641
2514
|
break;
|
|
1642
2515
|
case "help":
|
|
1643
2516
|
printUsage();
|
|
1644
2517
|
break;
|
|
1645
2518
|
default:
|
|
1646
2519
|
printUsage();
|
|
1647
|
-
if (
|
|
2520
|
+
if (command) {
|
|
2521
|
+
throw new CliExit(1);
|
|
2522
|
+
}
|
|
1648
2523
|
}
|
|
1649
2524
|
}
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
2525
|
+
function isPnpmExecWrapper() {
|
|
2526
|
+
var _a3, _b;
|
|
2527
|
+
const npmCommand = (_a3 = process.env.npm_command) != null ? _a3 : "";
|
|
2528
|
+
const userAgent = (_b = process.env.npm_config_user_agent) != null ? _b : "";
|
|
2529
|
+
return npmCommand === "exec" && userAgent.includes("pnpm/");
|
|
2530
|
+
}
|
|
2531
|
+
async function runCli(argv = process.argv) {
|
|
2532
|
+
const runtime = createRuntime(argv);
|
|
2533
|
+
const RED = "\x1B[31m";
|
|
2534
|
+
const RESET3 = "\x1B[0m";
|
|
2535
|
+
const strictExit = process.env.AOMI_CLI_STRICT_EXIT === "1";
|
|
2536
|
+
try {
|
|
2537
|
+
await main(runtime);
|
|
2538
|
+
} catch (err) {
|
|
2539
|
+
if (err instanceof CliExit) {
|
|
2540
|
+
if (!strictExit && isPnpmExecWrapper()) {
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
process.exit(err.code);
|
|
2544
|
+
return;
|
|
2545
|
+
}
|
|
2546
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2547
|
+
console.error(`${RED}\u274C ${message}${RESET3}`);
|
|
2548
|
+
process.exit(1);
|
|
1654
2549
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
// src/cli.ts
|
|
2553
|
+
void runCli();
|