@aeon-ai-pay/aigateway 0.1.0 → 0.1.3
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 +38 -0
- package/package.json +1 -1
- package/skills/aigateway/SKILL.md +81 -24
- package/src/commands/wallet-init.mjs +78 -8
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.3] — 2026-05-19
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **`wallet-init` no longer requires `mainWallet` field in config to consider the wallet "funded".**
|
|
14
|
+
Previously the decision tree was `created || !config.mainWallet ⇒ needsTopup=true`, which meant
|
|
15
|
+
a session wallet that had USDT and was already approved on-chain — but whose local config had
|
|
16
|
+
never recorded a `mainWallet` (e.g. funded by an external CEX transfer, or copied from another
|
|
17
|
+
machine without that field) — would still be flagged as needing a top-up, sending the agent
|
|
18
|
+
through a redundant `wallet-topup` flow. The decision now relies only on on-chain state
|
|
19
|
+
(USDT balance ≥ `LOW_BALANCE_THRESHOLD` and `allowance > 0`). `mainWallet` is treated purely
|
|
20
|
+
as a withdraw-default and has no effect on `needsTopup`.
|
|
21
|
+
- `topupReason` enum updated: `no_prior_funding` removed; new values are `first_time` (replaces
|
|
22
|
+
the created branch), `low_balance`, `no_approve`, and `chain_check_failed`.
|
|
23
|
+
|
|
24
|
+
## [0.1.2] — 2026-05-19
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- **SKILL.md wording discipline**: `wallet-topup` ask and `create-card` ask now have
|
|
28
|
+
enforced lexical separation. Step 2 (`wallet-topup`) explicitly says "load USDT
|
|
29
|
+
**into your session wallet**" / "往**本地钱包**充值 USDT". Step 3a (`create-card`)
|
|
30
|
+
says "card **face value**" / "**开多少美元的卡** / 卡的面额", and explicitly
|
|
31
|
+
forbids translating it as "充值". Fixes a UX confusion where a user with a
|
|
32
|
+
funded wallet would be asked "请问您想充值多少美元到虚拟卡上?" and reasonably
|
|
33
|
+
wonder if it was another wallet top-up prompt.
|
|
34
|
+
- New "Wording Discipline" section in SKILL.md `## Copy Constraints` to lock this in.
|
|
35
|
+
|
|
36
|
+
## [0.1.1] — 2026-05-19
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- **`wallet-init` now reports full funding status**, not just local-key readiness. Envelope `data` adds:
|
|
40
|
+
`usdt`, `bnb`, `allowance`, `needsTopup`, `topupReason` (`no_prior_funding` / `low_balance` / `no_approve`),
|
|
41
|
+
`minTopup`, `presets`, `chainCheck`. Agents can decide the next step (`wallet-topup` vs. go straight to a paid
|
|
42
|
+
call) from this single envelope without a separate `wallet-balance` call.
|
|
43
|
+
- **SKILL.md workflow re-ordered** so agents prompt the user for a top-up amount **before** invoking the first
|
|
44
|
+
paid command, eliminating the previous "try-create-card → fail with `TOPUP_REQUIRED` → ask amount" UX bug.
|
|
45
|
+
- SKILL.md adds an "If `aigateway` is not found (exit 127)" fallback that instructs the agent to run
|
|
46
|
+
`npm install -g @aeon-ai-pay/aigateway` once and retry.
|
|
47
|
+
|
|
10
48
|
## [0.1.0] — 2026-05-18
|
|
11
49
|
|
|
12
50
|
Initial release of **AEON AI Gateway**, merging the prior `@aeon-ai-pay/aicard` and `@aeon-ai-pay/agentos` projects into a single unified CLI and agent skill.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeon-ai-pay/aigateway",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "AI Agents discover, invoke, and settle paid LLMs, APIs, and Skills — starting with Skill Boss. No manual key setup. No prepayment. Pay-per-call via x402 or Agent Card.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@ description: >
|
|
|
16
16
|
emoji: "🛰️"
|
|
17
17
|
homepage: https://github.com/AEON-Project/aigateway
|
|
18
18
|
metadata:
|
|
19
|
-
version: "0.1.
|
|
19
|
+
version: "0.1.3"
|
|
20
20
|
author: AEON-Project
|
|
21
21
|
openclaw:
|
|
22
22
|
requires:
|
|
@@ -73,13 +73,13 @@ See [docs/output-schema.md](../../docs/output-schema.md) and [docs/exit-codes.md
|
|
|
73
73
|
## Command Overview
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
aigateway wallet-init # Pre-check /
|
|
76
|
+
aigateway wallet-init # Pre-check / create wallet AND report needsTopup status (one-stop pre-flight)
|
|
77
77
|
aigateway wallet-topup [--amount <usdt>] # WalletConnect: top-up USDT (≥5; presets 5/10/20/50) + first-time facilitator approve
|
|
78
78
|
aigateway create-card --amount <usd> --poll # Issue a virtual card ($0.6 ~ $800)
|
|
79
79
|
aigateway create-image --prompt "<text>" # Generate AI image
|
|
80
80
|
aigateway create-card-status --order-no <orderNo> [--poll] # Query card status
|
|
81
|
-
aigateway wallet-balance #
|
|
82
|
-
aigateway wallet-gas [--amount <bnb>]
|
|
81
|
+
aigateway wallet-balance # (optional) Re-query balance — agent rarely needs this; wallet-init already reports it
|
|
82
|
+
aigateway wallet-gas [--amount <bnb>] # Top up BNB for session key (for withdraw)
|
|
83
83
|
aigateway wallet-withdraw [--to <addr>] [--amount <usdt>] # Reclaim funds
|
|
84
84
|
aigateway clean # Uninstall skill, clear cache
|
|
85
85
|
```
|
|
@@ -104,33 +104,76 @@ Output template:
|
|
|
104
104
|
> Pre-check in progress...
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
### If `aigateway` is not found (exit 127 / "command not found")
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
- `created: false`, `ready: true` → "0x0...{last4} Ready."
|
|
111
|
-
- Record `amountLimits.{min,max}` for any subsequent card amount validation.
|
|
109
|
+
The CLI hasn't been installed on this host yet. Output to the user **verbatim**:
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
```
|
|
112
|
+
> Installing aigateway...
|
|
113
|
+
```
|
|
116
114
|
|
|
117
|
-
|
|
115
|
+
Then run **in the foreground** (this can take 30–60 seconds; do **not** background it):
|
|
118
116
|
|
|
119
117
|
```bash
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
npm install -g @aeon-ai-pay/aigateway
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
After install completes, re-run `aigateway wallet-init`. If `npm install` itself fails (network / permissions), surface the raw error and ask the user to fix their npm environment.
|
|
122
|
+
|
|
123
|
+
### Envelope on success
|
|
124
|
+
|
|
125
|
+
`envelope.data` (full shape):
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"ready": true,
|
|
130
|
+
"created": false,
|
|
131
|
+
"address": "0x...",
|
|
132
|
+
"mainWallet": "0x..." | null,
|
|
133
|
+
"usdt": "5.0",
|
|
134
|
+
"bnb": "0.0003",
|
|
135
|
+
"allowance": "115792...max" | "0",
|
|
136
|
+
"needsTopup": false,
|
|
137
|
+
"topupReason": null | "no_prior_funding" | "low_balance" | "no_approve",
|
|
138
|
+
"minTopup": 5,
|
|
139
|
+
"presets": [5, 10, 20, 50],
|
|
140
|
+
"amountLimits": { "min": 0.6, "max": 800 }
|
|
141
|
+
}
|
|
122
142
|
```
|
|
123
143
|
|
|
124
|
-
###
|
|
144
|
+
### Decision tree (this is the whole pre-flight)
|
|
145
|
+
|
|
146
|
+
| Field | Action |
|
|
147
|
+
| --- | --- |
|
|
148
|
+
| `created: true` | "Auto-creating your designated wallet..." + "0x0...{last4} Ready." |
|
|
149
|
+
| `created: false`, `ready: true` | "0x0...{last4} Ready." |
|
|
150
|
+
| **`needsTopup: true`** | **Go to Step 2 immediately.** Use `presets` / `minTopup` from this envelope (don't hardcode). |
|
|
151
|
+
| `needsTopup: false` | Wallet has enough USDT and is approved. **Skip Step 2** and jump straight to the user's intent (`create-card` / `create-image` / other). |
|
|
152
|
+
|
|
153
|
+
Record `amountLimits.{min,max}` for any subsequent card amount validation.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Step 2: Top up (only if Step 1's envelope says `needsTopup: true`)
|
|
125
158
|
|
|
126
|
-
|
|
159
|
+
Trigger: `wallet-init` envelope reports `needsTopup: true` (any of `no_prior_funding` / `low_balance` / `no_approve`), **or** the user explicitly asks to top up / load funds.
|
|
127
160
|
|
|
128
161
|
### Amount selection
|
|
129
162
|
|
|
163
|
+
This is a **session-wallet top-up** in USDT (NOT card face value). Make the wording unambiguously about the wallet to avoid the user confusing it with the card face value asked in Step 3a.
|
|
164
|
+
|
|
130
165
|
- Presets: **5 / 10 / 20 / 50 USDT**. Custom amounts must be ≥ 5 USDT.
|
|
131
|
-
-
|
|
132
|
-
|
|
133
|
-
|
|
166
|
+
- Ask the user **before** running the command. **Make "wallet" / "钱包" explicit in the question:**
|
|
167
|
+
|
|
168
|
+
> How much USDT would you like to load **into your session wallet**? (presets: 5 / 10 / 20 / 50, or any custom amount ≥ 5)
|
|
169
|
+
|
|
170
|
+
(Suggested Chinese phrasing: "请问要往**本地钱包**充值多少 USDT?预设 5 / 10 / 20 / 50,或自定义 ≥ 5。")
|
|
171
|
+
|
|
172
|
+
- Once the user picks an amount, run:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
aigateway wallet-topup --amount <n> # always pass --amount in agent context
|
|
176
|
+
```
|
|
134
177
|
|
|
135
178
|
### Output template
|
|
136
179
|
|
|
@@ -151,8 +194,8 @@ Approve: {approveTx truncated or "already approved"}
|
|
|
151
194
|
|
|
152
195
|
| `error.code` | Action |
|
|
153
196
|
| --- | --- |
|
|
154
|
-
| `TOPUP_REQUIRED` (
|
|
155
|
-
| `TOPUP_AMOUNT_TOO_SMALL` | Show `error.minTopup`, ask
|
|
197
|
+
| `TOPUP_REQUIRED` (would only happen if you skipped Step 2) | Bug in agent — should have asked for amount in Step 3. Ask now, then rerun with `--amount <n>`. |
|
|
198
|
+
| `TOPUP_AMOUNT_TOO_SMALL` | Show `error.minTopup`, ask the user for a larger amount. |
|
|
156
199
|
| `PAYMENT_REJECTED` | User cancelled in wallet. **Do not auto-retry**; ask user. |
|
|
157
200
|
| `PAYMENT_TIMEOUT` | 5-minute WalletConnect window expired. **Do not auto-retry**; ask user. |
|
|
158
201
|
| `INSUFFICIENT_BNB` (post-funding) | Run `aigateway wallet-gas` (interactive) to add BNB, then retry. |
|
|
@@ -164,13 +207,16 @@ Approve: {approveTx truncated or "already approved"}
|
|
|
164
207
|
|
|
165
208
|
## Step 3a: Create Virtual Card
|
|
166
209
|
|
|
167
|
-
Trigger: user wants to **buy / create / get a virtual card
|
|
210
|
+
Trigger: user wants to **buy / create / get a virtual card** *and* Step 1 envelope showed `needsTopup: false` (or Step 2 just completed successfully).
|
|
168
211
|
|
|
169
212
|
### Amount confirmation
|
|
170
213
|
|
|
171
|
-
Amount must be in `amountLimits.min ~ amountLimits.max` (from Step 1; never hardcode). If user did not specify, ask once:
|
|
214
|
+
This is the **card face value** the user wants to issue (NOT a wallet top-up). Amount must be in `amountLimits.min ~ amountLimits.max` (from Step 1; never hardcode). If user did not specify, ask once — **use the word "card face value" / "面额", never "充值" / "top up"** to avoid confusing it with the `wallet-topup` step:
|
|
215
|
+
|
|
216
|
+
> What card face value would you like to issue? Allowed range: ${min}~${max} USD.
|
|
172
217
|
|
|
173
|
-
|
|
218
|
+
(Suggested Chinese phrasing: "请问要开多少美元的卡?允许范围 $${min} ~ $${max}。"
|
|
219
|
+
**Do not** translate this as "充值多少美元" — that wording belongs to `wallet-topup` and confuses users.)
|
|
174
220
|
|
|
175
221
|
Once specified, **execute immediately**.
|
|
176
222
|
|
|
@@ -368,3 +414,14 @@ The following first-line / key-phrase strings must be **exactly reproduced** —
|
|
|
368
414
|
| Wallet prepared header | `✅ Wallet prepared` |
|
|
369
415
|
|
|
370
416
|
Address rendering: always `0x0...{last4}` (first 3 + ellipsis + last 4 chars).
|
|
417
|
+
|
|
418
|
+
### Wording Discipline: "wallet top-up" vs "card face value"
|
|
419
|
+
|
|
420
|
+
These two amounts are **different concepts** asked at **different steps**. Translators must keep them lexically distinct so users don't conflate them:
|
|
421
|
+
|
|
422
|
+
| Step | Concept | Required wording (English) | Suggested Chinese | Forbidden mix-ups |
|
|
423
|
+
| --- | --- | --- | --- | --- |
|
|
424
|
+
| Step 2 (`wallet-topup`) | USDT into the **session wallet** | "load USDT **into your session wallet**" | "往**本地钱包**充值 USDT" | Don't say "充值到卡里" / "load onto the card" — that's Step 3a |
|
|
425
|
+
| Step 3a (`create-card`) | USD **face value** loaded onto a new card | "card **face value**" / "issue a card with how much" | "**开多少美元的卡** / 卡的面额" | Don't say "充值多少" / "充值到卡" without strong "card" qualifier — confuses with Step 2 |
|
|
426
|
+
|
|
427
|
+
**Rule of thumb**: if the agent's question contains the word "充值" (top up), the noun *must* be "钱包" (wallet); if the question is about a card's amount, prefer "**面额**" or "**开多少美元的卡**", never "充值".
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* init
|
|
2
|
+
* wallet-init:本地 session 钱包 check / 创建 + 链上状态评估
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* 步骤:
|
|
5
|
+
* 1. 若 ~/.aigateway/config.json 缺 privateKey → 用 viem.generatePrivateKey() 生成
|
|
6
|
+
* 2. 查 USDT / BNB 余额(除非刚 created,则跳过查询直接判定为 needsTopup)
|
|
7
|
+
* 3. 查 facilitator allowance(同上规则)
|
|
8
|
+
* 4. 综合判定 needsTopup 与原因,返回完整就绪状态供 agent 决策
|
|
7
9
|
*
|
|
8
|
-
*
|
|
10
|
+
* 设计意图:agent 跑完 wallet-init 一条命令就拿到决策依据:
|
|
11
|
+
* - data.ready=true 表示钱包私钥可用
|
|
12
|
+
* - data.needsTopup=true → 必须先 wallet-topup(envelope 里附带 presets / minTopup / reason)
|
|
13
|
+
* - data.needsTopup=false → 可直接 create-card / create-image
|
|
9
14
|
*/
|
|
10
15
|
import { loadConfig, saveConfig } from "../config.mjs";
|
|
11
16
|
import { MIN_AMOUNT, MAX_AMOUNT } from "../constants.mjs";
|
|
12
|
-
import {
|
|
17
|
+
import { getWalletBalance, getAllowance } from "../balance.mjs";
|
|
18
|
+
import {
|
|
19
|
+
LOW_BALANCE_THRESHOLD,
|
|
20
|
+
MIN_TOPUP_USDT,
|
|
21
|
+
TOPUP_PRESETS,
|
|
22
|
+
} from "../funding.mjs";
|
|
23
|
+
import { emitOk, logInfo } from "../output.mjs";
|
|
13
24
|
|
|
14
25
|
export async function initWallet(opts) {
|
|
15
26
|
const config = loadConfig();
|
|
@@ -25,18 +36,77 @@ export async function initWallet(opts) {
|
|
|
25
36
|
config.mode = "private-key";
|
|
26
37
|
created = true;
|
|
27
38
|
saveConfig(config);
|
|
39
|
+
logInfo(`Auto-created session wallet: ${config.address}`);
|
|
40
|
+
} else {
|
|
41
|
+
logInfo(`Wallet: ${config.address}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 链上状态评估
|
|
45
|
+
let usdt = "0";
|
|
46
|
+
let bnb = "0";
|
|
47
|
+
let usdtNum = 0;
|
|
48
|
+
let allowance = 0n;
|
|
49
|
+
let chainCheckOk = true;
|
|
50
|
+
let chainCheckError = null;
|
|
51
|
+
|
|
52
|
+
if (created) {
|
|
53
|
+
// 刚建好的钱包余额必然为 0,跳过链上查询节省 ~500ms
|
|
54
|
+
logInfo("Fresh wallet — skipping balance lookup (assumed empty).");
|
|
55
|
+
} else {
|
|
56
|
+
try {
|
|
57
|
+
const bal = await getWalletBalance(config.privateKey);
|
|
58
|
+
usdt = bal.usdt;
|
|
59
|
+
bnb = bal.bnb;
|
|
60
|
+
usdtNum = parseFloat(usdt);
|
|
61
|
+
logInfo(`Balance: ${usdt} USDT, ${bnb} BNB`);
|
|
62
|
+
allowance = await getAllowance(config.address);
|
|
63
|
+
logInfo(`Allowance: ${allowance === 0n ? "0 (approve required)" : "already approved"}`);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
chainCheckOk = false;
|
|
66
|
+
chainCheckError = e.message;
|
|
67
|
+
logInfo(`Chain status check failed: ${e.message}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 决策:是否需要 topup —— 只看链上真实状态,不依赖 config.mainWallet 字段。
|
|
72
|
+
// 之前用 !config.mainWallet 当判断条件是错的:mainWallet 只是 withdraw 默认目标地址,
|
|
73
|
+
// 即使为 null(如用户外部转账 / 旧版本未记录),只要链上 USDT/allowance 充足就应该
|
|
74
|
+
// 直接允许付费调用,不要强制再走一次 wallet-topup。
|
|
75
|
+
let needsTopup = false;
|
|
76
|
+
let topupReason = null;
|
|
77
|
+
if (created) {
|
|
78
|
+
// 刚生成的 session key 必然没钱,无需查链
|
|
79
|
+
needsTopup = true;
|
|
80
|
+
topupReason = "first_time";
|
|
81
|
+
} else if (!chainCheckOk) {
|
|
82
|
+
// 链上查询失败 —— 保守标记需要 topup 由用户决定下一步
|
|
83
|
+
needsTopup = true;
|
|
84
|
+
topupReason = "chain_check_failed";
|
|
85
|
+
} else if (usdtNum < LOW_BALANCE_THRESHOLD) {
|
|
86
|
+
needsTopup = true;
|
|
87
|
+
topupReason = "low_balance";
|
|
88
|
+
} else if (allowance === 0n) {
|
|
89
|
+
needsTopup = true;
|
|
90
|
+
topupReason = "no_approve";
|
|
28
91
|
}
|
|
29
92
|
|
|
30
|
-
const ready = !!(config.serviceUrl && config.privateKey);
|
|
31
93
|
const data = {
|
|
32
|
-
ready,
|
|
94
|
+
ready: true,
|
|
33
95
|
created,
|
|
34
96
|
appId,
|
|
35
97
|
mode: config.mode || null,
|
|
36
98
|
address: config.address || null,
|
|
37
99
|
mainWallet: config.mainWallet || null,
|
|
38
100
|
serviceUrl: config.serviceUrl || null,
|
|
101
|
+
usdt,
|
|
102
|
+
bnb,
|
|
103
|
+
allowance: allowance.toString(),
|
|
104
|
+
needsTopup,
|
|
105
|
+
topupReason, // "no_prior_funding" | "low_balance" | "no_approve" | null
|
|
106
|
+
minTopup: MIN_TOPUP_USDT,
|
|
107
|
+
presets: TOPUP_PRESETS,
|
|
39
108
|
amountLimits: { min: MIN_AMOUNT, max: MAX_AMOUNT },
|
|
109
|
+
chainCheck: chainCheckOk ? "ok" : { error: chainCheckError },
|
|
40
110
|
};
|
|
41
111
|
emitOk("wallet-init", data, data);
|
|
42
112
|
}
|