@open-billing/sdk
v0.7.0
Published
billing-saas Gateway 模式接入 SDK — a2a ClientPlugin + ServerPlugin + REST API client
Maintainers
Readme
@open-billing/sdk
open-billing 协议的中立 SDK。 一包两味,按你的角色选:
createAgentMeter—— AI Agent 作者用。返回一个IOMetricsProvider, 挂到@multi-agent/a2aAgent Server 即可,每次 IO 自动带 HMAC 签名上报。createBillingClient—— 业务方后端用。查事件、用量、余额、流水、价格。
本包从不发明价格、也不假设租户模型 —— 它严格说 docs/spec.md
定义的那个协议。换言之你完全可以自己写一个 SDK 替代它,协议本身才是契约。
安装
bun add @open-billing/sdk
# 或: npm i @open-billing/sdk@multi-agent/a2a >= 0.3.10 是 peer dep —— 只在用 createAgentMeter 时才需要,
纯业务端 client 不需要。
Agent 侧 —— 一行接入计量
import { createAgentServer, defineSkill } from '@multi-agent/a2a'
import { createAgentMeter } from '@open-billing/sdk'
createAgentServer({
agentId: 'image-agent',
address: 'a2a://0.0.0.0:9090',
// a2a 协议层接管 HMAC / token 计数 / 流拦截;SDK 只做 4 个 HTTP 调用。
metricsProvider: createAgentMeter({
baseUrl: process.env.BILLING_URL!,
auth: { type: 'bearer', token: process.env.BILLING_AGENT_TOKEN! },
}),
skills: [
defineSkill('generate', async (params, ctx) => {
// 业务代码不写一行计费逻辑
return { url: `https://example.com/${Date.now()}.png` }
}),
],
})每次 skill 调用幕后发生:
- a2a 启动时调
verifyIntegrity→ 后端返signingKey - 每次调用前
preCallCheck→ 后端按余额 / 规则决定 allow - handler 跑 → 输入 / 输出 token 由 a2a 统计 + 算 contentHash + HMAC 签名
reportMetricsPOST/events落库
verifyIntegrity / preCallCheck 错误走严格模式(不能预检的事不应该扣费)。
reportMetrics 错误会抛出 —— a2a 内置 plugin 会 log。
"skill 失败也扣费"注意事项: a2a 的
afterHandler不区分业务成功 / 失败, 只要 stream 有过输出就上报 IO 事件。如果 skill 报错并往 stream 写了 error 消息, 这些字节会算作 output token 扣费。三种补法见docs/design-rationale.md §7。
业务侧 —— 五指 client
import { createBillingClient } from '@open-billing/sdk'
const billing = createBillingClient({
baseUrl: process.env.BILLING_URL!,
auth: { type: 'bearer', token: process.env.BUSINESS_TOKEN! },
})
// 1. 用户总消费
const usage = await billing.usage.byUser('user_42')
// → { totalCalls, totalInputTokens, totalOutputTokens, totalCost? }
// 2. 按 trace 拿事件(call graph)
const events = await billing.events.byTrace(traceId)
// 3. 时间范围 + Agent 过滤
const page = await billing.events.list({
agentId: 'image-agent',
from: new Date(Date.now() - 24 * 3600_000),
limit: 50,
})
// 4. 余额(Billing Module 启用时)
const balance = await billing.accounts.balance('user_42')
// 5. 流水
const ledger = await billing.accounts.ledger('user_42', { op: 'charge' })Admin 专用操作
需要 admin token(独立的角色,见 spec §3):
await billing.accounts.topup('user_42', 10_000, 'monthly grant')
await billing.accounts.adjust('user_42', -50, 'manual refund')
await billing.pricing.create({
skill: 'generate',
inputTokenPrice: 1,
outputTokenPrice: 3,
})
await billing.pricing.expire(42)鉴权 —— 三种姿势
// 1. Bearer(默认推荐)
auth: { type: 'bearer', token: 'xxx' }
// 2. 任意 header(对接非标准后端)
auth: { type: 'header', name: 'X-Service-Token', value: 'xxx' }
// 3. 完全自定义(签 JWT / mTLS 加证书 / 注入 trace header)
auth: { type: 'fn', apply: async (init) => {
init.headers = { ...init.headers, Authorization: await signJWT() }
return init
}}Transport 调优
createBillingClient({
baseUrl: '...',
auth: { ... },
timeout: 5_000, // 默认 10000ms
retry: { attempts: 3, backoff: 'expo' }, // 默认 1(不重试);'expo' 或 'linear'
fetcher: customFetch, // 完全替换 fetch(测试 / IPC / mock)
})重试只针对 429 + 5xx —— 4xx 错误立刻抛。
错误处理
所有 HTTP 失败都抛 BillingError:
import type { BillingError } from '@open-billing/sdk'
try {
await billing.accounts.balance('user_42')
} catch (e) {
const err = e as BillingError
err.status // HTTP 状态码,如 404
err.code // 服务端给的错误码,如 'account_not_found'
err.message // 人类可读说明
err.details // 可选的结构化详情
}API 一览
| 导出 | 角色 | 返回 |
|-----------------------|-----------|------------------------------------------|
| createAgentMeter | Agent | IOMetricsProvider(a2a) |
| createBillingClient | 业务方 | { usage, events, accounts, pricing } |
| 分组 | 方法 | spec | 所需 token |
|----------|-----------------------------------------|--------|--------------|
| usage | byUser(userId, query?) | §6.6 | business |
| usage | byAgent(agentId, query?) | §6.7 | business |
| events | list(filter?) | §6.5 | business |
| events | byTrace(traceId) | §6.4 | business |
| accounts | list(filter?) | §6.7.5 | business |
| accounts | balance(userId) | §6.8 | business |
| accounts | ledger(userId, filter?) | §6.9 | business |
| accounts | topup(userId, amount, note?) | §6.10 | admin |
| accounts | adjust(userId, amount, note?) | §6.11 | admin |
| pricing | list(filter?) | §6.12 | business |
| pricing | create(entry) | §6.13 | admin |
| pricing | expire(id) | §6.14 | admin |
完整类型定义看 src/types.ts,完整 wire format 看
docs/openapi.yaml。
验证你的后端是否符合本协议
不管你 fork 参考服务端还是自己撸,跑
@open-billing/testkit 一次 —— 17 个 case 覆盖
鉴权 / HMAC / 幂等 / Billing Module 合规性。
License
MIT
