@aeon-ai-pay/aigateway 0.2.1 → 0.2.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/README.md +216 -66
- package/bin/cli.mjs +5 -1
- package/package.json +1 -1
- package/skills/aigateway/SKILL.md +92 -12
- package/src/catalog.mjs +3 -2
- package/src/commands/sb-invoke.mjs +1 -1
- package/src/commands/sb-tools.mjs +70 -10
- package/src/error-codes.mjs +1 -0
package/README.md
CHANGED
|
@@ -1,115 +1,265 @@
|
|
|
1
1
|
# AEON AI Gateway
|
|
2
2
|
|
|
3
|
-
> AI Agents
|
|
3
|
+
> **Co-presented by AEON & SkillBoss** — AI Agents pay per-call in USDT on BSC to invoke 200+ AI tool capabilities.
|
|
4
4
|
>
|
|
5
|
-
> **
|
|
5
|
+
> **Zero API keys · Zero prepay · x402 protocol pay-per-call · Natural-language driven**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
`@aeon-ai-pay/aigateway` is a unified CLI + Agent Skill. Through a single session-key wallet and the [x402 protocol](https://www.x402.org/), it opens up SkillBoss's 200+ tool capabilities (image / video / audio / search / scraping / email / document / social data / UI generation, etc.) to AI Agents for pay-per-call invocation.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
---
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## About SkillBoss
|
|
12
|
+
|
|
13
|
+
**SkillBoss** is a unified AI API + Agent Skills platform — a single API Key gives you access to models and tool capabilities from multiple providers, covering chat & reasoning, search, web scraping, image generation, video generation, audio, document processing, email, data services, and website / full-stack app deployment. Native support for Claude Code, Codex, Cursor, Windsurf, and other AI Agent tools.
|
|
14
|
+
|
|
15
|
+
| Dimension | Data |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Public API endpoints** | 359 |
|
|
18
|
+
| **Service providers** | 50 |
|
|
19
|
+
| **Official Skill packages** | 1 main + 4 sub: `skillboss` / `skillboss-image` / `skillboss-video` / `skillboss-marketing` / `skillboss-cold-email` |
|
|
20
|
+
| **Skills Marketplace** | 500+ ready-to-use skills |
|
|
21
|
+
|
|
22
|
+
**Full capability surface**: LLM / Chat · Embedding · Search · Scraping · Image · Video · Audio (TTS / STT) · Document · Social / Business Data · Email · Finance / Utility · Platform / Storage · Marketing / Cold Email · Full-stack App / Website Build & Deploy
|
|
23
|
+
|
|
24
|
+
### SkillBoss Resources
|
|
25
|
+
|
|
26
|
+
| Entry | URL |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| API web catalog | https://www.skillboss.co/docs/api-catalog |
|
|
29
|
+
| API JSON catalog | https://www.skillboss.co/api-catalog.json |
|
|
30
|
+
| Skills marketplace | https://www.skillboss.co/skills |
|
|
31
|
+
| Skills index API | https://www.skillboss.co/api/skills/index |
|
|
32
|
+
| Skills search API | https://www.skillboss.co/api/skills/search |
|
|
33
|
+
| Agent install entry | https://www.skillboss.co/skill.md |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
┌────────────────────────────────────────────────────────────┐
|
|
41
|
+
│ AI Agent (Claude Code / Cursor / Codex / Windsurf / ...) │
|
|
42
|
+
└────────────────────┬───────────────────────────────────────┘
|
|
43
|
+
│ natural-language instructions
|
|
44
|
+
▼
|
|
45
|
+
┌────────────────────────────────────────────────────────────┐
|
|
46
|
+
│ aigateway CLI (@aeon-ai-pay/aigateway) │
|
|
47
|
+
│ sb tools ──→ server catalog (model + tier + schema) │
|
|
48
|
+
│ sb invoke ──→ client-side inputs validation │
|
|
49
|
+
│ ──→ x402 phase 1 (402 response: live price) │
|
|
50
|
+
│ ──→ EIP-712 signing (session key, gasless) │
|
|
51
|
+
│ ──→ auto-download image / video / audio │
|
|
52
|
+
└────────────────────┬───────────────────────────────────────┘
|
|
53
|
+
│ HTTP + x402
|
|
54
|
+
▼
|
|
55
|
+
┌────────────────────────────────────────────────────────────┐
|
|
56
|
+
│ AEON x402 Gateway (ai-api.aeon.xyz) │
|
|
57
|
+
│ dynamic pricing by model.priceUnit × usage │
|
|
58
|
+
│ proxies calls to SkillBoss upstream │
|
|
59
|
+
└────────────────────┬───────────────────────────────────────┘
|
|
60
|
+
│
|
|
61
|
+
▼
|
|
62
|
+
┌────────────────────────────────────────────────────────────┐
|
|
63
|
+
│ SkillBoss (api.skillboss.co) │
|
|
64
|
+
│ 50 vendors · 359 endpoints │
|
|
65
|
+
└────────────────────────────────────────────────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Capability Categories
|
|
71
|
+
|
|
72
|
+
| Category | Pricing Unit | Description |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `image` | `per_image` | Image generation / editing / upscaling / background removal |
|
|
75
|
+
| `video` | `per_second` | Video generation (requires `duration_seconds`) |
|
|
76
|
+
| `tts` | `per_1k_chars` | Text-to-speech / sound effect generation |
|
|
77
|
+
| `stt` | `per_minute` | Speech-to-text (requires `duration_minutes`) |
|
|
78
|
+
| `search` | `per_request` | Web search / map search |
|
|
79
|
+
| `scraper` | `per_request` | Web scraping / structured extraction |
|
|
80
|
+
| `social_data` | `per_request` | Social / business data |
|
|
81
|
+
| `sms` | `per_request` | SMS / OTP / email verification |
|
|
82
|
+
| `document` | `per_request` | Document parsing (PDF / DOCX → Markdown) |
|
|
83
|
+
| `ui_generation` | `per_request` | UI / prototype / slide deck generation |
|
|
84
|
+
| `embeddings` | `per_million_tokens` | Text embedding vectors |
|
|
85
|
+
| `financial` | `per_request` | Stock / forex / crypto / financial news |
|
|
86
|
+
| `news` | `per_request` | News APIs |
|
|
87
|
+
| `utility` | `per_request` | Domain / QR code / geo / dictionary and other utility APIs |
|
|
88
|
+
|
|
89
|
+
### Querying models at runtime
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Fetch the full catalog
|
|
93
|
+
aigateway sb tools
|
|
94
|
+
|
|
95
|
+
# Filter by category
|
|
96
|
+
aigateway sb tools --category image
|
|
97
|
+
aigateway sb tools --category video
|
|
98
|
+
|
|
99
|
+
# Filter by tier (price percentile within a category: price / balanced / quality)
|
|
100
|
+
aigateway sb tools --tier price
|
|
101
|
+
aigateway sb tools --category image --tier quality
|
|
102
|
+
|
|
103
|
+
# Look up a single model (with effectiveSchema)
|
|
104
|
+
aigateway sb tools --model <model_id>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Response shape: `categories[].models[]`. Each model carries `id` / `vendor` / `useCase` / `price` / `priceUnit` / `tier` / optional `inputsOverride`. Each category carries `agentTrigger` / `defaultInputsSchema`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Prerequisites
|
|
112
|
+
|
|
113
|
+
- Node.js ≥ 25
|
|
114
|
+
- A WalletConnect-compatible mobile wallet (MetaMask / OKX Wallet / Trust Wallet, etc.)
|
|
115
|
+
- Your main wallet holds USDT (BEP-20) plus a small amount of BNB (for the first-time approve gas, ~$0.002)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Installation
|
|
120
|
+
|
|
121
|
+
### Step 1: Install the CLI (npm)
|
|
12
122
|
|
|
13
123
|
```bash
|
|
14
|
-
|
|
15
|
-
npx skills add AEON-Project/aigateway -g -y
|
|
124
|
+
npm install -g @aeon-ai-pay/aigateway
|
|
16
125
|
|
|
17
|
-
#
|
|
18
|
-
|
|
126
|
+
# Verify
|
|
127
|
+
aigateway --version
|
|
19
128
|
```
|
|
20
129
|
|
|
21
|
-
|
|
130
|
+
### Step 2: Install the Agent Skill (optional, for repair)
|
|
131
|
+
|
|
132
|
+
When you run `npm install -g`, the `postinstall` script already installs the skill into all detected agents. If something was missed, install it manually:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npx skills add AEON-Project/aigateway -g -y # install into all detected agents
|
|
136
|
+
npx skills add AEON-Project/aigateway -a claude-code -a cursor -a codex -g -y # install into specific agents
|
|
137
|
+
```
|
|
22
138
|
|
|
23
|
-
|
|
139
|
+
Supported: Claude Code, Cursor, Codex, OpenClaw, Gemini CLI, GitHub Copilot, Windsurf, Roo Code, [39+ more](https://agentskills.io).
|
|
24
140
|
|
|
141
|
+
### Step 3: Initialize the wallet
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
aigateway wallet-init # generates the session key at ~/.aigateway/config.json and prints address + balance
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Step 4: First-time top-up (one-time)
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
aigateway wallet-topup --amount 5
|
|
25
151
|
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
152
|
+
|
|
153
|
+
After scanning the WalletConnect QR code, the main wallet signs 2 transactions: transfer USDT + a small amount of BNB to the session key; the session key then broadcasts a one-time `ERC20.approve(facilitator, MaxUint256)`. After that, `sb invoke` is fully gasless EIP-712 signing end-to-end.
|
|
154
|
+
|
|
155
|
+
### Step 5: Invoke SkillBoss tools
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
aigateway sb tools --category image # browse available models
|
|
159
|
+
aigateway sb invoke --model <model_id> --inputs '{"prompt":"..."}' # invoke
|
|
30
160
|
```
|
|
31
161
|
|
|
32
|
-
|
|
162
|
+
Images / videos / audio are auto-downloaded into `~/aigateway-{images,videos,audio}/`.
|
|
33
163
|
|
|
34
|
-
|
|
164
|
+
---
|
|
35
165
|
|
|
36
|
-
|
|
166
|
+
## CLI Command Reference
|
|
37
167
|
|
|
38
|
-
|
|
168
|
+
Every command accepts `--app-id <id>` (merchant ID, defaults to `TEST000001`) and emits a single JSON envelope line to stdout: `{ ok, command, version, data | error }`.
|
|
169
|
+
|
|
170
|
+
| Command | Description | Key flags |
|
|
39
171
|
| --- | --- | --- |
|
|
40
|
-
| `wallet-init` | Check / create the local session wallet (
|
|
41
|
-
| `wallet-topup` | WalletConnect USDT top-up (≥5 USDT, presets 5/10/20/50) +
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
| `
|
|
45
|
-
| `wallet` |
|
|
46
|
-
| `wallet-
|
|
47
|
-
| `
|
|
48
|
-
| `clean` | Remove skill + uninstall global package | — |
|
|
49
|
-
|
|
50
|
-
Global flags: `--legacy-output` (old JSON shape), `--verbose`, `--quiet`.
|
|
51
|
-
|
|
52
|
-
## Wallet & Funding Model
|
|
53
|
-
|
|
54
|
-
- **Session key**: A locally-generated private key stored at `~/.aigateway/config.json` (mode 0o600). It signs all paid calls and never leaves your machine.
|
|
55
|
-
- **Main wallet**: Your existing MetaMask / OKX / Trust wallet. Connects only via WalletConnect QR — its key never touches the CLI.
|
|
56
|
-
- **First-funding floor**: ≥ **1 USDT** (`LOW_BALANCE_THRESHOLD`) is enforced before any paid call.
|
|
57
|
-
- **Per-top-up minimum**: ≥ **5 USDT** (`MIN_TOPUP_USDT`). Presets: 5 / 10 / 20 / 50, or custom ≥ 5.
|
|
58
|
-
- **Approve once**: `wallet-topup` broadcasts a one-time `ERC20.approve(facilitator, MaxUint256)` (consumes ~0.0003 BNB). Subsequent paid calls reuse this allowance — no more on-chain transactions for the user.
|
|
59
|
-
- **Gasless paid calls**: Both `create-card` and `create-image` are pure EIP-712 signatures; the facilitator pays gas for the actual USDT transfer.
|
|
172
|
+
| `wallet-init` | Check / create the local session wallet (purely local — no QR, no on-chain action) | `--app-id <id>` |
|
|
173
|
+
| `wallet-topup` | WalletConnect USDT top-up (≥5 USDT, presets 5/10/20/50) + first-time approve | `--amount <usdt>`, `--private-key <key>` |
|
|
174
|
+
| **`sb invoke`** | **The only x402 paid invocation entry point** — invoke any SkillBoss model | `--model <id>` (required), `--inputs <json>` (required), `--output <dir>`, `--raw`, `--topup-amount <usdt>` |
|
|
175
|
+
| **`sb tools`** | Fetch the model catalog from the server in real time (no cache) | `--model <id>` / `--category <key>` / `--tier <price\|quality\|balanced>` |
|
|
176
|
+
| `wallet-balance` | Show the session wallet's USDT + BNB balance | `--private-key <key>` |
|
|
177
|
+
| `wallet-gas` | Transfer BNB from the main wallet to the session key via WalletConnect | `--amount <bnb>` (default `0.001`) |
|
|
178
|
+
| `wallet-withdraw` | Withdraw USDT + BNB from the session key back to the main wallet | `--amount <usdt>` (default all), `--to <address>` |
|
|
179
|
+
| `clean` | Uninstall the skill + global package and clear caches | — |
|
|
60
180
|
|
|
61
|
-
|
|
181
|
+
Global flags: `--legacy-output` (legacy JSON shape), `--verbose`, `--quiet`.
|
|
62
182
|
|
|
63
|
-
-
|
|
64
|
-
- A mobile wallet app with WalletConnect support (MetaMask, OKX Wallet, Trust Wallet, etc.)
|
|
65
|
-
- USDT (BEP-20) and a small BNB balance in your main wallet for the one-time approve gas (~$0.002)
|
|
183
|
+
**Usage-based pricing constraints** (enforced by `sb invoke` client-side preflight):
|
|
66
184
|
|
|
67
|
-
|
|
185
|
+
- `video`: must include `duration_seconds` (billed per second)
|
|
186
|
+
- `stt`: must include `duration_minutes` (billed per minute)
|
|
68
187
|
|
|
69
|
-
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Wallet & Pricing Model
|
|
191
|
+
|
|
192
|
+
- **Session key**: a locally generated private key (`~/.aigateway/config.json`, mode 0o600). All paid calls are signed by this key, and the private key never leaves your machine.
|
|
193
|
+
- **Main wallet**: your existing MetaMask / OKX / Trust wallet — only connected via the WalletConnect QR code, the main wallet's private key never touches the CLI.
|
|
194
|
+
- **First-call balance threshold**: wallet balance must be ≥ **1 USDT** before invocation (`LOW_BALANCE_THRESHOLD`).
|
|
195
|
+
- **Minimum top-up per session**: ≥ **5 USDT** (`MIN_TOPUP_USDT`), presets 5 / 10 / 20 / 50.
|
|
196
|
+
- **One-time approve**: `wallet-topup` broadcasts a single `ERC20.approve(facilitator, MaxUint256)` (consumes ~0.0003 BNB); all subsequent paid calls reuse the allowance — no further on-chain tx needed.
|
|
197
|
+
- **Gasless payments**: `sb invoke` is purely EIP-712 signing end-to-end; the server pays the gas for the on-chain USDT transfer.
|
|
198
|
+
- **Dynamic pricing**: the server computes `priceUnit × inputs usage` in real time:
|
|
199
|
+
- Image: `per_image × num_outputs`
|
|
200
|
+
- Video: `per_second × duration_seconds`
|
|
201
|
+
- TTS: `per_1k_chars × len(text)/1000`
|
|
202
|
+
- Transcription: `per_minute × duration_minutes`
|
|
203
|
+
- Embedding: `per_million_tokens × len(input)/4/1M`
|
|
204
|
+
- Others: `per_request × 1`
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Developer Integration
|
|
70
209
|
|
|
71
210
|
**Reference**
|
|
72
|
-
- [docs/output-schema.md](docs/output-schema.md) —
|
|
73
|
-
- [docs/exit-codes.md](docs/exit-codes.md) —
|
|
74
|
-
- [docs/env-vars.md](docs/env-vars.md) — `AIGATEWAY_SERVICE_URL
|
|
75
|
-
- [docs/troubleshooting.md](docs/troubleshooting.md) —
|
|
211
|
+
- [docs/output-schema.md](docs/output-schema.md) — Full envelope schema for every command
|
|
212
|
+
- [docs/exit-codes.md](docs/exit-codes.md) — Exit code categories + `error.code` index
|
|
213
|
+
- [docs/env-vars.md](docs/env-vars.md) — `AIGATEWAY_SERVICE_URL` / `EVM_PRIVATE_KEY` / config fallback rules
|
|
214
|
+
- [docs/troubleshooting.md](docs/troubleshooting.md) — Common issues
|
|
76
215
|
|
|
77
216
|
**Recipes**
|
|
78
|
-
- [docs/recipes/integrate-in-agent.md](docs/recipes/integrate-in-agent.md) —
|
|
79
|
-
- [docs/recipes/merchant-integration.md](docs/recipes/merchant-integration.md) —
|
|
80
|
-
- [docs/recipes/error-recovery.md](docs/recipes/error-recovery.md) —
|
|
81
|
-
- [docs/recipes/cron-issue-cards.md](docs/recipes/cron-issue-cards.md) — scheduled paid calls
|
|
217
|
+
- [docs/recipes/integrate-in-agent.md](docs/recipes/integrate-in-agent.md) — Node.js / Python subprocess wrapping
|
|
218
|
+
- [docs/recipes/merchant-integration.md](docs/recipes/merchant-integration.md) — Merchant onboarding (self-custody vs. managed wallet)
|
|
219
|
+
- [docs/recipes/error-recovery.md](docs/recipes/error-recovery.md) — Recovery strategies by error code
|
|
82
220
|
|
|
83
|
-
**Agent / IDE
|
|
84
|
-
- [docs/ide-setup.md](docs/ide-setup.md) —
|
|
221
|
+
**Agent / IDE integration**
|
|
222
|
+
- [docs/ide-setup.md](docs/ide-setup.md) — Manual install templates for various IDEs
|
|
85
223
|
|
|
86
|
-
**
|
|
87
|
-
- [docs/release-process.md](docs/release-process.md) —
|
|
88
|
-
- [CHANGELOG.md](CHANGELOG.md) —
|
|
224
|
+
**Release**
|
|
225
|
+
- [docs/release-process.md](docs/release-process.md) — Version sync, release, auto-upgrade
|
|
226
|
+
- [CHANGELOG.md](CHANGELOG.md) — Release history
|
|
89
227
|
|
|
90
|
-
Minimal Node.js example
|
|
228
|
+
### Minimal Node.js example
|
|
91
229
|
|
|
92
230
|
```js
|
|
93
231
|
import { spawn } from "node:child_process";
|
|
94
232
|
|
|
95
233
|
const child = spawn("aigateway", [
|
|
96
|
-
"--quiet",
|
|
234
|
+
"--quiet",
|
|
235
|
+
"sb", "invoke",
|
|
236
|
+
"--model", "<model_id>",
|
|
237
|
+
"--inputs", JSON.stringify({ prompt: "a cyberpunk fox" }),
|
|
238
|
+
"--app-id", "MY_AGENT_001",
|
|
97
239
|
]);
|
|
98
240
|
let stdout = "";
|
|
99
241
|
child.stdout.on("data", (b) => { stdout += b; });
|
|
100
|
-
child.on("close", (
|
|
242
|
+
child.on("close", () => {
|
|
101
243
|
const env = JSON.parse(stdout.trim().split("\n").pop());
|
|
102
|
-
if (env.ok)
|
|
103
|
-
|
|
244
|
+
if (env.ok) {
|
|
245
|
+
console.log("Image saved:", env.data.downloaded[0].localPath);
|
|
246
|
+
console.log("Tx:", env.data.transaction);
|
|
247
|
+
} else {
|
|
248
|
+
console.error(`[${env.error.code}] ${env.error.message}`);
|
|
249
|
+
}
|
|
104
250
|
});
|
|
105
251
|
```
|
|
106
252
|
|
|
253
|
+
---
|
|
254
|
+
|
|
107
255
|
## Configuration
|
|
108
256
|
|
|
109
|
-
Config lives at `~/.aigateway/config.json` (file mode 600). The default service URL (`https://ai-api.aeon.xyz`)
|
|
257
|
+
Config lives at `~/.aigateway/config.json` (file mode 600). The CLI ships with a default service URL (`https://ai-api.aeon.xyz`); for testing or a custom backend, override via environment variables:
|
|
258
|
+
|
|
259
|
+
- `AIGATEWAY_SERVICE_URL` — base URL of the x402 service
|
|
260
|
+
- `EVM_PRIVATE_KEY` — override the saved session key (development use)
|
|
110
261
|
|
|
111
|
-
|
|
112
|
-
- `EVM_PRIVATE_KEY` — override the saved session key (developer use)
|
|
262
|
+
---
|
|
113
263
|
|
|
114
264
|
## License
|
|
115
265
|
|
package/bin/cli.mjs
CHANGED
|
@@ -127,7 +127,11 @@ sb
|
|
|
127
127
|
|
|
128
128
|
sb
|
|
129
129
|
.command("tools")
|
|
130
|
-
.description("Fetch and display the AI tool catalog
|
|
130
|
+
.description("Fetch and display the AI tool catalog (with optional filters)")
|
|
131
|
+
.option("--app-id <id>", "Merchant app ID", DEFAULT_APP_ID)
|
|
132
|
+
.option("--model <id>", "Return only this model (+effectiveSchema)")
|
|
133
|
+
.option("--category <key>", "Return only this category (image / video / tts / etc.)")
|
|
134
|
+
.option("--tier <tier>", "Filter models by tier (price | quality | balanced)")
|
|
131
135
|
.action(async (opts) => {
|
|
132
136
|
const { sbTools } = await import("../src/commands/sb-tools.mjs");
|
|
133
137
|
return sbTools(opts);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeon-ai-pay/aigateway",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.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": {
|
|
@@ -26,7 +26,7 @@ description: >
|
|
|
26
26
|
emoji: "🛰️"
|
|
27
27
|
homepage: https://github.com/AEON-Project/aigateway
|
|
28
28
|
metadata:
|
|
29
|
-
version: "0.2.
|
|
29
|
+
version: "0.2.3"
|
|
30
30
|
author: AEON-Project
|
|
31
31
|
openclaw:
|
|
32
32
|
requires:
|
|
@@ -49,15 +49,31 @@ compatibility: 需要 Node.js >= 25 和 npm
|
|
|
49
49
|
|
|
50
50
|
完整工具索引(每个 `category` 含 `agentTrigger` / `defaultInputsSchema`;每个 `model` 含 `id` / `useCase` / `tier` / 可选 `inputsOverride`)由服务端集中维护,每次实时拉取。**无本地缓存** —— 服务端是 single source of truth,model 新增 / schema 改动立即生效。
|
|
51
51
|
|
|
52
|
-
**Agent 在 Phase 3.2 选 model
|
|
52
|
+
**Agent 在 Phase 3.2 选 model 时**,**优先用 CLI 自带的过滤参数**,避免自己写代码解析 list:
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
|
|
55
|
+
# 推荐:CLI 端过滤,直接拿你要的
|
|
56
|
+
aigateway sb tools --model replicate/black-forest-labs/flux-schnell # 单 model + effectiveSchema
|
|
57
|
+
aigateway sb tools --category image # 单类别(含所有 models 与 defaultInputsSchema)
|
|
58
|
+
aigateway sb tools --category image --tier price # 按 tier 过滤
|
|
59
|
+
aigateway sb tools --tier quality # 所有类别中 quality 档
|
|
60
|
+
|
|
61
|
+
# 备选:全量 catalog(少用,主要用于探索)
|
|
62
|
+
aigateway sb tools
|
|
56
63
|
```
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
**如果必须自己解析**(jq 推荐):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
aigateway sb tools | jq '.data.categories[] | select(.key=="image") | .models[]'
|
|
69
|
+
aigateway sb tools | jq '.data.categories[].models[] | select(.id=="<model_id>")'
|
|
70
|
+
```
|
|
59
71
|
|
|
60
|
-
|
|
72
|
+
⚠️ **不要在 Python list 上调 `.find()`** —— list 没有这个方法。用 `next(m for m in ...)` 或 dict 索引化。但通常**根本不需要**自己解析,用 `aigateway sb tools --model X` 就够了。
|
|
73
|
+
|
|
74
|
+
每次都从服务端实时获取,无本地缓存。
|
|
75
|
+
|
|
76
|
+
**价格在 catalog 里**:每个 model 含 `price`(USD 数值)+ `priceUnit`(`per_request` / `per_second` / `per_1k_chars` / `per_minute` / `per_image` / `per_million_tokens`),Agent 用这两个字段给用户**列候选 + 展示预估总价**(详见 Phase 3.2)。最终精确扣款金额由 x402 第一阶段(402 响应)返回,CLI 在 `💰 Charged` 行展示。
|
|
61
77
|
|
|
62
78
|
## 钱包模型(与 x402 的关系)
|
|
63
79
|
|
|
@@ -236,16 +252,73 @@ Approve: {approveTx truncated or "already approved"}
|
|
|
236
252
|
|
|
237
253
|
> 同一意图可能落到多个类别(如"做个含图的演示" = `image` + `ui_generation`),按用户**主诉求**选最匹配的一类先做。
|
|
238
254
|
|
|
239
|
-
### 3.2
|
|
255
|
+
### 3.2 列出候选 model,等用户挑
|
|
256
|
+
|
|
257
|
+
⭐ **默认模式**:**AI 不擅自选 model**,而是把候选 + 预估总价列给用户,让用户拍板。**推荐默认选最便宜的**(按 `tier: "price"` 优先排序)。
|
|
258
|
+
|
|
259
|
+
**例外**:用户原话已经指定了 model(`"用 flux-2-max 画"`) → 直接用,跳过列表。
|
|
260
|
+
|
|
261
|
+
#### Step A: 看 `priceUnit` 决定是否前置询问用量
|
|
262
|
+
|
|
263
|
+
catalog 中每个 model 都有 `priceUnit` 字段。**服务端按 `priceUnit` 强校验用量字段**,前置不问 → 调用直接报错。
|
|
264
|
+
|
|
265
|
+
| `priceUnit` | 用量字段 | 服务端强校验? | 前置询问? |
|
|
266
|
+
| --- | --- | --- | --- |
|
|
267
|
+
| `per_request` / `per_image` | `inputs.num_outputs` | 越界报错(1–10),缺省默认 1 | 否 |
|
|
268
|
+
| `per_second`(video) | `inputs.duration_seconds` | **必填**(1–300);缺 → `MISSING_DURATION` 400 | **必问 ——「视频按秒计费。你想生成多少秒?默认 5 秒」** |
|
|
269
|
+
| `per_1k_chars`(tts) | `inputs.text` 字符数 | text 必填非空;缺 → `MISSING_TEXT` 400 | 否(文本来自用户原话) |
|
|
270
|
+
| `per_minute`(stt) | `inputs.duration_minutes` | **必填**(1–360);缺 → `MISSING_DURATION` 400 | **必问 ——「按分钟计费。这段音频大约多少分钟?」** |
|
|
271
|
+
| `per_million_tokens`(embeddings) | `inputs.input` 字符数 / 4 | input 必填非空;缺 → `MISSING_INPUT` 400 | 否(服务端按字符长度估算 token) |
|
|
272
|
+
|
|
273
|
+
⚠️ **服务端强校验是为了计费安全**:
|
|
274
|
+
- 漏传 `duration_seconds` → 服务端无法按真实时长收费 → 拒绝
|
|
275
|
+
- 用户传 0 / 负数想绕过 → 拒绝
|
|
276
|
+
- 超出上限(5 分钟视频 / 6 小时音频)→ 拒绝
|
|
277
|
+
|
|
278
|
+
#### Step B: 候选展示模板(按字面渲染)
|
|
279
|
+
|
|
280
|
+
拿到用量后,跑 `aigateway sb tools --category <key>` 取所有 model,**按 tier 排序**(price → balanced → quality),渲染:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
✨ 可用 model({category 中文名}{ — 基于 {N}{unit-cn} 预估})
|
|
284
|
+
|
|
285
|
+
# Model ID 单价 预估总价 档位
|
|
286
|
+
1 {model_id} ${unitPrice}{unit-cn} ${total} {tier} ← 推荐
|
|
287
|
+
2 {model_id} ${unitPrice}{unit-cn} ${total} {tier}
|
|
288
|
+
...
|
|
289
|
+
|
|
290
|
+
直接回车或输入 1 用推荐项;或输入序号 / 完整 model_id 选其它。
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**字段规则**:
|
|
294
|
+
- 第 1 行**永远**是 tier=`price` 档(最便宜),并加 `← 推荐` 后缀
|
|
295
|
+
- `{N}{unit-cn}` 只在用量已知时显示(如 "基于 5 秒预估");per_request 类省略
|
|
296
|
+
- `${total}` = `unitPrice × quantity`(quantity 见上表)
|
|
297
|
+
- 用户输序号 / 完整 `model_id` / 直接回车 都接受
|
|
298
|
+
|
|
299
|
+
#### priceUnit → 中文单位 + quantity 公式
|
|
300
|
+
|
|
301
|
+
| `priceUnit` | `{unit-cn}` | quantity 公式 | 总价示例 |
|
|
302
|
+
| --- | --- | --- | --- |
|
|
303
|
+
| `per_request` | `/次` | `num_outputs` 或 1 | $0.02 × 1 = **$0.02** |
|
|
304
|
+
| `per_image` | `/张` | `num_outputs` 或 1 | $0.01 × 4 = **$0.04** |
|
|
305
|
+
| `per_second` | `/秒` | `duration_seconds` 或 5 | $0.20 × **6 秒** = **$1.20** |
|
|
306
|
+
| `per_1k_chars` | `/1K 字符` | `len(text) / 1000` | $0.05 × **2.5K 字** = **$0.125** |
|
|
307
|
+
| `per_minute` | `/分钟` | `duration_minutes` 或 1 | $0.02 × **3 分钟** = **$0.06** |
|
|
308
|
+
| `per_million_tokens` | `/M tokens` | `len(input) / 4 / 1M` | $0.26 × **0.5M tokens** ≈ **$0.13** |
|
|
309
|
+
|
|
310
|
+
> 价格是**预估**。**精确金额**由服务端按 `model.priceUnit × inputs 用量` 算出,并在 x402 第一阶段(402 响应)返回;CLI 在 `💰 Charged` 行展示真实扣款。
|
|
240
311
|
|
|
241
|
-
|
|
312
|
+
#### 用户偏好覆盖
|
|
242
313
|
|
|
243
|
-
|
|
|
314
|
+
| 用户原话 | AI 动作 |
|
|
244
315
|
| --- | --- |
|
|
245
|
-
| "
|
|
246
|
-
| "
|
|
247
|
-
|
|
|
248
|
-
|
|
|
316
|
+
| (无偏好)"画一只猫" | 列候选 → 等用户选 → 用户选完才调 `sb invoke` |
|
|
317
|
+
| "用便宜的画一只猫" | 直接用候选 #1(最便宜),跳过等待 |
|
|
318
|
+
| "用最好的画一只猫" | 直接用 `tier: "quality"` 档第一个,跳过等待 |
|
|
319
|
+
| "用 flux-2-max 画一只猫" | 直接用 `flux-2-max`,**完全跳过候选展示** |
|
|
320
|
+
| 用户输入序号 (e.g. "2") | 用候选列表第 2 行的 model |
|
|
321
|
+
| 用户输入完整 model_id | 用该 model_id |
|
|
249
322
|
|
|
250
323
|
**查询 model 清单**:跑 `aigateway sb tools` 拿到完整 catalog,从 stdout envelope 的 `data.categories[].models[]` 中按 `tier` 挑 `model_id`。
|
|
251
324
|
|
|
@@ -397,6 +470,10 @@ aigateway sb invoke \
|
|
|
397
470
|
| `DOWNLOAD_FAILED` | 3 | 服务端返回 URL 但本地下载失败;URL 仍在 `data.downloaded[].url` |
|
|
398
471
|
| `PAYMENT_FAILED` | 3 | 上游 vendor 错误;透传 `error.data`;5xx 重试一次 |
|
|
399
472
|
| `PAYMENT_FETCH_FAILED` | 3 | 拉取支付要求失败;网络问题 |
|
|
473
|
+
| `MISSING_DURATION` | 1 | 服务端强校验:video 缺 `inputs.duration_seconds`,或 stt 缺 `inputs.duration_minutes`。**必须前置问用户**再调 |
|
|
474
|
+
| `INVALID_DURATION` | 1 | 服务端强校验:duration 越界(video 1–300 秒 / stt 1–360 分钟) |
|
|
475
|
+
| `MISSING_TEXT` / `MISSING_INPUT` | 1 | TTS / embeddings 必填字段为空 |
|
|
476
|
+
| `INVALID_NUM_OUTPUTS` | 1 | `inputs.num_outputs` 越界(1–10) |
|
|
400
477
|
| `MODEL_PRICING_NOT_CONFIGURED` | 1 | 服务端未给该 model 配价;告知用户该 model 暂不可用,建议换 model(或联系运维补 catalog) |
|
|
401
478
|
| `INVALID_BODY` | 1 | 服务端拒绝 body 格式;通常是 CLI bug,提交反馈 |
|
|
402
479
|
| `CATALOG_FETCH_FAILED` | 3 | `sb tools` 拉取 catalog 失败;网络问题,stale cache 仍可用 |
|
|
@@ -531,6 +608,9 @@ aigateway clean # 卸载 skill、清缓存
|
|
|
531
608
|
| Phase 2 第一行 | `> Topping up wallet...` |
|
|
532
609
|
| Phase 2 成功 header | `✅ Wallet prepared` |
|
|
533
610
|
| Phase 4.1 sb invoke 第一行 | `> Invoking {model_id}...` |
|
|
611
|
+
| Phase 3.2 候选列表 header | `✨ 可用 model({category 中文名})` |
|
|
612
|
+
| Phase 3.2 推荐项后缀 | `← 推荐` |
|
|
613
|
+
| Phase 3.2 候选行格式 | `{#} {model_id} ${price}{unit}` |
|
|
534
614
|
| Phase 5.2 通用成功 header | `✅ Done` |
|
|
535
615
|
| Phase 5.2 Powered 行 | `🧩 Powered by Skillboss · {model_id}` |
|
|
536
616
|
| Phase 5.2 Path 行 | `📁 Path {localPath}` |
|
package/src/catalog.mjs
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
import axios from "axios";
|
|
9
9
|
|
|
10
10
|
/** Fetch catalog from server. Throws on network / HTTP failure. */
|
|
11
|
-
export async function fetchCatalog(serviceUrl) {
|
|
11
|
+
export async function fetchCatalog(serviceUrl, appId) {
|
|
12
12
|
if (!serviceUrl) throw new Error("serviceUrl is required");
|
|
13
|
-
const
|
|
13
|
+
const base = `${serviceUrl}/open/api/skillBoss/tools-catalog`;
|
|
14
|
+
const url = appId ? `${base}?appId=${encodeURIComponent(appId)}` : base;
|
|
14
15
|
const resp = await axios.get(url, { timeout: 15_000 });
|
|
15
16
|
return resp.data;
|
|
16
17
|
}
|
|
@@ -101,7 +101,7 @@ export async function invoke(opts) {
|
|
|
101
101
|
// failure (warn + skip; server still validates).
|
|
102
102
|
let catalog = null;
|
|
103
103
|
try {
|
|
104
|
-
catalog = await fetchCatalog(serviceUrl);
|
|
104
|
+
catalog = await fetchCatalog(serviceUrl, appId);
|
|
105
105
|
} catch (e) {
|
|
106
106
|
logInfo(`Warn: catalog fetch failed (${e.message}); skipping client-side validation — server will still check.`);
|
|
107
107
|
}
|
|
@@ -1,37 +1,97 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sb-tools: fetch and display the AI tool catalog from the server.
|
|
3
3
|
*
|
|
4
|
-
* aigateway sb tools
|
|
4
|
+
* aigateway sb tools # full catalog
|
|
5
|
+
* aigateway sb tools --model <id> # single model (+effectiveSchema)
|
|
6
|
+
* aigateway sb tools --category <key> # single category (+ all models)
|
|
7
|
+
* aigateway sb tools --tier <price|quality|balanced> # filter by tier
|
|
8
|
+
* (--category and --tier can combine)
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
10
|
+
* Filters are server-agnostic — applied client-side after fetching full catalog.
|
|
11
|
+
* Letting Agents target exactly what they need (via --model / --category) avoids
|
|
12
|
+
* the typical `.find()`-on-list type confusion when parsing the JSON manually.
|
|
8
13
|
*
|
|
9
|
-
* Endpoint: GET {serviceUrl}/open/api/skillBoss/tools-catalog
|
|
10
|
-
* (free, no x402; price fields are stripped server-side)
|
|
14
|
+
* Endpoint: GET {serviceUrl}/open/api/skillBoss/tools-catalog (no x402)
|
|
11
15
|
*/
|
|
12
16
|
import { resolve } from "../config.mjs";
|
|
13
17
|
import { emitOk, emitErr, logInfo } from "../output.mjs";
|
|
14
|
-
import { fetchCatalog } from "../catalog.mjs";
|
|
18
|
+
import { fetchCatalog, findModel } from "../catalog.mjs";
|
|
15
19
|
|
|
16
20
|
export async function sbTools(opts) {
|
|
17
21
|
const serviceUrl = resolve(opts.serviceUrl, "AIGATEWAY_SERVICE_URL", "serviceUrl");
|
|
22
|
+
const { appId } = opts;
|
|
18
23
|
if (!serviceUrl) {
|
|
19
|
-
emitErr("sb-tools", "SERVICE_URL_MISSING", {});
|
|
24
|
+
emitErr("sb-tools", "SERVICE_URL_MISSING", { appId });
|
|
20
25
|
return;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
logInfo("Fetching tools catalog from server...");
|
|
24
|
-
let
|
|
29
|
+
let catalog;
|
|
25
30
|
try {
|
|
26
|
-
|
|
31
|
+
catalog = await fetchCatalog(serviceUrl, appId);
|
|
27
32
|
} catch (e) {
|
|
28
33
|
emitErr("sb-tools", "CATALOG_FETCH_FAILED", {
|
|
29
34
|
message: `Failed to fetch tools catalog: ${e.message}`,
|
|
30
35
|
url: `${serviceUrl}/open/api/skillBoss/tools-catalog`,
|
|
31
36
|
status: e.response?.status,
|
|
37
|
+
appId,
|
|
32
38
|
});
|
|
33
39
|
return;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
|
|
42
|
+
// ─── --model <id> : return single model with effectiveSchema ────────────
|
|
43
|
+
if (opts.model) {
|
|
44
|
+
const found = findModel(catalog, opts.model);
|
|
45
|
+
if (!found) {
|
|
46
|
+
emitErr("sb-tools", "INVALID_MODEL_ID", {
|
|
47
|
+
message: `Model "${opts.model}" not found in catalog.`,
|
|
48
|
+
model: opts.model,
|
|
49
|
+
availableCategories: catalog.categories.map((c) => c.key),
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
emitOk("sb-tools", {
|
|
54
|
+
mode: "single-model",
|
|
55
|
+
category: found.category.key,
|
|
56
|
+
model: found.model,
|
|
57
|
+
effectiveSchema: found.effectiveSchema,
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ─── --category <key> : return single category ──────────────────────────
|
|
63
|
+
if (opts.category) {
|
|
64
|
+
const cat = catalog.categories.find((c) => c.key === opts.category);
|
|
65
|
+
if (!cat) {
|
|
66
|
+
emitErr("sb-tools", "CATEGORY_NOT_FOUND", {
|
|
67
|
+
message: `Category "${opts.category}" not found.`,
|
|
68
|
+
category: opts.category,
|
|
69
|
+
availableCategories: catalog.categories.map((c) => c.key),
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const filtered = applyTierFilter(cat, opts.tier);
|
|
74
|
+
emitOk("sb-tools", { mode: "single-category", category: filtered });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ─── --tier alone : filter all categories ───────────────────────────────
|
|
79
|
+
if (opts.tier) {
|
|
80
|
+
const cats = catalog.categories
|
|
81
|
+
.map((c) => applyTierFilter(c, opts.tier))
|
|
82
|
+
.filter((c) => c.models.length > 0);
|
|
83
|
+
emitOk("sb-tools", { ...catalog, categories: cats, mode: "tier-filtered", tier: opts.tier });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ─── default: full catalog ──────────────────────────────────────────────
|
|
88
|
+
emitOk("sb-tools", catalog, { success: true, ...catalog });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function applyTierFilter(cat, tier) {
|
|
92
|
+
if (!tier) return cat;
|
|
93
|
+
return {
|
|
94
|
+
...cat,
|
|
95
|
+
models: cat.models.filter((m) => m.tier === tier),
|
|
96
|
+
};
|
|
37
97
|
}
|
package/src/error-codes.mjs
CHANGED
|
@@ -25,6 +25,7 @@ export const ERROR_CODES = {
|
|
|
25
25
|
INVALID_INPUTS: { exit: 1, message: "Inputs failed schema validation." },
|
|
26
26
|
INPUTS_FILE_NOT_FOUND: { exit: 1, message: "Inputs file (passed via --inputs @path) not found." },
|
|
27
27
|
INVALID_MODEL_ID: { exit: 1, message: "Server rejected the model id." },
|
|
28
|
+
CATEGORY_NOT_FOUND: { exit: 1, message: "Category not found in catalog." },
|
|
28
29
|
MODEL_PRICING_NOT_CONFIGURED: { exit: 1, message: "This model is not yet priced on the gateway. Ask the operator to add it to skillboss-pricing.json." },
|
|
29
30
|
INVALID_BODY: { exit: 1, message: "Server rejected the request body." },
|
|
30
31
|
TOPUP_REQUIRED: { exit: 1, message: "Wallet top-up required. Choose an amount and rerun with --topup-amount <usdt>." },
|