@aeon-ai-pay/aigateway 0.2.2 → 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 CHANGED
@@ -1,115 +1,265 @@
1
1
  # AEON AI Gateway
2
2
 
3
- > AI Agents discover, invoke, and settle paid LLMs, APIs, and Skills starting with **Skill Boss**.
3
+ > **Co-presented by AEON & SkillBoss** — AI Agents pay per-call in USDT on BSC to invoke 200+ AI tool capabilities.
4
4
  >
5
- > **No manual key setup. No prepayment. Pay-per-call via x402 or Agent Card.**
5
+ > **Zero API keys · Zero prepay · x402 protocol pay-per-call · Natural-language driven**
6
6
 
7
- A unified CLI + agent skill that lets an AI agent **purchase virtual debit cards** *and* **invoke AI services (image generation via Skill Boss)** in the same wallet, paid per-call with USDT on BSC via the [x402 protocol](https://www.x402.org/).
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
- Published as `@aeon-ai-pay/aigateway` (CLI: `aigateway`).
9
+ ---
10
10
 
11
- ## Install Skill
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
- # Install to all detected agents (Claude Code, Cursor, Codex, OpenClaw, Gemini CLI, etc.)
15
- npx skills add AEON-Project/aigateway -g -y
124
+ npm install -g @aeon-ai-pay/aigateway
16
125
 
17
- # Install to specific agents
18
- npx skills add AEON-Project/aigateway -a claude-code -a cursor -a codex -g -y
126
+ # Verify
127
+ aigateway --version
19
128
  ```
20
129
 
21
- Supported agents: Claude Code, Cursor, Codex, OpenClaw, Gemini CLI, GitHub Copilot, Windsurf, Roo Code, and [39+ more](https://agentskills.io).
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
- ## One-Glance Flow
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
- aigateway wallet-init # 1. auto-create local session wallet (pure local, no QR)
27
- aigateway wallet-topup --amount 5 # 2. WalletConnect: USDT top-up + one-time facilitator approve
28
- aigateway create-card --amount 5 # 3a. paid call: $5 virtual card via x402
29
- aigateway create-image --prompt "cyberpunk fox" # 3b. paid call: AI image via x402
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
- Step 2 covers the **only** manual moment scanning a WalletConnect QR with your phone wallet to load ≥5 USDT once. Every subsequent paid call is a gasless EIP-712 signature against the local session key.
162
+ Images / videos / audio are auto-downloaded into `~/aigateway-{images,videos,audio}/`.
33
163
 
34
- ## CLI Commands
164
+ ---
35
165
 
36
- Every command accepts `--app-id <id>` (merchant identifier, default `TEST000001`). Every command emits a JSON *envelope* on stdout (`{ ok, command, version, data | error }`).
166
+ ## CLI Command Reference
37
167
 
38
- | Command | Description | Key Options |
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 (pure local — no QR, no on-chain) | `--app-id <id>` |
41
- | `wallet-topup` | WalletConnect USDT top-up (≥5 USDT, presets 5/10/20/50) + one-time facilitator approve | `--amount <usdt>`, `--app-id <id>`, `--private-key <key>` |
42
- | `create-card` | Issue a one-time virtual Visa/Mastercard ($0.6 ~ $800) | `--amount <usd>` (required), `--app-id <id>`, `--poll`, `--dry-run`, `--topup-amount <usdt>` |
43
- | `create-image` | Generate an AI image via Skill Boss | `--prompt <text>` (required), `--app-id <id>`, `--aspect-ratio`, `--output-format`, `--model`, `--output <dir>`, `--topup-amount <usdt>` |
44
- | `create-card-status` | Query the status of a card issued via `create-card` | `--order-no <orderNo>` (required), `--app-id <id>`, `--poll` |
45
- | `wallet` | Show local wallet USDT + BNB balance | `--app-id <id>`, `--private-key` |
46
- | `wallet-gas` | Send BNB from main wallet to session key via WalletConnect | `--amount <bnb>` (default `0.001`), `--app-id <id>` |
47
- | `wallet-withdraw` | Reclaim USDT + BNB from session key back to main wallet | `--amount <usdt>` (default: all), `--to <address>`, `--app-id <id>` |
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
- ## Prerequisites
181
+ Global flags: `--legacy-output` (legacy JSON shape), `--verbose`, `--quiet`.
62
182
 
63
- - Node.js 25
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
- ## Quickstart for Developers
185
+ - `video`: must include `duration_seconds` (billed per second)
186
+ - `stt`: must include `duration_minutes` (billed per minute)
68
187
 
69
- Bundling `aigateway` inside your own agent product or merchant service? See:
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) — full envelope schema per command
73
- - [docs/exit-codes.md](docs/exit-codes.md) — exit code categories + `error.code` reference
74
- - [docs/env-vars.md](docs/env-vars.md) — `AIGATEWAY_SERVICE_URL`, `EVM_PRIVATE_KEY`, and the config-file fallback
75
- - [docs/troubleshooting.md](docs/troubleshooting.md) — common issues + remedies
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) — generic Node.js / Python subprocess wrappers
79
- - [docs/recipes/merchant-integration.md](docs/recipes/merchant-integration.md) — merchant patterns (user-managed vs. custodial wallet, Express backend example)
80
- - [docs/recipes/error-recovery.md](docs/recipes/error-recovery.md) — code-by-code recovery strategy
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 adoption**
84
- - [docs/ide-setup.md](docs/ide-setup.md) — manual install templates for Cursor / Windsurf / Cline / Codex
221
+ **Agent / IDE integration**
222
+ - [docs/ide-setup.md](docs/ide-setup.md) — Manual install templates for various IDEs
85
223
 
86
- **Releasing**
87
- - [docs/release-process.md](docs/release-process.md) — version lock-step, publish, auto-upgrade flow
88
- - [CHANGELOG.md](CHANGELOG.md) — release history
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", "create-card", "--amount", "5", "--app-id", "MY_AGENT_001", "--poll",
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", (code) => {
242
+ child.on("close", () => {
101
243
  const env = JSON.parse(stdout.trim().split("\n").pop());
102
- if (env.ok) console.log("Card ready:", env.data.orderNo);
103
- else console.error(`[${env.error.code}] ${env.error.message}`);
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`) is wired into the CLI; staging / custom backends can be overridden through environment variables only:
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
- - `AIGATEWAY_SERVICE_URL` — x402 service base URL
112
- - `EVM_PRIVATE_KEY` — override the saved session key (developer use)
262
+ ---
113
263
 
114
264
  ## License
115
265
 
package/bin/cli.mjs CHANGED
@@ -128,6 +128,7 @@ sb
128
128
  sb
129
129
  .command("tools")
130
130
  .description("Fetch and display the AI tool catalog (with optional filters)")
131
+ .option("--app-id <id>", "Merchant app ID", DEFAULT_APP_ID)
131
132
  .option("--model <id>", "Return only this model (+effectiveSchema)")
132
133
  .option("--category <key>", "Return only this category (image / video / tts / etc.)")
133
134
  .option("--tier <tier>", "Filter models by tier (price | quality | balanced)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeon-ai-pay/aigateway",
3
- "version": "0.2.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.2"
29
+ version: "0.2.3"
30
30
  author: AEON-Project
31
31
  openclaw:
32
32
  requires:
@@ -73,7 +73,7 @@ aigateway sb tools | jq '.data.categories[].models[] | select(.id=="<model_id>")
73
73
 
74
74
  每次都从服务端实时获取,无本地缓存。
75
75
 
76
- 价格不在 catalog 里:x402 第一阶段(402 响应)会实时返回本次调用的 USDT 金额,CLI 自动展示给用户。
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` 行展示。
77
77
 
78
78
  ## 钱包模型(与 x402 的关系)
79
79
 
@@ -254,21 +254,37 @@ Approve: {approveTx truncated or "already approved"}
254
254
 
255
255
  ### 3.2 列出候选 model,等用户挑
256
256
 
257
- ⭐ **默认模式**:**AI 不擅自选 model**,而是把候选 + 价格列给用户,让用户拍板。**推荐默认选最便宜的**(按 `tier: "price"` 优先排序)。
257
+ ⭐ **默认模式**:**AI 不擅自选 model**,而是把候选 + 预估总价列给用户,让用户拍板。**推荐默认选最便宜的**(按 `tier: "price"` 优先排序)。
258
258
 
259
259
  **例外**:用户原话已经指定了 model(`"用 flux-2-max 画"`) → 直接用,跳过列表。
260
260
 
261
- #### 候选展示模板(按字面渲染)
261
+ #### Step A: 看 `priceUnit` 决定是否前置询问用量
262
262
 
263
- `aigateway sb tools --category <key>` 拿到该类所有 model,**按 tier 排序**(price balanced → quality)后用以下模板渲染:
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),渲染:
264
281
 
265
282
  ```
266
- ✨ 可用 model({category 中文名})
283
+ ✨ 可用 model({category 中文名}{ — 基于 {N}{unit-cn} 预估}
267
284
 
268
- # Model ID 价格 档位
269
- 1 {model_id} ${price}{unit} ← 推荐
270
- 2 {model_id} ${price}{unit}
271
- 3 {model_id} ${price}{unit}
285
+ # Model ID 单价 预估总价 档位
286
+ 1 {model_id} ${unitPrice}{unit-cn} ${total} {tier} ← 推荐
287
+ 2 {model_id} ${unitPrice}{unit-cn} ${total} {tier}
272
288
  ...
273
289
 
274
290
  直接回车或输入 1 用推荐项;或输入序号 / 完整 model_id 选其它。
@@ -276,23 +292,22 @@ Approve: {approveTx truncated or "already approved"}
276
292
 
277
293
  **字段规则**:
278
294
  - 第 1 行**永远**是 tier=`price` 档(最便宜),并加 `← 推荐` 后缀
279
- - `${price}` catalog `model.price`(USD 数值,保留小数)
280
- - `{unit}` category 推断(见下表)
281
- - 用户只输序号 `2` / 完整 `model_id` / 直接回车 都接受
282
- - 用户没回应 → 用 #1(推荐项)
295
+ - `{N}{unit-cn}` 只在用量已知时显示(如 "基于 5 秒预估");per_request 类省略
296
+ - `${total}` = `unitPrice × quantity`(quantity 见上表)
297
+ - 用户输序号 / 完整 `model_id` / 直接回车 都接受
283
298
 
284
- #### Category价格单位映射
299
+ #### priceUnit中文单位 + quantity 公式
285
300
 
286
- | Category | 价格单位 `{unit}` |
287
- | --- | --- |
288
- | `image` | `/张` |
289
- | `video` | `/秒` |
290
- | `tts` | `/1K 字符` |
291
- | `stt` | `/分钟` |
292
- | `embeddings` | `/M tokens` |
293
- | `search` / `scraper` / `social_data` / `email` / `sms` / `document` / `ui_generation` / `financial` / `news` / `geolocation` / `utility` / `apify` | `/次` |
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** |
294
309
 
295
- > 价格是**预估单价**,**最终金额**以 x402 第一阶段(402 响应)的实时数据为准(CLI 会在调用后展示 `💰 Charged`)。
310
+ > 价格是**预估**。**精确金额**由服务端按 `model.priceUnit × inputs 用量` 算出,并在 x402 第一阶段(402 响应)返回;CLI `💰 Charged` 行展示真实扣款。
296
311
 
297
312
  #### 用户偏好覆盖
298
313
 
@@ -455,6 +470,10 @@ aigateway sb invoke \
455
470
  | `DOWNLOAD_FAILED` | 3 | 服务端返回 URL 但本地下载失败;URL 仍在 `data.downloaded[].url` |
456
471
  | `PAYMENT_FAILED` | 3 | 上游 vendor 错误;透传 `error.data`;5xx 重试一次 |
457
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) |
458
477
  | `MODEL_PRICING_NOT_CONFIGURED` | 1 | 服务端未给该 model 配价;告知用户该 model 暂不可用,建议换 model(或联系运维补 catalog) |
459
478
  | `INVALID_BODY` | 1 | 服务端拒绝 body 格式;通常是 CLI bug,提交反馈 |
460
479
  | `CATALOG_FETCH_FAILED` | 3 | `sb tools` 拉取 catalog 失败;网络问题,stale cache 仍可用 |
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 url = `${serviceUrl}/open/api/skillBoss/tools-catalog`;
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
  }
@@ -19,20 +19,22 @@ import { fetchCatalog, findModel } from "../catalog.mjs";
19
19
 
20
20
  export async function sbTools(opts) {
21
21
  const serviceUrl = resolve(opts.serviceUrl, "AIGATEWAY_SERVICE_URL", "serviceUrl");
22
+ const { appId } = opts;
22
23
  if (!serviceUrl) {
23
- emitErr("sb-tools", "SERVICE_URL_MISSING", {});
24
+ emitErr("sb-tools", "SERVICE_URL_MISSING", { appId });
24
25
  return;
25
26
  }
26
27
 
27
28
  logInfo("Fetching tools catalog from server...");
28
29
  let catalog;
29
30
  try {
30
- catalog = await fetchCatalog(serviceUrl);
31
+ catalog = await fetchCatalog(serviceUrl, appId);
31
32
  } catch (e) {
32
33
  emitErr("sb-tools", "CATALOG_FETCH_FAILED", {
33
34
  message: `Failed to fetch tools catalog: ${e.message}`,
34
35
  url: `${serviceUrl}/open/api/skillBoss/tools-catalog`,
35
36
  status: e.response?.status,
37
+ appId,
36
38
  });
37
39
  return;
38
40
  }