@vultisig/cli 0.15.0 → 0.15.4
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/CHANGELOG.md +27 -0
- package/README.md +34 -6
- package/dist/index.js +382 -122
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 0.15.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#276](https://github.com/vultisig/vultisig-sdk/pull/276) [`59382c1`](https://github.com/vultisig/vultisig-sdk/commit/59382c1859512fbd362962ede5e92b100d3a5921) Thanks [@rcoderdev](https://github.com/rcoderdev)! - feat(cli): structured machine-readable errors for agent ask, pipe, and executor
|
|
8
|
+
- `agent ask --json` failures include stable `code` with existing `error` string
|
|
9
|
+
- NDJSON pipe `error` events and failed `tool_result` lines include `code`
|
|
10
|
+
- executor `ActionResult` failures carry `AgentErrorCode`; SSE errors accept optional backend `code`
|
|
11
|
+
- document error codes in CLI README
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`59382c1`](https://github.com/vultisig/vultisig-sdk/commit/59382c1859512fbd362962ede5e92b100d3a5921)]:
|
|
14
|
+
- @vultisig/sdk@0.15.4
|
|
15
|
+
- @vultisig/rujira@10.0.0
|
|
16
|
+
|
|
17
|
+
## 0.15.2
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#263](https://github.com/vultisig/vultisig-sdk/pull/263) [`6585c38`](https://github.com/vultisig/vultisig-sdk/commit/6585c38431db063f600e133d1a23f84b7c19e934) Thanks [@rcoderdev](https://github.com/rcoderdev)! - fix(cli): align agent executor with backend payloads and harden action handling
|
|
22
|
+
- model `tx_ready` / non-streaming transaction payloads with `TxReadyPayload`
|
|
23
|
+
- optional `vultisig` on agent config for shared SDK state (e.g. address book)
|
|
24
|
+
- executor improvements (chain locks, calldata resolution, EVM gas refresh) and unit tests
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [[`6585c38`](https://github.com/vultisig/vultisig-sdk/commit/6585c38431db063f600e133d1a23f84b7c19e934)]:
|
|
27
|
+
- @vultisig/sdk@0.15.2
|
|
28
|
+
- @vultisig/rujira@10.0.0
|
|
29
|
+
|
|
3
30
|
## 0.15.0
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -658,7 +658,7 @@ explorer:https://etherscan.io/tx/0x9f8e7d6c...
|
|
|
658
658
|
"session_id": "abc123-def456",
|
|
659
659
|
"response": "Your ETH balance is 1.5 ETH ($3,750.00 USD).",
|
|
660
660
|
"tool_calls": [
|
|
661
|
-
{ "action": "
|
|
661
|
+
{ "action": "get_balances", "success": true, "data": { "balances": [{ "chain": "Ethereum", "symbol": "ETH", "amount": "1.5", "decimals": 18, "raw_amount": "1500000000000000000" }] } }
|
|
662
662
|
],
|
|
663
663
|
"transactions": [
|
|
664
664
|
{ "hash": "0x9f8e7d6c...", "chain": "ethereum", "explorerUrl": "https://etherscan.io/tx/0x9f8e7d6c..." }
|
|
@@ -666,6 +666,36 @@ explorer:https://etherscan.io/tx/0x9f8e7d6c...
|
|
|
666
666
|
}
|
|
667
667
|
```
|
|
668
668
|
|
|
669
|
+
On failure, stdout is a single JSON object with both a human `error` string and a stable `code` (the `error` field is unchanged for older parsers):
|
|
670
|
+
|
|
671
|
+
```json
|
|
672
|
+
{ "error": "Agent backend unreachable at https://example.invalid", "code": "BACKEND_UNREACHABLE" }
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Each entry in `tool_calls` may include `code` when `success` is false (same values as below).
|
|
676
|
+
|
|
677
|
+
##### Error codes (`agent ask --json`, `--via-agent`, executor)
|
|
678
|
+
|
|
679
|
+
Orchestrators should branch on `code`. The message in `error` / `message` stays human-readable and may change between releases.
|
|
680
|
+
|
|
681
|
+
| Code | Typical meaning |
|
|
682
|
+
|------|-----------------|
|
|
683
|
+
| `BACKEND_UNREACHABLE` | Agent health check failed or backend not responding |
|
|
684
|
+
| `AUTH_FAILED` | Auth/token failure, HTTP 401/403, or wrong vault password |
|
|
685
|
+
| `VAULT_LOCKED` | Encrypted vault needs unlock (password) |
|
|
686
|
+
| `PASSWORD_REQUIRED` | Password was not supplied when required (e.g. pipe mode or signing) |
|
|
687
|
+
| `CONFIRMATION_REQUIRED` | User confirmation needed (pipe mode; message prefix `CONFIRMATION_REQUIRED:`) |
|
|
688
|
+
| `ACTION_NOT_IMPLEMENTED` | Local executor does not implement this action type |
|
|
689
|
+
| `INVALID_INPUT` | Bad parameters, unknown chain, malformed NDJSON input, etc. |
|
|
690
|
+
| `NETWORK_ERROR` | RPC/fetch connectivity (includes many SDK `VaultError` network cases) |
|
|
691
|
+
| `TIMEOUT` | Deadline exceeded, or abort where the message indicates a timeout |
|
|
692
|
+
| `TRANSACTION_FAILED` | Build/broadcast/gas errors mapped from the SDK |
|
|
693
|
+
| `SIGNING_FAILED` | MPC/signing failed |
|
|
694
|
+
| `SESSION_NOT_INITIALIZED` | Internal session state error |
|
|
695
|
+
| `UNKNOWN_ERROR` | Unclassified failure (default for opaque SSE `error` events). Plain `AbortError` without “timeout” in the message maps here. |
|
|
696
|
+
|
|
697
|
+
SSE `error` events may optionally include a `code` field from the backend; if it matches one of the values above, it is passed through unchanged. Otherwise the CLI infers a code from the message.
|
|
698
|
+
|
|
669
699
|
**Agent ask options:**
|
|
670
700
|
- `--session <id>` - Continue an existing conversation
|
|
671
701
|
- `--backend-url <url>` - Agent backend URL (default: https://abe.vultisig.com)
|
|
@@ -712,15 +742,13 @@ The pipe interface uses NDJSON (one JSON object per line) on stdin/stdout. Desig
|
|
|
712
742
|
| `ready` | `vault, addresses` | Session initialized, addresses for all chains |
|
|
713
743
|
| `session` | `id` | Conversation ID for resuming later |
|
|
714
744
|
| `history` | `messages[]` | Previous messages when resuming a session |
|
|
715
|
-
| `auth` | `status, error?` | Authentication result (`authenticated` or `failed`) |
|
|
716
|
-
| `conversation` | `id` | Conversation created or resumed |
|
|
717
745
|
| `text_delta` | `delta` | Streaming text chunk from the agent |
|
|
718
746
|
| `tool_call` | `id, action, params?, status` | Action started (`running`) |
|
|
719
|
-
| `tool_result` | `id, action, success, data?, error?` | Action completed |
|
|
747
|
+
| `tool_result` | `id, action, success, data?, error?, code?` | Action completed (`code` when `success` is false) |
|
|
720
748
|
| `tx_status` | `tx_hash, chain, status, explorer_url?` | Transaction broadcast/confirmed/failed |
|
|
721
749
|
| `assistant` | `content` | Full assistant response |
|
|
722
750
|
| `suggestions` | `suggestions[]` | Suggested follow-up actions |
|
|
723
|
-
| `error` | `message` | Error (
|
|
751
|
+
| `error` | `message, code` | Error or control signal (`PASSWORD_REQUIRED`, `CONFIRMATION_REQUIRED: …`; always includes stable `code`) |
|
|
724
752
|
| `done` | `{}` | Response cycle complete |
|
|
725
753
|
|
|
726
754
|
**Example session:**
|
|
@@ -740,7 +768,7 @@ echo '{"type":"message","content":"What is my ETH balance?"}' | vultisig agent -
|
|
|
740
768
|
{"type":"done"}
|
|
741
769
|
```
|
|
742
770
|
|
|
743
|
-
When the agent needs a password mid-session (e.g. for signing), it emits `{"type":"error","message":"PASSWORD_REQUIRED"}`. Respond with `{"type":"password","password":"..."}` on stdin.
|
|
771
|
+
When the agent needs a password mid-session (e.g. for signing), it emits `{"type":"error","message":"PASSWORD_REQUIRED","code":"PASSWORD_REQUIRED"}`. Respond with `{"type":"password","password":"..."}` on stdin.
|
|
744
772
|
|
|
745
773
|
#### Session Management
|
|
746
774
|
|
package/dist/index.js
CHANGED
|
@@ -1452,7 +1452,7 @@ var init_formatUnits = __esm({
|
|
|
1452
1452
|
// src/index.ts
|
|
1453
1453
|
import "dotenv/config";
|
|
1454
1454
|
import { promises as fs4 } from "node:fs";
|
|
1455
|
-
import { parseKeygenQR, Vultisig as
|
|
1455
|
+
import { parseKeygenQR, Vultisig as Vultisig6 } from "@vultisig/sdk";
|
|
1456
1456
|
import chalk15 from "chalk";
|
|
1457
1457
|
import { program } from "commander";
|
|
1458
1458
|
import inquirer8 from "inquirer";
|
|
@@ -3934,7 +3934,12 @@ Address Book${options.chain ? ` (${options.chain})` : ""}:
|
|
|
3934
3934
|
}
|
|
3935
3935
|
|
|
3936
3936
|
// src/commands/rujira.ts
|
|
3937
|
-
import {
|
|
3937
|
+
import {
|
|
3938
|
+
getRoutesSummary,
|
|
3939
|
+
listEasyRoutes,
|
|
3940
|
+
RujiraClient,
|
|
3941
|
+
VultisigRujiraProvider
|
|
3942
|
+
} from "@vultisig/rujira";
|
|
3938
3943
|
async function createRujiraClient(ctx2, options = {}) {
|
|
3939
3944
|
const vault = await ctx2.ensureActiveVault();
|
|
3940
3945
|
const provider = new VultisigRujiraProvider(vault);
|
|
@@ -4221,6 +4226,122 @@ function displayDiscountTier(tierInfo) {
|
|
|
4221
4226
|
import chalk9 from "chalk";
|
|
4222
4227
|
import Table from "cli-table3";
|
|
4223
4228
|
|
|
4229
|
+
// src/agent/agentErrors.ts
|
|
4230
|
+
import { VaultError, VaultErrorCode, VaultImportError, VaultImportErrorCode } from "@vultisig/sdk";
|
|
4231
|
+
var AgentErrorCode = /* @__PURE__ */ ((AgentErrorCode3) => {
|
|
4232
|
+
AgentErrorCode3["BACKEND_UNREACHABLE"] = "BACKEND_UNREACHABLE";
|
|
4233
|
+
AgentErrorCode3["AUTH_FAILED"] = "AUTH_FAILED";
|
|
4234
|
+
AgentErrorCode3["VAULT_LOCKED"] = "VAULT_LOCKED";
|
|
4235
|
+
AgentErrorCode3["PASSWORD_REQUIRED"] = "PASSWORD_REQUIRED";
|
|
4236
|
+
AgentErrorCode3["CONFIRMATION_REQUIRED"] = "CONFIRMATION_REQUIRED";
|
|
4237
|
+
AgentErrorCode3["ACTION_NOT_IMPLEMENTED"] = "ACTION_NOT_IMPLEMENTED";
|
|
4238
|
+
AgentErrorCode3["INVALID_INPUT"] = "INVALID_INPUT";
|
|
4239
|
+
AgentErrorCode3["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
4240
|
+
AgentErrorCode3["TIMEOUT"] = "TIMEOUT";
|
|
4241
|
+
AgentErrorCode3["TRANSACTION_FAILED"] = "TRANSACTION_FAILED";
|
|
4242
|
+
AgentErrorCode3["SIGNING_FAILED"] = "SIGNING_FAILED";
|
|
4243
|
+
AgentErrorCode3["SESSION_NOT_INITIALIZED"] = "SESSION_NOT_INITIALIZED";
|
|
4244
|
+
AgentErrorCode3["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
|
|
4245
|
+
return AgentErrorCode3;
|
|
4246
|
+
})(AgentErrorCode || {});
|
|
4247
|
+
var AGENT_ERROR_CODE_VALUES = new Set(Object.values(AgentErrorCode));
|
|
4248
|
+
function isAgentErrorCode(value) {
|
|
4249
|
+
return AGENT_ERROR_CODE_VALUES.has(value);
|
|
4250
|
+
}
|
|
4251
|
+
function mapVaultError(err) {
|
|
4252
|
+
if (err.code === VaultErrorCode.InvalidConfig && /failed to unlock vault/i.test(err.message)) {
|
|
4253
|
+
return "AUTH_FAILED" /* AUTH_FAILED */;
|
|
4254
|
+
}
|
|
4255
|
+
switch (err.code) {
|
|
4256
|
+
case VaultErrorCode.Timeout:
|
|
4257
|
+
return "TIMEOUT" /* TIMEOUT */;
|
|
4258
|
+
case VaultErrorCode.NetworkError:
|
|
4259
|
+
case VaultErrorCode.BalanceFetchFailed:
|
|
4260
|
+
return "NETWORK_ERROR" /* NETWORK_ERROR */;
|
|
4261
|
+
case VaultErrorCode.SigningFailed:
|
|
4262
|
+
return "SIGNING_FAILED" /* SIGNING_FAILED */;
|
|
4263
|
+
case VaultErrorCode.BroadcastFailed:
|
|
4264
|
+
case VaultErrorCode.GasEstimationFailed:
|
|
4265
|
+
return "TRANSACTION_FAILED" /* TRANSACTION_FAILED */;
|
|
4266
|
+
case VaultErrorCode.NotImplemented:
|
|
4267
|
+
return "ACTION_NOT_IMPLEMENTED" /* ACTION_NOT_IMPLEMENTED */;
|
|
4268
|
+
case VaultErrorCode.InvalidAmount:
|
|
4269
|
+
case VaultErrorCode.UnsupportedChain:
|
|
4270
|
+
case VaultErrorCode.UnsupportedToken:
|
|
4271
|
+
case VaultErrorCode.ChainNotSupported:
|
|
4272
|
+
case VaultErrorCode.InvalidVault:
|
|
4273
|
+
case VaultErrorCode.InvalidPublicKey:
|
|
4274
|
+
case VaultErrorCode.InvalidChainCode:
|
|
4275
|
+
case VaultErrorCode.AddressDerivationFailed:
|
|
4276
|
+
return "INVALID_INPUT" /* INVALID_INPUT */;
|
|
4277
|
+
case VaultErrorCode.InvalidConfig:
|
|
4278
|
+
return "INVALID_INPUT" /* INVALID_INPUT */;
|
|
4279
|
+
default:
|
|
4280
|
+
return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
function mapVaultImportError(err) {
|
|
4284
|
+
switch (err.code) {
|
|
4285
|
+
case VaultImportErrorCode.PASSWORD_REQUIRED:
|
|
4286
|
+
return "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */;
|
|
4287
|
+
case VaultImportErrorCode.INVALID_PASSWORD:
|
|
4288
|
+
return "AUTH_FAILED" /* AUTH_FAILED */;
|
|
4289
|
+
default:
|
|
4290
|
+
return "INVALID_INPUT" /* INVALID_INPUT */;
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
function networkishMessage(msg) {
|
|
4294
|
+
return /ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network|fetch failed|socket/i.test(msg) || /getaddrinfo|certificate|TLS|SSL/i.test(msg);
|
|
4295
|
+
}
|
|
4296
|
+
function inferAgentErrorCodeFromMessage(message) {
|
|
4297
|
+
const m = message.trim();
|
|
4298
|
+
if (!m) return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
4299
|
+
if (/agent backend unreachable/i.test(m)) return "BACKEND_UNREACHABLE" /* BACKEND_UNREACHABLE */;
|
|
4300
|
+
if (/authentication failed|^auth failed/i.test(m)) return "AUTH_FAILED" /* AUTH_FAILED */;
|
|
4301
|
+
if (m === "PASSWORD_REQUIRED") return "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */;
|
|
4302
|
+
if (/^CONFIRMATION_REQUIRED:/i.test(m)) return "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */;
|
|
4303
|
+
if (/password required|password not provided|use --password/i.test(m)) return "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */;
|
|
4304
|
+
if (/session not initialized/i.test(m)) return "SESSION_NOT_INITIALIZED" /* SESSION_NOT_INITIALIZED */;
|
|
4305
|
+
if (/not implemented locally|is not yet implemented|is not implemented locally|action type .*not implemented/i.test(m)) {
|
|
4306
|
+
return "ACTION_NOT_IMPLEMENTED" /* ACTION_NOT_IMPLEMENTED */;
|
|
4307
|
+
}
|
|
4308
|
+
if (/\(401\)|\(403\)|\b401\b|\b403\b|unauthorized|forbidden/i.test(m)) return "AUTH_FAILED" /* AUTH_FAILED */;
|
|
4309
|
+
if (/failed to unlock vault/i.test(m)) return "AUTH_FAILED" /* AUTH_FAILED */;
|
|
4310
|
+
if (/vault.*locked|must unlock|unlock.*vault/i.test(m)) return "VAULT_LOCKED" /* VAULT_LOCKED */;
|
|
4311
|
+
if (/timed out|timeout/i.test(m)) return "TIMEOUT" /* TIMEOUT */;
|
|
4312
|
+
if (networkishMessage(m)) return "NETWORK_ERROR" /* NETWORK_ERROR */;
|
|
4313
|
+
if (/unknown chain|unknown from_chain|unknown to_chain/i.test(m) || /\bis required\b|\bmissing\b|\brequires\b/i.test(m) || /no pending transaction|invalid or empty tx|could not stage calldata|server transaction missing/i.test(m) || /build_custom_tx requires|incomplete for a contract call|invalid der:/i.test(m)) {
|
|
4314
|
+
return "INVALID_INPUT" /* INVALID_INPUT */;
|
|
4315
|
+
}
|
|
4316
|
+
return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
4317
|
+
}
|
|
4318
|
+
function nodeErrCode(err) {
|
|
4319
|
+
if (err && typeof err === "object" && "code" in err && typeof err.code === "string") {
|
|
4320
|
+
return err.code;
|
|
4321
|
+
}
|
|
4322
|
+
return void 0;
|
|
4323
|
+
}
|
|
4324
|
+
function normalizeAgentError(err) {
|
|
4325
|
+
if (err instanceof VaultError) {
|
|
4326
|
+
return { code: mapVaultError(err), message: err.message };
|
|
4327
|
+
}
|
|
4328
|
+
if (err instanceof VaultImportError) {
|
|
4329
|
+
return { code: mapVaultImportError(err), message: err.message };
|
|
4330
|
+
}
|
|
4331
|
+
const name = err instanceof Error ? err.name : "";
|
|
4332
|
+
if (name === "AbortError") {
|
|
4333
|
+
const message2 = err instanceof Error ? err.message : "Aborted";
|
|
4334
|
+
const code = /timed out|timeout/i.test(message2) ? "TIMEOUT" /* TIMEOUT */ : "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
4335
|
+
return { code, message: message2 };
|
|
4336
|
+
}
|
|
4337
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4338
|
+
const nc = nodeErrCode(err);
|
|
4339
|
+
if (nc === "ECONNREFUSED" || nc === "ENOTFOUND" || nc === "ETIMEDOUT") {
|
|
4340
|
+
return { code: "NETWORK_ERROR" /* NETWORK_ERROR */, message };
|
|
4341
|
+
}
|
|
4342
|
+
return { code: inferAgentErrorCodeFromMessage(message), message };
|
|
4343
|
+
}
|
|
4344
|
+
|
|
4224
4345
|
// src/agent/ask.ts
|
|
4225
4346
|
var AskInterface = class {
|
|
4226
4347
|
session;
|
|
@@ -4247,10 +4368,10 @@ var AskInterface = class {
|
|
|
4247
4368
|
`);
|
|
4248
4369
|
}
|
|
4249
4370
|
},
|
|
4250
|
-
onToolResult: (_id, action, success2, data, error2) => {
|
|
4251
|
-
this.toolCalls.push({ action, success: success2, data, error: error2 });
|
|
4371
|
+
onToolResult: (_id, action, success2, data, error2, code) => {
|
|
4372
|
+
this.toolCalls.push({ action, success: success2, data, error: error2, code });
|
|
4252
4373
|
if (this.verbose) {
|
|
4253
|
-
const status = success2 ? "ok" : `error: ${error2}`;
|
|
4374
|
+
const status = success2 ? "ok" : `error: ${error2}${code ? ` [${code}]` : ""}`;
|
|
4254
4375
|
process.stderr.write(`[tool] ${action}: ${status}
|
|
4255
4376
|
`);
|
|
4256
4377
|
}
|
|
@@ -4269,8 +4390,8 @@ var AskInterface = class {
|
|
|
4269
4390
|
`);
|
|
4270
4391
|
}
|
|
4271
4392
|
},
|
|
4272
|
-
onError: (message) => {
|
|
4273
|
-
process.stderr.write(`[error] ${message}
|
|
4393
|
+
onError: (message, code) => {
|
|
4394
|
+
process.stderr.write(`[error] ${message} [${code}]
|
|
4274
4395
|
`);
|
|
4275
4396
|
},
|
|
4276
4397
|
onDone: () => {
|
|
@@ -4401,6 +4522,17 @@ function padTo32Bytes(buf) {
|
|
|
4401
4522
|
}
|
|
4402
4523
|
|
|
4403
4524
|
// src/agent/client.ts
|
|
4525
|
+
function sseErrorToMessage(value) {
|
|
4526
|
+
if (value == null) return "";
|
|
4527
|
+
if (typeof value === "string") return value;
|
|
4528
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
4529
|
+
if (value instanceof Error) return value.message;
|
|
4530
|
+
try {
|
|
4531
|
+
return JSON.stringify(value);
|
|
4532
|
+
} catch {
|
|
4533
|
+
return String(value);
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4404
4536
|
var AgentClient = class {
|
|
4405
4537
|
baseUrl;
|
|
4406
4538
|
authToken = null;
|
|
@@ -4455,7 +4587,9 @@ var AgentClient = class {
|
|
|
4455
4587
|
return this.post(`/agent/conversations/${conversationId}`, req);
|
|
4456
4588
|
}
|
|
4457
4589
|
async deleteConversation(conversationId, publicKey) {
|
|
4458
|
-
await this.delete(`/agent/conversations/${conversationId}`, {
|
|
4590
|
+
await this.delete(`/agent/conversations/${conversationId}`, {
|
|
4591
|
+
public_key: publicKey
|
|
4592
|
+
});
|
|
4459
4593
|
}
|
|
4460
4594
|
// ============================================================================
|
|
4461
4595
|
// Messages - JSON mode
|
|
@@ -4566,16 +4700,22 @@ var AgentClient = class {
|
|
|
4566
4700
|
case "tx_ready":
|
|
4567
4701
|
if (this.verbose) process.stderr.write(`[SSE:tx_ready] raw: ${data.slice(0, 2e3)}
|
|
4568
4702
|
`);
|
|
4569
|
-
|
|
4570
|
-
|
|
4703
|
+
{
|
|
4704
|
+
const txReady = parsed;
|
|
4705
|
+
result.transactions.push(txReady);
|
|
4706
|
+
callbacks.onTxReady?.(txReady);
|
|
4707
|
+
}
|
|
4571
4708
|
break;
|
|
4572
4709
|
case "message":
|
|
4573
4710
|
result.message = parsed.message || parsed;
|
|
4574
4711
|
callbacks.onMessage?.(result.message);
|
|
4575
4712
|
break;
|
|
4576
|
-
case "error":
|
|
4577
|
-
|
|
4713
|
+
case "error": {
|
|
4714
|
+
const msg = sseErrorToMessage(parsed.error);
|
|
4715
|
+
const codeFromBackend = typeof parsed.code === "string" && isAgentErrorCode(parsed.code) ? parsed.code : inferAgentErrorCodeFromMessage(msg);
|
|
4716
|
+
callbacks.onError?.(msg, codeFromBackend);
|
|
4578
4717
|
break;
|
|
4718
|
+
}
|
|
4579
4719
|
case "done":
|
|
4580
4720
|
break;
|
|
4581
4721
|
}
|
|
@@ -4782,7 +4922,7 @@ function getNativeTokenDecimals(chain) {
|
|
|
4782
4922
|
}
|
|
4783
4923
|
|
|
4784
4924
|
// src/agent/executor.ts
|
|
4785
|
-
import { Chain as Chain9, Vultisig as
|
|
4925
|
+
import { Chain as Chain9, evmCall, fiatCurrencies as fiatCurrencies3, Vultisig as VultisigSdk } from "@vultisig/sdk";
|
|
4786
4926
|
|
|
4787
4927
|
// node_modules/viem/_esm/index.js
|
|
4788
4928
|
init_formatUnits();
|
|
@@ -4999,6 +5139,8 @@ var EVM_GAS_RPC = {
|
|
|
4999
5139
|
};
|
|
5000
5140
|
var AgentExecutor = class {
|
|
5001
5141
|
vault;
|
|
5142
|
+
/** Owning SDK (optional); used for address book backed by app storage */
|
|
5143
|
+
vultisig;
|
|
5002
5144
|
pendingPayloads = /* @__PURE__ */ new Map();
|
|
5003
5145
|
password = null;
|
|
5004
5146
|
verbose;
|
|
@@ -5007,9 +5149,10 @@ var AgentExecutor = class {
|
|
|
5007
5149
|
chainLockReleases = /* @__PURE__ */ new Map();
|
|
5008
5150
|
/** Backend client for resolving calldata_id references. */
|
|
5009
5151
|
backendClient = null;
|
|
5010
|
-
constructor(vault, verbose = false, vaultId) {
|
|
5152
|
+
constructor(vault, verbose = false, vaultId, vultisig) {
|
|
5011
5153
|
this.vault = vault;
|
|
5012
5154
|
this.verbose = verbose;
|
|
5155
|
+
this.vultisig = vultisig;
|
|
5013
5156
|
if (vaultId) {
|
|
5014
5157
|
this.stateStore = new VaultStateStore(vaultId);
|
|
5015
5158
|
}
|
|
@@ -5023,6 +5166,8 @@ var AgentExecutor = class {
|
|
|
5023
5166
|
/**
|
|
5024
5167
|
* Store a server-built transaction (from tx_ready SSE event).
|
|
5025
5168
|
* This allows sign_tx to find and sign it when the backend requests signing.
|
|
5169
|
+
*
|
|
5170
|
+
* @returns true when a signable payload was stored; false for MCP errors or missing tx body
|
|
5026
5171
|
*/
|
|
5027
5172
|
storeServerTransaction(txReadyData) {
|
|
5028
5173
|
if (this.verbose)
|
|
@@ -5030,11 +5175,17 @@ var AgentExecutor = class {
|
|
|
5030
5175
|
`[executor] storeServerTransaction called, keys: ${Object.keys(txReadyData || {}).join(",")}
|
|
5031
5176
|
`
|
|
5032
5177
|
);
|
|
5033
|
-
const
|
|
5034
|
-
if (
|
|
5178
|
+
const nestedTx = txReadyData?.swap_tx || txReadyData?.send_tx || txReadyData?.tx;
|
|
5179
|
+
if (nestedTx?.status === "error" || nestedTx?.error) {
|
|
5180
|
+
if (this.verbose)
|
|
5181
|
+
process.stderr.write(`[executor] skipping error tx_ready: ${nestedTx.error || "unknown error"}
|
|
5182
|
+
`);
|
|
5183
|
+
return false;
|
|
5184
|
+
}
|
|
5185
|
+
if (!nestedTx) {
|
|
5035
5186
|
if (this.verbose) process.stderr.write(`[executor] storeServerTransaction: no swap_tx/send_tx/tx found in data
|
|
5036
5187
|
`);
|
|
5037
|
-
return;
|
|
5188
|
+
return false;
|
|
5038
5189
|
}
|
|
5039
5190
|
const chain = resolveChainFromTxReady(txReadyData) || Chain9.Ethereum;
|
|
5040
5191
|
this.pendingPayloads.clear();
|
|
@@ -5049,6 +5200,7 @@ var AgentExecutor = class {
|
|
|
5049
5200
|
`[executor] Stored server tx for chain ${chain}, pendingPayloads size=${this.pendingPayloads.size}
|
|
5050
5201
|
`
|
|
5051
5202
|
);
|
|
5203
|
+
return true;
|
|
5052
5204
|
}
|
|
5053
5205
|
hasPendingTransaction() {
|
|
5054
5206
|
return this.pendingPayloads.has("latest");
|
|
@@ -5072,11 +5224,13 @@ var AgentExecutor = class {
|
|
|
5072
5224
|
data
|
|
5073
5225
|
};
|
|
5074
5226
|
} catch (err) {
|
|
5227
|
+
const { code, message } = normalizeAgentError(err);
|
|
5075
5228
|
return {
|
|
5076
5229
|
action: action.type,
|
|
5077
5230
|
action_id: action.id,
|
|
5078
5231
|
success: false,
|
|
5079
|
-
error:
|
|
5232
|
+
error: message,
|
|
5233
|
+
code
|
|
5080
5234
|
};
|
|
5081
5235
|
}
|
|
5082
5236
|
}
|
|
@@ -5107,7 +5261,7 @@ var AgentExecutor = class {
|
|
|
5107
5261
|
case "sign_tx":
|
|
5108
5262
|
return this.signTx(params);
|
|
5109
5263
|
case "get_address_book":
|
|
5110
|
-
return this.getAddressBook();
|
|
5264
|
+
return this.getAddressBook(params);
|
|
5111
5265
|
case "address_book_add":
|
|
5112
5266
|
return this.addAddressBookEntry(params);
|
|
5113
5267
|
case "address_book_remove":
|
|
@@ -5153,15 +5307,34 @@ var AgentExecutor = class {
|
|
|
5153
5307
|
}
|
|
5154
5308
|
return { balances: entries };
|
|
5155
5309
|
}
|
|
5156
|
-
async getPortfolio(
|
|
5157
|
-
const
|
|
5158
|
-
const
|
|
5159
|
-
|
|
5310
|
+
async getPortfolio(params) {
|
|
5311
|
+
const currencyRaw = String(params.currency ?? "USD").trim().toLowerCase();
|
|
5312
|
+
const fiatCurrency = fiatCurrencies3.includes(currencyRaw) ? currencyRaw : "usd";
|
|
5313
|
+
const portfolio = await this.vault.portfolio(fiatCurrency);
|
|
5314
|
+
const chainFilter = params.chain;
|
|
5315
|
+
const tickerFilter = params.ticker;
|
|
5316
|
+
let rows = portfolio.balances.map((b) => ({
|
|
5317
|
+
chain: b.chainId || "",
|
|
5160
5318
|
symbol: b.symbol || "",
|
|
5161
5319
|
amount: b.formattedAmount || b.amount?.toString() || "0",
|
|
5162
|
-
decimals: b.decimals
|
|
5320
|
+
decimals: b.decimals ?? 18,
|
|
5321
|
+
raw_amount: b.amount,
|
|
5322
|
+
fiatValue: b.fiatValue,
|
|
5323
|
+
fiatCurrency: b.fiatCurrency ?? portfolio.currency
|
|
5163
5324
|
}));
|
|
5164
|
-
|
|
5325
|
+
if (chainFilter) {
|
|
5326
|
+
const chain = resolveChain(chainFilter);
|
|
5327
|
+
if (!chain) throw new Error(`Unknown chain: ${chainFilter}`);
|
|
5328
|
+
rows = rows.filter((r) => r.chain.toLowerCase() === chain.toLowerCase());
|
|
5329
|
+
}
|
|
5330
|
+
if (tickerFilter) {
|
|
5331
|
+
rows = rows.filter((r) => r.symbol.toLowerCase() === String(tickerFilter).toLowerCase());
|
|
5332
|
+
}
|
|
5333
|
+
return {
|
|
5334
|
+
balances: rows,
|
|
5335
|
+
totalValue: portfolio.totalValue,
|
|
5336
|
+
currency: portfolio.currency
|
|
5337
|
+
};
|
|
5165
5338
|
}
|
|
5166
5339
|
// ============================================================================
|
|
5167
5340
|
// Chain & Token Management
|
|
@@ -5261,13 +5434,28 @@ var AgentExecutor = class {
|
|
|
5261
5434
|
};
|
|
5262
5435
|
const amount = parseAmount(amountStr, balance.decimals);
|
|
5263
5436
|
const memo = params.memo;
|
|
5264
|
-
const payload = await this.vault.prepareSendTx({
|
|
5437
|
+
const payload = await this.vault.prepareSendTx({
|
|
5438
|
+
coin,
|
|
5439
|
+
receiver: toAddress,
|
|
5440
|
+
amount,
|
|
5441
|
+
memo
|
|
5442
|
+
});
|
|
5265
5443
|
await this.patchEvmNonce(chain, payload);
|
|
5266
5444
|
const messageHashes = await this.vault.extractMessageHashes(payload);
|
|
5267
5445
|
this.pendingPayloads.clear();
|
|
5268
5446
|
const payloadId = `tx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
5269
|
-
this.pendingPayloads.set(payloadId, {
|
|
5270
|
-
|
|
5447
|
+
this.pendingPayloads.set(payloadId, {
|
|
5448
|
+
payload,
|
|
5449
|
+
coin,
|
|
5450
|
+
chain,
|
|
5451
|
+
timestamp: Date.now()
|
|
5452
|
+
});
|
|
5453
|
+
this.pendingPayloads.set("latest", {
|
|
5454
|
+
payload,
|
|
5455
|
+
coin,
|
|
5456
|
+
chain,
|
|
5457
|
+
timestamp: Date.now()
|
|
5458
|
+
});
|
|
5271
5459
|
return {
|
|
5272
5460
|
keysign_payload: payloadId,
|
|
5273
5461
|
from_chain: chain.toString(),
|
|
@@ -5307,7 +5495,10 @@ var AgentExecutor = class {
|
|
|
5307
5495
|
const fromToken = params.from_contract || params.from_token_id;
|
|
5308
5496
|
const toToken = params.to_contract || params.to_token_id;
|
|
5309
5497
|
const fromCoin = { chain: fromChain, token: fromToken || void 0 };
|
|
5310
|
-
const toCoin = {
|
|
5498
|
+
const toCoin = {
|
|
5499
|
+
chain: toChain || fromChain,
|
|
5500
|
+
token: toToken || void 0
|
|
5501
|
+
};
|
|
5311
5502
|
const quote = await this.vault.getSwapQuote({
|
|
5312
5503
|
fromCoin,
|
|
5313
5504
|
toCoin,
|
|
@@ -5377,11 +5568,14 @@ var AgentExecutor = class {
|
|
|
5377
5568
|
chain: params.chain,
|
|
5378
5569
|
chain_id: params.chain_id
|
|
5379
5570
|
};
|
|
5380
|
-
this.storeServerTransaction({
|
|
5571
|
+
const stored = this.storeServerTransaction({
|
|
5381
5572
|
tx: txData,
|
|
5382
5573
|
chain: params.chain,
|
|
5383
5574
|
from_chain: params.chain
|
|
5384
5575
|
});
|
|
5576
|
+
if (!stored) {
|
|
5577
|
+
throw new Error("Could not stage calldata transaction for signing (invalid or empty tx payload)");
|
|
5578
|
+
}
|
|
5385
5579
|
const chain = resolveChain(params.chain) || Chain9.Ethereum;
|
|
5386
5580
|
const address = await this.vault.address(chain);
|
|
5387
5581
|
return {
|
|
@@ -5454,9 +5648,10 @@ var AgentExecutor = class {
|
|
|
5454
5648
|
}
|
|
5455
5649
|
const { payload, chain } = stored;
|
|
5456
5650
|
if (payload.__serverTx) {
|
|
5651
|
+
let result;
|
|
5457
5652
|
if (chain === "Solana" && (payload.swap_tx || payload.provider)) {
|
|
5458
5653
|
try {
|
|
5459
|
-
|
|
5654
|
+
result = await this.buildAndSignSolanaSwapLocally(payload);
|
|
5460
5655
|
} catch (e) {
|
|
5461
5656
|
if (e._phase === "prepare") {
|
|
5462
5657
|
if (this.verbose)
|
|
@@ -5467,7 +5662,9 @@ var AgentExecutor = class {
|
|
|
5467
5662
|
}
|
|
5468
5663
|
}
|
|
5469
5664
|
}
|
|
5470
|
-
|
|
5665
|
+
if (!result) result = await this.signServerTx(payload, chain, params);
|
|
5666
|
+
if (payload.sequence_id) result.sequence_id = payload.sequence_id;
|
|
5667
|
+
return result;
|
|
5471
5668
|
}
|
|
5472
5669
|
return this.signSdkTx(payload, chain, payloadId);
|
|
5473
5670
|
}
|
|
@@ -5503,7 +5700,7 @@ var AgentExecutor = class {
|
|
|
5503
5700
|
}
|
|
5504
5701
|
await this.releaseEvmLock(chain);
|
|
5505
5702
|
this.pendingPayloads.clear();
|
|
5506
|
-
const explorerUrl =
|
|
5703
|
+
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, txHash);
|
|
5507
5704
|
return {
|
|
5508
5705
|
tx_hash: txHash,
|
|
5509
5706
|
chain: chain.toString(),
|
|
@@ -5600,7 +5797,7 @@ var AgentExecutor = class {
|
|
|
5600
5797
|
}
|
|
5601
5798
|
await this.releaseEvmLock(chain);
|
|
5602
5799
|
this.pendingPayloads.clear();
|
|
5603
|
-
const explorerUrl =
|
|
5800
|
+
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, txHash);
|
|
5604
5801
|
return {
|
|
5605
5802
|
tx_hash: txHash,
|
|
5606
5803
|
chain: chain.toString(),
|
|
@@ -5625,9 +5822,15 @@ var AgentExecutor = class {
|
|
|
5625
5822
|
const fromChainName = serverTxData.from_chain || serverTxData.chain || "Solana";
|
|
5626
5823
|
const toChainName = serverTxData.to_chain;
|
|
5627
5824
|
const fromChain = resolveChain(fromChainName);
|
|
5628
|
-
if (!fromChain)
|
|
5825
|
+
if (!fromChain)
|
|
5826
|
+
throw Object.assign(new Error(`Unknown from_chain: ${fromChainName}`), {
|
|
5827
|
+
_phase: "prepare"
|
|
5828
|
+
});
|
|
5629
5829
|
const toChain = toChainName ? resolveChain(toChainName) : fromChain;
|
|
5630
|
-
if (!toChain)
|
|
5830
|
+
if (!toChain)
|
|
5831
|
+
throw Object.assign(new Error(`Unknown to_chain: ${toChainName}`), {
|
|
5832
|
+
_phase: "prepare"
|
|
5833
|
+
});
|
|
5631
5834
|
const amountStr = serverTxData.amount;
|
|
5632
5835
|
if (!amountStr)
|
|
5633
5836
|
throw Object.assign(new Error("Missing amount in tx_ready data for local Solana swap build"), {
|
|
@@ -5694,7 +5897,7 @@ var AgentExecutor = class {
|
|
|
5694
5897
|
signature
|
|
5695
5898
|
});
|
|
5696
5899
|
this.pendingPayloads.clear();
|
|
5697
|
-
const explorerUrl =
|
|
5900
|
+
const explorerUrl = VultisigSdk.getTxExplorerUrl(chain, txHash);
|
|
5698
5901
|
return {
|
|
5699
5902
|
tx_hash: txHash,
|
|
5700
5903
|
chain: chain.toString(),
|
|
@@ -5942,8 +6145,18 @@ var AgentExecutor = class {
|
|
|
5942
6145
|
// ============================================================================
|
|
5943
6146
|
// Address Book
|
|
5944
6147
|
// ============================================================================
|
|
5945
|
-
async getAddressBook() {
|
|
5946
|
-
|
|
6148
|
+
async getAddressBook(params) {
|
|
6149
|
+
if (!this.vultisig) {
|
|
6150
|
+
throw new Error(
|
|
6151
|
+
"get_address_book requires the CLI SDK instance. Ensure AgentConfig.vultisig is set when creating the session."
|
|
6152
|
+
);
|
|
6153
|
+
}
|
|
6154
|
+
const chainName = params.chain || params.chain_name;
|
|
6155
|
+
const chain = chainName ? resolveChain(chainName) : void 0;
|
|
6156
|
+
if (chainName && !chain) {
|
|
6157
|
+
throw new Error(`Unknown chain: ${chainName}`);
|
|
6158
|
+
}
|
|
6159
|
+
return await this.vultisig.getAddressBook(chain);
|
|
5947
6160
|
}
|
|
5948
6161
|
async addAddressBookEntry(_params) {
|
|
5949
6162
|
throw new Error("address_book_add is not yet implemented locally. The backend may handle this action server-side.");
|
|
@@ -5956,8 +6169,34 @@ var AgentExecutor = class {
|
|
|
5956
6169
|
// ============================================================================
|
|
5957
6170
|
// Token Search & Other
|
|
5958
6171
|
// ============================================================================
|
|
5959
|
-
async searchToken(
|
|
5960
|
-
|
|
6172
|
+
async searchToken(params) {
|
|
6173
|
+
const query = String(params.query ?? params.q ?? "").trim().toLowerCase();
|
|
6174
|
+
if (!query) {
|
|
6175
|
+
return { tokens: [] };
|
|
6176
|
+
}
|
|
6177
|
+
const limit = 20;
|
|
6178
|
+
const chainName = params.chain;
|
|
6179
|
+
const tokenMatchesQuery = (t) => {
|
|
6180
|
+
const tick = t.ticker.toLowerCase();
|
|
6181
|
+
const addr = (t.contractAddress ?? "").toLowerCase();
|
|
6182
|
+
const pid = (t.priceProviderId ?? "").toLowerCase();
|
|
6183
|
+
return tick.includes(query) || addr.includes(query) || pid.includes(query);
|
|
6184
|
+
};
|
|
6185
|
+
if (chainName) {
|
|
6186
|
+
const chain = resolveChain(chainName);
|
|
6187
|
+
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6188
|
+
const tokens = VultisigSdk.getKnownTokens(chain).filter(tokenMatchesQuery).slice(0, limit);
|
|
6189
|
+
return { tokens };
|
|
6190
|
+
}
|
|
6191
|
+
const out = [];
|
|
6192
|
+
for (const c of Object.values(Chain9)) {
|
|
6193
|
+
for (const t of VultisigSdk.getKnownTokens(c)) {
|
|
6194
|
+
if (!tokenMatchesQuery(t)) continue;
|
|
6195
|
+
out.push(t);
|
|
6196
|
+
if (out.length >= limit) return { tokens: out };
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
6199
|
+
return { tokens: out };
|
|
5961
6200
|
}
|
|
5962
6201
|
async listVaults() {
|
|
5963
6202
|
return {
|
|
@@ -5974,8 +6213,25 @@ var AgentExecutor = class {
|
|
|
5974
6213
|
async scanTx(_params) {
|
|
5975
6214
|
throw new Error("scan_tx is not yet implemented locally. The backend may handle this action server-side.");
|
|
5976
6215
|
}
|
|
5977
|
-
async readEvmContract(
|
|
5978
|
-
|
|
6216
|
+
async readEvmContract(params) {
|
|
6217
|
+
const chainName = params.chain;
|
|
6218
|
+
if (!chainName) throw new Error("read_evm_contract requires chain");
|
|
6219
|
+
const contractRaw = params.contract_address || params.contractAddress;
|
|
6220
|
+
if (!contractRaw) throw new Error("read_evm_contract requires contract_address");
|
|
6221
|
+
const functionName = params.function_name || params.functionName;
|
|
6222
|
+
if (!functionName) throw new Error("read_evm_contract requires function_name");
|
|
6223
|
+
const chain = resolveChain(chainName);
|
|
6224
|
+
if (!chain) throw new Error(`Unknown chain: ${chainName}`);
|
|
6225
|
+
if (!EVM_CHAINS.has(chain)) {
|
|
6226
|
+
throw new Error(`read_evm_contract only supports EVM chains (got ${chain})`);
|
|
6227
|
+
}
|
|
6228
|
+
const callParams = params.params ?? [];
|
|
6229
|
+
const data = await encodeContractCall(functionName, callParams);
|
|
6230
|
+
const addr = contractRaw.startsWith("0x") ? contractRaw : `0x${contractRaw}`;
|
|
6231
|
+
const to = addr;
|
|
6232
|
+
const from = params.from;
|
|
6233
|
+
const result = await evmCall(chain, { to, data, from });
|
|
6234
|
+
return { result };
|
|
5979
6235
|
}
|
|
5980
6236
|
};
|
|
5981
6237
|
async function encodeContractCall(functionName, params) {
|
|
@@ -6249,7 +6505,10 @@ function parseDERSignature(sigHex) {
|
|
|
6249
6505
|
}
|
|
6250
6506
|
let offset = 0;
|
|
6251
6507
|
if (raw.slice(offset, offset + 2) !== "30") {
|
|
6252
|
-
return {
|
|
6508
|
+
return {
|
|
6509
|
+
r: raw.slice(0, 64).padStart(64, "0"),
|
|
6510
|
+
s: raw.slice(64).padStart(64, "0")
|
|
6511
|
+
};
|
|
6253
6512
|
}
|
|
6254
6513
|
offset += 2;
|
|
6255
6514
|
offset += 2;
|
|
@@ -6324,7 +6583,12 @@ var PipeInterface = class {
|
|
|
6324
6583
|
const cmd = JSON.parse(nextLine);
|
|
6325
6584
|
await this.handleCommand(cmd);
|
|
6326
6585
|
} catch (err) {
|
|
6327
|
-
|
|
6586
|
+
const { message, code } = normalizeAgentError(err);
|
|
6587
|
+
this.emit({
|
|
6588
|
+
type: "error",
|
|
6589
|
+
message: `Invalid input: ${message}`,
|
|
6590
|
+
code: code === "UNKNOWN_ERROR" /* UNKNOWN_ERROR */ ? "INVALID_INPUT" /* INVALID_INPUT */ : code
|
|
6591
|
+
});
|
|
6328
6592
|
}
|
|
6329
6593
|
}
|
|
6330
6594
|
processing = false;
|
|
@@ -6365,8 +6629,16 @@ var PipeInterface = class {
|
|
|
6365
6629
|
onToolCall: (id, action, params) => {
|
|
6366
6630
|
this.emit({ type: "tool_call", id, action, params, status: "running" });
|
|
6367
6631
|
},
|
|
6368
|
-
onToolResult: (id, action, success2, data, error2) => {
|
|
6369
|
-
this.emit({
|
|
6632
|
+
onToolResult: (id, action, success2, data, error2, code) => {
|
|
6633
|
+
this.emit({
|
|
6634
|
+
type: "tool_result",
|
|
6635
|
+
id,
|
|
6636
|
+
action,
|
|
6637
|
+
success: success2,
|
|
6638
|
+
data,
|
|
6639
|
+
error: error2,
|
|
6640
|
+
...!success2 && code ? { code } : {}
|
|
6641
|
+
});
|
|
6370
6642
|
},
|
|
6371
6643
|
onAssistantMessage: (content) => {
|
|
6372
6644
|
this.emit({ type: "assistant", content });
|
|
@@ -6383,8 +6655,8 @@ var PipeInterface = class {
|
|
|
6383
6655
|
explorer_url: explorerUrl
|
|
6384
6656
|
});
|
|
6385
6657
|
},
|
|
6386
|
-
onError: (message) => {
|
|
6387
|
-
this.emit({ type: "error", message });
|
|
6658
|
+
onError: (message, code) => {
|
|
6659
|
+
this.emit({ type: "error", message, code });
|
|
6388
6660
|
},
|
|
6389
6661
|
onDone: () => {
|
|
6390
6662
|
this.emit({ type: "done" });
|
|
@@ -6392,13 +6664,17 @@ var PipeInterface = class {
|
|
|
6392
6664
|
requestPassword: async () => {
|
|
6393
6665
|
return new Promise((resolve) => {
|
|
6394
6666
|
this.pendingPasswordResolve = resolve;
|
|
6395
|
-
this.emit({ type: "error", message: "PASSWORD_REQUIRED" });
|
|
6667
|
+
this.emit({ type: "error", message: "PASSWORD_REQUIRED", code: "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */ });
|
|
6396
6668
|
});
|
|
6397
6669
|
},
|
|
6398
6670
|
requestConfirmation: async (message) => {
|
|
6399
6671
|
return new Promise((resolve) => {
|
|
6400
6672
|
this.pendingConfirmResolve = resolve;
|
|
6401
|
-
this.emit({
|
|
6673
|
+
this.emit({
|
|
6674
|
+
type: "error",
|
|
6675
|
+
message: `CONFIRMATION_REQUIRED: ${message}`,
|
|
6676
|
+
code: "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */
|
|
6677
|
+
});
|
|
6402
6678
|
});
|
|
6403
6679
|
}
|
|
6404
6680
|
};
|
|
@@ -6410,7 +6686,8 @@ var PipeInterface = class {
|
|
|
6410
6686
|
try {
|
|
6411
6687
|
await this.session.sendMessage(cmd.content, callbacks);
|
|
6412
6688
|
} catch (err) {
|
|
6413
|
-
|
|
6689
|
+
const { message, code } = normalizeAgentError(err);
|
|
6690
|
+
this.emit({ type: "error", message, code });
|
|
6414
6691
|
this.emit({ type: "done" });
|
|
6415
6692
|
}
|
|
6416
6693
|
break;
|
|
@@ -6430,7 +6707,11 @@ var PipeInterface = class {
|
|
|
6430
6707
|
break;
|
|
6431
6708
|
}
|
|
6432
6709
|
default:
|
|
6433
|
-
this.emit({
|
|
6710
|
+
this.emit({
|
|
6711
|
+
type: "error",
|
|
6712
|
+
message: `Unknown command type: ${cmd.type}`,
|
|
6713
|
+
code: "INVALID_INPUT" /* INVALID_INPUT */
|
|
6714
|
+
});
|
|
6434
6715
|
}
|
|
6435
6716
|
}
|
|
6436
6717
|
emit(event) {
|
|
@@ -6459,7 +6740,7 @@ var AgentSession = class {
|
|
|
6459
6740
|
this.config = config;
|
|
6460
6741
|
this.client = new AgentClient(config.backendUrl);
|
|
6461
6742
|
this.client.verbose = !!config.verbose;
|
|
6462
|
-
this.executor = new AgentExecutor(vault, !!config.verbose, vault.publicKeys.ecdsa);
|
|
6743
|
+
this.executor = new AgentExecutor(vault, !!config.verbose, vault.publicKeys.ecdsa, config.vultisig);
|
|
6463
6744
|
this.publicKey = vault.publicKeys.ecdsa;
|
|
6464
6745
|
if (config.password) {
|
|
6465
6746
|
this.executor.setPassword(config.password);
|
|
@@ -6613,9 +6894,11 @@ var AgentSession = class {
|
|
|
6613
6894
|
action_id: result.action_id,
|
|
6614
6895
|
success: result.success,
|
|
6615
6896
|
data: result.data || {},
|
|
6616
|
-
error: result.error || ""
|
|
6897
|
+
error: result.error || "",
|
|
6898
|
+
...!result.success && result.code ? { code: result.code } : {}
|
|
6617
6899
|
};
|
|
6618
6900
|
}
|
|
6901
|
+
let serverTxStoredFromStream = 0;
|
|
6619
6902
|
const streamResult = await this.client.sendMessageStream(
|
|
6620
6903
|
this.conversationId,
|
|
6621
6904
|
request,
|
|
@@ -6636,36 +6919,25 @@ var AgentSession = class {
|
|
|
6636
6919
|
ui.onSuggestions(suggestions);
|
|
6637
6920
|
},
|
|
6638
6921
|
onTxReady: (tx) => {
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
if (this.config.
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
return;
|
|
6645
|
-
}
|
|
6646
|
-
this.executor.storeServerTransaction(tx);
|
|
6647
|
-
if (this.config.password) {
|
|
6648
|
-
this.executor.setPassword(this.config.password);
|
|
6922
|
+
if (this.executor.storeServerTransaction(tx)) {
|
|
6923
|
+
serverTxStoredFromStream++;
|
|
6924
|
+
if (this.config.password) {
|
|
6925
|
+
this.executor.setPassword(this.config.password);
|
|
6926
|
+
}
|
|
6649
6927
|
}
|
|
6650
6928
|
},
|
|
6651
6929
|
onMessage: (_msg) => {
|
|
6652
6930
|
},
|
|
6653
|
-
onError: (error2) => {
|
|
6654
|
-
ui.onError(error2);
|
|
6931
|
+
onError: (error2, code) => {
|
|
6932
|
+
ui.onError(error2, code);
|
|
6655
6933
|
}
|
|
6656
6934
|
},
|
|
6657
6935
|
this.abortController?.signal
|
|
6658
6936
|
);
|
|
6659
6937
|
const responseText = streamResult.message?.content || streamResult.fullText || "";
|
|
6660
|
-
const
|
|
6661
|
-
if (
|
|
6662
|
-
|
|
6663
|
-
if (cleanText) {
|
|
6664
|
-
ui.onAssistantMessage(cleanText);
|
|
6665
|
-
}
|
|
6666
|
-
streamResult.actions.push(...inlineActions);
|
|
6667
|
-
} else if (responseText) {
|
|
6668
|
-
ui.onAssistantMessage(responseText);
|
|
6938
|
+
const displayText = stripLeakedToolCallTags(responseText);
|
|
6939
|
+
if (displayText) {
|
|
6940
|
+
ui.onAssistantMessage(displayText);
|
|
6669
6941
|
}
|
|
6670
6942
|
const actions = streamResult.actions.filter((a) => a.type !== "sign_tx");
|
|
6671
6943
|
if (actions.length > 0) {
|
|
@@ -6696,10 +6968,12 @@ var AgentSession = class {
|
|
|
6696
6968
|
return;
|
|
6697
6969
|
}
|
|
6698
6970
|
}
|
|
6699
|
-
if (
|
|
6971
|
+
if (serverTxStoredFromStream > 0) {
|
|
6700
6972
|
if (this.config.verbose)
|
|
6701
|
-
process.stderr.write(
|
|
6702
|
-
`
|
|
6973
|
+
process.stderr.write(
|
|
6974
|
+
`[session] ${serverTxStoredFromStream} stored server tx from tx_ready, signing client-side
|
|
6975
|
+
`
|
|
6976
|
+
);
|
|
6703
6977
|
const signAction = {
|
|
6704
6978
|
id: `tx_sign_${Date.now()}`,
|
|
6705
6979
|
type: "sign_tx",
|
|
@@ -6737,7 +7011,8 @@ var AgentSession = class {
|
|
|
6737
7011
|
action: action.type,
|
|
6738
7012
|
action_id: action.id,
|
|
6739
7013
|
success: false,
|
|
6740
|
-
error: "Password not provided"
|
|
7014
|
+
error: "Password not provided",
|
|
7015
|
+
code: "PASSWORD_REQUIRED" /* PASSWORD_REQUIRED */
|
|
6741
7016
|
});
|
|
6742
7017
|
continue;
|
|
6743
7018
|
}
|
|
@@ -6746,7 +7021,7 @@ var AgentSession = class {
|
|
|
6746
7021
|
ui.onToolCall(action.id, action.type, action.params);
|
|
6747
7022
|
const result = await this.executor.executeAction(action);
|
|
6748
7023
|
results.push(result);
|
|
6749
|
-
ui.onToolResult(action.id, action.type, result.success, result.data, result.error);
|
|
7024
|
+
ui.onToolResult(action.id, action.type, result.success, result.data, result.error, result.code);
|
|
6750
7025
|
if (action.type === "sign_tx" && result.success && result.data) {
|
|
6751
7026
|
const txHash = result.data.tx_hash;
|
|
6752
7027
|
const chain = result.data.chain;
|
|
@@ -6776,34 +7051,12 @@ var AgentSession = class {
|
|
|
6776
7051
|
this.historyMessages = [];
|
|
6777
7052
|
}
|
|
6778
7053
|
};
|
|
6779
|
-
function
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
while ((match = invokeRegex.exec(text)) !== null) {
|
|
6784
|
-
const actionType = match[1];
|
|
6785
|
-
const body = match[2];
|
|
6786
|
-
const params = {};
|
|
6787
|
-
const paramRegex = /<parameter\s+name="([^"]+)">([\s\S]*?)<\/parameter>/g;
|
|
6788
|
-
let paramMatch;
|
|
6789
|
-
while ((paramMatch = paramRegex.exec(body)) !== null) {
|
|
6790
|
-
const key = paramMatch[1];
|
|
6791
|
-
const value = paramMatch[2];
|
|
6792
|
-
try {
|
|
6793
|
-
params[key] = JSON.parse(value);
|
|
6794
|
-
} catch {
|
|
6795
|
-
params[key] = value;
|
|
6796
|
-
}
|
|
6797
|
-
}
|
|
6798
|
-
actions.push({
|
|
6799
|
-
id: `inline_${actionType}_${Date.now()}`,
|
|
6800
|
-
type: actionType,
|
|
6801
|
-
title: actionType,
|
|
6802
|
-
params,
|
|
6803
|
-
auto_execute: true
|
|
6804
|
-
});
|
|
7054
|
+
function stripLeakedToolCallTags(text) {
|
|
7055
|
+
if (!text) return "";
|
|
7056
|
+
if (!/<invoke\s+name="[^"]*">/.test(text) && !text.includes("minimax:tool_call")) {
|
|
7057
|
+
return text;
|
|
6805
7058
|
}
|
|
6806
|
-
return
|
|
7059
|
+
return text.replace(/<invoke\s+name="[^"]*">[\s\S]*?<\/invoke>/g, "").replace(/<\/?minimax:tool_call>/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
6807
7060
|
}
|
|
6808
7061
|
function getTokenCachePath() {
|
|
6809
7062
|
const dir = process.env.VULTISIG_CONFIG_DIR ?? join2(homedir2(), ".vultisig");
|
|
@@ -6979,7 +7232,7 @@ var ChatTUI = class {
|
|
|
6979
7232
|
console.log(` ${chalk8.yellow("\u26A1")} ${chalk8.yellow(action)} ${chalk8.gray("...")}`);
|
|
6980
7233
|
}
|
|
6981
7234
|
},
|
|
6982
|
-
onToolResult: (_id, action, success2, data, error2) => {
|
|
7235
|
+
onToolResult: (_id, action, success2, data, error2, code) => {
|
|
6983
7236
|
if (success2) {
|
|
6984
7237
|
if (this.verbose) {
|
|
6985
7238
|
const summary = data ? summarizeData(data) : "";
|
|
@@ -6988,7 +7241,8 @@ var ChatTUI = class {
|
|
|
6988
7241
|
console.log(` ${chalk8.green("\u2713")} ${chalk8.green(action)}`);
|
|
6989
7242
|
}
|
|
6990
7243
|
} else {
|
|
6991
|
-
|
|
7244
|
+
const suffix = code && this.verbose ? chalk8.gray(` (${code})`) : "";
|
|
7245
|
+
console.log(` ${chalk8.red("\u2717")} ${chalk8.red(action)}: ${chalk8.red(error2 || "failed")}${suffix}`);
|
|
6992
7246
|
}
|
|
6993
7247
|
},
|
|
6994
7248
|
onAssistantMessage: (content) => {
|
|
@@ -7016,12 +7270,13 @@ var ChatTUI = class {
|
|
|
7016
7270
|
console.log(` ${chalk8.blue.underline(explorerUrl)}`);
|
|
7017
7271
|
}
|
|
7018
7272
|
},
|
|
7019
|
-
onError: (message) => {
|
|
7273
|
+
onError: (message, code) => {
|
|
7020
7274
|
if (this.isStreaming) {
|
|
7021
7275
|
process.stdout.write("\n");
|
|
7022
7276
|
this.isStreaming = false;
|
|
7023
7277
|
}
|
|
7024
|
-
|
|
7278
|
+
const suffix = this.verbose ? chalk8.gray(` (${code})`) : "";
|
|
7279
|
+
console.log(` ${chalk8.red("Error")}: ${message}${suffix}`);
|
|
7025
7280
|
},
|
|
7026
7281
|
onDone: () => {
|
|
7027
7282
|
if (this.isStreaming) {
|
|
@@ -7214,6 +7469,7 @@ async function executeAgent(ctx2, options) {
|
|
|
7214
7469
|
const config = {
|
|
7215
7470
|
backendUrl: options.backendUrl || process.env.VULTISIG_AGENT_URL || "https://abe.vultisig.com",
|
|
7216
7471
|
vaultName: vault.name,
|
|
7472
|
+
vultisig: ctx2.sdk,
|
|
7217
7473
|
password: options.password,
|
|
7218
7474
|
viaAgent: options.viaAgent,
|
|
7219
7475
|
sessionId: options.sessionId,
|
|
@@ -7229,7 +7485,8 @@ async function executeAgent(ctx2, options) {
|
|
|
7229
7485
|
const addresses = session.getVaultAddresses();
|
|
7230
7486
|
await pipe.start(vault.name, addresses);
|
|
7231
7487
|
} catch (err) {
|
|
7232
|
-
|
|
7488
|
+
const { code, message } = normalizeAgentError(err);
|
|
7489
|
+
process.stdout.write(JSON.stringify({ type: "error", message, code }) + "\n");
|
|
7233
7490
|
process.exit(1);
|
|
7234
7491
|
}
|
|
7235
7492
|
} else {
|
|
@@ -7239,7 +7496,8 @@ async function executeAgent(ctx2, options) {
|
|
|
7239
7496
|
await session.initialize(callbacks);
|
|
7240
7497
|
await tui.start();
|
|
7241
7498
|
} catch (err) {
|
|
7242
|
-
|
|
7499
|
+
const { message } = normalizeAgentError(err);
|
|
7500
|
+
console.error(`Agent error: ${message}`);
|
|
7243
7501
|
process.exit(1);
|
|
7244
7502
|
}
|
|
7245
7503
|
}
|
|
@@ -7255,6 +7513,7 @@ async function executeAgentAsk(ctx2, message, options) {
|
|
|
7255
7513
|
const config = {
|
|
7256
7514
|
backendUrl: options.backendUrl || process.env.VULTISIG_AGENT_URL || "https://abe.vultisig.com",
|
|
7257
7515
|
vaultName: vault.name,
|
|
7516
|
+
vultisig: ctx2.sdk,
|
|
7258
7517
|
password: options.password,
|
|
7259
7518
|
sessionId: options.session,
|
|
7260
7519
|
verbose: options.verbose,
|
|
@@ -7293,10 +7552,11 @@ tx:${tx.chain}:${tx.hash}
|
|
|
7293
7552
|
}
|
|
7294
7553
|
}
|
|
7295
7554
|
} catch (err) {
|
|
7555
|
+
const { code, message: message2 } = normalizeAgentError(err);
|
|
7296
7556
|
if (options.json) {
|
|
7297
|
-
process.stdout.write(JSON.stringify({ error:
|
|
7557
|
+
process.stdout.write(JSON.stringify({ error: message2, code }) + "\n");
|
|
7298
7558
|
} else {
|
|
7299
|
-
process.stderr.write(`Error: ${
|
|
7559
|
+
process.stderr.write(`Error: ${message2} [${code}]
|
|
7300
7560
|
`);
|
|
7301
7561
|
}
|
|
7302
7562
|
process.exit(1);
|
|
@@ -7759,7 +8019,7 @@ var EventBuffer = class {
|
|
|
7759
8019
|
};
|
|
7760
8020
|
|
|
7761
8021
|
// src/interactive/session.ts
|
|
7762
|
-
import { fiatCurrencies as
|
|
8022
|
+
import { fiatCurrencies as fiatCurrencies4 } from "@vultisig/sdk";
|
|
7763
8023
|
import chalk12 from "chalk";
|
|
7764
8024
|
import ora3 from "ora";
|
|
7765
8025
|
import * as readline3 from "readline";
|
|
@@ -8577,9 +8837,9 @@ Error: ${error2.message}`));
|
|
|
8577
8837
|
i++;
|
|
8578
8838
|
}
|
|
8579
8839
|
}
|
|
8580
|
-
if (!
|
|
8840
|
+
if (!fiatCurrencies4.includes(currency)) {
|
|
8581
8841
|
console.log(chalk12.red(`Invalid currency: ${currency}`));
|
|
8582
|
-
console.log(chalk12.yellow(`Supported currencies: ${
|
|
8842
|
+
console.log(chalk12.yellow(`Supported currencies: ${fiatCurrencies4.join(", ")}`));
|
|
8583
8843
|
return;
|
|
8584
8844
|
}
|
|
8585
8845
|
const raw = args.includes("--raw");
|
|
@@ -8828,7 +9088,7 @@ var cachedVersion = null;
|
|
|
8828
9088
|
function getVersion() {
|
|
8829
9089
|
if (cachedVersion) return cachedVersion;
|
|
8830
9090
|
if (true) {
|
|
8831
|
-
cachedVersion = "0.15.
|
|
9091
|
+
cachedVersion = "0.15.4";
|
|
8832
9092
|
return cachedVersion;
|
|
8833
9093
|
}
|
|
8834
9094
|
try {
|
|
@@ -9323,7 +9583,7 @@ async function init(vaultOverride, unlockPassword, passwordTTL) {
|
|
|
9323
9583
|
}
|
|
9324
9584
|
const globalOptions = program.opts();
|
|
9325
9585
|
const serverEndpoints = resolveServerEndpoints(globalOptions);
|
|
9326
|
-
const sdk = new
|
|
9586
|
+
const sdk = new Vultisig6({
|
|
9327
9587
|
onPasswordRequired: createPasswordCallback(),
|
|
9328
9588
|
...serverEndpoints ? { serverEndpoints } : {},
|
|
9329
9589
|
...passwordTTL !== void 0 ? { passwordCache: { defaultTTL: passwordTTL } } : {}
|
|
@@ -9940,7 +10200,7 @@ program.command("update").description("Check for updates and show update command
|
|
|
9940
10200
|
setupCompletionCommand(program);
|
|
9941
10201
|
async function startInteractiveMode() {
|
|
9942
10202
|
const serverEndpoints = resolveServerEndpoints(parseServerEndpointOverridesFromArgv(process.argv.slice(2)));
|
|
9943
|
-
const sdk = new
|
|
10203
|
+
const sdk = new Vultisig6({
|
|
9944
10204
|
onPasswordRequired: createPasswordCallback(),
|
|
9945
10205
|
...serverEndpoints ? { serverEndpoints } : {}
|
|
9946
10206
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.4",
|
|
4
4
|
"description": "Command-line wallet for Vultisig - multi-chain MPC wallet management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@cosmjs/stargate": "^0.38.1",
|
|
56
56
|
"@noble/hashes": "^2.0.1",
|
|
57
57
|
"@vultisig/rujira": "^10.0.0",
|
|
58
|
-
"@vultisig/sdk": "^0.15.
|
|
58
|
+
"@vultisig/sdk": "^0.15.4",
|
|
59
59
|
"chalk": "^5.6.2",
|
|
60
60
|
"cli-table3": "^0.6.5",
|
|
61
61
|
"commander": "^14.0.3",
|