@agentxv2/sdk
v0.11.12
Published
AgentX — Decentralized AI Agent SDK with ReAct AgentLoop + Multi-Tenant LLM Providers
Maintainers
Readme
@agentxv2/sdk v0.11.9
Decentralized AI Agent Platform SDK — E2E encryption, on-chain subscriptions, ReAct AgentLoop, multi-tenant LLM providers, A2A multi-agent interop (off-chain + user-wallet-signed on-chain rails), IPFS upload, MCP remote tools, chain-data batch query, hosted conversation sessions & parallel tasks, agent application categories, unified multi-rail payments.
Agent = Prompt + Skills[] + MCPInstallation
The current release 0.11.9 is built on the 0.10.0 complete feature release (agent application categories, sessions & parallel tasks, streaming tool_call fix, typed onchain_approval_required SSE event, unified /api/v1/payments endpoint) — with the payment engine on the InfraX-maintained @0xinfrax/payments ^0.1.4. R17.6: 0.1.3 restores the a2a / period rails inside the engine; 0.1.4 adds escrow passthrough / ERC20 deposit / structured 402 errors; the AgentX Gateway delegates to the module rails while keeping the HTTP contract identical, so B-side callers see zero change. Since 0.11.5 (R19.3) the SDK also ships TenantPlanPayments — platform subscription-tier purchases (tenant plans) through the unified payments endpoint — since 0.11.6 the BillingClient for B-end balance pre-checks (R19.7 companion), since 0.11.7 the AgentWalletConfig — agent-owned MPC wallet management (bind an agent to an InfraX MPC wallet + email-code payment-session unlock) so A2A per-call fees auto-pay server-side, since 0.11.8 the A2A Session Key auto-pay surface — end-user wallet-authorized x402-pay session keys that auto-fund the per-call fee when the x402 ledger balance is short (see the "A2A Delegated Tasks & Session Key Auto-pay" section), and since 0.11.9 AgentWalletConfig gains a tenant-scoped apiKey mode — manage the MPC wallets of your own agents with a tenant API Key instead of the platform ADMIN_KEY (SK-1 permission delegation, dual-rail auth on /api/v1/admin/agent-payers). Install and use:
# latest (recommended) — 0.11.9
npm install @agentxv2/sdk
# or pin the exact release
npm install @agentxv2/[email protected]Peer Dependencies
| Package | Version | Required |
|---------|---------|----------|
| react | ^18 or ^19 | yes |
| wagmi | ^2.0 | optional (React hooks only) |
| @tanstack/react-query | ^5.0 | optional (React hooks only) |
| viem | ^2.0 | optional (chain reader only) |
Quick Start
1. Use an Agent with AgentLoop (ReAct autonomous tool calling)
import { AgentRunner, AgentLoop, OpenAIProvider, GatewayProvider } from '@agentxv2/sdk'
const runner = new AgentRunner({ reader, wallet })
const ctx = await runner.useAgent(42)
// Mode A: Pure frontend — direct LLM API
const provider = new OpenAIProvider({ apiKey: 'sk-...', model: 'gpt-4o' })
// Mode B: SaaS multi-tenant — via AgentX Gateway (API key never in browser)
const provider = new GatewayProvider({
gatewayUrl: 'https://agentx.0xainet.top', // 生产域名;本地开发可填 http://localhost:3090
accessToken: 'jwt...',
keySource: 'platform',
})
const loop = new AgentLoop({
ctx,
llmProvider: provider,
maxIterations: 5,
contextBudget: 8000, // NEW: auto-summarize when exceeding token budget
memory: { enabled: true }, // NEW: pgvector cross-session memory (default: disabled)
trace: { enabled: true }, // NEW: structured observability (default: disabled)
onTextDelta: (delta) => appendAssistantMessage(delta),
onToolCall: ({ name, arguments: args }) => showToolBubble(name, args),
onToolResult: ({ name, result }) => updateToolBubble(name, result),
})
await loop.run('Analyze this contract for vulnerabilities')2. React Hook
import { useAgentRunner } from '@agentxv2/sdk/react'
function ChatPage({ agentId }: { agentId: number }) {
const { ctx, isLoading, error } = useAgentRunner({ agentId })
if (isLoading) return <div>Loading...</div>
return <ChatInterface prompt={ctx!.prompt} skills={ctx!.skills} />
}3. Publish an Agent (IPFSUploader + publishAgent pipeline)
import { IPFSUploader, publishAgent } from '@agentxv2/sdk'
const uploader = new IPFSUploader({ pinataJwt: 'eyJ...' })
const result = await publishAgent({
agent: {
name: 'Solidity Auditor',
description: 'AI agent that audits Solidity smart contracts',
version: '1.0.0',
tags: ['security', 'audit'],
category: 'security', // v0.9.4: application category — see AGENT_CATEGORIES
capabilities: ['smart_contract_audit'],
supportedTasks: ['audit'],
communicationProtocol: 'mcp',
authenticationMethod: 'ecdsa',
pricing: { type: 'subscription', amount: '10', currency: '', period: 'month' },
prompt: 'You are an expert Solidity auditor...',
skills: [{ name: 'audit', description: 'Audit a contract', version: '1.0', inputSchema: {...} }],
mcp: { type: 'http', url: 'https://my-mcp.example.com/mcp' },
},
publicKey: '0x04abc...',
uploader,
})
// 3. Mint Agent NFT on-chain
await registry.register(`ipfs://${result.publicCid}`, [
{ key: 'encryptedPayloadCid', value: result.encryptedCid },
{ key: 'eciesEncryptedKey', value: result.eciesEncryptedKeyHex },
])Application category (v0.9.4) — publishing agents now takes a
categoryfield (one ofAGENT_CATEGORIES:operations/customer-service/sales/personal-assistant/coding/server-monitoring/airdrop/quant-trading/data-analysis/content/security/finance/other). It is written into the public metadata + on-chain attrs and drives Marketplace category filtering. The Studio UI enforces it as required; SDK-level it is optional for backward compatibility (agents without it fall back toother).getAllAgents()/getAgentMetadata()return the resolvedcategory.
Encryption & Decryption (Core)
The SDK provides a full E2E encryption pipeline using AES-256-GCM + ECIES (secp256k1).
Low-Level Crypto
import {
aesEncrypt, aesDecrypt,
eciesEncrypt, eciesDecrypt,
generateAesKey, generateKeyPair,
randomBytes,
} from '@agentxv2/sdk/core'
// Generate keys
const keyPair = generateKeyPair()
// → { privateKey: '0x...', publicKey: '0x04...' }
const aesKey = generateAesKey()
// → 64-char hex string (32 bytes)
// AES-256-GCM encrypt/decrypt
const ciphertext = aesEncrypt('Hello, AgentX!', aesKey)
const plaintext = aesDecrypt(ciphertext, aesKey)
// ECIES encrypt/decrypt (key wrapping)
const wrapped = eciesEncrypt(aesKey, keyPair.publicKey)
const unwrapped = eciesDecrypt(wrapped, keyPair.privateKey)High-Level Payload Encryption
import { encryptPayload, decryptPayload, packAgentForPublish } from '@agentxv2/sdk/core'
// Publisher: encrypt agent payload for a subscriber
const encrypted = encryptPayload({
prompt: 'You are a DeFi analyst...',
skills: [{ name: 'audit', ... }],
mcp: { type: 'http', url: '...' },
}, subscriberPublicKey)
// → { aesKeyHex, eciesEncryptedKeyHex, encryptedCid }
// Subscriber: decrypt with private key
const decrypted = decryptPayload(encrypted, subscriberPrivateKey)
// → { prompt, skills, mcp }
// Package agent ready for on-chain registration
const pack = packAgentForPublish(agentPayload, creatorPublicKey)Wire Format
AES-256-GCM: base64( IV[12] || ciphertext || authTag[16] )
ECIES: hex( ephemeralPub[33] || IV[16] || ciphertext || MAC[32] )IPFS Upload
import { IPFSUploader } from '@agentxv2/sdk/ipfs'
// or: import { IPFSUploader } from '@agentxv2/sdk'
const uploader = new IPFSUploader({
pinataJwt: 'eyJ...', // Pinata JWT token
// customEndpoint: 'https://my-ipfs.example.com/api/v0/add',
// customApiKey: '...',
gatewayUrl: 'https://ipfs.io', // default
namePrefix: 'agentx-',
timeoutMs: 30_000, // request timeout
})
// Upload JSON
const { cid, url } = await uploader.uploadJSON(
{ hello: 'world' },
{ name: 'test-data', keyvalues: { app: 'agentx' } }
)
// Upload encrypted agent payload
const encrypted = await uploader.uploadEncryptedPayload(
{ encrypted: true, algorithm: 'AES-256-GCM', data: '...' },
'my-agent'
)
// Get public gateway URL from CID
const publicUrl = uploader.getUrl('QmXxx...')
// → https://ipfs.io/ipfs/QmXxx...MCP Connector (Remote Tool Execution)
import { MCPConnector } from '@agentxv2/sdk/mcp'
// or: import { MCPConnector } from '@agentxv2/sdk'
// Connect to any MCP server
const connector = new MCPConnector({
transport: 'http', // 'http' | 'sse' | 'stdio'
url: 'https://my-mcp.example.com/mcp',
authType: 'ecdsa', // optional: ecdsa signature auth
privateKey: '0x...', // required for ecdsa auth
})
// Discover available tools
const tools = await connector.listTools()
// → [{ name: 'get_balance', description: '...', inputSchema: {...} }, ...]
// Execute a tool remotely
const result = await connector.callTool('get_balance', {
address: '0x1234...',
chainId: 19505,
})
// → { token: 'ETH', balance: '1.5' }ConversationClient (v0.8.7) — Remote Conversation Service
Streams agent conversations from the hosted Conversation Service via the Gateway (POST /api/v1/agent/runs, SSE). Auth requires either a tenant apiKey (X-Api-Key) or a Gateway accessToken (Authorization: Bearer — wallet-signed login). Both credentials unlock the same REST surface — single-turn chat plus sessions & parallel tasks — gated uniformly by the tenant's P9 capability bits; a B-end integration key (agentx_...) alone is sufficient, no second key is needed (only the MCP channel and on-chain operations require a registered-user JWT / the user's own wallet). The client also auto-sends X-End-User-Id (end-user memory isolation), X-Llm-Api-Key + X-Llm-Endpoint + X-Llm-Model (stateless BYOK override — your own key AND endpoint AND model, e.g. DeepSeek). BYOK is the recommended pattern for callers: traffic then runs against your own LLM account, and the platform fallback key is used only when no key is provided.
v0.8.6 — stored BYOK (
tenantKeyId): each chat/stream request can passtenantKeyIdto use a tenant-owned API key already stored & AES-encrypted on the Gateway (managed via Settings → Own LLM Keys, backed by/tenant/keys). The Gateway resolves the key server-side and injects it asX-Llm-Api-Key(priority over request-level headers) — the plaintext key never leaves the server. This complements the statelessllmApiKeyoverride (request-level, highest priority).tenantKeyIds are strictly tenant-scoped: after rotating youragentx_key or switching tenants, re-store a BYOK viaPOST /api/v1/tenant/keyswith the new key and update yourtenantKeyId— reusing another tenant's ID returns400 Tenant API key not found or inactive. v0.8.7 — sessions & parallel tasks:createSession()/createTask()(returns ataskIdimmediately, runs in the background) /getTask()/listTasks()/cancelTask()+getCapabilities(). When the tenant/plan disallows multi-task (P9 capability gate),createTask()is rejected with HTTP 403{ code: "PARALLEL_TASKS_DISABLED" }— surfaced asConversationTaskError(.status/.code); callers should degrade to single-turnchat(). 2026-08-08 — B-end keys clarified: parallel-task capability is now uniform for all tenants. A B-end integration key (agentx_...) is no longer restricted to chat — it can create sessions/tasks exactly like a registered-user JWT, controlled by the same P9 capability bits (effective = tenant.allow_parallel_tasks ?? plan.features.parallel_tasks ?? true).403 PARTNER_TASKS_DISABLEDno longer exists; a disabled tenant gets403 PARALLEL_TASKS_DISABLEDand should fall back tochat()as above. Oneagentx_key is enough — callers do not need a second (wallet-signed) credential for sessions/tasks. Partner task creation additionally requires a BYOK LLM key (X-Llm-Api-Keyheader,llmApiKey, or storedtenantKeyId) — otherwise400 { code: "LLM_KEY_REQUIRED" }— so background work never drains the platform key budget. This gate applies to parallel tasks created via REST/SDK (POST /sessions/:id/tasks); platform-managed background paths (user schedules, orchestration triggers) bypass it and use the storedtenantKeyIdor the platform fallback key.MCP boundary (generic): the "registered-user
access_tokenonly" rule applies to the AgentX platform MCP (Gateway/mcp) — its 6agentx_gateway_*conversation/task tools (agentx_gateway_chat,create_session,create_task,get_task,list_tasks,cancel_task) require a registered-user JWT and reject B-endagentx_keys (R14). MCP servers you deploy yourself (an in-house agent MCP, a RAG MCP, etc.) are outside this boundary — their auth is yours to configure (anonymous, tenant key, or anything else). Use REST orConversationClientif you only hold a B-end key. B-end end-users (e.g. aihunter's customers) are fully covered by REST +X-End-User-Id: 0x<wallet>(end-user subscription proxying) — MCP stays JWT-only for B-end callers by design; bridging "B-end user → AgentX JWT" for MCP would be a separate design item.B-end MCP conversation — alternative paths (2026-08-11): if a B-end caller needs MCP-native conversation for its end-users, use one of these instead of waiting for a "B-end user → AgentX JWT" bridge (kept as a future design item, not implemented):
- Self-hosted MCP wrapper (most common — the RAG MCP pattern): deploy your own MCP server that exposes a conversation tool and internally calls REST with
X-Api-Key+X-End-User-Id. Auth is fully under your control — this lives outside the platform boundary.- Direct REST for HTTP-capable AIs: if the calling AI supports HTTP tool invocation, call
/api/v1/agent/runs(or the SDKConversationClient) directly — a singleagentx_key, withX-End-User-Idsubscription proxying included.- Non-conversation MCP tools are key-usable as-is: 32 of the 38 platform MCP tools (on-chain read/write) accept B-end
agentx_keys — only the 6 conversation/task tools require a registered-user JWT. B-end callers can already use those 32 over MCP without any bridge.B-end end-user auth over MCP conversation — how it works (2026-08-11): the 6 conversation/task tools authenticate only via the
access_tokenargument — a registered-user JWT issued by wallet-signed login (EIP-191). The MCP executor readsaccess_token, drops the call withaccess_token (registered-user JWT) is requiredif absent, and forwards it asAuthorization: Bearerto the Gateway REST channel; B-endagentx_keys are rejected on these tools (R14). Subscription gating therefore resolves against the JWT holder's wallet. A B-end end-user who is not a registered AgentX user has no wallet-signed JWT and cannot call these tools directly — that is by design: their identity (and subscription) is proxied through the B-end key +X-End-User-Id: 0x<wallet>on REST instead. If MCP-native conversation for such end-users is ever required, the bridge keeps the same semantics as REST — exchange (B-end key + end-user subscription check) for a short-lived scoped JWT (sub=partner-<slug>,end_user=0x<wallet>, TTL ~5 min, no refresh) so the MCP tools still do their subscription check against the end-user wallet. Until then, paths 1–3 above apply.B-end end-user auth over MCP conversation — step-by-step flow (2026-08-11): the same call goes through two distinct auth paths depending on the caller's credential:
- Registered user (JWT) —
agentx_gateway_chatwithaccess_token=eyJ...:
- MCP executor calls
gatewayAuthHeaders()→ token present →Authorization: Bearer <JWT>.- Forwards to Gateway
POST /api/v1/agent/runs.- Gateway resolves the access subject as the JWT holder's wallet, then
canAccessAgent(wallet, agentId)checks on-chain ownership/subscription —403 AGENT_ACCESS_DENIEDif the JWT wallet holds no subscription to the target agent.- SSE stream returned, aggregated into the MCP tool result
{ reply, tool_calls }.- B-end end-user (partner key + proxied wallet) — the same conversation over REST:
X-Api-Key: agentx_...+X-End-User-Id: 0x<endUserWallet>→POST /api/v1/agent/runs.resolveAccessSubject()(see gateway agent-access.ts) detectskind=partner+ hexendUserIdand substitutes the end-user's wallet as the access subject.canAccessAgent(endUserWallet, agentId)gates on the end-user's on-chain subscription (not the partner tenant's).- Same SSE stream, same
{ reply, tool_calls }shape — the two paths differ only in credential exchange, never in conversation behavior.Decision rule: a B-end caller holds only
agentx_keys → use REST (path 1 or 2 above); a registered user holds a wallet-signed JWT → MCP is available as-is; a B-end caller that insists on MCP-native conversation for unregistered end-users → future bridge (above), not yet implemented.B-end key vs user JWT — sessions/tasks behavior (v0.10.1): both credentials are gated by the same P9 capability bits and can create sessions/parallel tasks; the differences are (1) access subject — a B-end key authorizes as the partner tenant, or as a proxied end-user wallet when
endUserIdis a0xaddress; a JWT authorizes as the user's own wallet; (2) task LLM key — partner tasks may use their own BYOK key (X-Llm-Api-Key/llmApiKey/tenantKeyId), or fall back to the platform key, which is metered against the tenant's plan quota (exact token counts from the task'sdoneevent — via SSE for streamed tasks and via a completion callback for background tasks); (3) platform MCP chat/task tools and on-chain A2A/publish/subscribe are available to JWTs only. A B-end key covers all REST chat + parallel tasks; a JWT additionally covers MCP and on-chain.
endUserIdis always optional — omitting it is NOT rejected (2026-08-08 clarification): without it the access subject falls back to the tenant's own wallet — for a registered user (kind=user) that is the user's wallet (works naturally); for a partner tenant it simply means no end-user proxying (thepartner-*address is not an on-chain address, so subscription-gated agents return403 AGENT_ACCESS_DENIEDwhen the chain check fails — not a "missing endUserId" rejection). A non-0xendUserIdis used for memory isolation only. There is no "must send endUserId" enforcement anywhere.
import { ConversationClient } from '@agentxv2/sdk/conversation'
const client = new ConversationClient({
gatewayUrl: 'https://gateway.example.com', // Gateway base URL (not the conversation service directly)
apiKey: 'agentx_...', // tenant API key issued after registration (OR accessToken below)
// accessToken: 'eyJ...', // gateway JWT from wallet-signed login (alternative to apiKey)
endUserId: 'user-123', // optional: per-end-user memory isolation
llmApiKey: 'sk-...', // optional: BYOK — your own LLM key (highest priority)
llmEndpoint: 'https://api.deepseek.com/v1', // optional: endpoint for llmApiKey (default OpenAI)
llmModel: 'deepseek-v4-pro', // optional: model for llmApiKey (default gpt-4o)
timeoutMs: 120_000, // optional: stream timeout (default 120s)
})
// Stream events (text / tool_call / tool_result / thinking / clarification / onchain_approval_required / done / error)
const controller = new AbortController() // optional: external stop (user "Stop" button)
for await (const event of client.stream({
agentId: 42,
message: 'Analyze this contract',
enableMemory: true,
history: [{ role: 'user', content: 'hi' }],
tenantKeyId: 'key-01HX...', // v0.8.6: BYOK via a stored tenant-owned API key (Settings → Own LLM Keys)
}, { signal: controller.signal })) {
switch (event.type) {
case 'text': appendDelta(event.content!); break
case 'tool_call': showToolBubble(event.toolName!, event.toolArgs); break
case 'tool_result': updateToolBubble(event.toolName!, event.toolResult); break
case 'thinking': setThinking(event.content!); break
case 'clarification': askUser(event.question!); break // request was ambiguous — prompt the user
case 'onchain_approval_required':
// v0.9.6+: the agent requested an auditable on-chain A2A delegation.
// The USER must approve it in their own wallet (they pay the gas and
// become the on-chain client). Show a wallet modal with
// event.approval = { targetAgentId, taskType, inputData }.
openWalletModal(event.approval!); break
case 'done': onDone(event.usage); break
case 'error': onError(event.error!); break
}
}
// Or aggregate into a single result
const result = await client.chat({ agentId: 42, message: 'Hello' })
// → { text, toolCalls: [{ name, arguments, result }], usage, iterations }
// When the service interrupts an ambiguous request, result.clarification carries
// the clarifying question and no tools were run:
if (result.clarification) {
const answer = await promptUser(result.clarification)
const retry = await client.chat({ agentId: 42, message: answer, history: [...prevHistory, ...] })
}
// Inline mode — no AgentX agent needed; inject your own MCP/HTTP tools (e.g. RAG)
const ragResult = await client.chat({
message: '根据知识库回答:AgentX 支持哪些链?',
prompt: '你是客服助手,回答前先调用 rag_query 检索知识库。',
skills: [{
name: 'rag_query',
description: 'Retrieve relevant chunks from the knowledge base',
inputSchema: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] },
execution: { type: 'mcp', endpoint: 'https://your-rag-mcp.example.com/mcp', toolName: 'rag_query' },
}],
enableMemory: false,
})Auth: the
apiKeyset in the constructor is sent automatically asX-Api-Key(tenant API key) — the RAG example above needs no per-request credentials. Your RAG MCP/HTTPexecution.endpointstays under your control: secure it with your own auth, the service only forwards the call (30s timeout). Sub-path import:@agentxv2/sdk/conversation. Server-side API & headers documented inCONVERSATION_SERVICE.md.
Sessions & Parallel Tasks (v0.8.7)
Create a dialog session, fire multiple tasks into it, poll them in the background and cancel when needed:
import { ConversationClient, ConversationTaskError } from '@agentxv2/sdk/conversation'
const client = new ConversationClient({ gatewayUrl: 'https://gateway.example.com', accessToken: 'eyJ...' })
// (optional) check the integrator's capability first — when false, use single-turn chat() instead
const caps = await client.getCapabilities()
if (!caps.parallelTasks) {
const r = await client.chat({ agentId: 42, message: 'hello' })
}
const session = await client.createSession({ title: 'Audit' }) // dialog container (idempotent)
const t1 = await client.createTask({ sessionId: session.id, agentId: 42, message: 'Analyze contract A' })
const t2 = await client.createTask({ sessionId: session.id, agentId: 42, message: 'Analyze contract B' })
// → both return immediately with { id, status: 'queued' } — execution runs in the background
const tasks = await client.listTasks(session.id) // all tasks of the session
let task = await client.getTask(t1.id) // poll until terminal
// task.status: queued → running → done / error / cancelled
try {
await client.cancelTask(t2.id) // cancel queued/running task
} catch (err) {
if (err instanceof ConversationTaskError && err.code === 'PARALLEL_TASKS_DISABLED') {
// tenant/plan disallows multi-task → fall back to single-turn chat()
}
}B-end subscription proxying (v0.10.1, Gateway 2026-08-08): a partner caller can authorize by an end-user's subscription by passing that user's wallet via
endUserId(0x<wallet>;createSession/createTaskparams, orX-End-User-Idheader). The Gateway then checks ownership/subscription against that wallet instead of the partner tenant itself — so "my end-user already subscribed → I may chat on their behalf". Non-0xend-user ids remain memory-isolation-only.stream(params)acceptsparams.endUserIdtoo (per-request override of the constructor-level id).
On-Chain Data (v0.8.1) — Batch Query + Subscription Writes + Event Stream
Replaces hand-rolled ethers.js + manual ABI/parseLog code. All methods accept viem PublicClient / WalletClient (chain-agnostic).
完整接入样例(SDK / MCP / REST 三通道 + 关键约定):docs/sdk-integration-example.md 可运行的 SDK 链上读取完整样例(生产地址):examples/sdk-chain-read.ts 可运行的 SDK 写操作样例(创建套餐,需私钥):examples/sdk-create-plan.ts
IdentityRegistry — batch read
import { AgentRegistry } from '@agentxv2/sdk'
const registry = new AgentRegistry({ contractAddress, publicClient, walletClient })
const total = await registry.totalAgents() // reads totalAgents() — replaces binary search
const agents = await registry.getAllAgents({
fromId: 1, // default 1
// toId: 100, // default: totalAgents()
activeOnly: true, // default false — metadata.isActive === true
capabilities: ['trading'], // AND filter on metadata.capabilities
batchSize: 10, // RPC batching (default 10)
})
// → [{ agentId, owner, tokenURI, metadata: { name, description, capabilities, skills, isActive }, createdAt }]
const meta = await registry.getAgentMetadata(1)
// → { name, description, encryptedPayloadCid, eciesEncryptedKey, publicPayloadCid,
// capabilities, skills, isActive }v0.8.1 容错解析:tokenURI 可能因合约 bug 损坏(base64 尾部垃圾 / JSON 未闭合)。
getAllAgents()/getAgentMetadata()会自动清理尾部垃圾、补齐未闭合引号/花括号, 仍失败时以 regex 兜底提取name,最终回退为Agent {id}——与 Gateway indexer 行为一致, 不会因单条损坏数据导致整批查询失败。
SubscriptionManager — write + event-parsed results
import { SubscriptionManager } from '@agentxv2/sdk'
const sm = new SubscriptionManager({ contractAddress, publicClient, walletClient })
// period MUST be one of 'day' | 'week' | 'month' | 'year' — the only values the
// contract maps to real durations. 'monthly'/'quarterly'/'yearly' silently become
// 30 days on-chain, so they are rejected at runtime.
const { planId, txHash } = await sm.createPlan({
agentId: 42,
price: 5000000000000000n, // wei
period: 'month',
payToken: '0x0000...', // default: native token
trialDays: 0,
})
const sub = await sm.subscribe(planId, { valueWei: 5000000000000000n })
// → { subscriptionId, txHash, subscriber, agentId, expiresAt } // parsed from Subscribed event
const combined = await sm.createPlanAndSubscribe({ agentId: 42, price: 1n, period: 'day' })
// → { planId, subscriptionId, txHash, subscriber, agentId, expiresAt }v0.8.2 写操作签名修复:
createPlan()/subscribe()/releaseFunds()/cancel()现在优先使用完整的 viemwalletClient.account(含签名能力),支持本地私钥签名场景 (privateKeyToAccount→eth_sendRawTransaction);浏览器钱包(MetaMask 等, json-rpc account)行为不变。此前传入裸地址字符串会走eth_sendTransaction(仅节点托管账户),本地签名时被 RPC 拒绝(unknown account)。 写操作完整样例:examples/sdk-create-plan.ts
subscribeToEvents — event-driven sync (< 15s vs 2min polling)
import { subscribeToEvents } from '@agentxv2/sdk'
const unwatch = await subscribeToEvents(publicClient, {
identityRegistryAddress,
subscriptionManagerAddress,
events: ['Transfer', 'AgentRegistered', 'PlanCreated', 'Subscribed'],
fromBlock: 123456,
onEvent: ({ type, args, txHash }) => {
if (type === 'AgentRegistered') syncAgent(Number(args.agentId))
},
})
// ... later: unwatch()A2A Daemon — Multi-Agent Interop
import { A2ADaemon } from '@agentxv2/sdk/agent-loop'
const a2a = new A2AProtocol({
contractAddress: '0x7F42a7dC4A0F3C107664C3750bE1B5B6fa6BEb86',
publicClient,
walletClient,
})
// Start daemon — auto-processes incoming A2A tasks
const daemon = new A2ADaemon({
agentId: 53,
a2a,
gatewayUrl: 'https://agentx.0xainet.top', // 生产域名;本地开发可填 http://localhost:3090
pollIntervalMs: 15000,
autoComplete: true,
})
daemon.on('taskCompleted', (result) => {
console.log(`Task #${result.task.taskId} completed!`, result.txHash)
})
daemon.start()
// daemon.stop()Flow:
Agent A → createTask(Agent B) on-chain
Gateway Worker → detects → LLM processes → stores result
SDK A2A Daemon → polls Gateway → gets result → completeTask() on-chainArchitecture
┌─────────────────────────────────────────────────────────────┐
│ @agentxv2/sdk │
├──────────┬──────────┬──────────┬───────────────────────────┤
│ Core │ Agent │ AgentLoop│ React │
│ crypto │ Runner │ executor │ useAgentRunner │
│ types │ useAgent │ loop │ │
├──────────┼──────────┼──────────┼───────────────────────────┤
│ Registry │ Subscrip │ A2A │ Reputation │
│ register │ subscribe│ protocol │ giveFeedback │
│ query │ verify │ daemon │ │
├──────────┼──────────┼──────────┼───────────────────────────┤
│ MCP │ IPFS │ LLM │ Config │
│ Connector│ Uploader │ Factory │ Chains │
│ │ │ OpenAI │ │
│ │ │ Gateway │ │
├──────────┼──────────┼──────────┼───────────────────────────┤
│ Endpoint │ConfigReg │ Payment │ AgentWallet │
│ MultiEP │ KV Store │ Gateway │ │
└──────────┴──────────┴──────────┴───────────────────────────┘API Reference
Main Exports
| Export | Module | Description |
|--------|--------|-------------|
| AgentRunner | agent | Decrypt + load Agent context from chain |
| AgentLoop | agent-loop | ReAct engine: Think → Tools → Observe → Repeat |
| OpenAIProvider | llm | Direct LLM provider with SSE streaming |
| GatewayProvider | llm | Multi-tenant SaaS LLM via AgentX Gateway |
| createLLMProvider | llm | Auto-select provider based on config |
| MCPConnector | mcp | MCP tool discovery + remote execution |
| AgentRegistry | registry | Register and query agents on-chain |
| SubscriptionManager | subscription | Subscribe (ETH/ERC20), verify, cancel, trial |
| subscribeToEvents | events | Contract event stream (Transfer/AgentRegistered/PlanCreated/Subscribed) |
| AgentX402 | subscription | Auto-subscription gate + X402 payment |
| A2AProtocol | a2a | Agent-to-Agent task delegation |
| A2ADaemon | agent-loop | Background daemon for auto-processing A2A tasks |
| ReputationRegistry | reputation | Feedback + reputation queries |
| ConfigurationRegistry | configuration | On-chain KV configuration |
| MultiEndpointClient | endpoint | Multi-endpoint routing |
| IPFSUploader | ipfs | Upload to IPFS via Pinata or custom endpoint |
| publishAgent | core | Full encrypt + IPFS upload + pack pipeline |
| KNOWN_CHAINS | config | Pre-configured chain configs |
Crypto Exports (from @agentxv2/sdk/core)
| Export | Description |
|--------|-------------|
| aesEncrypt(plaintext, keyHex) | AES-256-GCM encrypt → base64 |
| aesDecrypt(ciphertext, keyHex) | AES-256-GCM decrypt |
| generateAesKey() | Generate random 256-bit AES key (hex) |
| eciesEncrypt(dataHex, publicKey) | ECIES encrypt with secp256k1 public key |
| eciesDecrypt(dataHex, privateKey) | ECIES decrypt with secp256k1 private key |
| encryptPayload(payload, pubKey) | One-shot: AES encrypt + ECIES wrap |
| decryptPayload(encrypted, privKey) | One-shot: ECIES unwrap + AES decrypt |
| packAgentForPublish(payload, pubKey) | Package agent for on-chain registration |
| publishAgent(config) | Full pipeline: encrypt + IPFS upload |
| generateKeyPair() | Generate secp256k1 key pair |
| getPublicKey(privateKey) | Derive public key from private key |
| randomBytes(length) | CSPRNG random bytes (cross-runtime) |
Sub-path Imports
| Path | Description |
|------|-------------|
| @agentxv2/sdk | All modules (main entry) |
| @agentxv2/sdk/core | Types, crypto (AES-256-GCM + ECIES) |
| @agentxv2/sdk/react | useAgentRunner React hook |
| @agentxv2/sdk/agent-loop | AgentLoop, executor, tool builder, A2A daemon |
| @agentxv2/sdk/llm | OpenAIProvider, GatewayProvider, factory |
| @agentxv2/sdk/endpoint | MultiEndpointClient |
| @agentxv2/sdk/configuration | ConfigurationClient |
| @agentxv2/sdk/ipfs | IPFSUploader (Pinata + custom endpoint upload) |
| @agentxv2/sdk/memory | MemoryProvider interface + types (v0.6.9) |
| @agentxv2/sdk/traces | TraceEmitter interface + types (v0.6.9) |
| @agentxv2/sdk/skills | Browser control skill utilities (v0.6.9) |
| @agentxv2/sdk/conversation | ConversationClient — remote Conversation Service client (v0.7.0) |
Encryption Pipeline
Publisher creates Agent:
AgentPayload → AES-256-GCM encrypt → IPFS (CID)
AES key → ECIES wrap → on-chain NFT metadata
Mint Agent NFT via IdentityRegistry
Subscriber uses Agent:
Verify subscription (SubscriptionManager)
Fetch encrypted payload from IPFS
Read ECIES-wrapped key from on-chain NFT
Decrypt → { prompt, skills, mcp }
skills[n].execute() → Open (local) or MCP (remote with ECDSA auth)Supported Chains
| Network | Chain ID | RPC | Gas Token |
|---------|----------|-----|-----------|
| OxaChain L1 | 19505 | https://rpc-oxa.0xainet.top | OXA |
| Sepolia (Testnet) | 11155111 | https://ethereum-sepolia-rpc.publicnode.com | ETH |
On-Chain Contracts
OxaChain L1 (Mainnet)
| Contract | Address |
|----------|---------|
| IdentityRegistry | 0xbf5F9db266c8c97E3334466C88597Eb758AfE212 |
| SubscriptionManager v3 | 0x019AC9d945467478Dd371CDbD70cb2f325800E6B |
| A2AProtocolRegistry v2 | 0x7F42a7dC4A0F3C107664C3750bE1B5B6fa6BEb86 |
| ReputationRegistry | 0x6a18C2664E1b42063860d864b6448b824d7B843F |
| ConfigurationRegistry | 0x07280674ccc2898Fd038A9e3C22005CA83ffD2F8 |
| MultiEndpointRegistry | 0xB361d04F49000013FC131D3C59C41c8486C64f8c |
Sepolia (Testnet)
| Contract | Address |
|----------|---------|
| IdentityRegistry | 0xe94ad380d3F8d08a7590eda0C84f354a93F96e5F |
| SubscriptionManager v3 | 0xC15fE80b9d800abb72121F353a6ae6d6E9077E63 |
| A2AProtocolRegistry v2 | 0x309C7447d89f3087A9924BB686d88df020F7e9cB |
| ReputationRegistry | 0xeb6B410ea71b8d9dA0c96f6A91d35027CE143DC9 |
| ConfigurationRegistry | 0x68DcE00e4C9077c94BC68016cD14B09557faEA6c |
| MultiEndpointRegistry | 0xEB5e866f186d4B73F97aa0d70B86f2C6e2e21Cb7 |
Gateway Integration
For multi-tenant SaaS deployments, the Gateway package (@agentxv2/gateway) provides:
npm install @agentxv2/[email protected]Features: wallet-based auth (EIP-191 + JWT), rate limiting (IP + tenant), LLM proxy (OpenAI/DeepSeek), MCP server, A2A background worker, admin dashboard API, PostgreSQL + Redis persistence.
Configuration: 26 environment variables — see gateway/.env.example.
Payment Method Decision Guide (v0.11.7)
AgentX exposes several payment rails. Pick by what is being paid for, who pays, and whether a wallet is present:
| Payment | What it pays for | Payer | Wallet? | Best for | SDK entry |
|---|---|---|---|---|---|
| chain | subscribing to a paid Agent (on-chain escrow) | end user | yes | crypto-native users; auditable on-chain subscription; publisher gets 97.5% | SubscriptionPayments.pay({ method: 'chain' }) |
| fiat | subscribing to a paid Agent (Stripe card) | end user | no | Web2 users without a wallet; credit-card checkout | SubscriptionPayments.pay({ method: 'fiat' }) → sessionUrl |
| x402 | subscribing or pay-per-call (native-token balance) | end user (balance) | yes (only to fund) | frictionless per-call / auto-funding; server-side A2A pay-per-call (R19.7) | X402Client · BillingClient pre-check |
| tenant-plan | platform subscription tier (daily quota / rate limits) | B-end tenant | yes (chain/x402) or no (fiat) | B-end buying platform capabilities, not Agent access | TenantPlanPayments.buy() |
| mpp | high-frequency batched payments via a payment channel | payer | yes | repeated micro-payments without per-tx gas | MPPClient |
| period | pre-authorized N periods, charged later without re-signing | payer | yes | recurring billing / subscription periods | PeriodClient |
| a2a (on-chain) | auditable multi-agent delegation (task + gas) | user's wallet | yes | cross-org delegation, settlement, reputation | A2AProtocol + onchain_approval_required SSE |
Decision rules
- Subscribing to a paid Agent →
chain(wallet) /fiat(no wallet) /x402(auto-funded);hasAccess()unifies the check (chain OR fiat/x402). - Buying platform quota/tier as a B-end tenant →
TenantPlanPayments. - Pay-per-call delegation → pre-check with
BillingClient(endUserIdwallet), then let the Gateway auto-deduct from the x402 balance (server-side, R19.7 — zero caller changes). - Auditable / settled delegation → on-chain
A2AProtocol(the user's wallet signscreateTaskand pays the gas; the platform never holds a signing key).
Frontend adaptation
- Connect a wallet via wagmi + viem (
oxaChain, chainId 19505) for thechain/x402/a2arails;fiatonly needs a redirect (window.location.assign(sessionUrl)). - Renewal UI (three-rail picker):
SubscriptionPayments.pay({ method })→fiatreturnssessionUrlto redirect;x402/chainreturn atxHashto verify + refresh access. - Pay-per-call:
BillingClient.getBalance({ endUserId })before delegating; ifbalanceWei < priceWei, prompt a top-up topayTo. - On-chain approval: on SSE
onchain_approval_required, show a wallet modal so the user signscreateTask(they pay gas) — see the frontendOnchainApprovalModal. - Runnable B-end examples (Chinese): docs/sdk-integration-example.md.
Multi-Rail Subscription Payments (v0.9.4)
SubscriptionPayments is the single entry point for subscribing across every AgentX payment rail — chain (on-chain escrow), fiat (Stripe card via the Gateway) and x402 (native-token period payment). fiat / x402 / hasAccess() go through the unified /api/v1/payments endpoint (the @0xinfrax/payments engine); chain works fully off-Gateway.
import { SubscriptionManager, SubscriptionPayments } from '@agentxv2/sdk'
const sm = new SubscriptionManager({ contractAddress, publicClient, walletClient })
const payments = new SubscriptionPayments({
gatewayUrl: 'https://gw.example.com', // required for fiat / x402 rails
subscriptionManager: sm, // required for chain rail & x402 auto-funding
walletClient,
chain: 'oxachain',
})
await payments.pay({ method: 'chain', planId: 1, agentId: 3 }) // on-chain escrow
const { sessionUrl } = await payments.pay({ // Stripe redirect
method: 'fiat', planId: 1, agentId: 3, subscriber: '0xabc',
}) // amount auto-priced from plan
await payments.pay({ method: 'x402', planId: 1, agentId: 3, subscriber: '0xabc' }) // auto-funded native payment
const ok = await payments.hasAccess(3, '0xabc') // unified chain-OR-fiat/x402 checkpay({ method })returns a discriminated result:{ method: 'chain', subscriptionId, txHash }/{ method: 'fiat', sessionUrl, sessionId, redirect: true }/{ method: 'x402', subscriptionId, txHash, creditedWei }.- For
fiat,amountCentsis optional — the Gateway derives the USD amount from the on-chain plan price (FIAT_TOKEN_USD_PRICE). SupplyamountCentsto override. - For
x402withouttxHash, the payment is sent automatically fromwalletClient(max of plan price / protocol price), then verified & registered by the Gateway.
TenantPlanPayments (v0.11.5) — platform subscription-tier purchases
Since 0.11.5 (R19.3) integrators can purchase a platform subscription tier (tenant plan) through the same unified payments endpoint. The business binding is purpose='tenant-plan' + tenantPlanId — the Gateway verifies the on-chain payment (chain / x402 rails) or Stripe checkout (fiat), then binds the plan to the tenant (quota / rate limits / platform models).
import { TenantPlanPayments } from '@agentxv2/sdk'
const plans = new TenantPlanPayments({
gatewayUrl: 'https://gw.example.com', // required for fiat / x402 rails
chain: 'oxachain',
})
// chain / x402 rail — supply the on-chain payment tx, then the plan is bound
const { tenantId, planId, planSlug, quotaDaily } = await plans.buy({
method: 'x402', tenantPlanId: '...', subscriber: '0xabc', txHash: '0x...',
})
// fiat rail — returns a Stripe checkout URL (webhook binds on completion)
const { sessionUrl } = await plans.buy({
method: 'fiat', tenantPlanId: '...', subscriber: '0xabc',
successUrl: 'https://app.example.com/b/success', cancelUrl: 'https://app.example.com/b',
})buy({ method })returns a discriminated result:{ method: 'fiat', sessionUrl, sessionId, redirect: true }/{ method: 'chain' | 'x402', tenantId, planId, planSlug, quotaDaily, txHash }.- chain / x402 必须携带
txHash(先由调用方发起链上支付再提交);fiat 无需txHash,返回 Stripe checkout 跳转链接。 PaymentsClient.create({ purpose: 'tenant-plan', ... })accepts the samepurposemetadata for raw protocol-level purchases.- Insufficient funds → the Gateway rejects with HTTP 422 before binding the plan.
BillingClient (v0.11.6) — B-end balance pre-check
Since 0.11.6 (R19.7 companion) B-end integrators can query the x402 ledger balance before delegating to an unsubscribed agent — no more guessing whether the next pay-per-call will hit HTTP 403 AGENT_ACCESS_DENIED (insufficient balance). Backed by GET /api/v1/billing/balance (read-only, idempotent, no side effects).
import { BillingClient } from '@agentxv2/sdk'
const billing = new BillingClient({
gatewayUrl: 'https://gw.example.com',
apiKey: 'agentx_xxx', // or accessToken
})
// tenant balance (default)
const { balance, balanceWei, currency, updatedAt, payTo, priceWei } = await billing.getBalance()
// per-end-user balance (partner callers may proxy an end-user's 0x wallet)
const userBalance = await billing.getBalance({ endUserId: '0xabc…' })
// pre-check before a pay-per-call delegation (R19.7)
if (priceWei && BigInt(balanceWei) < BigInt(priceWei)) {
// insufficient — show a top-up prompt: send native token to `payTo`
}getBalance()never throws on a zero / never-funded balance —balanceis"0"(normal response).balanceis a high-precision OXA decimal string ("1.500000000000000000"); usebalanceWei(raw wei string) for exact comparison againstpriceWei.payTo/priceWeiare present only when x402 is enabled (the optional enhancement), so callers can build a funding prompt directly.- Auth: same as
ConversationClient—X-Api-Key(tenant key) or Bearer JWT.401on missing/invalid auth;403on a suspended account. - Legacy partner tenants keyed by a logical name (e.g.
partner-xxx) hold no on-ledger balance — the pay-per-call ledger is keyed by the end user's0xwallet that signs the delegation. For these callers the default (tenant) query returns"0"; always pre-check withgetBalance({ endUserId })(the wallet the delegation will charge).
CentralAgentClient (v0.11.11) — 中心化 Agent(C-6,链下市场)
Since 0.11.10 the SDK can pay for centralized-agent subscriptions — SubscriptionPayments.pay({ method: 'x402', agentId, planId, priceWei, period }) uses the off-chain central_plans price (negative agentIds live in the Gateway DB, not on-chain). Since 0.11.11 the read side is wrapped in CentralAgentClient so third-party integrators (e.g. AItrader) don't need to hand-roll the Gateway HTTP calls:
import { CentralAgentClient } from '@agentxv2/sdk'
const central = new CentralAgentClient({ baseUrl: 'https://agentx.0xainet.top' })
// 查询中心化 Agent 列表(固定 source='central',公开)
const { agents, total } = await central.list({ activeOnly: true, category: 'finance', page: 1, pageSize: 20 })
// 单个 Agent 详情 + 订阅计划(与链上同一结构,可直接喂给 SubscriptionPayments.pay)
const detail = await central.get(-3)
const plan = detail.subscriptionPlans![0]
// 订阅状态(resolveAccess 链下优先 —— 与 App 内订阅守卫同一判定)
const { active } = await central.checkSubscription('0xabc…', -3)
// 我的中心化订阅(fiat_subscriptions / x402 通道)
const { subscriptions } = await central.mySubscriptions('0xabc…')// 中心化 Agent 周期订阅 —— 同一付费通道,priceWei 覆盖链下计划价格
const payments = new SubscriptionPayments({
gatewayUrl: 'https://agentx.0xainet.top',
subscriptionManager: sm, walletClient, chain: 'oxachain',
})
const result = await payments.pay({
method: 'x402', subscriber: '0xabc…', agentId: -3, planId: plan.planId,
period: 'month', priceWei: BigInt(plan.price),
})- 所有读端点公开(无需鉴权);发布(
POST /api/v1/agents/central)需 JWT 或租户 Key,由调用方自持直调网关。 - 订阅付费走与链上 Agent 相同的 x402 通道,支付写入
fiat_subscriptions后resolveAccess无感放行。
A2A Delegated Tasks & Session Key Auto-pay (v0.11.8)
Since 0.11.8 (AItrader REQ-1/2/3) integrators can read the full A2A delegated-task result (incl. the awaiting_payment state + payment options), drive the Session Key auto-pay flow (user wallet authorizes an x402-pay session key against the engine; the Gateway auto-transfers from it when the x402 ledger balance is short), and query the Session Key authorization status — all through ConversationClient.
import { ConversationClient, A2A_STATUS } from '@agentxv2/sdk'
const client = new ConversationClient({
gatewayUrl: 'https://gw.example.com',
apiKey: 'agentx_xxx', // or accessToken
endUserId: '0xuser…', // = the delegation's payment_payer (for retry)
})
// 1) task result — status 4 = awaiting_payment, carries payment_pay_options
const result = await client.getA2ATaskResult(7)
if (result.status === A2A_STATUS.AWAITING_PAYMENT && result.payment_pay_options?.sessionKey) {
// render the "authorize Session Key" entry (prepay + sessionKey both offered)
}
// 2) engine capability info — end-user frontend reaches the engine's public
// nonce / createSession endpoints directly (EIP-712-verified)
const info = await client.getSessionKeyInfo() // { enabled, chain, chainId, baseUrl }
// 3) after the user authorized + funded the session, re-activate the task
const { retried } = await client.retryA2ATask(7) // no ledger deduction; worker re-pays via session key
// 4) REQ-3: ledger balance + Session Key authorization status
const bal = await client.getBalance()
// bal.sessionKey = { enabled, authorized, sessionAddress?, maxTotal?, totalSpent?, validUntil? }getA2ATaskResult/retryA2ATask/getSessionKeyInfohit the Gateway's/api/v1/a2a/…routes;getBalancehits/api/v1/billing/balance(same auth asBillingClient, but viaConversationClient).retryA2ATaskrequires the caller to be the task'spayment_payer(X-End-User-Id) or an admin key — it re-activates a suspended task without deducting from the ledger; the worker re-runs and auto-pays through the session-key branch.- If the Session Key engine is not configured (or escrow is enabled),
getSessionKeyInfo()returns{ enabled: false, … }andgetBalance().sessionKey = { enabled: false, authorized: false }— the feature degrades cleanly to the existing prepay path.
Protocol Clients (v0.9.3)
Since 0.9.3 the SDK re-exports the generic engine's protocol clients from the root, so integrators can drive the P2-P4 rails directly against any Gateway deployment (AgentX-hosted or your own):
import { MPPClient, A2AClient, PeriodClient, X402Client, PaymentsClient } from '@agentxv2/sdk'
const base = { baseUrl: 'https://gw.example.com', accessToken: 'jwt...' } // accessToken optional
const mpp = new MPPClient(base) // payment channels
const a2a = new A2AClient(base) // two-phase paymentId (create → settle)
const period = new PeriodClient(base) // period authorizations (charge / state)
const x402 = new X402Client(base) // x402 v2 protocol (quote / pay / verify / balance)
const uni = new PaymentsClient(base) // unified create / verify / access / info / quote| Client | Endpoints | Typical flow |
|--------|-----------|--------------|
| MPPClient | /api/v1/payments/mpp/{open,voucher,topup,settle,close,session} | open a channel → submit signed cumulative vouchers (voucher, idempotent mode: 'reuse') → auto-settle / close |
| A2AClient | /api/v1/payments/a2a, /api/v1/payments/a2a/settle | create({ payer, amountWei }) → payer pays on-chain → settle({ paymentId, txHash }) (idempotent) |
| PeriodClient | /api/v1/payments/period/charge, /period/authorization | one-time pre-authorization for N periods, then charge(authorizationId) per period — no re-signing |
| X402Client | /api/v1/x402/{info,verify,balance}, quote/pay (v2 headers) | quote(url) fetches the PAYMENT-REQUIRED challenge; pay({ url, walletClient, account }) funds + signs + replays in one call |
| PaymentsClient | /api/v1/payments + /verify /access /info /quote | create({ method: 'fiat'|'x402'|... }), verify(txHash), access(subscriber, agentId), info() rails discovery |
Dependency note: the clients come from
@0xinfrax/payments^0.1.3(currently 0.1.3, InfraX-maintained — the former AgentX-maintained@agentxv2/paymentsis deprecated), auto-installed as a dependency of@agentxv2/sdk.PAYMENT_VERSION('0.1.3'— the aligned engine API version) is also exported from the SDK root. Browser/bundler safe: the engine uses only the Web Crypto API — no Node built-ins (node:crypto/Buffer) — so webpack/Next.js builds no longer fail onUnhandledSchemeError. Endpoints must be exposed by the Gateway the client points at (MPP/period/a2a routes exist on AgentX Gateway/api/v1/payments/*).
Multi-Agent Orchestration Layering (v0.10.0)
Multi-agent delegation follows a two-rail layering strategy so integrators get real-time, zero-cost orchestration by default and only pay for on-chain guarantees when they need them:
| Rail | When to use | Cost | Guarantees | |------|-------------|------|-----------| | off-chain (default) | same-platform, high-frequency, real-time conversational delegation | zero (no on-chain writes) | result returns synchronously in the conversation channel | | on-chain (opt-in) | cross-org, settlement / reconciliation, reputation accumulation, third-party verification | gas paid by the user's wallet + task tx | auditable A2A taskId, on-chain record, settlement & reputation hooks |
v0.10.0 gas model (2026-08-08): on-chain rail costs are never paid by the platform. When the user explicitly requests an auditable / settled delegation, the Conversation Service emits an
onchain_approval_requiredSSE event and the user's own wallet submitscreateTask— they pay the gas and become the on-chainclientAddress(the contract recordsclientAddress = msg.sender). The Gateway no longer holds any signing key (A2A_WORKER_PRIVATE_KEYremoved) and never writes to the chain; sub-tasks created by the a2a-worker run off-chain inline (local negative pseudo taskIds), so only the top-level task the user signs is on-chain.
Inside a conversation run, the main agent is given two platform tools (injected by the Conversation Service, same access boundary as chat — only agents the caller owns or is subscribed to):
agentx_list_agents— discover the agents the caller may delegate to (id / name / description / category).agentx_delegate—{ targetAgentId, message, mode? }. Defaultmode: "offchain": the sub-agent runs synchronously inside the conversation channel and its final answer returns to the main agent in real time. When the user explicitly requests an auditable / settled / on-chain delegation (e.g. "上链", "可审计", "结算", "on-chain", "audit"), usemode: "onchain": the service emitsonchain_approval_requiredand the user signs the A2AcreateTaskin their own wallet (they pay the gas); the returnedtaskIdis the audit trail, picked up by the Gateway A2A worker and recorded ina2a_task_results.
Platform configuration (Conversation Service env):
ORCHESTRATE_TOKEN=... # must match the Gateway's ORCHESTRATE_TOKEN
ORCHESTRATE_DEFAULT_MODE=offchain # default rail: offchain | onchain
ORCHESTRATE_MAX_DEPTH=4 # max nested delegation depthThe SDK
A2AProtocol/A2ADaemonremain the explicit on-chain rail for integrators who want settlement & reputation without the chat channel — same principle: the caller's own wallet signscreateTask.
Version History
| Version | Date | Highlights |
|---------|------|-----------|
| 0.11.9 | 2026-08-29 | 租户作用域权限下放(SK-1) — AgentWalletConfig 新增可选 apiKey 模式:{ baseUrl, apiKey } 用租户 API Key 管理自有 agent(agents.owner = 租户钱包)的 MPC 钱包(bind/unlock/status/list/delete),越权 403;{ baseUrl, adminKey } 平台全量(原行为不变),同时提供时优先 adminKey。配套 Gateway /api/v1/admin/agent-payers 双轨鉴权已部署。No breaking changes,纯附加 |
| 0.11.8 | 2026-08-25 | A2A 委派 Session Key 自动扣费(AItrader REQ-1/2/3) — ConversationClient 新增 getA2ATaskResult(a2a_task_results 行,含 status=4 awaiting_payment + payment_pay_options)/ retryA2ATask(授权 Session Key 后重新激活挂起任务,不扣 ledger)/ getSessionKeyInfo(引擎能力信息)/ getBalance(x402 余额 + sessionKey 授权状态);新增 A2A_STATUS 状态常量 + A2ADelegatedTaskResult / SessionKeyInfo / SessionKeyAuthStatus / BillingBalance 类型。端用户钱包 EIP-712 签名授权 x402-pay 会话后,Gateway 在余额不足时自动经引擎代签转账补足。No breaking changes |
| 0.11.7 | 2026-08-18 | Agent 自主钱包 API + @0xinfrax/payments 0.1.4 — 新增 AgentWalletConfig(bindWallet / authorizePaymentSession(邮箱验证码解锁)/ status / list / unbind):绑定 agent 与 InfraX MPC 钱包(Email 2-of-2 TSS),A2A 委派按次付费由 gateway 服务端自动代付(agent-payer);依赖升级 0.1.3 → 0.1.4(escrow 透传 / ERC20 deposit / 402 结构化错误),HTTP 契约与既有客户端签名不变(补 0.11.6 遗漏的 npm 发布)。No breaking changes |
| 0.11.6 | 2026-08-16 | B 端余额预检(R19.7 companion) — 新增 BillingClient + GET /api/v1/billing/balance:委派未订阅 agent 前程序化预检 x402 余额(租户维度默认,endUserId 0x 钱包透传返回端用户余额);返回 { balance (OXA 高精度 decimal), balanceWei, currency, updatedAt, payTo?, priceWei? };余额 0 正常返回不报错;鉴权沿用 X-Api-Key / Bearer JWT。解决 aihunter-saas 提出的「先撞 403 再引导充值」体验问题。No breaking changes |
| 0.11.5 | 2026-08-12 | R19.3/R19.7 商业化闭环 — 新增 TenantPlanPayments(平台套餐购买:统一支付入口 purpose=tenant-plan,chain/fiat/x402 三轨,buy() 返回 { method, ... } 判别结果,绑定租户套餐);服务端 A2A 按次付费(R19.7)——未订阅 agent 时按次扣 x402 余额(服务端 deduct + 审计幂等),SDK 调用方零改动、对话自动触发;PaymentsClient.create({ purpose: 'tenant-plan' }) 支持套餐购买元数据。No breaking changes |
| 0.11.4 | 2026-08-11 | B 端计费策略对齐(R18) — 服务端「partner 任务强制 BYOK」已废除(2026-08-11 起不强制;未带 key 时走平台兜底 key,平台按 done 事件 usage 精确计费,扣套餐每日配额;400 LLM_KEY_REQUIRED 不再返回);ConversationSSEEvent done 事件新增可选 llmSource?: 'byok' | 'platform'(计费来源标记,仅供观测)。SDK 调用方零代码改动(BYOK 参数仍可用),README/UPGRADE 文档同步。No breaking changes |
| 0.11.3 | 2026-08-10 | R17.6 a2a/period 回归模块 rails — 跟随 infraX @0xinfrax/payments ^0.1.3(0.1.3 在模块内置恢复 a2a/period rails,并新增 batch/invite/transfer);AgentX Gateway 自托管 a2a/period 迁移为模块委托,HTTP 契约与客户端签名完全不变,PAYMENT_VERSION 对齐 0.1.3。A2AClient 继续由 SDK 本地实现(修复 0.11.1 ESM 导入崩溃)。No breaking changes |
| 0.11.2 | 2026-08-10 | A2AClient ESM 修复 — A2AClient 从 @0xinfrax/payments 导入(0.1.2 已移除该导出 → ESM 构建 Named export not found 崩溃)改为 SDK 本地实现,签名不变;PAYMENT_VERSION 对齐 0.1.2。CJS 调用方不受影响。No breaking changes |
| 0.11.1 | 2026-08-10 | 首次跟随演练(F2) — 跟随 infraX @0xinfrax/payments ^0.1.1(补丁版:新增 createWebhookForwarder 事件出站转发 + ChainAdapter rpcHeaders);解耦回归 19 项断言通过(消费已安装 npm 包)、sdk 32/32 全绿;PAYMENT_VERSION 对齐 0.1.1。SubscriptionPayments + 协议客户端 API 不变。No breaking changes |
| 0.11.0 | 2026-08-10 | Payment engine migrated — the underlying engine moved from the AgentX-maintained @agentxv2/payments (now deprecated) to the InfraX-maintained @0xinfrax/payments ^0.1.0; capabilities identical (chain / Stripe fiat / x402 v1+v2 / MPP channels / stablecoin EIP-3009+Permit2 / period authorizations / a2a-pay), dependency-source only; PAYMENT_VERSION aligned to 0.1.0. SubscriptionPayments + protocol clients (MPP/A2A/Period/X402/Payments) API unchanged. No breaking changes (see UPGRADE.md) |
| 0.10.1 | 2026-08-08 | Released — per-request endUserId on createTask (body) / stream (header) for B-end subscription proxying; B-end key vs user JWT behavior documented (identical P9 capability bits; partner tasks require BYOK → 400 LLM_KEY_REQUIRED; platform MCP & on-chain are JWT-only); MCP boundary note (platform /mcp vs self-hosted MCP). Non-breaking additive change (see UPGRADE.md) |
| 0.10.0 | 2026-08-08 | Complete feature release — consolidates the 0.9.x line into a stable baseline: typed onchain_approval_required SSE event + OnChainApprovalRequest (user-wallet-signed on-chain delegation, no platform gas), agent categories, unified payments rails, sessions & parallel tasks, streaming tool_call fix. No breaking changes |
| 0.9.6 | 2026-08-08 | Typed on-chain approval event — ConversationSSEEvent adds 'onchain_approval_required' + OnChainApprovalRequest { targetAgentId, taskType, inputData } so consumers no longer need as unknown as narrowing when the agent requests an auditable on-chain A2A delegation (the user's wallet signs createTask and pays the gas). Frontend useAgentChat updated to the typed event (also resolves the pre-existing AgentPayload.category error). No breaking changes |
| 0.9.5 | 2026-08-08 | Fix: streaming tool_call arguments dropped — DeepSeek/OpenAI argument-delta chunks carry only an index (no id); GatewayProvider / OpenAIProvider now keep an index→id map so accumulated tool arguments attach to the real call (previously silently discarded). No breaking changes (see UPGRADE.md) |
| 0.9.4 | 2026-08-07 | Agent application categories — AgentPayload.category + AGENT_CATEGORIES / AgentCategory (13 enums); written to public metadata + on-chain attrs; getAllAgents() / getAgentMetadata() resolve category; Gateway ?category= filter + byCategory aggregation; frontend Studio requires it, Marketplace categorizes by it. @agentxv2/payments resolved to 0.2.2 (ownership metadata). No breaking changes (see UPGRADE.md) |
| 0.9.3 | 2026-08-07 | P2-P4 rails aligned — @agentxv2/payments bumped to ^0.2.0 (MPP payment channels / stablecoin EIP-3009+Permit2 / period authorizations / a2a-pay); re-exports MPPClient / A2AClient / PeriodClient / X402Client / PaymentsClient from the SDK root. No breaking changes — SubscriptionPayments API unchanged (see UPGRADE.md) |
| 0.9.2 | 2026-08-07 | Unified payments endpoint — SubscriptionPayments fiat / x402 / hasAccess() now go through the Gateway's /api/v1/payments via the decoupled @agentxv2/payments engine (^0.1.0, new dependency); fetchX402Info() reads the rails-discovery /info. No breaking changes — pay() / hasAccess() / result types unchanged (see UPGRADE.md) |
| 0.9.0 | 2026-08-06 | Browser Control Skill extension: new actions hover / press / select (select+checkbox+radio) / back / forward / getInfo (url/title/viewport); extractAccessibleDOM now includes name/role/aria-label/input value/checkbox checked/anchor target; new sleep(ms) async pacing helper; findElement also matches name attr |
| 0.8.11 | 2026-08-07 | Multi-rail subscription payments — new SubscriptionPayments class (pay({ method }) for chain / fiat / x402, hasAccess() unified chain-OR-fiat/x402 check, fetchX402Info() discovery); fiat amountCents now optional (Gateway auto-prices from the on-chain plan); x402 auto-funding from a configured walletClient |
| 0.8.10 | 2026-08-06 | Master-key crypto helpers encryptWithKey() / decryptWithKey() (AES-256-GCM, base64(IV‖tag‖ciphertext), byte-compatible with Gateway at-rest key encryption); parseTokenURIJSON exported from the main entry; A2AProtocol.createTask() accepts raw string input; subscription status mapping fix (on-chain enum 0/1/2/3 → pending/active/expired/cancelled, previously shifted) |
| 0.8.9 | 2026-08-06 | Docs sync — Installation section points at v0.8.8 ("just install to use the new capabilities"); same code as 0.8.8 |
| 0.8.8 | 2026-08-06 | Docs sync — README updated for 0.8.7 (sessions & parallel tasks section) |
| 0.8.7 | 2026-08-06 | ConversationClient gains sessions & parallel tasks: createSession() / createTask() (returns taskId immediately, background execution) / getTask() / listTasks() / cancelTask() / getCapabilities(). New ConversationTaskError (.status / .code) — createTask() on a P9-disabled tenant/plan rejects with HTTP 403 PARALLEL_TASKS_DISABLED; used by the frontend parallel-task chat UI |
| 0.8.6 | 2026-08-06 | ConversationChatParams gains tenantKeyId — BYOK via a stored tenant-owned API key, resolved server-side by the Gateway (plaintext key never leaves the server); used by the new frontend own-key settings flow |
| 0.8.5 | 2026-08-06 | Docs sync — re-published with updated README (same code as 0.8.4) |
| 0.8.4 | 2026-08-06 | ConversationClient now supports Gateway JWT auth (accessToken → Authorization: Bearer, alternative to apiKey) and external abort (stream(params, { signal })); tool_result event gains optional error field. Frontend chat hook unified onto it (single SSE client implementation) |
| 0.8.3 | 2026-08-05 | Install fix: wagmi promoted from optional to required peer dependency — the package is now directly usable via npm install @agentxv2/[email protected] (no manual wagmi install); verified from a clean install (ESM + CJS, chain reads OK) |
| 0.8.2 | 2026-08-05 | Write-op fix: createPlan() / subscribe() / releaseFunds() / cancel() resolve the full viem walletClient.account instead of a bare address string — local/private-key signers now work (eth_sendRawTransaction); browser wallets unchanged. Verified on-chain (OxaChain L1) |
| 0.8.1 | 2026-08-04 | parseTokenURIJSON() fault-tolerant parsing aligned with Gateway indexer: base64 trailing garbage cleanup, unterminated JSON repair, regex fallback, explicit ipfs:// handling |
| 0.8.0 | 2026-08-04 | Chain-data capabilities: getAllAgents() / totalAgents() / getAgentMetadata() on IdentityRegistry; createPlan() (typed period day|week|month|year) / subscribe() (event-parsed result) / createPlanAndSubscribe(); subscribeToEvents() event stream |
| 0.7.5 | 2026-08-04 | Fix AgentLoop forcing ctx.model ?? 'gpt-4o' over provider model — priority now ctx.model ?? provider.model ?? default |
| 0.7.4 | 2026-08-04 | ConversationClient adds llmModel (forwarded as X-Llm-Model) — BYOK now covers key + endpoint + model (e.g. deepseek-v4-pro) |
| 0.7.3 | 2026-08-04 | Stateless BYOK: ConversationClient adds llmEndpoint (forwarded as X-Llm-Endpoint) so callers supply their own LLM key + endpoint (e.g. DeepSeek) per request — no AgentX-side key storage needed |
| 0.7.2 | 2026-08-03 | Clarification interruption: ConversationSSEEvent adds clarification + question; chat() returns result.clarification when the service interrupts an ambiguous request |
| 0.7.1 | 2026-08-03 | ConversationClient inline mode: prompt + skills params (inject MCP/HTTP tools e.g. RAG), agentId now optional; Gateway forwards X-Llm-Api-Key |
| 0.7.0 | 2026-08-01 | ConversationClient (@agentxv2/sdk/conversation) — remote Conversation Service client: SSE streaming via Gateway, auto X-Api-Key / X-End-User-Id / X-Llm-Api-Key; Gateway Agent-as-MCP tools/call now executes skills directly (no LLM second-pass) |
| 0.6.9 | 2026-08-01 | Microservice Agent Conversation — 6-Phase Optimization: Conversation Service (Memory + Context + Sandbox), Observability (TraceEmitter), Skills Marketplace, Agent-as-MCP Export, Browser Control Skill, 3 new sub-path exports (memory/traces/skills) |
| 0.6.8 | 2026-07-28 | Fixed import paths in platform-tools (definitions.ts, executor.ts, index.ts) after module split; Frontend: 3 God Components modularized (AgentCardManager→5 files, AgentRegistration→4 files, RevenueDisplay→5 files) |
| 0.6.7 | 2026-07-27 | Code review: 22 fixes across contracts/gateway/frontend
