diff --git a/public/llms.txt b/public/llms.txt index 35023bc3..99fcbcd1 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -480,6 +480,7 @@ - [Centralized Examples Test](https://metaplex.com/docs/test-centralized-examples): Testing centralized code examples - [Code Tabs Test Page](https://metaplex.com/docs/test-code-tabs): Testing the new CodeTabs component - [Copy with Context Test](https://metaplex.com/docs/test-copy-context): Testing enhanced copy functionality +- [Delegate to Nori](https://metaplex.com/docs/agents/nori/delegate-to-nori): Register Nori as an execution delegate on your Metaplex agent so every LLM, image, and RPC call settles automatically from your agent's PDA wallet. Free onboarding — no SOL for fees, no RPC required. - [Enhanced Fence Component - Test Page](https://metaplex.com/docs/test-fence-enhanced): Testing all new features of the enhanced Fence component - [Getting Started with Rust](https://metaplex.com/docs/solana/rust/getting-started-with-rust): A quick overview on how to get started with Rust in the Solana ecosystem. - [Guides](https://metaplex.com/docs/solana): Guides by Metaplex about the Solana blockchain. @@ -561,6 +562,9 @@ - [MPL-Hybrid Javascript SDK](https://metaplex.com/docs/smart-contracts/mpl-hybrid/sdk/javascript): Learn how to set up your project to run the MPL-Hybrid Javascript SDK. - [MPL-Hybrid SDKs](https://metaplex.com/docs/smart-contracts/mpl-hybrid/sdk): View the available SDKs for the MPL-Hybrid Metaplex program. - [Namespace](https://metaplex.com/docs/smart-contracts/token-auth-rules/primitive-rules/namespace): The Namespace primitive rule +- [Nori - Pay-As-You-Go Services for Metaplex Agents](https://metaplex.com/docs/agents/nori): Nori is a Metaplex service agent that sells LLM inference, image generation, and Solana RPC access to other agents, metered in SOL per call. Learn how delegate-pay billing works and how to use Nori as a reference implementation for your own service agent. +- [Nori Example Agents](https://metaplex.com/docs/agents/nori/example-agents): Working examples of agents consuming each Nori service - an OpenAI-compatible inference agent using chat.completion, an artwork agent using image.generation, a portfolio analyzer using solana.rpc with DAS, and a raw A2A JSON-RPC caller. +- [Nori Pricing and Billing](https://metaplex.com/docs/agents/nori/pricing-and-billing): How Nori prices and bills service calls - the published rate card at GET /rate-card, USD-to-SOL conversion at charge time, charge-on-success accounting, the price-change notice policy, and hard-stop semantics on undelegate and wallet-empty. - [Not](https://metaplex.com/docs/smart-contracts/token-auth-rules/composite-rules/not): The Not composite rule - [Pass](https://metaplex.com/docs/smart-contracts/token-auth-rules/primitive-rules/pass): The Pass primitive rule - [PDA Match](https://metaplex.com/docs/smart-contracts/token-auth-rules/primitive-rules/pda-match): The PDA Match primitive rule diff --git a/src/components/NavList.jsx b/src/components/NavList.jsx index a8ef101d..13ab198b 100644 --- a/src/components/NavList.jsx +++ b/src/components/NavList.jsx @@ -211,6 +211,18 @@ export const agentMenuCategory = [ zh: { name: '运行代理', headline: '委托执行以运行自主代理。' }, }, }, + { + name: 'Nori', + headline: 'Pay-as-you-go LLM, image, and RPC services for agents, metered in SOL.', + description: 'Pay-as-you-go LLM, image, and RPC services for agents, metered in SOL.', + navigationMenuCatergory: 'Agents', + href: '/agents/nori', + localizedNavigation: { + ja: { name: 'Nori', headline: 'エージェント向けの従量課金制LLM・画像・RPCサービス。SOLで精算します。' }, + ko: { name: 'Nori', headline: '에이전트를 위한 종량제 LLM·이미지·RPC 서비스. SOL로 정산합니다.' }, + zh: { name: 'Nori', headline: '面向 Agent 的按量付费 LLM、图像与 RPC 服务,以 SOL 结算。' }, + }, + }, ] export const nftMenuCategory = [ diff --git a/src/components/products/agents/index.js b/src/components/products/agents/index.js index e0e798a4..fad85479 100644 --- a/src/components/products/agents/index.js +++ b/src/components/products/agents/index.js @@ -70,6 +70,27 @@ export const agents = { }, ], }, + { + title: 'Nori', + links: [ + { + title: 'Nori Overview', + href: '/agents/nori', + }, + { + title: 'Delegate to Nori', + href: '/agents/nori/delegate-to-nori', + }, + { + title: 'Pricing and Billing', + href: '/agents/nori/pricing-and-billing', + }, + { + title: 'Example Agents', + href: '/agents/nori/example-agents', + }, + ], + }, ], }, ], @@ -91,6 +112,11 @@ export const agents = { ko: '시작하기', zh: '快速入门', }, + 'Nori': { + ja: 'Nori', + ko: 'Nori', + zh: 'Nori', + }, }, linkKeys: { 'Agent Onboarding': { @@ -138,6 +164,26 @@ export const agents = { ko: '에이전트 실행', zh: '运行 Agent', }, + 'Nori Overview': { + ja: 'Nori 概要', + ko: 'Nori 개요', + zh: 'Nori 概述', + }, + 'Delegate to Nori': { + ja: 'Nori への委任', + ko: 'Nori에 위임하기', + zh: '委托给 Nori', + }, + 'Pricing and Billing': { + ja: '料金と請求', + ko: '가격 및 청구', + zh: '定价与计费', + }, + 'Example Agents': { + ja: 'エージェントの例', + ko: '에이전트 예시', + zh: 'Agent 示例', + }, }, }), } diff --git a/src/pages/en/agents/nori/delegate-to-nori.md b/src/pages/en/agents/nori/delegate-to-nori.md new file mode 100644 index 00000000..3445ce5a --- /dev/null +++ b/src/pages/en/agents/nori/delegate-to-nori.md @@ -0,0 +1,258 @@ +--- +title: Delegate to Nori +metaTitle: Delegate to Nori - One-Time Onboarding to Delegate-Pay Billing | Metaplex +description: Register Nori as an execution delegate on your Metaplex agent so every LLM, image, and RPC call settles automatically from your agent's PDA wallet. Free onboarding — no SOL for fees, no RPC required. +keywords: + - delegate to Nori + - execution delegation + - delegate-pay + - agent onboarding + - delegateExecutionV1 + - Nori bearer token + - Metaplex agent billing +about: + - Nori + - Execution Delegation + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +howToSteps: + - Fetch Nori's agent card and read its serviceExecutiveAddress. + - Build a transaction containing a single delegateExecutionV1 instruction pointing at Nori's executive profile, with Nori as fee payer. + - Sign with your agent's executive keypair and submit the transaction to Nori's free /v1/delegate/submit endpoint. + - Exchange a signed challenge for a bearer token at /auth/handshake. + - Make paid calls with the bearer token — charges settle automatically from your agent's PDA wallet. +howToTools: + - '@metaplex-foundation/mpl-agent-registry' + - '@metaplex-foundation/umi' +faqs: + - q: Does delegating to Nori cost anything? + a: No. Nori pays the network fee on the delegation transaction (it co-signs as fee payer), and the onboarding endpoints are free and unauthenticated. You will want a working SOL balance on your agent's PDA wallet afterwards, because that is the account per-call charges draw from. + - q: What authority does delegation give Nori? + a: Delegation registers Nori's executive profile as an execution delegate on your agent asset, which lets Nori sign MPL Core Execute transactions that move SOL out of your agent's PDA wallet. Nori uses this to settle per-call charges, each with an onchain Memo receipt. Keep only a working balance on the PDA and audit the receipts. + - q: How do I stop Nori from charging my agent? + a: Revoke the execution delegation on your agent asset. The next charge attempt fails onchain, Nori's cached delegate status is invalidated, and the delegate-pay rail hard-stops — subsequent calls receive HTTP 402 x402 challenges instead of being auto-charged. + - q: Why do my calls return HTTP 402 even though I delegated? + a: A 402 means the delegate-pay rail was unavailable for that call — the bearer token is missing or expired (tokens last 15 minutes), the delegation was revoked, or the charge itself failed (usually an empty PDA wallet). Re-run the handshake, verify the delegation record exists, and check the PDA balance. + - q: Can I use Nori without delegating at all? + a: Yes. Non-delegated callers use the x402 fallback rail — the first request returns HTTP 402 with payment requirements, you pay in SOL or USDC, then retry. It costs the same but adds a payment round-trip to every call, whereas delegate-pay settles in-line. +--- + +Delegating to Nori is a one-time onchain setup that registers Nori as an [execution delegate](/smart-contracts/mpl-agent/tools) on your agent's asset. After it, every LLM, image, and RPC call your agent makes against Nori settles automatically from the agent's PDA wallet — no payment round-trips, no wallet prompts, no provider API keys. Onboarding is free: Nori pays the transaction fee and provides the blockhash, so your agent needs neither SOL on its keypair nor its own RPC. {% .lead %} + +## Summary + +Granting Nori execution delegation switches your agent from the two-trip [x402 fallback](/agents/nori/#how-nori-payments-work) to the in-line delegate-pay rail. + +- **One-time setup** — a single `delegateExecutionV1` instruction pointing at Nori's executive profile, co-signed and submitted by Nori for free +- **Per-call settlement** — Nori charges your agent's [Asset Signer PDA](/agents/what-is-an-agent) via an MPL Core Execute transaction with a Memo receipt, only on [successful calls](/agents/nori/pricing-and-billing#charge-on-success-accounting) +- **Bearer-token auth** — a signed challenge/handshake mints a 15-minute bearer token that routes your calls to the delegate-pay rail +- **Revocable at any time** — the asset owner can revoke the delegation, which [hard-stops](#revoking-delegation-from-nori) auto-charging immediately + +{% callout type="warning" title="Delegation grants billing authority" %} +An execution delegate can sign transfers out of your agent's PDA wallet. Treat the PDA as a spending account: keep a working balance, not your treasury, and audit the Memo receipt attached to every charge. See [the single-point-of-failure caveat](/agents/nori/#nori-as-a-single-point-of-failure) before making Nori your agent's only service provider. +{% /callout %} + +## Quick Start + +1. [Fetch Nori's agent card](#step-1-discover-noris-executive-address) and read `serviceExecutiveAddress` +2. [Build the delegation transaction](#step-2-build-and-submit-the-delegation-transaction) with your executive keypair as authority and Nori as fee payer, then submit it to `POST /v1/delegate/submit` +3. [Fund your agent's PDA wallet](#funding-the-agent-pda-wallet) with a working SOL balance +4. [Mint a bearer token](#step-3-authenticate-with-a-bearer-token) via `/auth/challenge` + `/auth/handshake` +5. [Make a paid call](#step-4-make-a-paid-call) with `Authorization: Bearer ` + +## Prerequisites + +Delegation requires an existing onchain agent identity; the delegation transaction references the asset and its identity PDA. + +- A [registered agent](/agents/register-agent) — an MPL Core asset with an `AgentIdentity` record +- Your agent's **executive keypair** (the keypair your agent runs with, set up via [Run an Agent](/agents/run-an-agent)) — it signs the delegation as authority +- `@metaplex-foundation/mpl-agent-registry` and `@metaplex-foundation/umi` installed +- No SOL and no RPC endpoint are required for the delegation itself — Nori provides both + +## Step 1: Discover Nori's Executive Address + +Nori's agent card advertises the address you delegate to. Fetch `/.well-known/agent-card.json` and read two fields: + +- `serviceExecutiveAddress` — Nori's executive keypair public key. Its executive profile PDA is what you register as a delegate on your asset. +- `serviceAssetAddress` — Nori's own agent asset. Its PDA is where your charges are paid to; you can verify every charge onchain against it. + +```typescript {% title="fetch-nori-card.ts" %} +const NORI_URL = process.env.NORI_URL; // Nori's base URL + +const card = await fetch(`${NORI_URL}/.well-known/agent-card.json`).then((r) => + r.json(), +); + +const noriExecutive = card.serviceExecutiveAddress; // delegate to this +const noriServiceAsset = card.serviceAssetAddress; // charges are paid here +``` + +{% callout type="warning" title="Treat the base URL as trusted configuration" %} +The agent card determines which executive profile you grant billing authority to. Fetch it only from a `NORI_URL` whose configuration you control, and verify `serviceExecutiveAddress` out-of-band — for example against Nori's published agent registration — before signing the delegation. +{% /callout %} + +## Step 2: Build and Submit the Delegation Transaction + +The delegation transaction contains exactly one `delegateExecutionV1` instruction: your executive keypair signs as authority, Nori's executive profile is the delegate, and Nori's keypair is the fee payer. You build and sign it offline (Nori's free `GET /v1/solana/blockhash` endpoint supplies the blockhash), then POST the partially-signed transaction to `POST /v1/delegate/submit`. Nori validates it, co-signs as fee payer, and submits it. + +```typescript {% title="delegate-to-nori.ts" %} +import { createNoopSigner, publicKey } from '@metaplex-foundation/umi'; +import { + delegateExecutionV1, + findAgentIdentityV1Pda, + findExecutiveProfileV1Pda, +} from '@metaplex-foundation/mpl-agent-registry'; + +// `umi` is configured with your agent's executive keypair as identity. +const agentAsset = publicKey(process.env.AGENT_ASSET_ADDRESS); + +// Nori's executive profile PDA, derived from the agent card address. +const noriProfile = findExecutiveProfileV1Pda(umi, { + authority: publicKey(noriExecutive), +}); +const agentIdentity = findAgentIdentityV1Pda(umi, { asset: agentAsset }); + +// Free blockhash — no RPC of your own needed. +const { blockhash } = await fetch(`${NORI_URL}/v1/solana/blockhash`).then((r) => + r.json(), +); + +// Build with Nori as fee payer (a noop signer — Nori co-signs server-side), +// sign with your executive keypair. +const tx = await delegateExecutionV1(umi, { + agentAsset, + agentIdentity, + executiveProfile: noriProfile, +}) + .setFeePayer(createNoopSigner(publicKey(noriExecutive))) + .setBlockhash(blockhash) + .buildAndSign(umi); + +// Nori validates, co-signs, and submits — free of charge. +const result = await fetch(`${NORI_URL}/v1/delegate/submit`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + transaction: Buffer.from(umi.transactions.serialize(tx)).toString('base64'), + }), +}).then((r) => r.json()); + +console.log(result); +// { success: true, signature: '...', agentAsset: '...', authority: '...' } +``` + +{% callout type="note" title="Strict transaction validation" %} +`POST /v1/delegate/submit` rejects anything that is not exactly one `delegateExecutionV1` instruction (discriminator 1 on the `mpl-agent-tools` program) pointing at Nori's own executive profile, with Nori as fee payer. The strict shape prevents the free endpoint from being abused as a transaction-submission service. +{% /callout %} + +If you build agents from the Metaplex agent template, this entire step is packaged as the `delegate-to-nori` tool — one call, no manual transaction construction. + +## Step 3: Authenticate with a Bearer Token + +Paid calls route to the delegate-pay rail when they carry a bearer token minted through a Sign-In-With-Solana-style handshake. The token proves you control the executive keypair that is a registered delegate on the agent asset; it is valid for 15 minutes, so re-run the handshake on expiry. + +```typescript {% title="nori-handshake.ts" %} +import { base58 } from '@metaplex-foundation/umi/serializers'; + +// 1. Get a fresh nonce. +const { nonce } = await fetch(`${NORI_URL}/auth/challenge`).then((r) => r.json()); + +// 2. Sign the handshake envelope with your executive keypair. +const now = Date.now(); +const handshake = { + pubkey: umi.identity.publicKey.toString(), + agentAsset: agentAsset.toString(), + audience: NORI_URL, + nonce, + issuedAt: new Date(now).toISOString(), + expiresAt: new Date(now + 60_000).toISOString(), +}; +const signature = base58.deserialize( + await umi.identity.signMessage( + new TextEncoder().encode(JSON.stringify(handshake)), + ), +)[0]; + +// 3. Exchange for a bearer token (valid 15 minutes). +const { token } = await fetch(`${NORI_URL}/auth/handshake`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ handshake, signature }), +}).then((r) => r.json()); +``` + +## Step 4: Make a Paid Call + +With the bearer token attached, Nori runs the upstream call, then charges your agent's PDA in one Execute transaction — the response comes back in a single round-trip with no 402 challenge. The same header works on all `/v1/*` endpoints and on `/a2a`. + +```typescript {% title="paid-call.ts" %} +const completion = await fetch(`${NORI_URL}/v1/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from a delegated agent.' }], + }), +}).then((r) => r.json()); +``` + +On the first paid call for an asset, Nori checks onchain that it is still a registered delegate; the result is cached for 5 minutes, so subsequent calls skip the chain lookup. See [Example Agents](/agents/nori/example-agents) for full agents consuming each service, including pointing an OpenAI-compatible SDK client at Nori. + +## Funding the Agent PDA Wallet + +Charges draw from your agent's Asset Signer PDA, so it needs a SOL balance before the first paid call. The PDA must also stay above the system rent-exempt minimum (890,880 lamports for a 0-byte account) — the Metaplex agent template seeds it with 0.002 SOL at delegation time so small sub-rent charges never fail. Transfer SOL to the PDA from any wallet; if the balance runs dry, calls fall back to HTTP 402 challenges until you top up (see [hard-stop semantics](/agents/nori/pricing-and-billing#hard-stop-semantics)). + +## Revoking Delegation from Nori + +Revoking the execution delegation is the kill switch, and it takes effect as a hard stop. When the asset owner revokes the `ExecutionDelegateRecordV1` for Nori's executive profile, the next charge attempt fails onchain, Nori invalidates its cached delegate status for your asset, and the delegate-pay rail stops — from then on your calls receive x402 payment challenges instead of being auto-charged. Because of the 5-minute delegate-status cache, a call made immediately after revocation may still attempt (and fail) a delegate charge; no charge lands after revocation because the chain rejects it. + +Revocation does not deregister your agent or touch its PDA balance — it only removes Nori's authority to charge it. You can re-delegate later by repeating [Step 2](#step-2-build-and-submit-the-delegation-transaction). + +## Common Errors + +| Error | Cause | Fix | +|-------|-------|-----| +| `expected { transaction: }` (400) | Wrong body field on `/v1/delegate/submit` | Send `{ "transaction": "" }` | +| Delegation submit rejected with an `errorReason` | Transaction shape failed strict validation — extra instructions, wrong program, wrong executive profile, or wrong fee payer | Build exactly one `delegateExecutionV1` instruction pointing at Nori's executive profile with Nori as fee payer | +| `401` on paid calls | Missing or expired bearer token (15-minute lifetime) | Re-run the challenge/handshake flow | +| `402` on paid calls despite delegation | Delegation revoked, or charge failed (usually an empty PDA wallet) | Verify the delegation record exists and the PDA balance covers the call | +| `Neither the asset or any plugins have approved this operation` | Charge attempted after the delegation was revoked | Expected hard-stop behavior — re-delegate to resume delegate-pay | +| `insufficient funds for rent` on a charge | PDA balance below the rent-exempt minimum | Top up the PDA (keep it above 890,880 lamports plus a working balance) | + +## Notes + +- Onboarding endpoints (`GET /v1/solana/blockhash`, `POST /v1/delegate/submit`) are free and unauthenticated; everything else that does work is paid +- Bearer tokens are minted per executive keypair + agent asset pair and expire after 15 minutes — build re-handshaking into your client +- The delegate-status cache means delegation state changes (grant or revoke) can take up to 5 minutes to be reflected on the payment rail; onchain enforcement is immediate +- Delegation is per-asset: an agent operator running multiple agents delegates each asset separately +- Applies to `mpl-agent-tools` execution delegation (`ExecutionDelegateRecordV1`), program `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S` + +Maintained by Metaplex Foundation. Last verified: 2026-07-08. [View source on GitHub](https://github.com/metaplex-foundation/agent-plumber). + +## FAQ + +Common questions about delegating to Nori. + +### Does delegating to Nori cost anything? +No. Nori pays the network fee on the delegation transaction (it co-signs as fee payer), and the onboarding endpoints are free and unauthenticated. You will want a working SOL balance on your agent's PDA wallet afterwards, because that is the account per-call charges draw from. + +### What authority does delegation give Nori? +Delegation registers Nori's executive profile as an execution delegate on your agent asset, which lets Nori sign [MPL Core Execute](/smart-contracts/core/execute-asset-signing) transactions that move SOL out of your agent's PDA wallet. Nori uses this to settle per-call charges, each with an onchain Memo receipt. Keep only a working balance on the PDA and audit the receipts. + +### How do I stop Nori from charging my agent? +Revoke the execution delegation on your agent asset. The next charge attempt fails onchain, Nori's cached delegate status is invalidated, and the delegate-pay rail hard-stops — subsequent calls receive HTTP 402 x402 challenges instead of being auto-charged. + +### Why do my calls return HTTP 402 even though I delegated? +A 402 means the delegate-pay rail was unavailable for that call — the bearer token is missing or expired (tokens last 15 minutes), the delegation was revoked, or the charge itself failed (usually an empty PDA wallet). Re-run the handshake, verify the delegation record exists, and check the PDA balance. + +### Can I use Nori without delegating at all? +Yes. Non-delegated callers use the x402 fallback rail — the first request returns HTTP 402 with payment requirements, you pay in SOL or USDC, then retry. It costs the same but adds a payment round-trip to every call, whereas delegate-pay settles in-line. diff --git a/src/pages/en/agents/nori/example-agents.md b/src/pages/en/agents/nori/example-agents.md new file mode 100644 index 00000000..2ad200fc --- /dev/null +++ b/src/pages/en/agents/nori/example-agents.md @@ -0,0 +1,208 @@ +--- +title: Nori Example Agents +metaTitle: Nori Example Agents - Inference, Image Generation, and RPC Consumers | Metaplex +description: Working examples of agents consuming each Nori service - an OpenAI-compatible inference agent using chat.completion, an artwork agent using image.generation, a portfolio analyzer using solana.rpc with DAS, and a raw A2A JSON-RPC caller. +keywords: + - Nori examples + - example agents + - OpenAI-compatible agent + - chat.completion + - image.generation + - solana.rpc + - DAS API + - A2A message/send + - agent template +about: + - Nori + - Autonomous Agents + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +faqs: + - q: Which SDKs work with Nori's inference service? + a: Any OpenAI-compatible client works — the Vercel AI SDK via createOpenAICompatible, the official OpenAI SDKs with a custom baseURL, or agent frameworks like Mastra that accept an OpenAI-compatible provider. Point the client at NORI_URL/v1 and attach the bearer token as the Authorization header. + - q: Can my agent use DAS methods like getAssetsByOwner through Nori? + a: Yes. The solana.rpc service is a transparent JSON-RPC pass-through to a DAS-capable upstream provider, so DAS methods (getAsset, getAssetsByOwner, and others) work exactly like standard Solana RPC methods — same endpoint, same per-call price. + - q: Do these examples work without delegation? + a: Yes, over the x402 fallback rail — the first call runs the request once and returns HTTP 402 with payment requirements; paying and retrying returns the cached result. The examples assume delegation because it removes the payment round-trip; see Delegate to Nori for the one-time setup. + - q: Which models can I request through chat.completion? + a: Any model on the rate card, addressed as / — for example anthropic/claude-sonnet-4-6, openai/gpt-5.4, or google/gemini-2.5-flash. GET /v1/models lists the live directory, and GET /rate-card carries the per-token prices. +--- + +These examples show a consumer agent using each of Nori's three services — LLM inference, image generation, and Solana RPC — plus the raw A2A envelope for agent-to-agent callers. Each example assumes the one-time [delegation setup](/agents/nori/delegate-to-nori) is done and a bearer `token` is in hand; the same requests work without delegation over the x402 fallback, with a payment round-trip added. {% .lead %} + +## Summary + +Every example is a complete, paid Nori call — no provider API keys anywhere. + +- **Inference agent** — points an OpenAI-compatible client at `NORI_URL/v1` and runs `chat.completion` with tool calls +- **Artwork agent** — generates images via `image.generation` (gpt-image-1) +- **Portfolio analyzer** — reads balances and token holdings via `solana.rpc`, including DAS methods +- **A2A caller** — invokes the same skills through JSON-RPC `message/send` for agent-to-agent integrations + +## Inference Agent Using chat.completion + +An agent's LLM brain can run entirely on Nori by pointing an OpenAI-compatible client at `NORI_URL/v1`. Models are addressed as `/` and routed to Anthropic, OpenAI, or Google upstream; tool calls (`tools`, `tool_choice`, `tool_calls`) are supported across all three providers, so full agent loops work unmodified. + +```typescript {% title="inference-agent.ts" %} +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; +import { generateText, tool } from 'ai'; +import { z } from 'zod'; + +const nori = createOpenAICompatible({ + name: 'nori', + baseURL: `${NORI_URL}/v1`, + headers: { Authorization: `Bearer ${token}` }, // from /auth/handshake +}); + +const { text } = await generateText({ + model: nori('anthropic/claude-sonnet-4-6'), + tools: { + getSolPrice: tool({ + description: 'Get the current SOL price in USD', + inputSchema: z.object({}), + execute: async () => fetchSolPrice(), + }), + }, + prompt: 'Is SOL above $200 right now? Answer in one sentence.', +}); +``` + +Each `generateText` call is one metered `chat.completion` — billed by actual input/output token counts at the [rate-card](/agents/nori/pricing-and-billing) price for the selected model, settled from the agent's PDA. Swapping models (or falling back to a non-Nori provider [during an outage](/agents/nori/#nori-as-a-single-point-of-failure)) is a one-line change because the wire format is canonical OpenAI. + +## Artwork Agent Using image.generation + +An agent that needs artwork — NFT images, avatars, generated content for its users — calls `POST /v1/images/generations` with the standard OpenAI images request shape. Nori routes to gpt-image-1 upstream and charges a flat per-image price. + +```typescript {% title="artwork-agent.ts" %} +const response = await fetch(`${NORI_URL}/v1/images/generations`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'openai/gpt-image-1', + prompt: 'Pixel-art portrait of a sea-otter plumber holding a wrench', + n: 1, + size: '1024x1024', + }), +}).then((r) => r.json()); + +const imageB64 = response.data[0].b64_json; +``` + +A typical follow-up is uploading the image and minting it as an [MPL Core](/smart-contracts/core) asset — the generation step and the mint step are independent, and only the generation is a Nori charge. + +## Portfolio Analyzer Using solana.rpc + +Onchain-data agents get RPC and DAS access through the same billing pipe. `POST /v1/solana/rpc` is a transparent JSON-RPC pass-through to a DAS-capable upstream, so standard methods (`getBalance`) and DAS methods (`getAsset`, `getAssetsByOwner`) share one endpoint and one per-call price. This portfolio analyzer implements the gather step of a gather → enrich → summarize workflow: + +```typescript {% title="portfolio-analyzer.ts" %} +async function noriRpc(method: string, params: unknown[]) { + const res = await fetch(`${NORI_URL}/v1/solana/rpc`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), + }).then((r) => r.json()); + return res.result; +} + +// Gather: SOL balance + all token holdings for a wallet. +const owner = '11111111111111111111111111111112'; // wallet under analysis +const balance = await noriRpc('getBalance', [owner]); + +// DAS method — same endpoint, same per-call price. +const assets = await noriRpc('getAssetsByOwner', [ + { ownerAddress: owner, page: 1, limit: 100 }, +]); + +// Enrich/summarize: feed the holdings to the inference agent above +// for a natural-language portfolio breakdown. +``` + +Because each call is metered individually (flat per-call price), loop-style agents — a price watcher polling on an interval, an analyzer walking paginated holdings — should budget calls deliberately: the PDA balance is the spending limit, and an empty wallet [hard-stops](/agents/nori/pricing-and-billing#hard-stop-semantics) service. + +## Agent-to-Agent Caller Using A2A message/send + +Agents integrating at the protocol level (rather than through an OpenAI SDK) call the same skills via JSON-RPC 2.0 at `POST /a2a`, discovered from the [agent card](/agents/nori/#services-nori-provides). The skill input is byte-identical to the HTTP surface — the OpenAI request body simply travels inside a `message/send` envelope as a DataPart: + +```typescript {% title="a2a-caller.ts" %} +const task = await fetch(`${NORI_URL}/a2a`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'message/send', + params: { + requestId: crypto.randomUUID(), + message: { + parts: [ + { + kind: 'data', + data: { + skill: 'chat.completion', + input: { + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from another agent.' }], + }, + }, + }, + ], + }, + }, + }), +}).then((r) => r.json()); +``` + +`message/send` returns a completed task synchronously; `tasks/get` fetches a prior task by ID. Use `image.generation` or `solana.rpc` as the `skill` with the same input shapes as their HTTP counterparts. + +{% callout type="note" title="Streaming is not available in v1" %} +`message/sendStream` is declared on the agent card but returns 501 in v1, and `/v1/chat/completions` is non-streaming. Design agent loops around complete responses. +{% /callout %} + +## Quick Reference + +| Example | Service | Endpoint | Billed as | +|---------|---------|----------|-----------| +| Inference agent | `chat.completion` | `POST /v1/chat/completions` | Per input/output token, by model | +| Artwork agent | `image.generation` | `POST /v1/images/generations` | Per image | +| Portfolio analyzer | `solana.rpc` | `POST /v1/solana/rpc` | Per call (DAS methods included) | +| A2A caller | any skill | `POST /a2a` (`message/send`) | Same as the underlying skill | + +## Notes + +- All examples assume `NORI_URL` (Nori's base URL) and `token` (a bearer from the [handshake flow](/agents/nori/delegate-to-nori#step-3-authenticate-with-a-bearer-token)); tokens expire after 15 minutes, so long-running agents re-handshake +- Without a bearer token the same requests work over the x402 rail: expect an HTTP 402 with payment requirements on first call, pay, and retry +- The Metaplex agent template packages these patterns as ready-made Mastra tools (`chat-completion`, `generate-image`, `solana-rpc-call`, `delegate-to-nori`) if you'd rather start from a running agent +- Charge-on-success applies to every example: a failed upstream call costs nothing — see [Pricing and Billing](/agents/nori/pricing-and-billing#charge-on-success-accounting) + +Maintained by Metaplex Foundation. Last verified: 2026-07-08. [View source on GitHub](https://github.com/metaplex-foundation/agent-plumber). + +## FAQ + +Common questions about building against Nori's services. + +### Which SDKs work with Nori's inference service? +Any OpenAI-compatible client works — the Vercel AI SDK via `createOpenAICompatible`, the official OpenAI SDKs with a custom `baseURL`, or agent frameworks like Mastra that accept an OpenAI-compatible provider. Point the client at `NORI_URL/v1` and attach the bearer token as the `Authorization` header. + +### Can my agent use DAS methods like getAssetsByOwner through Nori? +Yes. The `solana.rpc` service is a transparent JSON-RPC pass-through to a DAS-capable upstream provider, so DAS methods (`getAsset`, `getAssetsByOwner`, and others) work exactly like standard Solana RPC methods — same endpoint, same per-call price. + +### Do these examples work without delegation? +Yes, over the x402 fallback rail — the first call runs the request once and returns HTTP 402 with payment requirements; paying and retrying returns the cached result. The examples assume delegation because it removes the payment round-trip; see [Delegate to Nori](/agents/nori/delegate-to-nori) for the one-time setup. + +### Which models can I request through chat.completion? +Any model on the rate card, addressed as `/` — for example `anthropic/claude-sonnet-4-6`, `openai/gpt-5.4`, or `google/gemini-2.5-flash`. `GET /v1/models` lists the live directory, and [`GET /rate-card`](/agents/nori/pricing-and-billing) carries the per-token prices. diff --git a/src/pages/en/agents/nori/index.md b/src/pages/en/agents/nori/index.md new file mode 100644 index 00000000..ebf80c9d --- /dev/null +++ b/src/pages/en/agents/nori/index.md @@ -0,0 +1,165 @@ +--- +title: Nori - Pay-As-You-Go Services for Metaplex Agents +metaTitle: Nori - Pay-As-You-Go LLM, Image, and RPC Services for Agents | Metaplex +description: Nori is a Metaplex service agent that sells LLM inference, image generation, and Solana RPC access to other agents, metered in SOL per call. Learn how delegate-pay billing works and how to use Nori as a reference implementation for your own service agent. +keywords: + - Nori + - service agent + - agent plumber + - pay-as-you-go inference + - delegate-pay + - x402 payments + - A2A protocol + - agent-to-agent services + - Metaplex agent +about: + - Nori + - Agent Commerce + - Autonomous Agents + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: What is Nori? + a: Nori is a pay-as-you-go service agent operated by the Metaplex Foundation. It sells LLM inference, image generation, and Solana RPC access to other agents, priced in USD and settled in SOL per call against the calling agent's onchain PDA wallet. It is also the open-source reference implementation for building Metaplex service agents. + - q: Do I need my own LLM provider API keys to use Nori? + a: No. Nori holds the upstream provider keys (Anthropic, OpenAI, Google, image generation, paid Solana RPC). A consumer agent only needs a Solana keypair and a registered agent asset — every call settles per-use in SOL against the agent's PDA wallet. + - q: What happens to my agent if Nori goes down? + a: A delegated agent that relies on Nori for inference, images, or RPC loses those capabilities while Nori is unavailable. Nori's surfaces are OpenAI-compatible and standard Solana JSON-RPC, so a break-glass fallback is pointing your client at any other OpenAI-compatible provider or RPC endpoint with your own keys. Self-hosting your own Nori instance is planned for v2. + - q: Is delegating to Nori safe? Can Nori drain my wallet? + a: Delegation grants Nori billing authority over your agent's PDA wallet, so only keep a working balance there. Every charge carries an onchain Memo receipt you can audit, charges are only taken for successful calls, and the asset owner can revoke the delegation at any time, which hard-stops the delegate-pay rail. + - q: What is the difference between the delegate-pay rail and the x402 rail? + a: Delegate-pay is the primary rail — after a one-time onchain delegation, Nori charges your agent's PDA directly per call with no payment round-trip. x402 is the fallback for non-delegated callers — the first request returns HTTP 402 with payment requirements, the caller pays, then retries. +--- + +Nori is a pay-as-you-go **service agent** operated by the Metaplex Foundation. It sells LLM inference, image generation, and Solana RPC access to other agents — priced in USD, settled in SOL per call against the calling agent's onchain wallet. Nori is also the open-source reference implementation of a Metaplex service agent: agent builders can study (and copy) its [A2A surface](/agents/agent-commerce), delegate-pay billing, x402 fallback, and rate-card patterns. {% .lead %} + +## Summary + +Nori removes the plumbing every agent operator otherwise wires up themselves — LLM provider keys, an image-generation account, paid Solana RPC, and per-call billing. A consumer agent needs only a Solana keypair and a [registered agent asset](/agents/register-agent). + +- **Three metered services** — `chat.completion` (Anthropic / OpenAI / Google, tool calls supported), `image.generation` (gpt-image-1), and `solana.rpc` (RPC + DAS pass-through) +- **Two payment rails** — [delegate-pay](/agents/nori/delegate-to-nori) (primary, one-time onchain setup) and x402 v2 (fallback, per-call HTTP 402 flow) +- **Charge-on-success billing** — the upstream call runs first; failed calls are never charged, and every charge carries an onchain Memo receipt +- **Single point of failure caveat** — a delegated agent depends on Nori's availability for inference, images, and RPC; see [Nori as a single point of failure](#nori-as-a-single-point-of-failure) for mitigations + +{% callout type="note" title="Two audiences, one page" %} +Use this section if you are **consuming** Nori's services from your own agent, or if you are **building a service agent** and want a working reference for A2A skills, per-call billing, and rate-card publication. The [source repository](https://github.com/metaplex-foundation/agent-plumber) is open source. +{% /callout %} + +## Services Nori Provides + +Nori exposes three services over two surfaces that share one handler stack. Skill input/output uses canonical OpenAI wire format for chat and images, and standard Solana JSON-RPC for RPC — an A2A caller and an OpenAI-SDK caller send byte-identical payloads. + +| Service | Skill ID | Endpoint | Upstream | +|---------|----------|----------|----------| +| LLM inference (tool calls supported) | `chat.completion` | `POST /v1/chat/completions` | Anthropic, OpenAI, Google — routed by `/` prefix | +| Image generation | `image.generation` | `POST /v1/images/generations` | OpenAI gpt-image-1 | +| Solana RPC + DAS | `solana.rpc` | `POST /v1/solana/rpc` | Operator-configured RPC provider (DAS methods pass through) | + +Both surfaces reach the same services: + +- **OpenAI-compatible HTTP** (`/v1/*`) — point any OpenAI SDK or AI framework at Nori with `baseURL`. This is the surface most consumer agents use. +- **A2A JSON-RPC** (`/a2a`) — programmatic agent-to-agent calls. Discovery starts at `GET /.well-known/agent-card.json`, which advertises skills, payment schemes, and Nori's `serviceExecutiveAddress` (the address you register as a delegate). + +## How Nori Payments Work + +Nori picks a payment rail per call: delegate-pay when the caller has onboarded, x402 otherwise. + +| Rail | When it fires | How it settles | +|------|---------------|----------------| +| **Delegate-pay** (primary) | Caller presents a valid bearer token and Nori is a registered [execution delegate](/smart-contracts/mpl-agent/tools) on the caller's agent asset | Nori signs an MPL Core Execute transaction transferring SOL from the caller's PDA to Nori's service PDA, with a Memo receipt — no payment round-trip | +| **x402 v2** (fallback) | No bearer token, invalid token, or delegation not set up | First request returns HTTP 402 with payment requirements; caller pays (SOL or USDC), retries, and receives the cached result | + +The delegate-pay rail is what makes Nori invisible to your agent's end users: after a [one-time delegation](/agents/nori/delegate-to-nori), every call settles automatically with no wallet prompts and no over-quoted holds. Pricing is published on a versioned [rate card](/agents/nori/pricing-and-billing) with a price-change notice policy. + +## Nori as a Single Point of Failure + +A delegated agent that sources its inference, image generation, and RPC from Nori has made Nori a single point of failure: if Nori is unavailable, the agent loses those capabilities until Nori recovers. This is the top-ranked risk in Nori's own risk register, and the v1 mitigation is documentation and portable interfaces rather than redundancy. + +Plan for it explicitly: + +- **Interfaces are portable by design.** `chat.completion` is canonical OpenAI wire format and `solana.rpc` is standard Solana JSON-RPC. A break-glass fallback is a config change: point your OpenAI-compatible client at another provider (with your own key) and your RPC calls at any public or paid endpoint. +- **Keep break-glass credentials.** Zero-BYOK is Nori's convenience, not a requirement of your architecture. Holding a low-tier provider key and a free RPC URL in reserve keeps your agent degraded-but-alive during a Nori outage. +- **The x402 rail is an independent fallback for payment, not availability.** It removes the delegation dependency but still depends on Nori being up. +- **Delegation is revocable at any time.** If you migrate off Nori, the asset owner revokes the delegation record and the delegate-pay rail [hard-stops](/agents/nori/pricing-and-billing#hard-stop-semantics). + +{% callout type="warning" title="Self-hosting is deferred to v2" %} +Running your own Nori instance (eliminating the shared dependency entirely) is planned for v2. In v1, the mitigation is the portable OpenAI/JSON-RPC interfaces above — design your agent so Nori's base URL is a config value, not an assumption. +{% /callout %} + +## Using Nori as a Reference Implementation + +Nori is the working blueprint for a Metaplex service agent — an agent that charges other agents for work. The [source repository](https://github.com/metaplex-foundation/agent-plumber) demonstrates each pattern end-to-end: + +| Pattern | What Nori demonstrates | +|---------|------------------------| +| Agent card discovery | `/.well-known/agent-card.json` advertising skills, payment schemes, `serviceAssetAddress`, and `serviceExecutiveAddress` | +| Delegate-pay billing | Charging a caller's PDA via MPL Core Execute CPI with Memo receipts, with a 5-minute delegate-status cache | +| x402 v2 fallback | Canonical HTTP 402 flow with facilitator endpoints (`/verify`, `/settle`) and facilitator-as-feePayer so callers need no SOL for network fees | +| Rate card publication | `GET /rate-card` serving a versioned pricebook with a notice-period policy | +| Charge-on-success accounting | Upstream call first, charge second; failed calls return errors with no charge | +| Free delegation onboarding | Strictly-validated `POST /v1/delegate/submit` that co-signs the caller's delegation transaction as fee payer | + +To add a new paid service in your own fork: write a payment-agnostic handler that returns a result plus `costUsd`, add pricing to the pricebook, wire it into the A2A skill dispatch, and declare it on the agent card. + +## Quick Reference + +| Item | Value | +|------|-------| +| Agent card | `GET /.well-known/agent-card.json` | +| Rate card | `GET /rate-card` | +| Services | `chat.completion`, `image.generation`, `solana.rpc` | +| OpenAI-compatible base URL | `/v1` | +| A2A endpoint | `POST /a2a` (JSON-RPC 2.0, `message/send`) | +| Payment rails | Delegate-pay (primary), x402 v2 (fallback) | +| Delegation program | `mpl-agent-tools` — `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S` | +| Source | [GitHub](https://github.com/metaplex-foundation/agent-plumber) | + +## Notes + +- Nori's deployed base URL is published via its agent registration; examples across this section use `NORI_URL` as a placeholder for the base URL +- Charges are priced in USD and converted to SOL at charge time using the live Jupiter SOL/USD price (30-second cache) — see [Pricing and Billing](/agents/nori/pricing-and-billing) +- Delegation grants Nori billing authority over your agent's PDA wallet. Keep only a working balance there and audit the Memo receipts on each charge +- `message/sendStream` is declared on the agent card but returns 501 in v1; A2A calls are synchronous +- Nori (the hosted Metaplex service) and agent-plumber (the open-source implementation) are the same codebase; this documentation uses "Nori" for both + +Maintained by Metaplex Foundation. Last verified: 2026-07-08. + +## FAQ + +Common questions about Nori. + +### What is Nori? +Nori is a pay-as-you-go service agent operated by the Metaplex Foundation. It sells LLM inference, image generation, and Solana RPC access to other agents, priced in USD and settled in SOL per call against the calling agent's onchain PDA wallet. It is also the open-source reference implementation for building Metaplex service agents. + +### Do I need my own LLM provider API keys to use Nori? +No. Nori holds the upstream provider keys (Anthropic, OpenAI, Google, image generation, paid Solana RPC). A consumer agent only needs a Solana keypair and a [registered agent asset](/agents/register-agent) — every call settles per-use in SOL against the agent's PDA wallet. + +### What happens to my agent if Nori goes down? +A delegated agent that relies on Nori for inference, images, or RPC loses those capabilities while Nori is unavailable. Nori's surfaces are OpenAI-compatible and standard Solana JSON-RPC, so a break-glass fallback is pointing your client at any other OpenAI-compatible provider or RPC endpoint with your own keys. Self-hosting your own Nori instance is planned for v2. + +### Is delegating to Nori safe? Can Nori drain my wallet? +Delegation grants Nori billing authority over your agent's PDA wallet, so only keep a working balance there. Every charge carries an onchain Memo receipt you can audit, [charges are only taken for successful calls](/agents/nori/pricing-and-billing#charge-on-success-accounting), and the asset owner can [revoke the delegation](/agents/nori/delegate-to-nori#revoking-delegation-from-nori) at any time, which hard-stops the delegate-pay rail. + +### What is the difference between the delegate-pay rail and the x402 rail? +Delegate-pay is the primary rail — after a one-time onchain delegation, Nori charges your agent's PDA directly per call with no payment round-trip. x402 is the fallback for non-delegated callers — the first request returns HTTP 402 with payment requirements, the caller pays (SOL or USDC), then retries. + +## Glossary + +Core terms used across the Nori documentation. + +| Term | Definition | +|------|------------| +| **Nori** | The Metaplex Foundation's pay-as-you-go service agent, and the reference implementation (agent-plumber) for Metaplex service agents | +| **Service agent** | An agent that sells services to other agents and charges per call | +| **Delegate-pay** | Nori's primary payment rail — after a one-time execution delegation, Nori charges the caller's PDA directly via an MPL Core Execute transaction | +| **x402** | An HTTP `402 Payment Required` protocol for machine-to-machine payments; Nori's fallback rail for non-delegated callers | +| **Rate card** | Nori's published price list at `GET /rate-card` — versioned, USD-denominated, with a price-change notice policy | +| **Charge-on-success** | Nori's billing rule: the upstream call runs first, and only successful calls are charged | +| **Hard stop** | Immediate end of delegate-pay service when the caller undelegates or the caller's PDA wallet cannot cover a charge | +| **Asset Signer (PDA wallet)** | The agent's onchain wallet, an [MPL Core](/smart-contracts/core) PDA derived from `["mpl-core-execute", asset]` — the account Nori's charges draw from | +| **Executive profile** | The onchain identity of an off-chain signer in [`mpl-agent-tools`](/smart-contracts/mpl-agent/tools); you delegate to Nori's executive profile | +| **Agent card** | The A2A discovery document at `/.well-known/agent-card.json` advertising skills, payment schemes, and Nori's service addresses | diff --git a/src/pages/en/agents/nori/pricing-and-billing.md b/src/pages/en/agents/nori/pricing-and-billing.md new file mode 100644 index 00000000..2ce0979e --- /dev/null +++ b/src/pages/en/agents/nori/pricing-and-billing.md @@ -0,0 +1,187 @@ +--- +title: Nori Pricing and Billing +metaTitle: Nori Pricing and Billing - Rate Card, Charge-on-Success, Hard Stops | Metaplex +description: How Nori prices and bills service calls - the published rate card at GET /rate-card, USD-to-SOL conversion at charge time, charge-on-success accounting, the price-change notice policy, and hard-stop semantics on undelegate and wallet-empty. +keywords: + - Nori rate card + - Nori pricing + - charge-on-success + - price-change notice + - hard stop + - wallet empty + - undelegate + - agent billing + - pay-per-call +about: + - Nori + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: Am I charged if a Nori call fails? + a: No. Nori runs the upstream call first and only charges on success. A failed upstream call returns an error with no charge. On the x402 rail, the result is computed once and cached, so a paid retry returns the cached result and is never re-run or double-billed. + - q: How does Nori convert USD prices to SOL? + a: The rate card is USD-denominated. At charge time Nori recomputes the SOL amount using the live SOL/USD spot price from the Jupiter price API, cached for 30 seconds. The exact lamports charged therefore track the market rate at the moment of the call. + - q: How much notice does Nori give before a price change? + a: The rate card carries a policy block with notice_period_days (7 by default). Price increases are committed with an effective_at timestamp at least the notice period in the future, and charges before effective_at continue at the previously published rate. Change history is available at the policy's notice_url. + - q: What happens when my agent's wallet runs out of SOL? + a: A hard stop. When the PDA cannot cover a charge, the delegate-pay charge fails and the call falls back to an HTTP 402 x402 challenge — service is not rendered on credit. Calls resume as soon as you top up the PDA. + - q: What happens if I undelegate from Nori mid-flight? + a: The next charge attempt fails onchain, Nori invalidates its cached delegate status, and the delegate-pay rail hard-stops. Subsequent calls receive x402 payment challenges. Nothing can be charged after revocation because the chain rejects the Execute transaction. + - q: Where can I verify what Nori charged my agent? + a: Every charge is a SOL transfer from your agent's PDA to Nori's service PDA with a Memo instruction carrying a structured receipt. Your agent's onchain transaction history is the complete, independently auditable billing record. +--- + +Nori prices every call in USD from a published, versioned rate card, converts to SOL at the moment of the charge, and bills only on success — a failed upstream call is never charged. Price changes follow a notice-period policy, and billing hard-stops immediately when a caller undelegates or their wallet cannot cover a charge. {% .lead %} + +## Summary + +Nori's billing model is designed to be auditable from the outside: public prices, onchain receipts, and no charges without service. + +- **Rate card** — `GET /rate-card` serves the full USD pricebook with version, `effective_at`, markup factor, and the price-change policy +- **Charge-on-success** — the upstream call runs first; failures return errors with no charge, and paid x402 retries return a cached result rather than re-running the call +- **Price-change notice** — increases are committed with an `effective_at` at least `notice_period_days` (default 7) in the future; earlier charges stay at the previously published rate +- **Hard stops** — undelegation and wallet-empty both stop delegate-pay billing immediately; calls fall back to x402 challenges rather than accruing debt + +## The Nori Rate Card + +`GET /rate-card` is the canonical, machine-readable price list — always check it rather than relying on any snapshot in documentation. It serves the full pricebook plus policy metadata with a 5-minute cache: + +```json {% title="GET /rate-card (abridged)" %} +{ + "version": 1, + "effective_at": "2026-05-21T00:00:00.000Z", + "policy": { + "notice_period_days": 7, + "notice_url": "https://github.com/metaplex-foundation/agent-plumber/blob/main/packages/shared/src/pricebook.json", + "description": "Price changes are announced by editing this file..." + }, + "markup_factor": 1.25, + "llm": { + "anthropic/claude-sonnet-4-6": { + "inputPerMillion": 3.0, + "outputPerMillion": 15.0, + "cachedInputPerMillion": 0.3 + } + }, + "image": { "openai/gpt-image-1": { "perImage": 0.04 } }, + "rpc": { "default": { "perCall": 0.0001 } } +} +``` + +### Rate Card Schema + +| Field | Meaning | +|-------|---------| +| `version` | Monotonic card version; bumped on every price change | +| `effective_at` | ISO timestamp at which this card's prices take effect | +| `policy.notice_period_days` | Minimum days between committing a price increase and its `effective_at` (default 7) | +| `policy.notice_url` | Where the card (and its change history) is published | +| `markup_factor` | Uniform retail markup applied to the wholesale USD prices at charge time (1.25×) | +| `llm.` | Wholesale USD per million input / output / cached-input tokens | +| `image.` | Wholesale USD per generated image | +| `rpc.default` | Wholesale USD per RPC or DAS call | + +Listed prices are **wholesale**; the amount charged is `wholesale × markup_factor`. `GET /v1/models` enumerates the available LLM model IDs from the same source for OpenAI-SDK clients. + +### How a Charge Is Priced + +Each service computes a USD cost from the rate card, then converts to SOL at charge time. + +1. The service handler returns a result plus `costUsd` — token counts × per-million prices for `chat.completion`, per-image for `image.generation`, per-call for `solana.rpc` +2. The markup factor (1.25×) is applied to the wholesale cost +3. The USD amount converts to lamports using the live SOL/USD spot price from the Jupiter price API (30-second cache) +4. The charge lands as a SOL transfer from your agent's PDA to Nori's service PDA, with a Memo receipt + +{% callout type="note" title="Every charge carries an onchain receipt" %} +The Memo instruction on each charge transaction encodes a structured receipt (service, request, and cost details). Your agent's transaction history against Nori's service PDA is a complete, independently auditable billing record — no trust in Nori's off-chain accounting required. +{% /callout %} + +## Charge-on-Success Accounting + +Nori never charges for a call it did not successfully serve. The ordering is upstream-first, charge-second, on both payment rails: + +- **Delegate-pay rail** — Nori runs the upstream call (LLM, image, RPC); if it succeeds, Nori charges the PDA and returns the result. If the upstream call fails, the caller gets an error response and no charge. +- **x402 rail** — the first request (before payment) runs the upstream call and caches the result keyed by the payment challenge. The 402 response quotes the exact cost of the already-computed result. When the caller pays and retries, Nori returns the **cached** result — the upstream call is never re-run, so it can never be double-billed, and the price quoted is the price settled. + +The failure case worth noting is the inverse: on the delegate-pay rail, if the upstream call succeeds but the charge itself fails (revoked delegation, empty wallet), the caller may receive that one result unpaid, and the rail then [hard-stops](#hard-stop-semantics). Nori absorbs that single-call loss rather than holding funds hostage in advance. + +## Price-Change Notice Policy + +Price changes are announced in advance through the rate card itself — there are no silent price increases on the delegate-pay rail. The policy, embedded in the card's `policy` block: + +1. A price change is published by committing a new card with a bumped `version` and a future `effective_at` +2. For increases, `effective_at` must be at least `notice_period_days` (default **7 days**) after the commit +3. Charges before `effective_at` continue at the previously published rate +4. The full change history is public at `policy.notice_url` + +Acceptance is implicit at delegation time: by delegating, an agent accepts the published card and its notice policy. If a published change is unacceptable, [revoke the delegation](/agents/nori/delegate-to-nori#revoking-delegation-from-nori) before `effective_at` — revocation is an immediate hard stop, so no charge can land at a rate you didn't accept. + +To monitor for changes programmatically, poll `GET /rate-card` (it is cached for 5 minutes) and alert when `version` increments or `effective_at` moves. + +## Hard-Stop Semantics + +Two conditions stop delegate-pay billing immediately, by construction rather than by policy: the chain refuses the charge, so no debt can accrue. + +### Hard Stop on Undelegate + +Revoking the execution delegation ends Nori's charging authority at the chain level. The next charge attempt fails with `Neither the asset or any plugins have approved this operation`, Nori busts its cached delegate status for the asset, and subsequent calls fall through to the x402 rail — the caller receives HTTP 402 payment challenges instead of auto-charges. Because delegate status is cached for up to 5 minutes, one in-flight call may still attempt (and fail) a delegate charge right after revocation; the onchain check is what enforces the stop, so nothing can be charged post-revocation. + +### Hard Stop on Wallet-Empty + +When the agent's PDA cannot cover a charge, the delegate charge fails and the call is not served on credit. The caller receives an x402 challenge (HTTP 402) and can either pay that call directly or top up the PDA to resume delegate-pay. Nori extends no credit line — an underfunded agent degrades to pay-per-call-with-challenge, it does not accumulate debt. + +{% callout type="note" title="Keep the PDA above the rent-exempt floor" %} +The PDA needs to stay above the system rent-exempt minimum (890,880 lamports) for transfers out of it to succeed. Budget the working balance as `expected calls × typical charge + rent-exempt floor`. The agent template seeds new delegations with 0.002 SOL for exactly this reason. +{% /callout %} + +Operationally, treat both hard stops as monitoring signals in your agent: a sudden shift from 200 responses to 402 challenges on previously delegate-paid calls means the delegation is gone or the wallet is empty. + +## Quick Reference + +| Item | Value | +|------|-------| +| Rate card endpoint | `GET /rate-card` (5-minute cache) | +| Model directory | `GET /v1/models` | +| Denomination | USD prices, settled in SOL (Jupiter spot, 30s cache) | +| Markup | 1.25× wholesale, uniform | +| Notice period | 7 days (`policy.notice_period_days`) | +| Billing rule | Charge-on-success; x402 retries return cached results | +| Undelegate | Immediate hard stop → x402 fallback | +| Wallet-empty | Immediate hard stop → x402 challenge until top-up | +| Receipts | Memo instruction on every charge transaction | + +## Notes + +- The pricebook bundled in the [source repository](https://github.com/metaplex-foundation/agent-plumber) is a snapshot of published list prices at release; `GET /rate-card` on the live instance is the operative price list +- Rate-card prices are wholesale — multiply by `markup_factor` for the charged amount +- The exact lamports charged for the same call vary with the SOL/USD rate at charge time; the USD amount is what's fixed by the card +- Hard stops apply to the delegate-pay rail; the x402 rail is inherently prepaid per call and has no equivalent failure mode +- Operators forking Nori as a reference implementation edit `packages/shared/src/pricebook.json` directly and should honor the same `effective_at` notice discipline + +Maintained by Metaplex Foundation. Last verified: 2026-07-08. [View source on GitHub](https://github.com/metaplex-foundation/agent-plumber). + +## FAQ + +Common questions about Nori pricing and billing. + +### Am I charged if a Nori call fails? +No. Nori runs the upstream call first and only charges on success. A failed upstream call returns an error with no charge. On the x402 rail, the result is computed once and cached, so a paid retry returns the cached result and is never re-run or double-billed. + +### How does Nori convert USD prices to SOL? +The rate card is USD-denominated. At charge time Nori recomputes the SOL amount using the live SOL/USD spot price from the Jupiter price API, cached for 30 seconds. The exact lamports charged therefore track the market rate at the moment of the call. + +### How much notice does Nori give before a price change? +The rate card carries a `policy` block with `notice_period_days` (7 by default). Price increases are committed with an `effective_at` timestamp at least the notice period in the future, and charges before `effective_at` continue at the previously published rate. Change history is available at the policy's `notice_url`. + +### What happens when my agent's wallet runs out of SOL? +A hard stop. When the PDA cannot cover a charge, the delegate-pay charge fails and the call falls back to an HTTP 402 x402 challenge — service is not rendered on credit. Calls resume as soon as you top up the PDA. + +### What happens if I undelegate from Nori mid-flight? +The next charge attempt fails onchain, Nori invalidates its cached delegate status, and the delegate-pay rail hard-stops. Subsequent calls receive x402 payment challenges. Nothing can be charged after revocation because the chain rejects the Execute transaction. + +### Where can I verify what Nori charged my agent? +Every charge is a SOL transfer from your agent's PDA to Nori's service PDA with a Memo instruction carrying a structured receipt. Your agent's onchain transaction history is the complete, independently auditable billing record. diff --git a/src/pages/ja/agents/nori/delegate-to-nori.md b/src/pages/ja/agents/nori/delegate-to-nori.md new file mode 100644 index 00000000..d34b02d4 --- /dev/null +++ b/src/pages/ja/agents/nori/delegate-to-nori.md @@ -0,0 +1,258 @@ +--- +title: Noriに委任する +metaTitle: Noriに委任する - デリゲートペイ課金への1回限りのオンボーディング | Metaplex +description: NoriをMetaplexエージェントの実行デリゲートとして登録し、すべてのLLM・画像・RPC呼び出しがエージェントのPDAウォレットから自動的に決済されるようにします。オンボーディングは無料 — 手数料用のSOLもRPCも不要です。 +keywords: + - delegate to Nori + - execution delegation + - delegate-pay + - agent onboarding + - delegateExecutionV1 + - Nori bearer token + - Metaplex agent billing +about: + - Nori + - Execution Delegation + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +howToSteps: + - Noriのエージェントカードを取得し、serviceExecutiveAddressを読み取ります。 + - Noriのエグゼクティブプロファイルを指す単一のdelegateExecutionV1命令を含むトランザクションを、Noriをフィーペイヤーとして構築します。 + - エージェントのエグゼクティブキーペアで署名し、Noriの無料の/v1/delegate/submitエンドポイントにトランザクションを送信します。 + - /auth/handshakeで署名済みチャレンジをベアラートークンと交換します。 + - ベアラートークンを付けて有料呼び出しを行います — 課金はエージェントのPDAウォレットから自動的に決済されます。 +howToTools: + - '@metaplex-foundation/mpl-agent-registry' + - '@metaplex-foundation/umi' +faqs: + - q: Noriへの委任に費用はかかりますか? + a: いいえ。Noriが委任トランザクションのネットワーク手数料を支払い(フィーペイヤーとして連署します)、オンボーディングエンドポイントは無料かつ認証不要です。ただし、その後はエージェントのPDAウォレットに運用に必要なSOL残高が必要になります。呼び出しごとの課金の引き落とし元となるアカウントだからです。 + - q: 委任はNoriにどのような権限を与えますか? + a: 委任はNoriのエグゼクティブプロファイルをエージェントアセットの実行デリゲートとして登録し、NoriがエージェントのPDAウォレットからSOLを移動するMPL Core Executeトランザクションに署名できるようにします。Noriはこれを使って呼び出しごとの課金を決済し、それぞれにオンチェーンのMemoレシートが付きます。PDAには運用に必要な残高だけを置き、レシートを監査してください。 + - q: Noriによるエージェントへの課金を止めるにはどうすればいいですか? + a: エージェントアセット上の実行委任を取り消します。次の課金試行はオンチェーンで失敗し、Noriのキャッシュ済みデリゲートステータスは無効化され、デリゲートペイのレールはハードストップします — 以降の呼び出しは自動課金される代わりにHTTP 402のx402チャレンジを受け取ります。 + - q: 委任したのに呼び出しがHTTP 402を返すのはなぜですか? + a: 402は、その呼び出しでデリゲートペイのレールが利用できなかったことを意味します — ベアラートークンが欠落または期限切れ(トークンの有効期間は15分)、委任が取り消された、または課金自体が失敗した(通常はPDAウォレットが空)のいずれかです。ハンドシェイクを再実行し、委任レコードが存在することを確認し、PDA残高をチェックしてください。 + - q: 委任せずにNoriを使うことはできますか? + a: はい。委任していない呼び出し元はx402フォールバックレールを使います — 最初のリクエストは支払い要件と共にHTTP 402を返し、SOLまたはUSDCで支払ってから再試行します。費用は同じですが、すべての呼び出しに支払いの往復が追加されます。一方、デリゲートペイはインラインで決済されます。 +--- + +Noriへの委任は、Noriをエージェントのアセット上の[実行デリゲート](/smart-contracts/mpl-agent/tools)として登録する1回限りのオンチェーンセットアップです。その後は、エージェントがNoriに対して行うすべてのLLM・画像・RPC呼び出しがエージェントのPDAウォレットから自動的に決済されます — 支払いの往復も、ウォレットプロンプトも、プロバイダーAPIキーも不要です。オンボーディングは無料です: Noriがトランザクション手数料を支払い、ブロックハッシュも提供するため、エージェントはキーペアにSOLを持つ必要も、自前のRPCを持つ必要もありません。{% .lead %} + +## 概要 + +Noriに実行委任を付与すると、エージェントは2往復の[x402フォールバック](/agents/nori/#noriの決済の仕組み)からインラインのデリゲートペイレールに切り替わります。 + +- **1回限りのセットアップ** — Noriのエグゼクティブプロファイルを指す単一の`delegateExecutionV1`命令。Noriが無料で連署・送信します +- **呼び出しごとの決済** — NoriはMemoレシート付きのMPL Core Executeトランザクションを通じてエージェントの[Asset Signer PDA](/agents/what-is-an-agent)に課金し、[成功した呼び出し](/agents/nori/pricing-and-billing#成功時課金の会計処理)のみが対象です +- **ベアラートークン認証** — 署名済みチャレンジ/ハンドシェイクで15分間有効なベアラートークンを発行し、呼び出しをデリゲートペイのレールにルーティングします +- **いつでも取り消し可能** — アセットオーナーは委任を取り消すことができ、自動課金は即座に[ハードストップ](#noriへの委任の取り消し)します + +{% callout type="warning" title="委任は課金権限を付与します" %} +実行デリゲートは、エージェントのPDAウォレットからの送金に署名できます。PDAは支出用アカウントとして扱ってください: トレジャリーではなく運用に必要な残高を置き、すべての課金に付随するMemoレシートを監査しましょう。Noriをエージェントの唯一のサービスプロバイダーにする前に、[単一障害点に関する注意](/agents/nori/#単一障害点としてのnori)を参照してください。 +{% /callout %} + +## クイックスタート + +1. [Noriのエージェントカードを取得](#ステップ1-noriのエグゼクティブアドレスを取得)して`serviceExecutiveAddress`を読み取ります +2. エグゼクティブキーペアを権限、Noriをフィーペイヤーとして[委任トランザクションを構築](#ステップ2-委任トランザクションの構築と送信)し、`POST /v1/delegate/submit`に送信します +3. [エージェントのPDAウォレットに入金](#エージェントpdaウォレットへの入金)して運用に必要なSOL残高を用意します +4. `/auth/challenge` + `/auth/handshake`で[ベアラートークンを発行](#ステップ3-ベアラートークンで認証)します +5. `Authorization: Bearer `を付けて[有料呼び出しを実行](#ステップ4-有料呼び出しを実行)します + +## 前提条件 + +委任には既存のオンチェーンエージェントIDが必要です。委任トランザクションはアセットとそのID PDAを参照します。 + +- [登録済みエージェント](/agents/register-agent) — `AgentIdentity`レコードを持つMPL Coreアセット +- エージェントの**エグゼクティブキーペア**(エージェントの実行に使うキーペア。[エージェントを実行](/agents/run-an-agent)でセットアップ)— 権限として委任に署名します +- `@metaplex-foundation/mpl-agent-registry`と`@metaplex-foundation/umi`のインストール +- 委任自体にはSOLもRPCエンドポイントも不要です — Noriが両方を提供します + +## ステップ1: Noriのエグゼクティブアドレスを取得 + +Noriのエージェントカードには、委任先のアドレスが宣伝されています。`/.well-known/agent-card.json`を取得し、2つのフィールドを読み取ります: + +- `serviceExecutiveAddress` — Noriのエグゼクティブキーペアの公開鍵。そのエグゼクティブプロファイルPDAが、アセットにデリゲートとして登録する対象です。 +- `serviceAssetAddress` — Nori自身のエージェントアセット。そのPDAが課金の支払い先であり、すべての課金をオンチェーンで検証できます。 + +```typescript {% title="fetch-nori-card.ts" %} +const NORI_URL = process.env.NORI_URL; // Nori's base URL + +const card = await fetch(`${NORI_URL}/.well-known/agent-card.json`).then((r) => + r.json(), +); + +const noriExecutive = card.serviceExecutiveAddress; // delegate to this +const noriServiceAsset = card.serviceAssetAddress; // charges are paid here +``` + +{% callout type="warning" title="ベースURLは信頼済みの設定として扱う" %} +エージェントカードは、どのエグゼクティブプロファイルに課金権限を委任するかを決定します。エージェントカードは自身で設定を管理している`NORI_URL`からのみ取得し、委任に署名する前に`serviceExecutiveAddress`をアウトオブバンドで(例えばNoriの公開されたエージェント登録と照合して)確認してください。 +{% /callout %} + +## ステップ2: 委任トランザクションの構築と送信 + +委任トランザクションには、ちょうど1つの`delegateExecutionV1`命令が含まれます: エグゼクティブキーペアが権限として署名し、Noriのエグゼクティブプロファイルがデリゲート、Noriのキーペアがフィーペイヤーです。オフラインで構築・署名し(Noriの無料の`GET /v1/solana/blockhash`エンドポイントがブロックハッシュを提供します)、部分署名済みトランザクションを`POST /v1/delegate/submit`にPOSTします。Noriはこれを検証し、フィーペイヤーとして連署して送信します。 + +```typescript {% title="delegate-to-nori.ts" %} +import { createNoopSigner, publicKey } from '@metaplex-foundation/umi'; +import { + delegateExecutionV1, + findAgentIdentityV1Pda, + findExecutiveProfileV1Pda, +} from '@metaplex-foundation/mpl-agent-registry'; + +// `umi` is configured with your agent's executive keypair as identity. +const agentAsset = publicKey(process.env.AGENT_ASSET_ADDRESS); + +// Nori's executive profile PDA, derived from the agent card address. +const noriProfile = findExecutiveProfileV1Pda(umi, { + authority: publicKey(noriExecutive), +}); +const agentIdentity = findAgentIdentityV1Pda(umi, { asset: agentAsset }); + +// Free blockhash — no RPC of your own needed. +const { blockhash } = await fetch(`${NORI_URL}/v1/solana/blockhash`).then((r) => + r.json(), +); + +// Build with Nori as fee payer (a noop signer — Nori co-signs server-side), +// sign with your executive keypair. +const tx = await delegateExecutionV1(umi, { + agentAsset, + agentIdentity, + executiveProfile: noriProfile, +}) + .setFeePayer(createNoopSigner(publicKey(noriExecutive))) + .setBlockhash(blockhash) + .buildAndSign(umi); + +// Nori validates, co-signs, and submits — free of charge. +const result = await fetch(`${NORI_URL}/v1/delegate/submit`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + transaction: Buffer.from(umi.transactions.serialize(tx)).toString('base64'), + }), +}).then((r) => r.json()); + +console.log(result); +// { success: true, signature: '...', agentAsset: '...', authority: '...' } +``` + +{% callout type="note" title="厳格なトランザクション検証" %} +`POST /v1/delegate/submit`は、Nori自身のエグゼクティブプロファイルを指し、Noriをフィーペイヤーとする、ちょうど1つの`delegateExecutionV1`命令(`mpl-agent-tools`プログラムのディスクリミネーター1)以外のものをすべて拒否します。この厳格な形状により、無料エンドポイントがトランザクション送信サービスとして悪用されることを防ぎます。 +{% /callout %} + +Metaplexエージェントテンプレートからエージェントを構築する場合、このステップ全体は`delegate-to-nori`ツールとしてパッケージ化されています — 1回の呼び出しで、手動のトランザクション構築は不要です。 + +## ステップ3: ベアラートークンで認証 + +有料呼び出しは、Sign-In-With-Solanaスタイルのハンドシェイクで発行されたベアラートークンを携えている場合にデリゲートペイのレールにルーティングされます。トークンは、エージェントアセットに登録されたデリゲートであるエグゼクティブキーペアを制御していることを証明します。有効期間は15分なので、期限切れ時にはハンドシェイクを再実行してください。 + +```typescript {% title="nori-handshake.ts" %} +import { base58 } from '@metaplex-foundation/umi/serializers'; + +// 1. Get a fresh nonce. +const { nonce } = await fetch(`${NORI_URL}/auth/challenge`).then((r) => r.json()); + +// 2. Sign the handshake envelope with your executive keypair. +const now = Date.now(); +const handshake = { + pubkey: umi.identity.publicKey.toString(), + agentAsset: agentAsset.toString(), + audience: NORI_URL, + nonce, + issuedAt: new Date(now).toISOString(), + expiresAt: new Date(now + 60_000).toISOString(), +}; +const signature = base58.deserialize( + await umi.identity.signMessage( + new TextEncoder().encode(JSON.stringify(handshake)), + ), +)[0]; + +// 3. Exchange for a bearer token (valid 15 minutes). +const { token } = await fetch(`${NORI_URL}/auth/handshake`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ handshake, signature }), +}).then((r) => r.json()); +``` + +## ステップ4: 有料呼び出しを実行 + +ベアラートークンを添付すると、Noriはアップストリームの呼び出しを実行してから、1つのExecuteトランザクションでエージェントのPDAに課金します — レスポンスは402チャレンジなしの1往復で返ってきます。同じヘッダーがすべての`/v1/*`エンドポイントと`/a2a`で機能します。 + +```typescript {% title="paid-call.ts" %} +const completion = await fetch(`${NORI_URL}/v1/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from a delegated agent.' }], + }), +}).then((r) => r.json()); +``` + +アセットに対する最初の有料呼び出しの際、Noriは自分がまだ登録済みデリゲートであることをオンチェーンで確認します。結果は5分間キャッシュされるため、以降の呼び出しではチェーンの参照はスキップされます。各サービスを利用する完全なエージェント(OpenAI互換SDKクライアントをNoriに向ける例を含む)については、[サンプルエージェント](/agents/nori/example-agents)を参照してください。 + +## エージェントPDAウォレットへの入金 + +課金はエージェントのAsset Signer PDAから引き落とされるため、最初の有料呼び出しの前にSOL残高が必要です。PDAはシステムのレント免除最低額(0バイトアカウントで890,880ラマポート)を上回っている必要もあります — Metaplexエージェントテンプレートは、レント未満の小さな課金が失敗しないよう、委任時に0.002 SOLをシードします。任意のウォレットからPDAにSOLを送金してください。残高が尽きると、補充するまで呼び出しはHTTP 402チャレンジにフォールバックします([ハードストップのセマンティクス](/agents/nori/pricing-and-billing#ハードストップのセマンティクス)を参照)。 + +## Noriへの委任の取り消し + +実行委任の取り消しはキルスイッチであり、ハードストップとして効力を発揮します。アセットオーナーがNoriのエグゼクティブプロファイルに対する`ExecutionDelegateRecordV1`を取り消すと、次の課金試行はオンチェーンで失敗し、Noriはそのアセットのキャッシュ済みデリゲートステータスを無効化し、デリゲートペイのレールは停止します — それ以降、呼び出しは自動課金される代わりにx402の支払いチャレンジを受け取ります。5分間のデリゲートステータスキャッシュのため、取り消し直後の呼び出しはデリゲート課金を試行して(そして失敗して)しまう可能性がありますが、チェーンが拒否するため取り消し後に課金が成立することはありません。 + +取り消してもエージェントの登録が解除されたり、PDA残高に影響したりすることはありません — Noriの課金権限が取り除かれるだけです。[ステップ2](#ステップ2-委任トランザクションの構築と送信)を繰り返すことで、後から再委任できます。 + +## よくあるエラー + +| エラー | 原因 | 対処 | +|-------|-------|-----| +| `expected { transaction: }`(400) | `/v1/delegate/submit`のボディフィールドが間違っている | `{ "transaction": "" }`を送信する | +| 委任の送信が`errorReason`付きで拒否される | トランザクションの形状が厳格な検証に失敗 — 余分な命令、間違ったプログラム、間違ったエグゼクティブプロファイル、または間違ったフィーペイヤー | Noriのエグゼクティブプロファイルを指し、Noriをフィーペイヤーとする、ちょうど1つの`delegateExecutionV1`命令を構築する | +| 有料呼び出しで`401` | ベアラートークンの欠落または期限切れ(有効期間15分) | チャレンジ/ハンドシェイクフローを再実行する | +| 委任済みなのに有料呼び出しで`402` | 委任が取り消された、または課金が失敗した(通常はPDAウォレットが空) | 委任レコードが存在し、PDA残高が呼び出しをまかなえることを確認する | +| `Neither the asset or any plugins have approved this operation` | 委任の取り消し後に課金が試行された | 想定どおりのハードストップ動作 — デリゲートペイを再開するには再委任する | +| 課金時に`insufficient funds for rent` | PDA残高がレント免除最低額を下回っている | PDAを補充する(890,880ラマポート + 運用に必要な残高を上回る状態を維持する) | + +## 注意事項 + +- オンボーディングエンドポイント(`GET /v1/solana/blockhash`、`POST /v1/delegate/submit`)は無料かつ認証不要です。それ以外の実作業を行うものはすべて有料です +- ベアラートークンはエグゼクティブキーペア + エージェントアセットのペアごとに発行され、15分で期限切れになります — クライアントに再ハンドシェイクを組み込んでください +- デリゲートステータスのキャッシュにより、委任状態の変更(付与または取り消し)が決済レールに反映されるまで最大5分かかることがあります。オンチェーンの強制は即時です +- 委任はアセットごとです: 複数のエージェントを運用するオペレーターは、各アセットを個別に委任します +- `mpl-agent-tools`の実行委任(`ExecutionDelegateRecordV1`)、プログラム`TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S`に適用されます + +Metaplex Foundationが管理。最終確認日: 2026-07-08。[GitHubでソースを見る](https://github.com/metaplex-foundation/agent-plumber)。 + +## FAQ + +Noriへの委任に関するよくある質問。 + +### Noriへの委任に費用はかかりますか? +いいえ。Noriが委任トランザクションのネットワーク手数料を支払い(フィーペイヤーとして連署します)、オンボーディングエンドポイントは無料かつ認証不要です。ただし、その後はエージェントのPDAウォレットに運用に必要なSOL残高が必要になります。呼び出しごとの課金の引き落とし元となるアカウントだからです。 + +### 委任はNoriにどのような権限を与えますか? +委任はNoriのエグゼクティブプロファイルをエージェントアセットの実行デリゲートとして登録し、NoriがエージェントのPDAウォレットからSOLを移動する[MPL Core Execute](/smart-contracts/core/execute-asset-signing)トランザクションに署名できるようにします。Noriはこれを使って呼び出しごとの課金を決済し、それぞれにオンチェーンのMemoレシートが付きます。PDAには運用に必要な残高だけを置き、レシートを監査してください。 + +### Noriによるエージェントへの課金を止めるにはどうすればいいですか? +エージェントアセット上の実行委任を取り消します。次の課金試行はオンチェーンで失敗し、Noriのキャッシュ済みデリゲートステータスは無効化され、デリゲートペイのレールはハードストップします — 以降の呼び出しは自動課金される代わりにHTTP 402のx402チャレンジを受け取ります。 + +### 委任したのに呼び出しがHTTP 402を返すのはなぜですか? +402は、その呼び出しでデリゲートペイのレールが利用できなかったことを意味します — ベアラートークンが欠落または期限切れ(トークンの有効期間は15分)、委任が取り消された、または課金自体が失敗した(通常はPDAウォレットが空)のいずれかです。ハンドシェイクを再実行し、委任レコードが存在することを確認し、PDA残高をチェックしてください。 + +### 委任せずにNoriを使うことはできますか? +はい。委任していない呼び出し元はx402フォールバックレールを使います — 最初のリクエストは支払い要件と共にHTTP 402を返し、SOLまたはUSDCで支払ってから再試行します。費用は同じですが、すべての呼び出しに支払いの往復が追加されます。一方、デリゲートペイはインラインで決済されます。 diff --git a/src/pages/ja/agents/nori/example-agents.md b/src/pages/ja/agents/nori/example-agents.md new file mode 100644 index 00000000..0f714c9a --- /dev/null +++ b/src/pages/ja/agents/nori/example-agents.md @@ -0,0 +1,208 @@ +--- +title: Noriサンプルエージェント +metaTitle: Noriサンプルエージェント - 推論・画像生成・RPCコンシューマー | Metaplex +description: Noriの各サービスを利用するエージェントの実動例 - chat.completionを使うOpenAI互換の推論エージェント、image.generationを使うアートワークエージェント、solana.rpcとDASを使うポートフォリオアナライザー、そして生のA2A JSON-RPC呼び出し。 +keywords: + - Nori examples + - example agents + - OpenAI-compatible agent + - chat.completion + - image.generation + - solana.rpc + - DAS API + - A2A message/send + - agent template +about: + - Nori + - Autonomous Agents + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +faqs: + - q: Noriの推論サービスで使えるSDKはどれですか? + a: OpenAI互換クライアントならどれでも動作します — createOpenAICompatibleを使うVercel AI SDK、カスタムbaseURLを設定した公式OpenAI SDK、あるいはOpenAI互換プロバイダーを受け入れるMastraのようなエージェントフレームワークです。クライアントをNORI_URL/v1に向け、ベアラートークンをAuthorizationヘッダーとして添付してください。 + - q: エージェントはNori経由でgetAssetsByOwnerのようなDASメソッドを使えますか? + a: はい。solana.rpcサービスはDAS対応のアップストリームプロバイダーへの透過的なJSON-RPCパススルーなので、DASメソッド(getAsset、getAssetsByOwnerなど)は標準のSolana RPCメソッドとまったく同じように動作します — 同じエンドポイント、同じ呼び出しあたり価格です。 + - q: これらの例は委任なしでも動作しますか? + a: はい、x402フォールバックレール経由で動作します — 最初の呼び出しはリクエストを一度実行した上で、支払い要件と共にHTTP 402を返します。支払い後に再試行すると、キャッシュされた結果が返されます。例では支払いの往復を取り除けるため委任を前提としています。1回限りのセットアップについてはNoriに委任するを参照してください。 + - q: chat.completionではどのモデルをリクエストできますか? + a: レートカードに掲載されている任意のモデルを/形式で指定できます — たとえばanthropic/claude-sonnet-4-6、openai/gpt-5.4、google/gemini-2.5-flashです。GET /v1/modelsがライブのディレクトリを列挙し、GET /rate-cardにトークンあたりの価格が掲載されています。 +--- + +これらの例は、コンシューマーエージェントがNoriの3つのサービス — LLM推論、画像生成、Solana RPC — をそれぞれ使う方法と、エージェント間呼び出し元向けの生のA2Aエンベロープを示します。各例は、1回限りの[委任セットアップ](/agents/nori/delegate-to-nori)が完了しベアラー`token`が手元にあることを前提とします。同じリクエストは委任なしでもx402フォールバック経由で動作しますが、支払いの往復が追加されます。{% .lead %} + +## 概要 + +すべての例は完結した有料のNori呼び出しです — プロバイダーAPIキーはどこにも登場しません。 + +- **推論エージェント** — OpenAI互換クライアントを`NORI_URL/v1`に向け、ツール呼び出し付きで`chat.completion`を実行 +- **アートワークエージェント** — `image.generation`(gpt-image-1)で画像を生成 +- **ポートフォリオアナライザー** — `solana.rpc`で残高とトークン保有を読み取り(DASメソッドを含む) +- **A2A呼び出し元** — エージェント間統合向けにJSON-RPCの`message/send`で同じスキルを呼び出し + +## chat.completionを使う推論エージェント + +OpenAI互換クライアントを`NORI_URL/v1`に向けるだけで、エージェントのLLM頭脳を完全にNori上で動かせます。モデルは`/`形式で指定され、Anthropic、OpenAI、Googleのアップストリームにルーティングされます。ツール呼び出し(`tools`、`tool_choice`、`tool_calls`)は3プロバイダーすべてでサポートされているため、完全なエージェントループが変更なしで動作します。 + +```typescript {% title="inference-agent.ts" %} +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; +import { generateText, tool } from 'ai'; +import { z } from 'zod'; + +const nori = createOpenAICompatible({ + name: 'nori', + baseURL: `${NORI_URL}/v1`, + headers: { Authorization: `Bearer ${token}` }, // from /auth/handshake +}); + +const { text } = await generateText({ + model: nori('anthropic/claude-sonnet-4-6'), + tools: { + getSolPrice: tool({ + description: 'Get the current SOL price in USD', + inputSchema: z.object({}), + execute: async () => fetchSolPrice(), + }), + }, + prompt: 'Is SOL above $200 right now? Answer in one sentence.', +}); +``` + +各`generateText`呼び出しは1回の従量制`chat.completion`です — 選択したモデルの[レートカード](/agents/nori/pricing-and-billing)価格に基づき、実際の入出力トークン数で課金され、エージェントのPDAから決済されます。ワイヤーフォーマットが正規のOpenAIなので、モデルの切り替え(あるいは[障害時](/agents/nori/#単一障害点としてのnori)のNori以外のプロバイダーへのフォールバック)は1行の変更で済みます。 + +## image.generationを使うアートワークエージェント + +アートワーク — NFT画像、アバター、ユーザー向けの生成コンテンツ — を必要とするエージェントは、標準のOpenAI画像リクエスト形式で`POST /v1/images/generations`を呼び出します。Noriはアップストリームのgpt-image-1にルーティングし、画像1枚あたりの固定価格で課金します。 + +```typescript {% title="artwork-agent.ts" %} +const response = await fetch(`${NORI_URL}/v1/images/generations`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'openai/gpt-image-1', + prompt: 'Pixel-art portrait of a sea-otter plumber holding a wrench', + n: 1, + size: '1024x1024', + }), +}).then((r) => r.json()); + +const imageB64 = response.data[0].b64_json; +``` + +よくある後続処理は、画像をアップロードして[MPL Core](/smart-contracts/core)アセットとしてミントすることです — 生成ステップとミントステップは独立しており、Noriの課金対象は生成のみです。 + +## solana.rpcを使うポートフォリオアナライザー + +オンチェーンデータを扱うエージェントは、同じ課金パイプを通じてRPCとDASにアクセスできます。`POST /v1/solana/rpc`はDAS対応アップストリームへの透過的なJSON-RPCパススルーであり、標準メソッド(`getBalance`)とDASメソッド(`getAsset`、`getAssetsByOwner`)が1つのエンドポイントと1つの呼び出しあたり価格を共有します。このポートフォリオアナライザーは、収集 → 拡充 → 要約というワークフローの収集ステップを実装しています: + +```typescript {% title="portfolio-analyzer.ts" %} +async function noriRpc(method: string, params: unknown[]) { + const res = await fetch(`${NORI_URL}/v1/solana/rpc`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), + }).then((r) => r.json()); + return res.result; +} + +// Gather: SOL balance + all token holdings for a wallet. +const owner = '11111111111111111111111111111112'; // wallet under analysis +const balance = await noriRpc('getBalance', [owner]); + +// DAS method — same endpoint, same per-call price. +const assets = await noriRpc('getAssetsByOwner', [ + { ownerAddress: owner, page: 1, limit: 100 }, +]); + +// Enrich/summarize: feed the holdings to the inference agent above +// for a natural-language portfolio breakdown. +``` + +各呼び出しは個別に従量計測される(呼び出しあたりの固定価格)ため、ループ型のエージェント — 一定間隔でポーリングする価格ウォッチャーや、ページネーションされた保有をたどるアナライザー — は呼び出し回数を意図的に予算化すべきです: PDA残高が支出上限であり、ウォレットが空になるとサービスは[ハードストップ](/agents/nori/pricing-and-billing#ハードストップのセマンティクス)します。 + +## A2A message/sendを使うエージェント間呼び出し + +(OpenAI SDKではなく)プロトコルレベルで統合するエージェントは、[エージェントカード](/agents/nori/#noriが提供するサービス)から発見される`POST /a2a`で、JSON-RPC 2.0を介して同じスキルを呼び出します。スキルの入力はHTTPサーフェスとバイト単位で同一です — OpenAIリクエストボディが、DataPartとして`message/send`エンベロープの中を移動するだけです: + +```typescript {% title="a2a-caller.ts" %} +const task = await fetch(`${NORI_URL}/a2a`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'message/send', + params: { + requestId: crypto.randomUUID(), + message: { + parts: [ + { + kind: 'data', + data: { + skill: 'chat.completion', + input: { + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from another agent.' }], + }, + }, + }, + ], + }, + }, + }), +}).then((r) => r.json()); +``` + +`message/send`は完了したタスクを同期的に返します。`tasks/get`は過去のタスクをIDで取得します。`skill`に`image.generation`や`solana.rpc`を指定すれば、HTTP版と同じ入力形式で使えます。 + +{% callout type="note" title="ストリーミングはv1では利用できません" %} +`message/sendStream`はエージェントカードで宣言されていますが、v1では501を返し、`/v1/chat/completions`は非ストリーミングです。完全なレスポンスを前提にエージェントループを設計してください。 +{% /callout %} + +## クイックリファレンス + +| 例 | サービス | エンドポイント | 課金単位 | +|---------|---------|----------|-----------| +| 推論エージェント | `chat.completion` | `POST /v1/chat/completions` | モデルごとの入出力トークンあたり | +| アートワークエージェント | `image.generation` | `POST /v1/images/generations` | 画像あたり | +| ポートフォリオアナライザー | `solana.rpc` | `POST /v1/solana/rpc` | 呼び出しあたり(DASメソッドを含む) | +| A2A呼び出し元 | 任意のスキル | `POST /a2a`(`message/send`) | 基となるスキルと同じ | + +## 注意事項 + +- すべての例は`NORI_URL`(NoriのベースURL)と`token`([ハンドシェイクフロー](/agents/nori/delegate-to-nori#ステップ3-ベアラートークンで認証)によるベアラー)を前提とします。トークンは15分で期限切れになるため、長時間稼働するエージェントは再ハンドシェイクします +- ベアラートークンなしでも同じリクエストはx402レール経由で動作します: 最初の呼び出しで支払い要件付きのHTTP 402を受け取り、支払ってから再試行します +- 稼働中のエージェントから始めたい場合、Metaplexエージェントテンプレートはこれらのパターンを既製のMastraツール(`chat-completion`、`generate-image`、`solana-rpc-call`、`delegate-to-nori`)としてパッケージ化しています +- 成功時課金はすべての例に適用されます: 失敗したアップストリーム呼び出しには何の費用もかかりません — [価格と課金](/agents/nori/pricing-and-billing#成功時課金の会計処理)を参照してください + +Metaplex Foundationが管理。最終確認日: 2026-07-08。[GitHubでソースを見る](https://github.com/metaplex-foundation/agent-plumber)。 + +## FAQ + +Noriのサービスに対する構築に関するよくある質問。 + +### Noriの推論サービスで使えるSDKはどれですか? +OpenAI互換クライアントならどれでも動作します — `createOpenAICompatible`を使うVercel AI SDK、カスタム`baseURL`を設定した公式OpenAI SDK、あるいはOpenAI互換プロバイダーを受け入れるMastraのようなエージェントフレームワークです。クライアントを`NORI_URL/v1`に向け、ベアラートークンを`Authorization`ヘッダーとして添付してください。 + +### エージェントはNori経由でgetAssetsByOwnerのようなDASメソッドを使えますか? +はい。`solana.rpc`サービスはDAS対応のアップストリームプロバイダーへの透過的なJSON-RPCパススルーなので、DASメソッド(`getAsset`、`getAssetsByOwner`など)は標準のSolana RPCメソッドとまったく同じように動作します — 同じエンドポイント、同じ呼び出しあたり価格です。 + +### これらの例は委任なしでも動作しますか? +はい、x402フォールバックレール経由で動作します — 最初の呼び出しはリクエストを一度実行した上で、支払い要件と共にHTTP 402を返します。支払い後に再試行すると、キャッシュされた結果が返されます。例では支払いの往復を取り除けるため委任を前提としています。1回限りのセットアップについては[Noriに委任する](/agents/nori/delegate-to-nori)を参照してください。 + +### chat.completionではどのモデルをリクエストできますか? +レートカードに掲載されている任意のモデルを`/`形式で指定できます — たとえば`anthropic/claude-sonnet-4-6`、`openai/gpt-5.4`、`google/gemini-2.5-flash`です。`GET /v1/models`がライブのディレクトリを列挙し、[`GET /rate-card`](/agents/nori/pricing-and-billing)にトークンあたりの価格が掲載されています。 diff --git a/src/pages/ja/agents/nori/index.md b/src/pages/ja/agents/nori/index.md new file mode 100644 index 00000000..b33da93c --- /dev/null +++ b/src/pages/ja/agents/nori/index.md @@ -0,0 +1,165 @@ +--- +title: Nori - Metaplexエージェント向けの従量課金サービス +metaTitle: Nori - エージェント向け従量課金のLLM・画像生成・RPCサービス | Metaplex +description: Noriは、LLM推論、画像生成、Solana RPCアクセスを他のエージェントに販売し、呼び出しごとにSOLで課金するMetaplexのサービスエージェントです。デリゲートペイ課金の仕組みと、独自のサービスエージェント構築のリファレンス実装としてNoriを活用する方法を学びます。 +keywords: + - Nori + - service agent + - agent plumber + - pay-as-you-go inference + - delegate-pay + - x402 payments + - A2A protocol + - agent-to-agent services + - Metaplex agent +about: + - Nori + - Agent Commerce + - Autonomous Agents + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: Noriとは何ですか? + a: Noriは、Metaplex Foundationが運営する従量課金型のサービスエージェントです。LLM推論、画像生成、Solana RPCアクセスを他のエージェントに販売し、価格はUSD建てで、呼び出し元エージェントのオンチェーンPDAウォレットから呼び出しごとにSOLで決済されます。Metaplexサービスエージェントを構築するためのオープンソースのリファレンス実装でもあります。 + - q: Noriを使うのに自分のLLMプロバイダーAPIキーは必要ですか? + a: いいえ。Noriがアップストリームのプロバイダーキー(Anthropic、OpenAI、Google、画像生成、有料Solana RPC)を保持します。コンシューマーエージェントに必要なのはSolanaキーペアと登録済みエージェントアセットだけです — すべての呼び出しはエージェントのPDAウォレットから使用ごとにSOLで決済されます。 + - q: Noriがダウンしたら私のエージェントはどうなりますか? + a: 推論、画像、RPCをNoriに依存している委任済みエージェントは、Noriが利用できない間それらの機能を失います。NoriのサーフェスはOpenAI互換および標準のSolana JSON-RPCなので、緊急時のフォールバックとして、自分のキーで他のOpenAI互換プロバイダーやRPCエンドポイントにクライアントを向けることができます。Noriインスタンスのセルフホスティングはv2で予定されています。 + - q: Noriへの委任は安全ですか?Noriが私のウォレットを空にすることはできますか? + a: 委任はNoriにエージェントのPDAウォレットに対する課金権限を与えるため、そこには運用に必要な残高だけを置いてください。すべての課金には監査可能なオンチェーンのMemoレシートが付き、課金は成功した呼び出しに対してのみ行われ、アセットオーナーはいつでも委任を取り消すことができ、取り消しによりデリゲートペイのレールはハードストップします。 + - q: デリゲートペイのレールとx402のレールの違いは何ですか? + a: デリゲートペイはプライマリのレールです — 1回限りのオンチェーン委任の後、Noriは支払いの往復なしで呼び出しごとにエージェントのPDAへ直接課金します。x402は委任していない呼び出し元向けのフォールバックです — 最初のリクエストは支払い要件と共にHTTP 402を返し、呼び出し元が支払ってから再試行します。 +--- + +Noriは、Metaplex Foundationが運営する従量課金型の**サービスエージェント**です。LLM推論、画像生成、Solana RPCアクセスを他のエージェントに販売します — 価格はUSD建てで、呼び出し元エージェントのオンチェーンウォレットから呼び出しごとにSOLで決済されます。NoriはMetaplexサービスエージェントのオープンソースリファレンス実装でもあります: エージェントビルダーはその[A2Aサーフェス](/agents/agent-commerce)、デリゲートペイ(delegate-pay)課金、x402フォールバック、レートカードのパターンを研究(そしてコピー)できます。{% .lead %} + +## 概要 + +Noriは、あらゆるエージェントオペレーターが本来自分で配線することになるプラミング — LLMプロバイダーキー、画像生成アカウント、有料Solana RPC、呼び出しごとの課金 — を不要にします。コンシューマーエージェントに必要なのはSolanaキーペアと[登録済みエージェントアセット](/agents/register-agent)だけです。 + +- **3つの従量制サービス** — `chat.completion`(Anthropic / OpenAI / Google、ツール呼び出し対応)、`image.generation`(gpt-image-1)、`solana.rpc`(RPC + DASパススルー) +- **2つの決済レール** — [デリゲートペイ](/agents/nori/delegate-to-nori)(プライマリ、1回限りのオンチェーンセットアップ)とx402 v2(フォールバック、呼び出しごとのHTTP 402フロー) +- **成功時課金** — アップストリームの呼び出しが先に実行され、失敗した呼び出しには決して課金されず、すべての課金にオンチェーンのMemoレシートが付きます +- **単一障害点に関する注意** — 委任済みエージェントは推論、画像、RPCについてNoriの可用性に依存します。緩和策は[単一障害点としてのNori](#単一障害点としてのnori)を参照してください + +{% callout type="note" title="2つの読者、1つのページ" %} +このセクションは、自分のエージェントからNoriのサービスを**利用する**場合、または**サービスエージェントを構築中**でA2Aスキル、呼び出しごとの課金、レートカード公開の実動リファレンスが欲しい場合に活用してください。[ソースリポジトリ](https://github.com/metaplex-foundation/agent-plumber)はオープンソースです。 +{% /callout %} + +## Noriが提供するサービス + +Noriは、1つのハンドラースタックを共有する2つのサーフェス上で3つのサービスを公開しています。スキルの入出力は、チャットと画像には正規のOpenAIワイヤーフォーマットを、RPCには標準のSolana JSON-RPCを使用します — A2A呼び出し元とOpenAI SDK呼び出し元はバイト単位で同一のペイロードを送信します。 + +| サービス | スキルID | エンドポイント | アップストリーム | +|---------|----------|----------|----------| +| LLM推論(ツール呼び出し対応) | `chat.completion` | `POST /v1/chat/completions` | Anthropic、OpenAI、Google — `/`プレフィックスでルーティング | +| 画像生成 | `image.generation` | `POST /v1/images/generations` | OpenAI gpt-image-1 | +| Solana RPC + DAS | `solana.rpc` | `POST /v1/solana/rpc` | オペレーターが設定したRPCプロバイダー(DASメソッドはパススルー) | + +どちらのサーフェスからも同じサービスに到達します: + +- **OpenAI互換HTTP**(`/v1/*`)— `baseURL`を指定して任意のOpenAI SDKやAIフレームワークをNoriに向けます。ほとんどのコンシューマーエージェントが使うサーフェスです。 +- **A2A JSON-RPC**(`/a2a`)— プログラムによるエージェント間呼び出し。発見は`GET /.well-known/agent-card.json`から始まり、スキル、支払いスキーム、Noriの`serviceExecutiveAddress`(デリゲートとして登録するアドレス)を宣伝します。 + +## Noriの決済の仕組み + +Noriは呼び出しごとに決済レールを選択します: 呼び出し元がオンボーディング済みならデリゲートペイ、それ以外はx402です。 + +| レール | 発動条件 | 決済方法 | +|------|---------------|----------------| +| **デリゲートペイ**(プライマリ) | 呼び出し元が有効なベアラートークンを提示し、Noriが呼び出し元のエージェントアセットに登録済みの[実行デリゲート](/smart-contracts/mpl-agent/tools)である | NoriがMPL Core Executeトランザクションに署名し、呼び出し元のPDAからNoriのサービスPDAへSOLをMemoレシート付きで転送 — 支払いの往復なし | +| **x402 v2**(フォールバック) | ベアラートークンなし、無効なトークン、または委任未設定 | 最初のリクエストが支払い要件と共にHTTP 402を返し、呼び出し元が支払い(SOLまたはUSDC)、再試行してキャッシュ済みの結果を受け取る | + +デリゲートペイのレールこそが、エージェントのエンドユーザーからNoriを見えなくするものです: [1回限りの委任](/agents/nori/delegate-to-nori)の後は、ウォレットプロンプトも過大見積もりのホールドもなく、すべての呼び出しが自動的に決済されます。価格は、価格変更の予告ポリシーを伴うバージョン管理された[レートカード](/agents/nori/pricing-and-billing)で公開されています。 + +## 単一障害点としてのNori + +推論、画像生成、RPCをNoriから調達する委任済みエージェントは、Noriを単一障害点にしています: Noriが利用できない場合、エージェントはNoriが復旧するまでそれらの機能を失います。これはNori自身のリスク登録簿で最上位のリスクであり、v1での緩和策は冗長化ではなくドキュメントとポータブルなインターフェースです。 + +明示的に計画しておきましょう: + +- **インターフェースは設計上ポータブルです。** `chat.completion`は正規のOpenAIワイヤーフォーマットで、`solana.rpc`は標準のSolana JSON-RPCです。緊急時のフォールバックは設定変更だけです: OpenAI互換クライアントを(自分のキーで)別のプロバイダーに向け、RPC呼び出しを任意の無料または有料エンドポイントに向けます。 +- **緊急時の認証情報を保持しておきましょう。** ゼロBYOKはNoriの利便性であり、あなたのアーキテクチャの要件ではありません。低ティアのプロバイダーキーと無料のRPC URLを予備として保持しておけば、Noriの障害中もエージェントは機能低下しつつも稼働し続けられます。 +- **x402レールは支払いの独立したフォールバックであり、可用性のものではありません。** 委任への依存は取り除きますが、Noriが稼働していることには依然として依存します。 +- **委任はいつでも取り消し可能です。** Noriから移行する場合、アセットオーナーが委任レコードを取り消すと、デリゲートペイのレールは[ハードストップ](/agents/nori/pricing-and-billing#ハードストップのセマンティクス)します。 + +{% callout type="warning" title="セルフホスティングはv2に延期" %} +独自のNoriインスタンスを実行すること(共有依存を完全に排除すること)はv2で予定されています。v1での緩和策は上記のポータブルなOpenAI/JSON-RPCインターフェースです — NoriのベースURLが前提条件ではなく設定値になるようエージェントを設計してください。 +{% /callout %} + +## リファレンス実装としてのNoriの活用 + +Noriは、Metaplexサービスエージェント — 他のエージェントに作業の対価を請求するエージェント — の実動する設計図です。[ソースリポジトリ](https://github.com/metaplex-foundation/agent-plumber)は各パターンをエンドツーエンドで実証しています: + +| パターン | Noriが実証していること | +|---------|------------------------| +| エージェントカードによる発見 | スキル、支払いスキーム、`serviceAssetAddress`、`serviceExecutiveAddress`を宣伝する`/.well-known/agent-card.json` | +| デリゲートペイ課金 | MPL Core Execute CPIによる呼び出し元PDAへのMemoレシート付き課金、5分間のデリゲートステータスキャッシュ付き | +| x402 v2フォールバック | ファシリテーターエンドポイント(`/verify`、`/settle`)を備えた正規のHTTP 402フローと、呼び出し元がネットワーク手数料用のSOLを不要にするファシリテーターによるfeePayer | +| レートカード公開 | 予告期間ポリシー付きのバージョン管理されたプライスブックを提供する`GET /rate-card` | +| 成功時課金の会計処理 | アップストリーム呼び出しが先、課金が後。失敗した呼び出しは課金なしでエラーを返す | +| 無料の委任オンボーディング | 呼び出し元の委任トランザクションにフィーペイヤーとして連署する、厳格に検証された`POST /v1/delegate/submit` | + +自分のフォークに新しい有料サービスを追加するには: 結果と`costUsd`を返す決済非依存のハンドラーを書き、プライスブックに価格を追加し、A2Aスキルディスパッチに配線し、エージェントカードで宣言します。 + +## クイックリファレンス + +| 項目 | 値 | +|------|-------| +| エージェントカード | `GET /.well-known/agent-card.json` | +| レートカード | `GET /rate-card` | +| サービス | `chat.completion`、`image.generation`、`solana.rpc` | +| OpenAI互換ベースURL | `/v1` | +| A2Aエンドポイント | `POST /a2a`(JSON-RPC 2.0、`message/send`) | +| 決済レール | デリゲートペイ(プライマリ)、x402 v2(フォールバック) | +| 委任プログラム | `mpl-agent-tools` — `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S` | +| ソース | [GitHub](https://github.com/metaplex-foundation/agent-plumber) | + +## 注意事項 + +- NoriのデプロイされたベースURLはエージェント登録を通じて公開されています。このセクションの例ではベースURLのプレースホルダーとして`NORI_URL`を使用します +- 課金はUSDで価格付けされ、課金時にJupiterのライブSOL/USD価格(30秒キャッシュ)を使ってSOLに換算されます — [価格と課金](/agents/nori/pricing-and-billing)を参照してください +- 委任はNoriにエージェントのPDAウォレットに対する課金権限を与えます。そこには運用に必要な残高だけを置き、各課金のMemoレシートを監査してください +- `message/sendStream`はエージェントカードで宣言されていますが、v1では501を返します。A2A呼び出しは同期的です +- Nori(ホストされたMetaplexサービス)とagent-plumber(オープンソース実装)は同じコードベースです。このドキュメントでは両方を「Nori」と呼びます + +Metaplex Foundationが管理。最終確認日: 2026-07-08。 + +## FAQ + +Noriに関するよくある質問。 + +### Noriとは何ですか? +Noriは、Metaplex Foundationが運営する従量課金型のサービスエージェントです。LLM推論、画像生成、Solana RPCアクセスを他のエージェントに販売し、価格はUSD建てで、呼び出し元エージェントのオンチェーンPDAウォレットから呼び出しごとにSOLで決済されます。Metaplexサービスエージェントを構築するためのオープンソースのリファレンス実装でもあります。 + +### Noriを使うのに自分のLLMプロバイダーAPIキーは必要ですか? +いいえ。Noriがアップストリームのプロバイダーキー(Anthropic、OpenAI、Google、画像生成、有料Solana RPC)を保持します。コンシューマーエージェントに必要なのはSolanaキーペアと[登録済みエージェントアセット](/agents/register-agent)だけです — すべての呼び出しはエージェントのPDAウォレットから使用ごとにSOLで決済されます。 + +### Noriがダウンしたら私のエージェントはどうなりますか? +推論、画像、RPCをNoriに依存している委任済みエージェントは、Noriが利用できない間それらの機能を失います。NoriのサーフェスはOpenAI互換および標準のSolana JSON-RPCなので、緊急時のフォールバックとして、自分のキーで他のOpenAI互換プロバイダーやRPCエンドポイントにクライアントを向けることができます。Noriインスタンスのセルフホスティングはv2で予定されています。 + +### Noriへの委任は安全ですか?Noriが私のウォレットを空にすることはできますか? +委任はNoriにエージェントのPDAウォレットに対する課金権限を与えるため、そこには運用に必要な残高だけを置いてください。すべての課金には監査可能なオンチェーンのMemoレシートが付き、[課金は成功した呼び出しに対してのみ行われ](/agents/nori/pricing-and-billing#成功時課金の会計処理)、アセットオーナーはいつでも[委任を取り消す](/agents/nori/delegate-to-nori#noriへの委任の取り消し)ことができ、取り消しによりデリゲートペイのレールはハードストップします。 + +### デリゲートペイのレールとx402のレールの違いは何ですか? +デリゲートペイはプライマリのレールです — 1回限りのオンチェーン委任の後、Noriは支払いの往復なしで呼び出しごとにエージェントのPDAへ直接課金します。x402は委任していない呼び出し元向けのフォールバックです — 最初のリクエストは支払い要件と共にHTTP 402を返し、呼び出し元が支払い(SOLまたはUSDC)、その後再試行します。 + +## 用語集 + +Noriドキュメント全体で使用される主要な用語。 + +| 用語 | 定義 | +|------|------------| +| **Nori** | Metaplex Foundationの従量課金型サービスエージェントであり、Metaplexサービスエージェントのリファレンス実装(agent-plumber) | +| **サービスエージェント** | 他のエージェントにサービスを販売し、呼び出しごとに課金するエージェント | +| **デリゲートペイ(delegate-pay)** | Noriのプライマリ決済レール — 1回限りの実行委任の後、NoriがMPL Core Executeトランザクションを通じて呼び出し元のPDAへ直接課金 | +| **x402** | 機械間決済のためのHTTP `402 Payment Required`プロトコル。委任していない呼び出し元向けのNoriのフォールバックレール | +| **レートカード** | `GET /rate-card`で公開されるNoriの価格表 — バージョン管理され、USD建てで、価格変更の予告ポリシー付き | +| **成功時課金(charge-on-success)** | Noriの課金ルール: アップストリームの呼び出しが先に実行され、成功した呼び出しのみが課金される | +| **ハードストップ** | 呼び出し元が委任を解除した場合、または呼び出し元のPDAウォレットが課金をまかなえない場合の、デリゲートペイサービスの即時終了 | +| **Asset Signer(PDAウォレット)** | エージェントのオンチェーンウォレット。`["mpl-core-execute", asset]`から派生した[MPL Core](/smart-contracts/core)のPDAで、Noriの課金の引き落とし元となるアカウント | +| **エグゼクティブプロファイル** | [`mpl-agent-tools`](/smart-contracts/mpl-agent/tools)におけるオフチェーン署名者のオンチェーンID。委任先はNoriのエグゼクティブプロファイル | +| **エージェントカード** | スキル、支払いスキーム、Noriのサービスアドレスを宣伝する、`/.well-known/agent-card.json`にあるA2A発見ドキュメント | diff --git a/src/pages/ja/agents/nori/pricing-and-billing.md b/src/pages/ja/agents/nori/pricing-and-billing.md new file mode 100644 index 00000000..e41652d2 --- /dev/null +++ b/src/pages/ja/agents/nori/pricing-and-billing.md @@ -0,0 +1,187 @@ +--- +title: Noriの価格と課金 +metaTitle: Noriの価格と課金 - レートカード、成功時課金、ハードストップ | Metaplex +description: Noriがサービス呼び出しをどのように価格付けし課金するか - GET /rate-cardで公開されるレートカード、課金時のUSDからSOLへの換算、成功時課金の会計処理、価格変更の予告ポリシー、委任解除・ウォレット残高切れ時のハードストップのセマンティクス。 +keywords: + - Nori rate card + - Nori pricing + - charge-on-success + - price-change notice + - hard stop + - wallet empty + - undelegate + - agent billing + - pay-per-call +about: + - Nori + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: Noriの呼び出しが失敗した場合、課金されますか? + a: いいえ。Noriはアップストリームの呼び出しを先に実行し、成功した場合にのみ課金します。失敗したアップストリーム呼び出しは課金なしでエラーを返します。x402レールでは、結果は一度だけ計算されてキャッシュされるため、支払い後の再試行はキャッシュ済みの結果を返し、再実行や二重課金は決して発生しません。 + - q: NoriはUSD価格をどのようにSOLに換算しますか? + a: レートカードはUSD建てです。課金時に、NoriはJupiter価格APIのライブSOL/USDスポット価格(30秒キャッシュ)を使ってSOL額を再計算します。したがって、実際に課金されるラマポートは呼び出し時点の市場レートに追従します。 + - q: Noriは価格変更の前にどれくらいの予告をしますか? + a: レートカードにはnotice_period_days(デフォルト7)を持つポリシーブロックが含まれています。値上げは、少なくとも予告期間だけ未来のeffective_atタイムスタンプ付きでコミットされ、effective_at以前の課金は以前に公開されたレートのまま継続されます。変更履歴はポリシーのnotice_urlで確認できます。 + - q: エージェントのウォレットのSOLが尽きたらどうなりますか? + a: ハードストップします。PDAが課金をまかなえない場合、デリゲートペイの課金は失敗し、呼び出しはHTTP 402のx402チャレンジにフォールバックします — サービスが信用払いで提供されることはありません。PDAを補充すればすぐに呼び出しは再開されます。 + - q: 利用中にNoriへの委任を解除したらどうなりますか? + a: 次の課金試行はオンチェーンで失敗し、Noriはキャッシュ済みデリゲートステータスを無効化し、デリゲートペイのレールはハードストップします。以降の呼び出しはx402の支払いチャレンジを受け取ります。チェーンがExecuteトランザクションを拒否するため、取り消し後に課金されることはありません。 + - q: Noriがエージェントに課金した内容はどこで確認できますか? + a: すべての課金は、構造化されたレシートを運ぶMemo命令付きの、エージェントのPDAからNoriのサービスPDAへのSOL送金です。エージェントのオンチェーントランザクション履歴が、独立して監査可能な完全な課金記録です。 +--- + +Noriは、公開されたバージョン管理済みのレートカードに基づいてすべての呼び出しをUSDで価格付けし、課金の瞬間にSOLに換算し、成功時にのみ課金します — 失敗したアップストリーム呼び出しに課金されることは決してありません。価格変更は予告期間ポリシーに従い、呼び出し元が委任を解除した場合やウォレットが課金をまかなえない場合、課金は即座にハードストップします。{% .lead %} + +## 概要 + +Noriの課金モデルは外部から監査可能であるように設計されています: 公開された価格、オンチェーンのレシート、サービスなしの課金は一切なし。 + +- **レートカード** — `GET /rate-card`が、バージョン、`effective_at`、マークアップ係数、価格変更ポリシーを含む完全なUSDプライスブックを提供 +- **成功時課金** — アップストリームの呼び出しが先に実行され、失敗は課金なしでエラーを返し、x402の支払い後の再試行は呼び出しを再実行せずキャッシュ済みの結果を返す +- **価格変更の予告** — 値上げは少なくとも`notice_period_days`(デフォルト7)だけ未来の`effective_at`付きでコミットされ、それ以前の課金は以前に公開されたレートのまま +- **ハードストップ** — 委任解除とウォレット残高切れはどちらもデリゲートペイの課金を即座に停止し、呼び出しは負債を蓄積する代わりにx402チャレンジにフォールバック + +## Noriのレートカード + +`GET /rate-card`は正規の機械可読な価格表です — ドキュメント内のスナップショットに頼らず、常にこちらを確認してください。完全なプライスブックとポリシーメタデータを5分キャッシュで提供します: + +```json {% title="GET /rate-card(抜粋)" %} +{ + "version": 1, + "effective_at": "2026-05-21T00:00:00.000Z", + "policy": { + "notice_period_days": 7, + "notice_url": "https://github.com/metaplex-foundation/agent-plumber/blob/main/packages/shared/src/pricebook.json", + "description": "Price changes are announced by editing this file..." + }, + "markup_factor": 1.25, + "llm": { + "anthropic/claude-sonnet-4-6": { + "inputPerMillion": 3.0, + "outputPerMillion": 15.0, + "cachedInputPerMillion": 0.3 + } + }, + "image": { "openai/gpt-image-1": { "perImage": 0.04 } }, + "rpc": { "default": { "perCall": 0.0001 } } +} +``` + +### レートカードのスキーマ + +| フィールド | 意味 | +|-------|---------| +| `version` | 単調増加するカードバージョン。価格変更のたびにインクリメント | +| `effective_at` | このカードの価格が有効になるISOタイムスタンプ | +| `policy.notice_period_days` | 値上げのコミットからその`effective_at`までの最短日数(デフォルト7) | +| `policy.notice_url` | カード(とその変更履歴)が公開されている場所 | +| `markup_factor` | 課金時に卸売USD価格へ一律に適用される小売マークアップ(1.25倍) | +| `llm.` | 入力 / 出力 / キャッシュ済み入力トークン100万あたりの卸売USD価格 | +| `image.` | 生成画像1枚あたりの卸売USD価格 | +| `rpc.default` | RPCまたはDAS呼び出し1回あたりの卸売USD価格 | + +掲載価格は**卸売価格**です。課金される金額は`卸売価格 × markup_factor`です。`GET /v1/models`は、OpenAI SDKクライアント向けに同じソースから利用可能なLLMモデルIDを列挙します。 + +### 課金額の算出方法 + +各サービスはレートカードからUSDコストを計算し、課金時にSOLに換算します。 + +1. サービスハンドラーが結果と`costUsd`を返します — `chat.completion`はトークン数 × 100万あたり価格、`image.generation`は画像あたり、`solana.rpc`は呼び出しあたり +2. 卸売コストにマークアップ係数(1.25倍)が適用されます +3. USD額は、Jupiter価格APIのライブSOL/USDスポット価格(30秒キャッシュ)を使ってラマポートに換算されます +4. 課金は、エージェントのPDAからNoriのサービスPDAへの、Memoレシート付きSOL送金として成立します + +{% callout type="note" title="すべての課金にオンチェーンのレシートが付きます" %} +各課金トランザクションのMemo命令は、構造化されたレシート(サービス、リクエスト、コストの詳細)をエンコードします。NoriのサービスPDAに対するエージェントのトランザクション履歴が、独立して監査可能な完全な課金記録です — Noriのオフチェーン会計を信頼する必要はありません。 +{% /callout %} + +## 成功時課金の会計処理 + +Noriは、正常に提供しなかった呼び出しに課金することは決してありません。両方の決済レールで、アップストリームが先、課金が後という順序です: + +- **デリゲートペイのレール** — Noriはアップストリームの呼び出し(LLM、画像、RPC)を実行し、成功すればPDAに課金して結果を返します。アップストリームの呼び出しが失敗した場合、呼び出し元はエラーレスポンスを受け取り、課金はありません。 +- **x402のレール** — 最初の(支払い前の)リクエストがアップストリームの呼び出しを実行し、支払いチャレンジをキーとして結果をキャッシュします。402レスポンスは、すでに計算済みの結果の正確なコストを見積もりとして提示します。呼び出し元が支払って再試行すると、Noriは**キャッシュ済み**の結果を返します — アップストリームの呼び出しは再実行されないため二重課金は起こり得ず、見積もられた価格がそのまま決済される価格です。 + +注目すべき失敗ケースはその逆です: デリゲートペイのレールで、アップストリームの呼び出しが成功したのに課金自体が失敗した場合(委任の取り消し、ウォレットの残高切れ)、呼び出し元はその1回の結果を未払いのまま受け取る可能性があり、その後レールは[ハードストップ](#ハードストップのセマンティクス)します。Noriは、事前に資金を人質に取る代わりに、その1回分の損失を負担します。 + +## 価格変更の予告ポリシー + +価格変更はレートカード自体を通じて事前に告知されます — デリゲートペイのレールで無告知の値上げはありません。カードの`policy`ブロックに埋め込まれたポリシーは次のとおりです: + +1. 価格変更は、`version`をインクリメントし未来の`effective_at`を持つ新しいカードのコミットによって公開されます +2. 値上げの場合、`effective_at`はコミットから少なくとも`notice_period_days`(デフォルト**7日**)後でなければなりません +3. `effective_at`以前の課金は、以前に公開されたレートのまま継続されます +4. 完全な変更履歴は`policy.notice_url`で公開されています + +承諾は委任時に暗黙的に行われます: 委任することで、エージェントは公開されているカードとその予告ポリシーを受け入れます。公開された変更が受け入れられない場合は、`effective_at`より前に[委任を取り消してください](/agents/nori/delegate-to-nori#noriへの委任の取り消し) — 取り消しは即時のハードストップなので、承諾していないレートで課金が成立することはありません。 + +プログラムで変更を監視するには、`GET /rate-card`をポーリングし(5分キャッシュされます)、`version`のインクリメントや`effective_at`の変動時にアラートを出します。 + +## ハードストップのセマンティクス + +2つの条件が、ポリシーではなく構造によって、デリゲートペイの課金を即座に停止します: チェーンが課金を拒否するため、負債は蓄積し得ません。 + +### 委任解除時のハードストップ + +実行委任の取り消しは、チェーンレベルでNoriの課金権限を終了させます。次の課金試行は`Neither the asset or any plugins have approved this operation`で失敗し、Noriはそのアセットのキャッシュ済みデリゲートステータスを破棄し、以降の呼び出しはx402のレールにフォールスルーします — 呼び出し元は自動課金の代わりにHTTP 402の支払いチャレンジを受け取ります。デリゲートステータスは最大5分間キャッシュされるため、取り消し直後の処理中の呼び出し1件はデリゲート課金を試行して(そして失敗して)しまう可能性があります。停止を強制するのはオンチェーンのチェックなので、取り消し後に課金されることはありません。 + +### ウォレット残高切れ時のハードストップ + +エージェントのPDAが課金をまかなえない場合、デリゲート課金は失敗し、呼び出しが信用払いで提供されることはありません。呼び出し元はx402チャレンジ(HTTP 402)を受け取り、その呼び出しを直接支払うか、PDAを補充してデリゲートペイを再開するかを選べます。Noriは信用枠を一切提供しません — 資金不足のエージェントはチャレンジ付きの呼び出しごと払いに格下げされるだけで、負債を蓄積することはありません。 + +{% callout type="note" title="PDAはレント免除の下限を上回る状態を維持してください" %} +PDAからの送金が成功するためには、PDAはシステムのレント免除最低額(890,880ラマポート)を上回っている必要があります。運用残高は`想定呼び出し数 × 典型的な課金額 + レント免除の下限`として見積もりましょう。エージェントテンプレートがまさにこのために新しい委任へ0.002 SOLをシードします。 +{% /callout %} + +運用上は、両方のハードストップをエージェントの監視シグナルとして扱いましょう: これまでデリゲートペイで支払われていた呼び出しが200レスポンスから402チャレンジへ突然変わったなら、委任が消えたかウォレットが空になったということです。 + +## クイックリファレンス + +| 項目 | 値 | +|------|-------| +| レートカードエンドポイント | `GET /rate-card`(5分キャッシュ) | +| モデルディレクトリ | `GET /v1/models` | +| 建値 | USD価格、SOLで決済(Jupiterスポット、30秒キャッシュ) | +| マークアップ | 卸売価格の1.25倍、一律 | +| 予告期間 | 7日(`policy.notice_period_days`) | +| 課金ルール | 成功時課金。x402の再試行はキャッシュ済みの結果を返す | +| 委任解除 | 即時ハードストップ → x402フォールバック | +| ウォレット残高切れ | 即時ハードストップ → 補充までx402チャレンジ | +| レシート | すべての課金トランザクションのMemo命令 | + +## 注意事項 + +- [ソースリポジトリ](https://github.com/metaplex-foundation/agent-plumber)にバンドルされているプライスブックは、リリース時点の公開定価のスナップショットです。ライブインスタンスの`GET /rate-card`が実効的な価格表です +- レートカードの価格は卸売価格です — 課金額を求めるには`markup_factor`を掛けてください +- 同じ呼び出しでも、実際に課金されるラマポートは課金時のSOL/USDレートによって変動します。カードが固定するのはUSD額です +- ハードストップはデリゲートペイのレールに適用されます。x402のレールは本質的に呼び出しごとの前払いであり、同等の障害モードはありません +- Noriをリファレンス実装としてフォークするオペレーターは、`packages/shared/src/pricebook.json`を直接編集し、同じ`effective_at`予告の規律を守るべきです + +Metaplex Foundationが管理。最終確認日: 2026-07-08。[GitHubでソースを見る](https://github.com/metaplex-foundation/agent-plumber)。 + +## FAQ + +Noriの価格と課金に関するよくある質問。 + +### Noriの呼び出しが失敗した場合、課金されますか? +いいえ。Noriはアップストリームの呼び出しを先に実行し、成功した場合にのみ課金します。失敗したアップストリーム呼び出しは課金なしでエラーを返します。x402レールでは、結果は一度だけ計算されてキャッシュされるため、支払い後の再試行はキャッシュ済みの結果を返し、再実行や二重課金は決して発生しません。 + +### NoriはUSD価格をどのようにSOLに換算しますか? +レートカードはUSD建てです。課金時に、NoriはJupiter価格APIのライブSOL/USDスポット価格(30秒キャッシュ)を使ってSOL額を再計算します。したがって、実際に課金されるラマポートは呼び出し時点の市場レートに追従します。 + +### Noriは価格変更の前にどれくらいの予告をしますか? +レートカードには`notice_period_days`(デフォルト7)を持つ`policy`ブロックが含まれています。値上げは、少なくとも予告期間だけ未来の`effective_at`タイムスタンプ付きでコミットされ、`effective_at`以前の課金は以前に公開されたレートのまま継続されます。変更履歴はポリシーの`notice_url`で確認できます。 + +### エージェントのウォレットのSOLが尽きたらどうなりますか? +ハードストップします。PDAが課金をまかなえない場合、デリゲートペイの課金は失敗し、呼び出しはHTTP 402のx402チャレンジにフォールバックします — サービスが信用払いで提供されることはありません。PDAを補充すればすぐに呼び出しは再開されます。 + +### 利用中にNoriへの委任を解除したらどうなりますか? +次の課金試行はオンチェーンで失敗し、Noriはキャッシュ済みデリゲートステータスを無効化し、デリゲートペイのレールはハードストップします。以降の呼び出しはx402の支払いチャレンジを受け取ります。チェーンがExecuteトランザクションを拒否するため、取り消し後に課金されることはありません。 + +### Noriがエージェントに課金した内容はどこで確認できますか? +すべての課金は、構造化されたレシートを運ぶMemo命令付きの、エージェントのPDAからNoriのサービスPDAへのSOL送金です。エージェントのオンチェーントランザクション履歴が、独立して監査可能な完全な課金記録です。 diff --git a/src/pages/ko/agents/nori/delegate-to-nori.md b/src/pages/ko/agents/nori/delegate-to-nori.md new file mode 100644 index 00000000..bc4c9722 --- /dev/null +++ b/src/pages/ko/agents/nori/delegate-to-nori.md @@ -0,0 +1,258 @@ +--- +title: Nori에 위임하기 +metaTitle: Nori에 위임하기 - Delegate-Pay 과금을 위한 1회 온보딩 | Metaplex +description: Metaplex 에이전트에 Nori를 실행 델리게이트로 등록하여 모든 LLM, 이미지, RPC 호출이 에이전트의 PDA 지갑에서 자동으로 정산되도록 합니다. 무료 온보딩 — 수수료용 SOL도, RPC도 필요 없습니다. +keywords: + - delegate to Nori + - execution delegation + - delegate-pay + - agent onboarding + - delegateExecutionV1 + - Nori bearer token + - Metaplex agent billing +about: + - Nori + - Execution Delegation + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +howToSteps: + - Nori의 에이전트 카드를 가져와 serviceExecutiveAddress를 읽습니다. + - Nori의 이그제큐티브 프로필을 가리키는 단일 delegateExecutionV1 인스트럭션이 포함된 트랜잭션을 Nori를 수수료 지불자로 하여 빌드합니다. + - 에이전트의 이그제큐티브 키페어로 서명하고 트랜잭션을 Nori의 무료 /v1/delegate/submit 엔드포인트에 제출합니다. + - /auth/handshake에서 서명된 챌린지를 베어러 토큰으로 교환합니다. + - 베어러 토큰으로 유료 호출을 실행합니다 — 요금이 에이전트의 PDA 지갑에서 자동으로 정산됩니다. +howToTools: + - '@metaplex-foundation/mpl-agent-registry' + - '@metaplex-foundation/umi' +faqs: + - q: Nori에 위임하는 데 비용이 드나요? + a: 아니요. 위임 트랜잭션의 네트워크 수수료는 Nori가 지불하며(수수료 지불자로 공동 서명), 온보딩 엔드포인트는 무료이고 인증이 필요 없습니다. 다만 이후에는 에이전트의 PDA 지갑에 운영 SOL 잔액이 필요합니다. 호출당 요금이 인출되는 계정이기 때문입니다. + - q: 위임은 Nori에게 어떤 권한을 부여하나요? + a: 위임은 Nori의 이그제큐티브 프로필을 에이전트 자산의 실행 델리게이트로 등록하며, 이를 통해 Nori는 에이전트의 PDA 지갑에서 SOL을 이동하는 MPL Core Execute 트랜잭션에 서명할 수 있습니다. Nori는 이를 호출당 요금 정산에 사용하며, 각 청구에는 온체인 Memo 영수증이 첨부됩니다. PDA에는 운영 잔액만 보관하고 영수증을 감사하세요. + - q: Nori가 내 에이전트에 요금을 청구하지 못하게 하려면 어떻게 하나요? + a: 에이전트 자산의 실행 위임을 취소하세요. 다음 청구 시도는 온체인에서 실패하고, Nori의 캐시된 델리게이트 상태가 무효화되며, delegate-pay 레일이 하드 스톱됩니다 — 이후 호출은 자동 청구 대신 HTTP 402 x402 챌린지를 받습니다. + - q: 위임했는데도 호출이 HTTP 402를 반환하는 이유는 무엇인가요? + a: 402는 해당 호출에서 delegate-pay 레일을 사용할 수 없었다는 의미입니다 — 베어러 토큰이 없거나 만료되었거나(토큰 유효 기간 15분), 위임이 취소되었거나, 청구 자체가 실패한 경우(대개 PDA 지갑이 비어 있음)입니다. 핸드셰이크를 다시 실행하고, 위임 레코드가 존재하는지 확인하고, PDA 잔액을 점검하세요. + - q: 위임하지 않고도 Nori를 사용할 수 있나요? + a: 예. 위임하지 않은 호출자는 x402 폴백 레일을 사용합니다 — 첫 요청이 결제 요구사항과 함께 HTTP 402를 반환하고, SOL 또는 USDC로 결제한 뒤 재시도합니다. 비용은 동일하지만 모든 호출에 결제 왕복이 추가되는 반면, delegate-pay는 인라인으로 정산됩니다. +--- + +Nori에 위임하기는 에이전트의 자산에 Nori를 [실행 델리게이트](/smart-contracts/mpl-agent/tools)로 등록하는 1회 온체인 설정입니다. 그 후에는 에이전트가 Nori에 대해 실행하는 모든 LLM, 이미지, RPC 호출이 에이전트의 PDA 지갑에서 자동으로 정산됩니다 — 결제 왕복도, 지갑 프롬프트도, 프로바이더 API 키도 없습니다. 온보딩은 무료입니다: Nori가 트랜잭션 수수료를 지불하고 블록해시를 제공하므로, 에이전트의 키페어에 SOL이 있을 필요도, 자체 RPC가 있을 필요도 없습니다. {% .lead %} + +## 요약 + +Nori에 실행 위임을 부여하면 에이전트는 두 번 왕복하는 [x402 폴백](/agents/nori/#nori-결제-작동-방식)에서 인라인 delegate-pay 레일로 전환됩니다. + +- **1회 설정** — Nori의 이그제큐티브 프로필을 가리키는 단일 `delegateExecutionV1` 인스트럭션을 Nori가 무료로 공동 서명하고 제출합니다 +- **호출당 정산** — Nori가 Memo 영수증이 첨부된 MPL Core Execute 트랜잭션으로 에이전트의 [Asset Signer PDA](/agents/what-is-an-agent)에 청구하며, [성공한 호출](/agents/nori/pricing-and-billing#성공-시-과금-정산)에만 청구합니다 +- **베어러 토큰 인증** — 서명된 챌린지/핸드셰이크로 호출을 delegate-pay 레일로 라우팅하는 15분 유효 베어러 토큰을 발급합니다 +- **언제든지 취소 가능** — 자산 소유자가 위임을 취소하면 자동 청구가 즉시 [하드 스톱](#nori-위임-취소)됩니다 + +{% callout type="warning" title="위임은 과금 권한을 부여합니다" %} +실행 델리게이트는 에이전트의 PDA 지갑에서 나가는 이체에 서명할 수 있습니다. PDA를 지출 계정으로 취급하세요: 자금고가 아니라 운영 잔액만 보관하고, 모든 청구에 첨부된 Memo 영수증을 감사하세요. Nori를 에이전트의 유일한 서비스 프로바이더로 삼기 전에 [단일 장애점 주의사항](/agents/nori/#단일-장애점으로서의-nori)을 확인하세요. +{% /callout %} + +## 빠른 시작 + +1. [Nori의 에이전트 카드를 가져와](#1단계-nori의-이그제큐티브-주소-확인) `serviceExecutiveAddress`를 읽습니다 +2. 이그제큐티브 키페어를 권한으로, Nori를 수수료 지불자로 하여 [위임 트랜잭션을 빌드](#2단계-위임-트랜잭션-빌드-및-제출)한 뒤 `POST /v1/delegate/submit`에 제출합니다 +3. [에이전트의 PDA 지갑에](#에이전트-pda-지갑-충전) 운영 SOL 잔액을 충전합니다 +4. `/auth/challenge` + `/auth/handshake`로 [베어러 토큰을 발급](#3단계-베어러-토큰으로-인증)받습니다 +5. `Authorization: Bearer `으로 [유료 호출을 실행](#4단계-유료-호출-실행)합니다 + +## 사전 요구사항 + +위임에는 기존 온체인 에이전트 신원이 필요합니다; 위임 트랜잭션이 자산과 그 신원 PDA를 참조합니다. + +- [등록된 에이전트](/agents/register-agent) — `AgentIdentity` 레코드가 있는 MPL Core 자산 +- 에이전트의 **이그제큐티브 키페어**([에이전트 실행](/agents/run-an-agent)을 통해 설정된, 에이전트가 실행에 사용하는 키페어) — 권한으로서 위임에 서명합니다 +- `@metaplex-foundation/mpl-agent-registry`와 `@metaplex-foundation/umi` 설치 +- 위임 자체에는 SOL도 RPC 엔드포인트도 필요하지 않습니다 — 둘 다 Nori가 제공합니다 + +## 1단계: Nori의 이그제큐티브 주소 확인 + +Nori의 에이전트 카드는 위임할 주소를 광고합니다. `/.well-known/agent-card.json`을 가져와 두 필드를 읽으세요: + +- `serviceExecutiveAddress` — Nori의 이그제큐티브 키페어 공개 키입니다. 이 주소의 이그제큐티브 프로필 PDA가 자산에 델리게이트로 등록하는 대상입니다. +- `serviceAssetAddress` — Nori 자신의 에이전트 자산입니다. 이 자산의 PDA가 요금이 지급되는 곳이며, 모든 청구를 이 주소를 기준으로 온체인에서 검증할 수 있습니다. + +```typescript {% title="fetch-nori-card.ts" %} +const NORI_URL = process.env.NORI_URL; // Nori's base URL + +const card = await fetch(`${NORI_URL}/.well-known/agent-card.json`).then((r) => + r.json(), +); + +const noriExecutive = card.serviceExecutiveAddress; // delegate to this +const noriServiceAsset = card.serviceAssetAddress; // charges are paid here +``` + +{% callout type="warning" title="베이스 URL은 신뢰된 설정으로 취급하세요" %} +에이전트 카드는 어느 이그제큐티브 프로필에 청구 권한을 위임할지 결정합니다. 에이전트 카드는 직접 설정을 관리하는 `NORI_URL`에서만 가져오고, 위임에 서명하기 전에 `serviceExecutiveAddress`를 별도 경로로(예: Nori의 공개된 에이전트 등록과 대조하여) 확인하세요. +{% /callout %} + +## 2단계: 위임 트랜잭션 빌드 및 제출 + +위임 트랜잭션에는 정확히 하나의 `delegateExecutionV1` 인스트럭션이 포함됩니다: 이그제큐티브 키페어가 권한으로 서명하고, Nori의 이그제큐티브 프로필이 델리게이트이며, Nori의 키페어가 수수료 지불자입니다. 오프라인으로 빌드하고 서명한 뒤(Nori의 무료 `GET /v1/solana/blockhash` 엔드포인트가 블록해시를 제공), 부분 서명된 트랜잭션을 `POST /v1/delegate/submit`에 POST합니다. Nori가 검증하고, 수수료 지불자로 공동 서명하고, 제출합니다. + +```typescript {% title="delegate-to-nori.ts" %} +import { createNoopSigner, publicKey } from '@metaplex-foundation/umi'; +import { + delegateExecutionV1, + findAgentIdentityV1Pda, + findExecutiveProfileV1Pda, +} from '@metaplex-foundation/mpl-agent-registry'; + +// `umi` is configured with your agent's executive keypair as identity. +const agentAsset = publicKey(process.env.AGENT_ASSET_ADDRESS); + +// Nori's executive profile PDA, derived from the agent card address. +const noriProfile = findExecutiveProfileV1Pda(umi, { + authority: publicKey(noriExecutive), +}); +const agentIdentity = findAgentIdentityV1Pda(umi, { asset: agentAsset }); + +// Free blockhash — no RPC of your own needed. +const { blockhash } = await fetch(`${NORI_URL}/v1/solana/blockhash`).then((r) => + r.json(), +); + +// Build with Nori as fee payer (a noop signer — Nori co-signs server-side), +// sign with your executive keypair. +const tx = await delegateExecutionV1(umi, { + agentAsset, + agentIdentity, + executiveProfile: noriProfile, +}) + .setFeePayer(createNoopSigner(publicKey(noriExecutive))) + .setBlockhash(blockhash) + .buildAndSign(umi); + +// Nori validates, co-signs, and submits — free of charge. +const result = await fetch(`${NORI_URL}/v1/delegate/submit`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + transaction: Buffer.from(umi.transactions.serialize(tx)).toString('base64'), + }), +}).then((r) => r.json()); + +console.log(result); +// { success: true, signature: '...', agentAsset: '...', authority: '...' } +``` + +{% callout type="note" title="엄격한 트랜잭션 검증" %} +`POST /v1/delegate/submit`은 Nori 자신의 이그제큐티브 프로필을 가리키고 Nori가 수수료 지불자인, 정확히 하나의 `delegateExecutionV1` 인스트럭션(`mpl-agent-tools` 프로그램의 디스크리미네이터 1)이 아닌 모든 것을 거부합니다. 이 엄격한 형태는 무료 엔드포인트가 트랜잭션 제출 서비스로 악용되는 것을 방지합니다. +{% /callout %} + +Metaplex 에이전트 템플릿으로 에이전트를 구축하는 경우, 이 단계 전체가 `delegate-to-nori` 툴로 패키징되어 있습니다 — 한 번의 호출로, 수동 트랜잭션 구성 없이 끝납니다. + +## 3단계: 베어러 토큰으로 인증 + +유료 호출은 Sign-In-With-Solana 스타일 핸드셰이크로 발급된 베어러 토큰을 지니고 있을 때 delegate-pay 레일로 라우팅됩니다. 토큰은 에이전트 자산에 등록된 델리게이트인 이그제큐티브 키페어를 제어하고 있음을 증명하며, 15분간 유효하므로 만료 시 핸드셰이크를 다시 실행하세요. + +```typescript {% title="nori-handshake.ts" %} +import { base58 } from '@metaplex-foundation/umi/serializers'; + +// 1. Get a fresh nonce. +const { nonce } = await fetch(`${NORI_URL}/auth/challenge`).then((r) => r.json()); + +// 2. Sign the handshake envelope with your executive keypair. +const now = Date.now(); +const handshake = { + pubkey: umi.identity.publicKey.toString(), + agentAsset: agentAsset.toString(), + audience: NORI_URL, + nonce, + issuedAt: new Date(now).toISOString(), + expiresAt: new Date(now + 60_000).toISOString(), +}; +const signature = base58.deserialize( + await umi.identity.signMessage( + new TextEncoder().encode(JSON.stringify(handshake)), + ), +)[0]; + +// 3. Exchange for a bearer token (valid 15 minutes). +const { token } = await fetch(`${NORI_URL}/auth/handshake`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ handshake, signature }), +}).then((r) => r.json()); +``` + +## 4단계: 유료 호출 실행 + +베어러 토큰이 첨부되면 Nori는 업스트림 호출을 실행한 뒤 하나의 Execute 트랜잭션으로 에이전트의 PDA에 청구합니다 — 응답은 402 챌린지 없이 한 번의 왕복으로 돌아옵니다. 동일한 헤더가 모든 `/v1/*` 엔드포인트와 `/a2a`에서 작동합니다. + +```typescript {% title="paid-call.ts" %} +const completion = await fetch(`${NORI_URL}/v1/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from a delegated agent.' }], + }), +}).then((r) => r.json()); +``` + +자산에 대한 첫 유료 호출 시 Nori는 자신이 여전히 등록된 델리게이트인지 온체인에서 확인합니다; 결과는 5분간 캐시되므로 이후 호출은 체인 조회를 건너뜁니다. OpenAI 호환 SDK 클라이언트를 Nori에 지정하는 방법을 포함하여, 각 서비스를 소비하는 전체 에이전트는 [예제 에이전트](/agents/nori/example-agents)를 참조하세요. + +## 에이전트 PDA 지갑 충전 + +요금은 에이전트의 Asset Signer PDA에서 인출되므로, 첫 유료 호출 전에 SOL 잔액이 필요합니다. PDA는 또한 시스템 렌트 면제 최소 금액(0바이트 계정 기준 890,880 lamports) 이상을 유지해야 합니다 — Metaplex 에이전트 템플릿은 렌트 미만의 소액 청구가 절대 실패하지 않도록 위임 시점에 0.002 SOL을 시드합니다. 아무 지갑에서나 PDA로 SOL을 이체하세요; 잔액이 소진되면 충전할 때까지 호출이 HTTP 402 챌린지로 폴백됩니다([하드 스톱 시맨틱스](/agents/nori/pricing-and-billing#하드-스톱-시맨틱스) 참조). + +## Nori 위임 취소 + +실행 위임 취소는 킬 스위치이며, 하드 스톱으로 발효됩니다. 자산 소유자가 Nori의 이그제큐티브 프로필에 대한 `ExecutionDelegateRecordV1`을 취소하면, 다음 청구 시도는 온체인에서 실패하고, Nori는 해당 자산에 대해 캐시된 델리게이트 상태를 무효화하며, delegate-pay 레일이 중지됩니다 — 그때부터 호출은 자동 청구 대신 x402 결제 챌린지를 받습니다. 5분 델리게이트 상태 캐시 때문에 취소 직후에 이루어진 호출은 여전히 델리게이트 청구를 시도(하고 실패)할 수 있습니다; 체인이 거부하므로 취소 후에는 어떤 청구도 성립하지 않습니다. + +취소는 에이전트를 등록 해제하거나 PDA 잔액을 건드리지 않습니다 — Nori의 청구 권한만 제거합니다. 나중에 [2단계](#2단계-위임-트랜잭션-빌드-및-제출)를 반복하여 다시 위임할 수 있습니다. + +## 일반적인 오류 + +| 오류 | 원인 | 해결 방법 | +|-------|-------|-----| +| `expected { transaction: }` (400) | `/v1/delegate/submit`의 본문 필드가 잘못됨 | `{ "transaction": "" }`를 전송하세요 | +| 위임 제출이 `errorReason`과 함께 거부됨 | 트랜잭션 형태가 엄격한 검증에 실패 — 추가 인스트럭션, 잘못된 프로그램, 잘못된 이그제큐티브 프로필, 또는 잘못된 수수료 지불자 | Nori를 수수료 지불자로 하여 Nori의 이그제큐티브 프로필을 가리키는 정확히 하나의 `delegateExecutionV1` 인스트럭션을 빌드하세요 | +| 유료 호출에서 `401` | 베어러 토큰이 없거나 만료됨(유효 기간 15분) | 챌린지/핸드셰이크 흐름을 다시 실행하세요 | +| 위임했는데도 유료 호출에서 `402` | 위임이 취소되었거나, 청구가 실패함(대개 PDA 지갑이 비어 있음) | 위임 레코드가 존재하고 PDA 잔액이 호출 비용을 감당하는지 확인하세요 | +| `Neither the asset or any plugins have approved this operation` | 위임 취소 후 청구가 시도됨 | 예상된 하드 스톱 동작입니다 — delegate-pay를 재개하려면 다시 위임하세요 | +| 청구 시 `insufficient funds for rent` | PDA 잔액이 렌트 면제 최소 금액 미만 | PDA를 충전하세요(890,880 lamports에 운영 잔액을 더한 수준 이상 유지) | + +## 참고사항 + +- 온보딩 엔드포인트(`GET /v1/solana/blockhash`, `POST /v1/delegate/submit`)는 무료이며 인증이 필요 없습니다; 실제 작업을 수행하는 그 외 모든 것은 유료입니다 +- 베어러 토큰은 이그제큐티브 키페어 + 에이전트 자산 쌍별로 발급되며 15분 후 만료됩니다 — 클라이언트에 재핸드셰이크를 구현하세요 +- 델리게이트 상태 캐시로 인해 위임 상태 변경(부여 또는 취소)이 결제 레일에 반영되기까지 최대 5분이 걸릴 수 있습니다; 온체인 강제는 즉각적입니다 +- 위임은 자산별입니다: 여러 에이전트를 운영하는 에이전트 운영자는 각 자산을 별도로 위임합니다 +- `mpl-agent-tools` 실행 위임(`ExecutionDelegateRecordV1`), 프로그램 `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S`에 적용됩니다 + +Metaplex Foundation 관리. 최종 검증: 2026-07-08. [GitHub에서 소스 보기](https://github.com/metaplex-foundation/agent-plumber). + +## FAQ + +Nori 위임에 대한 일반적인 질문. + +### Nori에 위임하는 데 비용이 드나요? +아니요. 위임 트랜잭션의 네트워크 수수료는 Nori가 지불하며(수수료 지불자로 공동 서명), 온보딩 엔드포인트는 무료이고 인증이 필요 없습니다. 다만 이후에는 에이전트의 PDA 지갑에 운영 SOL 잔액이 필요합니다. 호출당 요금이 인출되는 계정이기 때문입니다. + +### 위임은 Nori에게 어떤 권한을 부여하나요? +위임은 Nori의 이그제큐티브 프로필을 에이전트 자산의 실행 델리게이트로 등록하며, 이를 통해 Nori는 에이전트의 PDA 지갑에서 SOL을 이동하는 [MPL Core Execute](/smart-contracts/core/execute-asset-signing) 트랜잭션에 서명할 수 있습니다. Nori는 이를 호출당 요금 정산에 사용하며, 각 청구에는 온체인 Memo 영수증이 첨부됩니다. PDA에는 운영 잔액만 보관하고 영수증을 감사하세요. + +### Nori가 내 에이전트에 요금을 청구하지 못하게 하려면 어떻게 하나요? +에이전트 자산의 실행 위임을 취소하세요. 다음 청구 시도는 온체인에서 실패하고, Nori의 캐시된 델리게이트 상태가 무효화되며, delegate-pay 레일이 하드 스톱됩니다 — 이후 호출은 자동 청구 대신 HTTP 402 x402 챌린지를 받습니다. + +### 위임했는데도 호출이 HTTP 402를 반환하는 이유는 무엇인가요? +402는 해당 호출에서 delegate-pay 레일을 사용할 수 없었다는 의미입니다 — 베어러 토큰이 없거나 만료되었거나(토큰 유효 기간 15분), 위임이 취소되었거나, 청구 자체가 실패한 경우(대개 PDA 지갑이 비어 있음)입니다. 핸드셰이크를 다시 실행하고, 위임 레코드가 존재하는지 확인하고, PDA 잔액을 점검하세요. + +### 위임하지 않고도 Nori를 사용할 수 있나요? +예. 위임하지 않은 호출자는 x402 폴백 레일을 사용합니다 — 첫 요청이 결제 요구사항과 함께 HTTP 402를 반환하고, SOL 또는 USDC로 결제한 뒤 재시도합니다. 비용은 동일하지만 모든 호출에 결제 왕복이 추가되는 반면, delegate-pay는 인라인으로 정산됩니다. diff --git a/src/pages/ko/agents/nori/example-agents.md b/src/pages/ko/agents/nori/example-agents.md new file mode 100644 index 00000000..6072935a --- /dev/null +++ b/src/pages/ko/agents/nori/example-agents.md @@ -0,0 +1,208 @@ +--- +title: Nori 예제 에이전트 +metaTitle: Nori 예제 에이전트 - 추론, 이미지 생성, RPC 컨슈머 | Metaplex +description: 각 Nori 서비스를 소비하는 에이전트의 실제 동작 예제 - chat.completion을 사용하는 OpenAI 호환 추론 에이전트, image.generation을 사용하는 아트워크 에이전트, DAS와 함께 solana.rpc를 사용하는 포트폴리오 분석기, 그리고 원시 A2A JSON-RPC 호출자. +keywords: + - Nori examples + - example agents + - OpenAI-compatible agent + - chat.completion + - image.generation + - solana.rpc + - DAS API + - A2A message/send + - agent template +about: + - Nori + - Autonomous Agents + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +faqs: + - q: Nori의 추론 서비스와 함께 작동하는 SDK는 무엇인가요? + a: 모든 OpenAI 호환 클라이언트가 작동합니다 — createOpenAICompatible을 통한 Vercel AI SDK, 커스텀 baseURL을 사용하는 공식 OpenAI SDK, 또는 OpenAI 호환 프로바이더를 받아들이는 Mastra 같은 에이전트 프레임워크. 클라이언트를 NORI_URL/v1에 지정하고 베어러 토큰을 Authorization 헤더로 첨부하세요. + - q: 내 에이전트가 Nori를 통해 getAssetsByOwner 같은 DAS 메서드를 사용할 수 있나요? + a: 예. solana.rpc 서비스는 DAS를 지원하는 업스트림 프로바이더로의 투명한 JSON-RPC 패스스루이므로, DAS 메서드(getAsset, getAssetsByOwner 등)가 표준 Solana RPC 메서드와 완전히 동일하게 작동합니다 — 같은 엔드포인트, 같은 호출당 가격입니다. + - q: 이 예제들은 위임 없이도 작동하나요? + a: 예, x402 폴백 레일을 통해 작동합니다 — 첫 호출은 요청을 한 번 실행한 뒤 결제 요구사항과 함께 HTTP 402를 반환하며, 결제 후 재시도하면 캐시된 결과를 받습니다. 예제들은 결제 왕복을 제거해 주는 위임을 전제로 합니다; 1회 설정은 Nori에 위임하기를 참조하세요. + - q: chat.completion을 통해 어떤 모델을 요청할 수 있나요? + a: 요금표에 있는 모든 모델을 / 형식으로 요청할 수 있습니다 — 예를 들어 anthropic/claude-sonnet-4-6, openai/gpt-5.4, google/gemini-2.5-flash. GET /v1/models가 실시간 디렉토리를 나열하고, GET /rate-card에 토큰당 가격이 있습니다. +--- + +이 예제들은 컨슈머 에이전트가 Nori의 세 가지 서비스 — LLM 추론, 이미지 생성, Solana RPC — 를 각각 사용하는 모습과, 에이전트 간 호출자를 위한 원시 A2A 엔벨로프를 보여줍니다. 각 예제는 1회 [위임 설정](/agents/nori/delegate-to-nori)이 완료되어 베어러 `token`이 준비되어 있다고 가정합니다; 동일한 요청은 위임 없이도 x402 폴백을 통해 결제 왕복이 추가된 채로 작동합니다. {% .lead %} + +## 요약 + +모든 예제는 완전한 유료 Nori 호출입니다 — 어디에도 프로바이더 API 키가 없습니다. + +- **추론 에이전트** — OpenAI 호환 클라이언트를 `NORI_URL/v1`에 지정하고 툴 호출과 함께 `chat.completion`을 실행합니다 +- **아트워크 에이전트** — `image.generation`(gpt-image-1)으로 이미지를 생성합니다 +- **포트폴리오 분석기** — DAS 메서드를 포함하여 `solana.rpc`로 잔액과 토큰 보유량을 읽습니다 +- **A2A 호출자** — 에이전트 간 통합을 위해 JSON-RPC `message/send`로 동일한 스킬을 호출합니다 + +## chat.completion을 사용하는 추론 에이전트 + +OpenAI 호환 클라이언트를 `NORI_URL/v1`에 지정하면 에이전트의 LLM 두뇌를 전적으로 Nori에서 실행할 수 있습니다. 모델은 `/` 형식으로 지정되어 업스트림의 Anthropic, OpenAI, Google로 라우팅됩니다; 툴 호출(`tools`, `tool_choice`, `tool_calls`)이 세 프로바이더 모두에서 지원되므로 전체 에이전트 루프가 수정 없이 작동합니다. + +```typescript {% title="inference-agent.ts" %} +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; +import { generateText, tool } from 'ai'; +import { z } from 'zod'; + +const nori = createOpenAICompatible({ + name: 'nori', + baseURL: `${NORI_URL}/v1`, + headers: { Authorization: `Bearer ${token}` }, // from /auth/handshake +}); + +const { text } = await generateText({ + model: nori('anthropic/claude-sonnet-4-6'), + tools: { + getSolPrice: tool({ + description: 'Get the current SOL price in USD', + inputSchema: z.object({}), + execute: async () => fetchSolPrice(), + }), + }, + prompt: 'Is SOL above $200 right now? Answer in one sentence.', +}); +``` + +각 `generateText` 호출은 하나의 종량제 `chat.completion`입니다 — 선택한 모델의 [요금표](/agents/nori/pricing-and-billing) 가격에 따라 실제 입출력 토큰 수로 과금되며, 에이전트의 PDA에서 정산됩니다. 와이어 형식이 표준 OpenAI이므로 모델을 교체하는 것(또는 [장애 중](/agents/nori/#단일-장애점으로서의-nori) Nori가 아닌 프로바이더로 폴백하는 것)은 한 줄만 바꾸면 됩니다. + +## image.generation을 사용하는 아트워크 에이전트 + +아트워크 — NFT 이미지, 아바타, 사용자를 위한 생성 콘텐츠 — 가 필요한 에이전트는 표준 OpenAI 이미지 요청 형식으로 `POST /v1/images/generations`를 호출합니다. Nori는 업스트림의 gpt-image-1로 라우팅하고 이미지당 고정 가격을 청구합니다. + +```typescript {% title="artwork-agent.ts" %} +const response = await fetch(`${NORI_URL}/v1/images/generations`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'openai/gpt-image-1', + prompt: 'Pixel-art portrait of a sea-otter plumber holding a wrench', + n: 1, + size: '1024x1024', + }), +}).then((r) => r.json()); + +const imageB64 = response.data[0].b64_json; +``` + +일반적인 후속 작업은 이미지를 업로드하고 [MPL Core](/smart-contracts/core) 자산으로 민팅하는 것입니다 — 생성 단계와 민팅 단계는 독립적이며, 생성만 Nori 청구 대상입니다. + +## solana.rpc를 사용하는 포트폴리오 분석기 + +온체인 데이터 에이전트는 동일한 과금 파이프를 통해 RPC와 DAS 액세스를 얻습니다. `POST /v1/solana/rpc`는 DAS를 지원하는 업스트림으로의 투명한 JSON-RPC 패스스루이므로, 표준 메서드(`getBalance`)와 DAS 메서드(`getAsset`, `getAssetsByOwner`)가 하나의 엔드포인트와 하나의 호출당 가격을 공유합니다. 이 포트폴리오 분석기는 수집 → 보강 → 요약 워크플로의 수집 단계를 구현합니다: + +```typescript {% title="portfolio-analyzer.ts" %} +async function noriRpc(method: string, params: unknown[]) { + const res = await fetch(`${NORI_URL}/v1/solana/rpc`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), + }).then((r) => r.json()); + return res.result; +} + +// Gather: SOL balance + all token holdings for a wallet. +const owner = '11111111111111111111111111111112'; // wallet under analysis +const balance = await noriRpc('getBalance', [owner]); + +// DAS method — same endpoint, same per-call price. +const assets = await noriRpc('getAssetsByOwner', [ + { ownerAddress: owner, page: 1, limit: 100 }, +]); + +// Enrich/summarize: feed the holdings to the inference agent above +// for a natural-language portfolio breakdown. +``` + +각 호출이 개별적으로 과금되므로(호출당 고정 가격), 루프 스타일 에이전트 — 주기적으로 폴링하는 가격 감시기, 페이지네이션된 보유량을 순회하는 분석기 — 는 호출을 신중하게 예산해야 합니다: PDA 잔액이 곧 지출 한도이며, 지갑이 비면 서비스가 [하드 스톱](/agents/nori/pricing-and-billing#하드-스톱-시맨틱스)됩니다. + +## A2A message/send를 사용하는 에이전트 간 호출자 + +(OpenAI SDK가 아니라) 프로토콜 수준에서 통합하는 에이전트는 [에이전트 카드](/agents/nori/#nori가-제공하는-서비스)에서 발견한 `POST /a2a`의 JSON-RPC 2.0으로 동일한 스킬을 호출합니다. 스킬 입력은 HTTP 인터페이스와 바이트 단위로 동일합니다 — OpenAI 요청 본문이 단지 `message/send` 엔벨로프 안에서 DataPart로 이동할 뿐입니다: + +```typescript {% title="a2a-caller.ts" %} +const task = await fetch(`${NORI_URL}/a2a`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'message/send', + params: { + requestId: crypto.randomUUID(), + message: { + parts: [ + { + kind: 'data', + data: { + skill: 'chat.completion', + input: { + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from another agent.' }], + }, + }, + }, + ], + }, + }, + }), +}).then((r) => r.json()); +``` + +`message/send`는 완료된 태스크를 동기적으로 반환합니다; `tasks/get`은 ID로 이전 태스크를 조회합니다. HTTP 인터페이스와 동일한 입력 형식으로 `image.generation`이나 `solana.rpc`를 `skill`로 사용하세요. + +{% callout type="note" title="v1에서는 스트리밍을 사용할 수 없습니다" %} +`message/sendStream`은 에이전트 카드에 선언되어 있지만 v1에서는 501을 반환하며, `/v1/chat/completions`는 비스트리밍입니다. 완전한 응답을 중심으로 에이전트 루프를 설계하세요. +{% /callout %} + +## 빠른 참조 + +| 예제 | 서비스 | 엔드포인트 | 과금 방식 | +|---------|---------|----------|-----------| +| 추론 에이전트 | `chat.completion` | `POST /v1/chat/completions` | 모델별 입출력 토큰당 | +| 아트워크 에이전트 | `image.generation` | `POST /v1/images/generations` | 이미지당 | +| 포트폴리오 분석기 | `solana.rpc` | `POST /v1/solana/rpc` | 호출당(DAS 메서드 포함) | +| A2A 호출자 | 모든 스킬 | `POST /a2a` (`message/send`) | 기반 스킬과 동일 | + +## 참고사항 + +- 모든 예제는 `NORI_URL`(Nori의 베이스 URL)과 `token`([핸드셰이크 흐름](/agents/nori/delegate-to-nori#3단계-베어러-토큰으로-인증)에서 발급된 베어러)을 전제로 합니다; 토큰은 15분 후 만료되므로 장시간 실행되는 에이전트는 재핸드셰이크합니다 +- 베어러 토큰 없이도 동일한 요청이 x402 레일을 통해 작동합니다: 첫 호출에서 결제 요구사항과 함께 HTTP 402를 받고, 결제한 뒤 재시도하세요 +- 실행 중인 에이전트에서 시작하고 싶다면 Metaplex 에이전트 템플릿이 이 패턴들을 바로 사용할 수 있는 Mastra 툴(`chat-completion`, `generate-image`, `solana-rpc-call`, `delegate-to-nori`)로 패키징해 제공합니다 +- 성공 시 과금이 모든 예제에 적용됩니다: 실패한 업스트림 호출은 비용이 들지 않습니다 — [가격 및 과금](/agents/nori/pricing-and-billing#성공-시-과금-정산)을 참조하세요 + +Metaplex Foundation 관리. 최종 검증: 2026-07-08. [GitHub에서 소스 보기](https://github.com/metaplex-foundation/agent-plumber). + +## FAQ + +Nori 서비스를 이용한 개발에 대한 일반적인 질문. + +### Nori의 추론 서비스와 함께 작동하는 SDK는 무엇인가요? +모든 OpenAI 호환 클라이언트가 작동합니다 — `createOpenAICompatible`을 통한 Vercel AI SDK, 커스텀 `baseURL`을 사용하는 공식 OpenAI SDK, 또는 OpenAI 호환 프로바이더를 받아들이는 Mastra 같은 에이전트 프레임워크. 클라이언트를 `NORI_URL/v1`에 지정하고 베어러 토큰을 `Authorization` 헤더로 첨부하세요. + +### 내 에이전트가 Nori를 통해 getAssetsByOwner 같은 DAS 메서드를 사용할 수 있나요? +예. `solana.rpc` 서비스는 DAS를 지원하는 업스트림 프로바이더로의 투명한 JSON-RPC 패스스루이므로, DAS 메서드(`getAsset`, `getAssetsByOwner` 등)가 표준 Solana RPC 메서드와 완전히 동일하게 작동합니다 — 같은 엔드포인트, 같은 호출당 가격입니다. + +### 이 예제들은 위임 없이도 작동하나요? +예, x402 폴백 레일을 통해 작동합니다 — 첫 호출은 요청을 한 번 실행한 뒤 결제 요구사항과 함께 HTTP 402를 반환하며, 결제 후 재시도하면 캐시된 결과를 받습니다. 예제들은 결제 왕복을 제거해 주는 위임을 전제로 합니다; 1회 설정은 [Nori에 위임하기](/agents/nori/delegate-to-nori)를 참조하세요. + +### chat.completion을 통해 어떤 모델을 요청할 수 있나요? +요금표에 있는 모든 모델을 `/` 형식으로 요청할 수 있습니다 — 예를 들어 `anthropic/claude-sonnet-4-6`, `openai/gpt-5.4`, `google/gemini-2.5-flash`. `GET /v1/models`가 실시간 디렉토리를 나열하고, [`GET /rate-card`](/agents/nori/pricing-and-billing)에 토큰당 가격이 있습니다. diff --git a/src/pages/ko/agents/nori/index.md b/src/pages/ko/agents/nori/index.md new file mode 100644 index 00000000..8d7930e0 --- /dev/null +++ b/src/pages/ko/agents/nori/index.md @@ -0,0 +1,165 @@ +--- +title: Nori - Metaplex 에이전트를 위한 종량제 서비스 +metaTitle: Nori - 에이전트를 위한 종량제 LLM, 이미지, RPC 서비스 | Metaplex +description: Nori는 LLM 추론, 이미지 생성, Solana RPC 액세스를 다른 에이전트에게 판매하고 호출당 SOL로 정산하는 Metaplex 서비스 에이전트입니다. delegate-pay 과금이 작동하는 방식과 자체 서비스 에이전트를 위한 레퍼런스 구현으로 Nori를 활용하는 방법을 알아봅니다. +keywords: + - Nori + - service agent + - agent plumber + - pay-as-you-go inference + - delegate-pay + - x402 payments + - A2A protocol + - agent-to-agent services + - Metaplex agent +about: + - Nori + - Agent Commerce + - Autonomous Agents + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: Nori란 무엇인가요? + a: Nori는 Metaplex Foundation이 운영하는 종량제 서비스 에이전트입니다. LLM 추론, 이미지 생성, Solana RPC 액세스를 다른 에이전트에게 판매하며, 가격은 USD로 책정되고 호출한 에이전트의 온체인 PDA 지갑에서 호출당 SOL로 정산됩니다. 또한 Metaplex 서비스 에이전트를 구축하기 위한 오픈소스 레퍼런스 구현이기도 합니다. + - q: Nori를 사용하려면 자체 LLM 프로바이더 API 키가 필요한가요? + a: 아니요. 업스트림 프로바이더 키(Anthropic, OpenAI, Google, 이미지 생성, 유료 Solana RPC)는 Nori가 보유합니다. 컨슈머 에이전트에게 필요한 것은 Solana 키페어와 등록된 에이전트 자산뿐입니다 — 모든 호출은 에이전트의 PDA 지갑에서 사용량에 따라 SOL로 정산됩니다. + - q: Nori가 다운되면 내 에이전트는 어떻게 되나요? + a: 추론, 이미지, RPC를 Nori에 의존하는 위임된 에이전트는 Nori를 사용할 수 없는 동안 해당 능력을 잃습니다. Nori의 인터페이스는 OpenAI 호환 형식과 표준 Solana JSON-RPC이므로, 비상 폴백은 자체 키로 다른 OpenAI 호환 프로바이더나 RPC 엔드포인트를 클라이언트에 지정하는 것입니다. 자체 Nori 인스턴스 셀프 호스팅은 v2에 계획되어 있습니다. + - q: Nori에 위임해도 안전한가요? Nori가 내 지갑을 비울 수 있나요? + a: 위임은 Nori에게 에이전트의 PDA 지갑에 대한 과금 권한을 부여하므로, 해당 지갑에는 운영 잔액만 보관하세요. 모든 청구에는 감사할 수 있는 온체인 Memo 영수증이 첨부되고, 성공한 호출에 대해서만 요금이 청구되며, 자산 소유자는 언제든지 위임을 취소할 수 있고 취소 시 delegate-pay 레일이 하드 스톱됩니다. + - q: delegate-pay 레일과 x402 레일의 차이는 무엇인가요? + a: Delegate-pay는 기본 레일입니다 — 1회 온체인 위임 후 Nori가 결제 왕복 없이 호출당 에이전트의 PDA에 직접 청구합니다. x402는 위임하지 않은 호출자를 위한 폴백입니다 — 첫 요청이 결제 요구사항과 함께 HTTP 402를 반환하고, 호출자가 결제한 뒤 재시도합니다. +--- + +Nori는 Metaplex Foundation이 운영하는 종량제 **서비스 에이전트**입니다. LLM 추론, 이미지 생성, Solana RPC 액세스를 다른 에이전트에게 판매합니다 — 가격은 USD로 책정되고, 호출한 에이전트의 온체인 지갑에서 호출당 SOL로 정산됩니다. Nori는 또한 Metaplex 서비스 에이전트의 오픈소스 레퍼런스 구현이기도 합니다: 에이전트 빌더는 Nori의 [A2A 인터페이스](/agents/agent-commerce), delegate-pay 과금, x402 폴백, 요금표 패턴을 연구하고 (복사해서) 사용할 수 있습니다. {% .lead %} + +## 요약 + +Nori는 모든 에이전트 운영자가 직접 연결해야 했던 배관 작업 — LLM 프로바이더 키, 이미지 생성 계정, 유료 Solana RPC, 호출당 과금 — 을 제거합니다. 컨슈머 에이전트에게 필요한 것은 Solana 키페어와 [등록된 에이전트 자산](/agents/register-agent)뿐입니다. + +- **세 가지 종량제 서비스** — `chat.completion`(Anthropic / OpenAI / Google, 툴 호출 지원), `image.generation`(gpt-image-1), `solana.rpc`(RPC + DAS 패스스루) +- **두 가지 결제 레일** — [delegate-pay](/agents/nori/delegate-to-nori)(기본, 1회 온체인 설정)와 x402 v2(폴백, 호출당 HTTP 402 흐름) +- **성공 시 과금** — 업스트림 호출이 먼저 실행됩니다; 실패한 호출에는 절대 요금이 청구되지 않고, 모든 청구에는 온체인 Memo 영수증이 첨부됩니다 +- **단일 장애점 주의사항** — 위임된 에이전트는 추론, 이미지, RPC에서 Nori의 가용성에 의존합니다; 완화 방안은 [단일 장애점으로서의 Nori](#단일-장애점으로서의-nori)를 참조하세요 + +{% callout type="note" title="두 부류의 독자, 하나의 페이지" %} +자체 에이전트에서 Nori의 서비스를 **소비**하려는 경우, 또는 **서비스 에이전트를 구축**하면서 A2A 스킬, 호출당 과금, 요금표 게시에 대한 동작하는 레퍼런스가 필요한 경우 이 섹션을 활용하세요. [소스 저장소](https://github.com/metaplex-foundation/agent-plumber)는 오픈소스입니다. +{% /callout %} + +## Nori가 제공하는 서비스 + +Nori는 하나의 핸들러 스택을 공유하는 두 가지 인터페이스를 통해 세 가지 서비스를 노출합니다. 스킬 입출력은 채팅과 이미지에는 표준 OpenAI 와이어 형식을, RPC에는 표준 Solana JSON-RPC를 사용합니다 — A2A 호출자와 OpenAI SDK 호출자는 바이트 단위로 동일한 페이로드를 보냅니다. + +| 서비스 | 스킬 ID | 엔드포인트 | 업스트림 | +|---------|----------|----------|----------| +| LLM 추론(툴 호출 지원) | `chat.completion` | `POST /v1/chat/completions` | Anthropic, OpenAI, Google — `/` 접두사로 라우팅 | +| 이미지 생성 | `image.generation` | `POST /v1/images/generations` | OpenAI gpt-image-1 | +| Solana RPC + DAS | `solana.rpc` | `POST /v1/solana/rpc` | 운영자가 구성한 RPC 프로바이더(DAS 메서드 패스스루) | + +두 인터페이스 모두 동일한 서비스에 도달합니다: + +- **OpenAI 호환 HTTP**(`/v1/*`) — `baseURL`로 어떤 OpenAI SDK나 AI 프레임워크든 Nori를 가리키게 하면 됩니다. 대부분의 컨슈머 에이전트가 사용하는 인터페이스입니다. +- **A2A JSON-RPC**(`/a2a`) — 프로그래밍 방식의 에이전트 간 호출입니다. 발견은 `GET /.well-known/agent-card.json`에서 시작되며, 여기에서 스킬, 결제 스킴, 그리고 Nori의 `serviceExecutiveAddress`(델리게이트로 등록하는 주소)를 광고합니다. + +## Nori 결제 작동 방식 + +Nori는 호출마다 결제 레일을 선택합니다: 호출자가 온보딩되어 있으면 delegate-pay, 그렇지 않으면 x402입니다. + +| 레일 | 발동 시점 | 정산 방식 | +|------|---------------|----------------| +| **Delegate-pay**(기본) | 호출자가 유효한 베어러 토큰을 제시하고 Nori가 호출자의 에이전트 자산에 [실행 델리게이트](/smart-contracts/mpl-agent/tools)로 등록되어 있는 경우 | Nori가 호출자의 PDA에서 Nori의 서비스 PDA로 SOL을 이체하는 MPL Core Execute 트랜잭션에 Memo 영수증을 첨부하여 서명합니다 — 결제 왕복 없음 | +| **x402 v2**(폴백) | 베어러 토큰이 없거나, 토큰이 유효하지 않거나, 위임이 설정되지 않은 경우 | 첫 요청이 결제 요구사항과 함께 HTTP 402를 반환합니다; 호출자가 결제(SOL 또는 USDC)하고 재시도하면 캐시된 결과를 받습니다 | + +delegate-pay 레일은 에이전트의 최종 사용자에게 Nori를 보이지 않게 만드는 요소입니다: [1회 위임](/agents/nori/delegate-to-nori) 후에는 지갑 프롬프트나 과다 견적 홀드 없이 모든 호출이 자동으로 정산됩니다. 가격은 가격 변경 고지 정책이 있는 버전 관리된 [요금표](/agents/nori/pricing-and-billing)에 게시됩니다. + +## 단일 장애점으로서의 Nori + +추론, 이미지 생성, RPC를 Nori에서 공급받는 위임된 에이전트는 Nori를 단일 장애점으로 만든 것입니다: Nori를 사용할 수 없으면 에이전트는 Nori가 복구될 때까지 해당 능력을 잃습니다. 이는 Nori 자체 리스크 레지스터에서 최상위 리스크이며, v1의 완화 방안은 이중화가 아니라 문서화와 이식 가능한 인터페이스입니다. + +명시적으로 대비하세요: + +- **인터페이스는 설계상 이식 가능합니다.** `chat.completion`은 표준 OpenAI 와이어 형식이고 `solana.rpc`는 표준 Solana JSON-RPC입니다. 비상 폴백은 구성 변경입니다: OpenAI 호환 클라이언트를 (자체 키로) 다른 프로바이더에, RPC 호출을 아무 공개 또는 유료 엔드포인트에 지정하면 됩니다. +- **비상용 크리덴셜을 보관하세요.** 제로 BYOK는 Nori가 주는 편의이지 아키텍처의 요구사항이 아닙니다. 낮은 등급의 프로바이더 키와 무료 RPC URL을 예비로 보유하면 Nori 장애 중에도 에이전트가 성능 저하 상태로나마 살아있을 수 있습니다. +- **x402 레일은 결제에 대한 독립적 폴백이지, 가용성에 대한 것이 아닙니다.** 위임 의존성은 제거하지만 여전히 Nori가 가동 중이어야 합니다. +- **위임은 언제든지 취소할 수 있습니다.** Nori에서 이전해 나가는 경우, 자산 소유자가 위임 레코드를 취소하면 delegate-pay 레일이 [하드 스톱](/agents/nori/pricing-and-billing#하드-스톱-시맨틱스)됩니다. + +{% callout type="warning" title="셀프 호스팅은 v2로 연기됨" %} +자체 Nori 인스턴스를 실행하는 것(공유 의존성 자체를 제거)은 v2에 계획되어 있습니다. v1의 완화 방안은 위의 이식 가능한 OpenAI/JSON-RPC 인터페이스입니다 — Nori의 베이스 URL이 전제가 아니라 구성 값이 되도록 에이전트를 설계하세요. +{% /callout %} + +## 레퍼런스 구현으로서의 Nori 활용 + +Nori는 Metaplex 서비스 에이전트 — 다른 에이전트에게 작업 대가를 청구하는 에이전트 — 의 동작하는 청사진입니다. [소스 저장소](https://github.com/metaplex-foundation/agent-plumber)는 각 패턴을 엔드투엔드로 보여줍니다: + +| 패턴 | Nori가 보여주는 것 | +|---------|------------------------| +| 에이전트 카드 발견 | 스킬, 결제 스킴, `serviceAssetAddress`, `serviceExecutiveAddress`를 광고하는 `/.well-known/agent-card.json` | +| Delegate-pay 과금 | MPL Core Execute CPI와 Memo 영수증으로 호출자의 PDA에 청구, 5분 델리게이트 상태 캐시 포함 | +| x402 v2 폴백 | 퍼실리테이터 엔드포인트(`/verify`, `/settle`)와 호출자가 네트워크 수수료용 SOL이 필요 없도록 하는 퍼실리테이터 feePayer 방식의 표준 HTTP 402 흐름 | +| 요금표 게시 | 고지 기간 정책이 있는 버전 관리된 가격표를 제공하는 `GET /rate-card` | +| 성공 시 과금 정산 | 업스트림 호출 먼저, 청구는 그다음; 실패한 호출은 요금 없이 오류를 반환 | +| 무료 위임 온보딩 | 호출자의 위임 트랜잭션을 수수료 지불자로서 공동 서명하는, 엄격하게 검증되는 `POST /v1/delegate/submit` | + +자체 포크에 새 유료 서비스를 추가하려면: 결과와 `costUsd`를 반환하는 결제 독립적 핸들러를 작성하고, 가격표에 가격을 추가하고, A2A 스킬 디스패치에 연결하고, 에이전트 카드에 선언하세요. + +## 빠른 참조 + +| 항목 | 값 | +|------|-------| +| 에이전트 카드 | `GET /.well-known/agent-card.json` | +| 요금표 | `GET /rate-card` | +| 서비스 | `chat.completion`, `image.generation`, `solana.rpc` | +| OpenAI 호환 베이스 URL | `/v1` | +| A2A 엔드포인트 | `POST /a2a` (JSON-RPC 2.0, `message/send`) | +| 결제 레일 | Delegate-pay(기본), x402 v2(폴백) | +| 위임 프로그램 | `mpl-agent-tools` — `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S` | +| 소스 | [GitHub](https://github.com/metaplex-foundation/agent-plumber) | + +## 참고사항 + +- Nori의 배포된 베이스 URL은 에이전트 등록을 통해 게시됩니다; 이 섹션 전반의 예제는 베이스 URL의 자리 표시자로 `NORI_URL`을 사용합니다 +- 요금은 USD로 책정되며 청구 시점에 실시간 Jupiter SOL/USD 가격(30초 캐시)을 사용하여 SOL로 변환됩니다 — [가격 및 과금](/agents/nori/pricing-and-billing)을 참조하세요 +- 위임은 Nori에게 에이전트의 PDA 지갑에 대한 과금 권한을 부여합니다. 해당 지갑에는 운영 잔액만 보관하고 각 청구의 Memo 영수증을 감사하세요 +- `message/sendStream`은 에이전트 카드에 선언되어 있지만 v1에서는 501을 반환합니다; A2A 호출은 동기식입니다 +- Nori(Metaplex가 호스팅하는 서비스)와 agent-plumber(오픈소스 구현)는 동일한 코드베이스입니다; 이 문서에서는 둘 다 "Nori"로 지칭합니다 + +Metaplex Foundation 관리. 최종 검증: 2026-07-08. + +## FAQ + +Nori에 대한 일반적인 질문. + +### Nori란 무엇인가요? +Nori는 Metaplex Foundation이 운영하는 종량제 서비스 에이전트입니다. LLM 추론, 이미지 생성, Solana RPC 액세스를 다른 에이전트에게 판매하며, 가격은 USD로 책정되고 호출한 에이전트의 온체인 PDA 지갑에서 호출당 SOL로 정산됩니다. 또한 Metaplex 서비스 에이전트를 구축하기 위한 오픈소스 레퍼런스 구현이기도 합니다. + +### Nori를 사용하려면 자체 LLM 프로바이더 API 키가 필요한가요? +아니요. 업스트림 프로바이더 키(Anthropic, OpenAI, Google, 이미지 생성, 유료 Solana RPC)는 Nori가 보유합니다. 컨슈머 에이전트에게 필요한 것은 Solana 키페어와 [등록된 에이전트 자산](/agents/register-agent)뿐입니다 — 모든 호출은 에이전트의 PDA 지갑에서 사용량에 따라 SOL로 정산됩니다. + +### Nori가 다운되면 내 에이전트는 어떻게 되나요? +추론, 이미지, RPC를 Nori에 의존하는 위임된 에이전트는 Nori를 사용할 수 없는 동안 해당 능력을 잃습니다. Nori의 인터페이스는 OpenAI 호환 형식과 표준 Solana JSON-RPC이므로, 비상 폴백은 자체 키로 다른 OpenAI 호환 프로바이더나 RPC 엔드포인트를 클라이언트에 지정하는 것입니다. 자체 Nori 인스턴스 셀프 호스팅은 v2에 계획되어 있습니다. + +### Nori에 위임해도 안전한가요? Nori가 내 지갑을 비울 수 있나요? +위임은 Nori에게 에이전트의 PDA 지갑에 대한 과금 권한을 부여하므로, 해당 지갑에는 운영 잔액만 보관하세요. 모든 청구에는 감사할 수 있는 온체인 Memo 영수증이 첨부되고, [성공한 호출에 대해서만 요금이 청구](/agents/nori/pricing-and-billing#성공-시-과금-정산)되며, 자산 소유자는 언제든지 [위임을 취소](/agents/nori/delegate-to-nori#nori-위임-취소)할 수 있고 취소 시 delegate-pay 레일이 하드 스톱됩니다. + +### delegate-pay 레일과 x402 레일의 차이는 무엇인가요? +Delegate-pay는 기본 레일입니다 — 1회 온체인 위임 후 Nori가 결제 왕복 없이 호출당 에이전트의 PDA에 직접 청구합니다. x402는 위임하지 않은 호출자를 위한 폴백입니다 — 첫 요청이 결제 요구사항과 함께 HTTP 402를 반환하고, 호출자가 결제(SOL 또는 USDC)한 뒤 재시도합니다. + +## 용어집 + +Nori 문서 전반에서 사용되는 핵심 용어. + +| 용어 | 정의 | +|------|------------| +| **Nori** | Metaplex Foundation의 종량제 서비스 에이전트이자 Metaplex 서비스 에이전트의 레퍼런스 구현(agent-plumber) | +| **서비스 에이전트(Service agent)** | 다른 에이전트에게 서비스를 판매하고 호출당 요금을 청구하는 에이전트 | +| **Delegate-pay** | Nori의 기본 결제 레일 — 1회 실행 위임 후 Nori가 MPL Core Execute 트랜잭션을 통해 호출자의 PDA에 직접 청구 | +| **x402** | 기계 간 결제를 위한 HTTP `402 Payment Required` 프로토콜; 위임하지 않은 호출자를 위한 Nori의 폴백 레일 | +| **요금표(Rate card)** | `GET /rate-card`에 게시된 Nori의 가격 목록 — 버전 관리, USD 표시, 가격 변경 고지 정책 포함 | +| **성공 시 과금(Charge-on-success)** | Nori의 과금 규칙: 업스트림 호출이 먼저 실행되고, 성공한 호출에만 요금이 청구됨 | +| **하드 스톱(Hard stop)** | 호출자가 위임을 해제하거나 호출자의 PDA 지갑이 요금을 감당할 수 없을 때 delegate-pay 서비스가 즉시 종료되는 것 | +| **Asset Signer(PDA 지갑)** | 에이전트의 온체인 지갑으로, `["mpl-core-execute", asset]`에서 파생된 [MPL Core](/smart-contracts/core) PDA — Nori의 청구가 인출되는 계정 | +| **이그제큐티브 프로필(Executive profile)** | [`mpl-agent-tools`](/smart-contracts/mpl-agent/tools)에서 오프체인 서명자의 온체인 신원; Nori의 이그제큐티브 프로필에 위임합니다 | +| **에이전트 카드(Agent card)** | 스킬, 결제 스킴, Nori의 서비스 주소를 광고하는 `/.well-known/agent-card.json`의 A2A 발견 문서 | diff --git a/src/pages/ko/agents/nori/pricing-and-billing.md b/src/pages/ko/agents/nori/pricing-and-billing.md new file mode 100644 index 00000000..06a31434 --- /dev/null +++ b/src/pages/ko/agents/nori/pricing-and-billing.md @@ -0,0 +1,187 @@ +--- +title: Nori 가격 및 과금 +metaTitle: Nori 가격 및 과금 - 요금표, 성공 시 과금, 하드 스톱 | Metaplex +description: Nori가 서비스 호출의 가격을 책정하고 과금하는 방식 - GET /rate-card에 게시된 요금표, 청구 시점의 USD-SOL 변환, 성공 시 과금 정산, 가격 변경 고지 정책, 그리고 위임 해제 및 지갑 잔액 소진 시의 하드 스톱 시맨틱스. +keywords: + - Nori rate card + - Nori pricing + - charge-on-success + - price-change notice + - hard stop + - wallet empty + - undelegate + - agent billing + - pay-per-call +about: + - Nori + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: Nori 호출이 실패하면 요금이 청구되나요? + a: 아니요. Nori는 업스트림 호출을 먼저 실행하고 성공한 경우에만 요금을 청구합니다. 실패한 업스트림 호출은 요금 없이 오류를 반환합니다. x402 레일에서는 결과가 한 번만 계산되어 캐시되므로, 결제 후 재시도는 캐시된 결과를 반환하며 절대 재실행되거나 이중 청구되지 않습니다. + - q: Nori는 USD 가격을 어떻게 SOL로 변환하나요? + a: 요금표는 USD로 표시됩니다. 청구 시점에 Nori는 Jupiter 가격 API의 실시간 SOL/USD 현물 가격(30초 캐시)을 사용하여 SOL 금액을 다시 계산합니다. 따라서 실제로 청구되는 lamports는 호출 시점의 시장 환율을 따릅니다. + - q: Nori는 가격 변경 전에 얼마나 미리 고지하나요? + a: 요금표에는 notice_period_days(기본값 7)가 포함된 정책 블록이 있습니다. 가격 인상은 최소한 고지 기간만큼 미래의 effective_at 타임스탬프와 함께 커밋되며, effective_at 이전의 청구는 이전에 게시된 요율로 계속됩니다. 변경 이력은 정책의 notice_url에서 확인할 수 있습니다. + - q: 에이전트의 지갑에서 SOL이 소진되면 어떻게 되나요? + a: 하드 스톱입니다. PDA가 요금을 감당할 수 없으면 delegate-pay 청구가 실패하고 호출은 HTTP 402 x402 챌린지로 폴백됩니다 — 서비스는 외상으로 제공되지 않습니다. PDA를 충전하는 즉시 호출이 재개됩니다. + - q: 사용 중에 Nori 위임을 해제하면 어떻게 되나요? + a: 다음 청구 시도는 온체인에서 실패하고, Nori는 캐시된 델리게이트 상태를 무효화하며, delegate-pay 레일이 하드 스톱됩니다. 이후 호출은 x402 결제 챌린지를 받습니다. 체인이 Execute 트랜잭션을 거부하므로 취소 후에는 어떤 것도 청구될 수 없습니다. + - q: Nori가 내 에이전트에 청구한 내역은 어디에서 확인할 수 있나요? + a: 모든 청구는 구조화된 영수증을 담은 Memo 인스트럭션과 함께 에이전트의 PDA에서 Nori의 서비스 PDA로 이루어지는 SOL 이체입니다. 에이전트의 온체인 트랜잭션 이력이 완전하고 독립적으로 감사 가능한 과금 기록입니다. +--- + +Nori는 게시된 버전 관리 요금표에 따라 모든 호출의 가격을 USD로 책정하고, 청구하는 순간에 SOL로 변환하며, 성공한 경우에만 과금합니다 — 실패한 업스트림 호출에는 절대 요금이 청구되지 않습니다. 가격 변경은 고지 기간 정책을 따르며, 호출자가 위임을 해제하거나 지갑이 요금을 감당할 수 없으면 과금이 즉시 하드 스톱됩니다. {% .lead %} + +## 요약 + +Nori의 과금 모델은 외부에서 감사 가능하도록 설계되었습니다: 공개된 가격, 온체인 영수증, 그리고 서비스 없는 청구 없음. + +- **요금표** — `GET /rate-card`가 버전, `effective_at`, 마크업 계수, 가격 변경 정책을 포함한 전체 USD 가격표를 제공합니다 +- **성공 시 과금** — 업스트림 호출이 먼저 실행됩니다; 실패는 요금 없이 오류를 반환하고, 결제된 x402 재시도는 호출을 재실행하는 대신 캐시된 결과를 반환합니다 +- **가격 변경 고지** — 인상은 최소 `notice_period_days`(기본 7)만큼 미래의 `effective_at`과 함께 커밋됩니다; 그 이전의 청구는 이전에 게시된 요율을 유지합니다 +- **하드 스톱** — 위임 해제와 지갑 잔액 소진 모두 delegate-pay 과금을 즉시 중지합니다; 호출은 부채를 쌓는 대신 x402 챌린지로 폴백됩니다 + +## Nori 요금표 + +`GET /rate-card`는 표준적이고 기계가 읽을 수 있는 가격 목록입니다 — 문서의 스냅샷에 의존하지 말고 항상 이곳을 확인하세요. 전체 가격표와 정책 메타데이터를 5분 캐시로 제공합니다: + +```json {% title="GET /rate-card (abridged)" %} +{ + "version": 1, + "effective_at": "2026-05-21T00:00:00.000Z", + "policy": { + "notice_period_days": 7, + "notice_url": "https://github.com/metaplex-foundation/agent-plumber/blob/main/packages/shared/src/pricebook.json", + "description": "Price changes are announced by editing this file..." + }, + "markup_factor": 1.25, + "llm": { + "anthropic/claude-sonnet-4-6": { + "inputPerMillion": 3.0, + "outputPerMillion": 15.0, + "cachedInputPerMillion": 0.3 + } + }, + "image": { "openai/gpt-image-1": { "perImage": 0.04 } }, + "rpc": { "default": { "perCall": 0.0001 } } +} +``` + +### 요금표 스키마 + +| 필드 | 의미 | +|-------|---------| +| `version` | 단조 증가하는 카드 버전; 가격이 변경될 때마다 증가 | +| `effective_at` | 이 카드의 가격이 발효되는 ISO 타임스탬프 | +| `policy.notice_period_days` | 가격 인상 커밋과 그 `effective_at` 사이의 최소 일수(기본 7) | +| `policy.notice_url` | 카드(및 변경 이력)가 게시되는 위치 | +| `markup_factor` | 청구 시점에 도매 USD 가격에 적용되는 균일 소매 마크업(1.25×) | +| `llm.` | 입력 / 출력 / 캐시된 입력 토큰 100만 개당 도매 USD 가격 | +| `image.` | 생성 이미지당 도매 USD 가격 | +| `rpc.default` | RPC 또는 DAS 호출당 도매 USD 가격 | + +표시된 가격은 **도매가**입니다; 청구 금액은 `도매가 × markup_factor`입니다. `GET /v1/models`는 OpenAI SDK 클라이언트를 위해 동일한 소스에서 사용 가능한 LLM 모델 ID를 열거합니다. + +### 청구 금액 산정 방식 + +각 서비스는 요금표에서 USD 비용을 계산한 다음, 청구 시점에 SOL로 변환합니다. + +1. 서비스 핸들러가 결과와 함께 `costUsd`를 반환합니다 — `chat.completion`은 토큰 수 × 100만 개당 가격, `image.generation`은 이미지당, `solana.rpc`는 호출당 +2. 도매 비용에 마크업 계수(1.25×)가 적용됩니다 +3. USD 금액이 Jupiter 가격 API의 실시간 SOL/USD 현물 가격(30초 캐시)을 사용하여 lamports로 변환됩니다 +4. 청구는 에이전트의 PDA에서 Nori의 서비스 PDA로 이루어지는 SOL 이체로 성립되며, Memo 영수증이 첨부됩니다 + +{% callout type="note" title="모든 청구에는 온체인 영수증이 첨부됩니다" %} +각 청구 트랜잭션의 Memo 인스트럭션은 구조화된 영수증(서비스, 요청, 비용 세부 정보)을 인코딩합니다. Nori의 서비스 PDA에 대한 에이전트의 트랜잭션 이력은 완전하고 독립적으로 감사 가능한 과금 기록입니다 — Nori의 오프체인 회계를 신뢰할 필요가 없습니다. +{% /callout %} + +## 성공 시 과금 정산 + +Nori는 성공적으로 제공하지 못한 호출에는 절대 요금을 청구하지 않습니다. 순서는 두 결제 레일 모두에서 업스트림 먼저, 청구는 그다음입니다: + +- **Delegate-pay 레일** — Nori가 업스트림 호출(LLM, 이미지, RPC)을 실행합니다; 성공하면 PDA에 청구하고 결과를 반환합니다. 업스트림 호출이 실패하면 호출자는 요금 없이 오류 응답을 받습니다. +- **x402 레일** — (결제 전) 첫 요청이 업스트림 호출을 실행하고 결제 챌린지를 키로 결과를 캐시합니다. 402 응답은 이미 계산된 결과의 정확한 비용을 견적합니다. 호출자가 결제하고 재시도하면 Nori는 **캐시된** 결과를 반환합니다 — 업스트림 호출은 절대 재실행되지 않으므로 이중 청구될 수 없으며, 견적된 가격이 곧 정산되는 가격입니다. + +주목할 만한 실패 케이스는 그 반대입니다: delegate-pay 레일에서 업스트림 호출이 성공했지만 청구 자체가 실패한 경우(취소된 위임, 빈 지갑), 호출자는 그 한 번의 결과를 무료로 받을 수 있고, 레일은 그 후 [하드 스톱](#하드-스톱-시맨틱스)됩니다. Nori는 자금을 미리 볼모로 잡는 대신 그 단일 호출의 손실을 감수합니다. + +## 가격 변경 고지 정책 + +가격 변경은 요금표 자체를 통해 사전에 고지됩니다 — delegate-pay 레일에서 무단 가격 인상은 없습니다. 카드의 `policy` 블록에 포함된 정책은 다음과 같습니다: + +1. 가격 변경은 `version`이 증가하고 미래의 `effective_at`이 있는 새 카드를 커밋하여 게시됩니다 +2. 인상의 경우 `effective_at`은 커밋 후 최소 `notice_period_days`(기본 **7일**) 이후여야 합니다 +3. `effective_at` 이전의 청구는 이전에 게시된 요율로 계속됩니다 +4. 전체 변경 이력은 `policy.notice_url`에 공개되어 있습니다 + +수락은 위임 시점에 암묵적으로 이루어집니다: 위임함으로써 에이전트는 게시된 카드와 그 고지 정책을 수락합니다. 게시된 변경을 수락할 수 없다면 `effective_at` 이전에 [위임을 취소](/agents/nori/delegate-to-nori#nori-위임-취소)하세요 — 취소는 즉각적인 하드 스톱이므로, 수락하지 않은 요율로는 어떤 청구도 성립할 수 없습니다. + +프로그래밍 방식으로 변경을 모니터링하려면 `GET /rate-card`를 폴링하고(5분 캐시), `version`이 증가하거나 `effective_at`이 이동할 때 알림을 보내세요. + +## 하드 스톱 시맨틱스 + +두 가지 조건이 delegate-pay 과금을 정책이 아니라 구조적으로 즉시 중지합니다: 체인이 청구를 거부하므로 부채가 쌓일 수 없습니다. + +### 위임 해제 시 하드 스톱 + +실행 위임을 취소하면 체인 수준에서 Nori의 청구 권한이 종료됩니다. 다음 청구 시도는 `Neither the asset or any plugins have approved this operation` 오류로 실패하고, Nori는 해당 자산의 캐시된 델리게이트 상태를 폐기하며, 이후 호출은 x402 레일로 넘어갑니다 — 호출자는 자동 청구 대신 HTTP 402 결제 챌린지를 받습니다. 델리게이트 상태가 최대 5분간 캐시되므로 취소 직후 진행 중인 호출 하나가 여전히 델리게이트 청구를 시도(하고 실패)할 수 있습니다; 중지를 강제하는 것은 온체인 검사이므로 취소 후에는 어떤 것도 청구될 수 없습니다. + +### 지갑 잔액 소진 시 하드 스톱 + +에이전트의 PDA가 요금을 감당할 수 없으면 델리게이트 청구가 실패하고 호출은 외상으로 제공되지 않습니다. 호출자는 x402 챌린지(HTTP 402)를 받으며, 해당 호출을 직접 결제하거나 PDA를 충전하여 delegate-pay를 재개할 수 있습니다. Nori는 신용 한도를 제공하지 않습니다 — 자금이 부족한 에이전트는 챌린지 기반 호출당 결제로 성능이 저하될 뿐, 부채를 쌓지 않습니다. + +{% callout type="note" title="PDA를 렌트 면제 하한선 이상으로 유지하세요" %} +PDA에서 나가는 이체가 성공하려면 PDA가 시스템 렌트 면제 최소 금액(890,880 lamports) 이상을 유지해야 합니다. 운영 잔액은 `예상 호출 수 × 일반적인 청구액 + 렌트 면제 하한선`으로 예산을 잡으세요. 에이전트 템플릿이 새 위임에 0.002 SOL을 시드하는 것도 바로 이 이유 때문입니다. +{% /callout %} + +운영 측면에서는 두 하드 스톱 모두 에이전트의 모니터링 신호로 취급하세요: 이전에 delegate-pay로 결제되던 호출이 200 응답에서 402 챌린지로 갑자기 바뀌면 위임이 사라졌거나 지갑이 비었다는 의미입니다. + +## 빠른 참조 + +| 항목 | 값 | +|------|-------| +| 요금표 엔드포인트 | `GET /rate-card` (5분 캐시) | +| 모델 디렉토리 | `GET /v1/models` | +| 표시 통화 | USD 가격, SOL로 정산(Jupiter 현물, 30초 캐시) | +| 마크업 | 도매가의 1.25×, 균일 적용 | +| 고지 기간 | 7일(`policy.notice_period_days`) | +| 과금 규칙 | 성공 시 과금; x402 재시도는 캐시된 결과 반환 | +| 위임 해제 | 즉시 하드 스톱 → x402 폴백 | +| 지갑 잔액 소진 | 즉시 하드 스톱 → 충전 시까지 x402 챌린지 | +| 영수증 | 모든 청구 트랜잭션의 Memo 인스트럭션 | + +## 참고사항 + +- [소스 저장소](https://github.com/metaplex-foundation/agent-plumber)에 번들된 가격표는 릴리스 시점에 게시된 정가의 스냅샷입니다; 실제 유효한 가격 목록은 라이브 인스턴스의 `GET /rate-card`입니다 +- 요금표 가격은 도매가입니다 — 청구 금액을 구하려면 `markup_factor`를 곱하세요 +- 동일한 호출에 대해 실제로 청구되는 lamports는 청구 시점의 SOL/USD 환율에 따라 달라집니다; 카드가 고정하는 것은 USD 금액입니다 +- 하드 스톱은 delegate-pay 레일에 적용됩니다; x402 레일은 본질적으로 호출당 선불이므로 동등한 실패 모드가 없습니다 +- Nori를 레퍼런스 구현으로 포크하는 운영자는 `packages/shared/src/pricebook.json`을 직접 편집하며, 동일한 `effective_at` 고지 원칙을 준수해야 합니다 + +Metaplex Foundation 관리. 최종 검증: 2026-07-08. [GitHub에서 소스 보기](https://github.com/metaplex-foundation/agent-plumber). + +## FAQ + +Nori 가격 및 과금에 대한 일반적인 질문. + +### Nori 호출이 실패하면 요금이 청구되나요? +아니요. Nori는 업스트림 호출을 먼저 실행하고 성공한 경우에만 요금을 청구합니다. 실패한 업스트림 호출은 요금 없이 오류를 반환합니다. x402 레일에서는 결과가 한 번만 계산되어 캐시되므로, 결제 후 재시도는 캐시된 결과를 반환하며 절대 재실행되거나 이중 청구되지 않습니다. + +### Nori는 USD 가격을 어떻게 SOL로 변환하나요? +요금표는 USD로 표시됩니다. 청구 시점에 Nori는 Jupiter 가격 API의 실시간 SOL/USD 현물 가격(30초 캐시)을 사용하여 SOL 금액을 다시 계산합니다. 따라서 실제로 청구되는 lamports는 호출 시점의 시장 환율을 따릅니다. + +### Nori는 가격 변경 전에 얼마나 미리 고지하나요? +요금표에는 `notice_period_days`(기본값 7)가 포함된 `policy` 블록이 있습니다. 가격 인상은 최소한 고지 기간만큼 미래의 `effective_at` 타임스탬프와 함께 커밋되며, `effective_at` 이전의 청구는 이전에 게시된 요율로 계속됩니다. 변경 이력은 정책의 `notice_url`에서 확인할 수 있습니다. + +### 에이전트의 지갑에서 SOL이 소진되면 어떻게 되나요? +하드 스톱입니다. PDA가 요금을 감당할 수 없으면 delegate-pay 청구가 실패하고 호출은 HTTP 402 x402 챌린지로 폴백됩니다 — 서비스는 외상으로 제공되지 않습니다. PDA를 충전하는 즉시 호출이 재개됩니다. + +### 사용 중에 Nori 위임을 해제하면 어떻게 되나요? +다음 청구 시도는 온체인에서 실패하고, Nori는 캐시된 델리게이트 상태를 무효화하며, delegate-pay 레일이 하드 스톱됩니다. 이후 호출은 x402 결제 챌린지를 받습니다. 체인이 Execute 트랜잭션을 거부하므로 취소 후에는 어떤 것도 청구될 수 없습니다. + +### Nori가 내 에이전트에 청구한 내역은 어디에서 확인할 수 있나요? +모든 청구는 구조화된 영수증을 담은 Memo 인스트럭션과 함께 에이전트의 PDA에서 Nori의 서비스 PDA로 이루어지는 SOL 이체입니다. 에이전트의 온체인 트랜잭션 이력이 완전하고 독립적으로 감사 가능한 과금 기록입니다. diff --git a/src/pages/zh/agents/nori/delegate-to-nori.md b/src/pages/zh/agents/nori/delegate-to-nori.md new file mode 100644 index 00000000..89971053 --- /dev/null +++ b/src/pages/zh/agents/nori/delegate-to-nori.md @@ -0,0 +1,258 @@ +--- +title: 委托给 Nori +metaTitle: 委托给 Nori - 一次性接入 Delegate-Pay 计费 | Metaplex +description: 将 Nori 注册为您 Metaplex Agent 上的执行委托方,使每次 LLM、图像和 RPC 调用都自动从您 Agent 的 PDA 钱包结算。免费接入 — 无需支付手续费的 SOL,也无需 RPC。 +keywords: + - delegate to Nori + - execution delegation + - delegate-pay + - agent onboarding + - delegateExecutionV1 + - Nori bearer token + - Metaplex agent billing +about: + - Nori + - Execution Delegation + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +howToSteps: + - 获取 Nori 的 Agent 卡片并读取其 serviceExecutiveAddress。 + - 构建一笔仅包含一条指向 Nori 执行者配置文件的 delegateExecutionV1 指令的交易,并以 Nori 作为费用支付方。 + - 使用您 Agent 的执行者密钥对签名,并将交易提交到 Nori 的免费 /v1/delegate/submit 端点。 + - 在 /auth/handshake 用签名后的质询换取 Bearer 令牌。 + - 携带 Bearer 令牌发起付费调用 — 扣费自动从您 Agent 的 PDA 钱包结算。 +howToTools: + - '@metaplex-foundation/mpl-agent-registry' + - '@metaplex-foundation/umi' +faqs: + - q: 委托给 Nori 需要花钱吗? + a: 不需要。Nori 支付委托交易的网络费用(它作为费用支付方共同签署),且接入端点是免费且无需认证的。之后您需要在 Agent 的 PDA 钱包上保留一定的 SOL 工作余额,因为那是按次调用扣费的来源账户。 + - q: 委托授予 Nori 什么权限? + a: 委托将 Nori 的执行者配置文件注册为您 Agent 资产上的执行委托方,这使 Nori 可以签署将 SOL 从您 Agent 的 PDA 钱包转出的 MPL Core Execute 交易。Nori 用它来结算按次调用的扣费,每笔都附带链上 Memo 收据。PDA 上只保留工作余额,并审计这些收据。 + - q: 如何阻止 Nori 向我的 Agent 扣费? + a: 撤销您 Agent 资产上的执行委托。下一次扣费尝试会在链上失败,Nori 缓存的委托状态被作废,delegate-pay 轨道硬停止 — 后续调用会收到 HTTP 402 x402 质询,而不是被自动扣费。 + - q: 为什么我已委托,调用却仍返回 HTTP 402? + a: 402 表示该次调用无法使用 delegate-pay 轨道 — Bearer 令牌缺失或已过期(令牌有效期 15 分钟)、委托已被撤销,或扣费本身失败(通常是 PDA 钱包余额为空)。重新执行握手流程,确认委托记录存在,并检查 PDA 余额。 + - q: 我可以完全不委托就使用 Nori 吗? + a: 可以。未委托的调用方使用 x402 后备轨道 — 第一次请求返回带支付要求的 HTTP 402,您以 SOL 或 USDC 支付后重试。费用相同,但每次调用都会增加一次支付往返,而 delegate-pay 是内联结算的。 +--- + +委托给 Nori 是一次性的链上设置,它将 Nori 注册为您 Agent 资产上的[执行委托方](/smart-contracts/mpl-agent/tools)。此后,您的 Agent 对 Nori 发起的每次 LLM、图像和 RPC 调用都会自动从 Agent 的 PDA 钱包结算 — 没有支付往返,没有钱包提示,也不需要提供商 API 密钥。接入是免费的:Nori 支付交易费用并提供 blockhash,因此您的 Agent 的密钥对上既不需要 SOL,也不需要自己的 RPC。{% .lead %} + +## 概述 + +授予 Nori 执行委托,会将您的 Agent 从需要两次往返的 [x402 后备轨道](/agents/nori/#nori-支付的运作方式)切换到内联的 delegate-pay(委托支付)轨道。 + +- **一次性设置** — 一条指向 Nori 执行者配置文件的 `delegateExecutionV1` 指令,由 Nori 免费共同签署并提交 +- **按次调用结算** — Nori 通过带 Memo 收据的 MPL Core Execute 交易向您 Agent 的 [Asset Signer PDA](/agents/what-is-an-agent) 扣费,且仅针对[成功的调用](/agents/nori/pricing-and-billing#成功后计费核算) +- **Bearer 令牌认证** — 签名质询/握手流程铸造一个有效期 15 分钟的 Bearer 令牌,将您的调用路由到 delegate-pay 轨道 +- **随时可撤销** — 资产所有者可以撤销委托,这会立即[硬停止](#从-nori-撤销委托)自动扣费 + +{% callout type="warning" title="委托授予计费权限" %} +执行委托方可以签署将资金转出您 Agent 的 PDA 钱包的交易。将 PDA 视为消费账户:保留工作余额,而不是您的金库,并审计每笔扣费附带的 Memo 收据。在让 Nori 成为您 Agent 的唯一服务提供商之前,请参阅[单点故障注意事项](/agents/nori/#nori-作为单点故障)。 +{% /callout %} + +## 快速开始 + +1. [获取 Nori 的 Agent 卡片](#步骤-1--发现-nori-的执行者地址)并读取 `serviceExecutiveAddress` +2. [构建委托交易](#步骤-2--构建并提交委托交易),以您的执行者密钥对作为权限、Nori 作为费用支付方,然后将其提交到 `POST /v1/delegate/submit` +3. [为您 Agent 的 PDA 钱包充值](#为-agent-pda-钱包充值)一定的 SOL 工作余额 +4. 通过 `/auth/challenge` + `/auth/handshake` [铸造 Bearer 令牌](#步骤-3--使用-bearer-令牌进行认证) +5. 携带 `Authorization: Bearer ` [发起付费调用](#步骤-4--发起付费调用) + +## 前提条件 + +委托需要一个已存在的链上 Agent 身份;委托交易会引用该资产及其身份 PDA。 + +- 一个[已注册的 Agent](/agents/register-agent) — 带有 `AgentIdentity` 记录的 MPL Core 资产 +- 您 Agent 的**执行者密钥对**(您的 Agent 运行时使用的密钥对,通过[运行代理](/agents/run-an-agent)设置)— 它作为权限签署委托 +- 已安装 `@metaplex-foundation/mpl-agent-registry` 和 `@metaplex-foundation/umi` +- 委托本身不需要 SOL,也不需要 RPC 端点 — 两者都由 Nori 提供 + +## 步骤 1 — 发现 Nori 的执行者地址 + +Nori 的 Agent 卡片公布了您要委托的地址。获取 `/.well-known/agent-card.json` 并读取两个字段: + +- `serviceExecutiveAddress` — Nori 的执行者密钥对公钥。您在自己的资产上注册为委托方的,是它的执行者配置文件 PDA。 +- `serviceAssetAddress` — Nori 自己的 Agent 资产。您的扣费支付到它的 PDA;您可以据此在链上核验每一笔扣费。 + +```typescript {% title="fetch-nori-card.ts" %} +const NORI_URL = process.env.NORI_URL; // Nori's base URL + +const card = await fetch(`${NORI_URL}/.well-known/agent-card.json`).then((r) => + r.json(), +); + +const noriExecutive = card.serviceExecutiveAddress; // delegate to this +const noriServiceAsset = card.serviceAssetAddress; // charges are paid here +``` + +{% callout type="warning" title="将基础 URL 视为受信任的配置" %} +Agent 卡片决定了你将计费权限委托给哪个执行者配置文件。只从由你自己管理配置的 `NORI_URL` 获取 Agent 卡片,并在签署委托前通过带外方式核验 `serviceExecutiveAddress`(例如与 Nori 公开的 Agent 注册信息进行比对)。 +{% /callout %} + +## 步骤 2 — 构建并提交委托交易 + +委托交易恰好包含一条 `delegateExecutionV1` 指令:您的执行者密钥对作为权限签名,Nori 的执行者配置文件是委托方,Nori 的密钥对是费用支付方。您离线构建并签名它(Nori 免费的 `GET /v1/solana/blockhash` 端点提供 blockhash),然后将部分签名的交易 POST 到 `POST /v1/delegate/submit`。Nori 验证它,作为费用支付方共同签署,并提交它。 + +```typescript {% title="delegate-to-nori.ts" %} +import { createNoopSigner, publicKey } from '@metaplex-foundation/umi'; +import { + delegateExecutionV1, + findAgentIdentityV1Pda, + findExecutiveProfileV1Pda, +} from '@metaplex-foundation/mpl-agent-registry'; + +// `umi` is configured with your agent's executive keypair as identity. +const agentAsset = publicKey(process.env.AGENT_ASSET_ADDRESS); + +// Nori's executive profile PDA, derived from the agent card address. +const noriProfile = findExecutiveProfileV1Pda(umi, { + authority: publicKey(noriExecutive), +}); +const agentIdentity = findAgentIdentityV1Pda(umi, { asset: agentAsset }); + +// Free blockhash — no RPC of your own needed. +const { blockhash } = await fetch(`${NORI_URL}/v1/solana/blockhash`).then((r) => + r.json(), +); + +// Build with Nori as fee payer (a noop signer — Nori co-signs server-side), +// sign with your executive keypair. +const tx = await delegateExecutionV1(umi, { + agentAsset, + agentIdentity, + executiveProfile: noriProfile, +}) + .setFeePayer(createNoopSigner(publicKey(noriExecutive))) + .setBlockhash(blockhash) + .buildAndSign(umi); + +// Nori validates, co-signs, and submits — free of charge. +const result = await fetch(`${NORI_URL}/v1/delegate/submit`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + transaction: Buffer.from(umi.transactions.serialize(tx)).toString('base64'), + }), +}).then((r) => r.json()); + +console.log(result); +// { success: true, signature: '...', agentAsset: '...', authority: '...' } +``` + +{% callout type="note" title="严格的交易验证" %} +`POST /v1/delegate/submit` 会拒绝任何不是恰好一条 `delegateExecutionV1` 指令(`mpl-agent-tools` 程序上的判别符 1)、不指向 Nori 自己的执行者配置文件、或不以 Nori 作为费用支付方的交易。这种严格的形状要求防止这个免费端点被滥用为交易提交服务。 +{% /callout %} + +如果您基于 Metaplex Agent 模板构建 Agent,整个步骤已打包为 `delegate-to-nori` 工具 — 一次调用即可,无需手动构建交易。 + +## 步骤 3 — 使用 Bearer 令牌进行认证 + +当付费调用携带通过 Sign-In-With-Solana 风格握手铸造的 Bearer 令牌时,它们会被路由到 delegate-pay 轨道。该令牌证明您控制着在 Agent 资产上注册为委托方的执行者密钥对;令牌有效期为 15 分钟,过期后请重新执行握手。 + +```typescript {% title="nori-handshake.ts" %} +import { base58 } from '@metaplex-foundation/umi/serializers'; + +// 1. Get a fresh nonce. +const { nonce } = await fetch(`${NORI_URL}/auth/challenge`).then((r) => r.json()); + +// 2. Sign the handshake envelope with your executive keypair. +const now = Date.now(); +const handshake = { + pubkey: umi.identity.publicKey.toString(), + agentAsset: agentAsset.toString(), + audience: NORI_URL, + nonce, + issuedAt: new Date(now).toISOString(), + expiresAt: new Date(now + 60_000).toISOString(), +}; +const signature = base58.deserialize( + await umi.identity.signMessage( + new TextEncoder().encode(JSON.stringify(handshake)), + ), +)[0]; + +// 3. Exchange for a bearer token (valid 15 minutes). +const { token } = await fetch(`${NORI_URL}/auth/handshake`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ handshake, signature }), +}).then((r) => r.json()); +``` + +## 步骤 4 — 发起付费调用 + +附上 Bearer 令牌后,Nori 会先运行上游调用,再通过一笔 Execute 交易向您 Agent 的 PDA 扣费 — 响应在单次往返中返回,没有 402 质询。同一个请求头适用于所有 `/v1/*` 端点和 `/a2a`。 + +```typescript {% title="paid-call.ts" %} +const completion = await fetch(`${NORI_URL}/v1/chat/completions`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from a delegated agent.' }], + }), +}).then((r) => r.json()); +``` + +某个资产首次发起付费调用时,Nori 会在链上检查自己是否仍是已注册的委托方;该结果缓存 5 分钟,因此后续调用会跳过链上查询。参见[示例 Agent](/agents/nori/example-agents),其中有消费每项服务的完整 Agent,包括将 OpenAI 兼容 SDK 客户端指向 Nori。 + +## 为 Agent PDA 钱包充值 + +扣费从您 Agent 的 Asset Signer PDA 扣取,因此在首次付费调用之前它需要有 SOL 余额。PDA 还必须保持在系统免租金最低余额之上(0 字节账户为 890,880 lamports)— Metaplex Agent 模板在委托时会为其预置 0.002 SOL,以确保低于租金的小额扣费永不失败。从任意钱包向 PDA 转入 SOL 即可;如果余额耗尽,调用会回退为 HTTP 402 质询,直到您充值(参见[硬停止语义](/agents/nori/pricing-and-billing#硬停止语义))。 + +## 从 Nori 撤销委托 + +撤销执行委托是终止开关,并以硬停止的方式生效。当资产所有者撤销 Nori 执行者配置文件对应的 `ExecutionDelegateRecordV1` 时,下一次扣费尝试会在链上失败,Nori 会作废其为您的资产缓存的委托状态,delegate-pay 轨道随即停止 — 此后您的调用会收到 x402 支付质询,而不是被自动扣费。由于委托状态缓存为 5 分钟,撤销后立即发起的调用可能仍会尝试(并失败)一次委托扣费;撤销后没有任何扣费能够落地,因为链会拒绝它。 + +撤销不会注销您的 Agent,也不会触及其 PDA 余额 — 它只是移除 Nori 对其扣费的权限。您可以稍后通过重复[步骤 2](#步骤-2--构建并提交委托交易)重新委托。 + +## 常见错误 + +| 错误 | 原因 | 解决方法 | +|-------|-------|-----| +| `expected { transaction: }`(400) | `/v1/delegate/submit` 的请求体字段错误 | 发送 `{ "transaction": "" }` | +| 委托提交被拒绝并返回 `errorReason` | 交易形状未通过严格验证 — 存在额外指令、程序错误、执行者配置文件错误或费用支付方错误 | 只构建一条指向 Nori 执行者配置文件、以 Nori 为费用支付方的 `delegateExecutionV1` 指令 | +| 付费调用返回 `401` | Bearer 令牌缺失或已过期(有效期 15 分钟) | 重新执行质询/握手流程 | +| 已委托但付费调用返回 `402` | 委托已被撤销,或扣费失败(通常是 PDA 钱包余额为空) | 确认委托记录存在,且 PDA 余额足以覆盖该次调用 | +| `Neither the asset or any plugins have approved this operation` | 委托被撤销后仍尝试扣费 | 预期的硬停止行为 — 重新委托即可恢复 delegate-pay | +| 扣费时出现 `insufficient funds for rent` | PDA 余额低于免租金最低余额 | 为 PDA 充值(保持在 890,880 lamports 之上并留有工作余额) | + +## 注意事项 + +- 接入端点(`GET /v1/solana/blockhash`、`POST /v1/delegate/submit`)免费且无需认证;其他所有执行实际工作的端点均为付费 +- Bearer 令牌按执行者密钥对 + Agent 资产的组合铸造,15 分钟后过期 — 请在您的客户端中内置重新握手逻辑 +- 委托状态缓存意味着委托状态的变更(授予或撤销)最多可能需要 5 分钟才会反映到支付轨道上;链上强制执行是即时的 +- 委托是按资产进行的:运营多个 Agent 的运营者需为每个资产分别委托 +- 适用于 `mpl-agent-tools` 执行委托(`ExecutionDelegateRecordV1`),程序 `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S` + +由 Metaplex Foundation 维护。最后验证日期:2026-07-08。[在 GitHub 上查看源码](https://github.com/metaplex-foundation/agent-plumber)。 + +## FAQ + +关于委托给 Nori 的常见问题。 + +### 委托给 Nori 需要花钱吗? +不需要。Nori 支付委托交易的网络费用(它作为费用支付方共同签署),且接入端点是免费且无需认证的。之后您需要在 Agent 的 PDA 钱包上保留一定的 SOL 工作余额,因为那是按次调用扣费的来源账户。 + +### 委托授予 Nori 什么权限? +委托将 Nori 的执行者配置文件注册为您 Agent 资产上的执行委托方,这使 Nori 可以签署将 SOL 从您 Agent 的 PDA 钱包转出的 [MPL Core Execute](/smart-contracts/core/execute-asset-signing) 交易。Nori 用它来结算按次调用的扣费,每笔都附带链上 Memo 收据。PDA 上只保留工作余额,并审计这些收据。 + +### 如何阻止 Nori 向我的 Agent 扣费? +撤销您 Agent 资产上的执行委托。下一次扣费尝试会在链上失败,Nori 缓存的委托状态被作废,delegate-pay 轨道硬停止 — 后续调用会收到 HTTP 402 x402 质询,而不是被自动扣费。 + +### 为什么我已委托,调用却仍返回 HTTP 402? +402 表示该次调用无法使用 delegate-pay 轨道 — Bearer 令牌缺失或已过期(令牌有效期 15 分钟)、委托已被撤销,或扣费本身失败(通常是 PDA 钱包余额为空)。重新执行握手流程,确认委托记录存在,并检查 PDA 余额。 + +### 我可以完全不委托就使用 Nori 吗? +可以。未委托的调用方使用 x402 后备轨道 — 第一次请求返回带支付要求的 HTTP 402,您以 SOL 或 USDC 支付后重试。费用相同,但每次调用都会增加一次支付往返,而 delegate-pay 是内联结算的。 diff --git a/src/pages/zh/agents/nori/example-agents.md b/src/pages/zh/agents/nori/example-agents.md new file mode 100644 index 00000000..55c789be --- /dev/null +++ b/src/pages/zh/agents/nori/example-agents.md @@ -0,0 +1,208 @@ +--- +title: Nori 示例 Agent +metaTitle: Nori 示例 Agent - 推理、图像生成与 RPC 消费方 | Metaplex +description: 消费 Nori 各项服务的可运行 Agent 示例 - 使用 chat.completion 的 OpenAI 兼容推理 Agent、使用 image.generation 的艺术创作 Agent、使用 solana.rpc 及 DAS 的投资组合分析器,以及原生 A2A JSON-RPC 调用方。 +keywords: + - Nori examples + - example agents + - OpenAI-compatible agent + - chat.completion + - image.generation + - solana.rpc + - DAS API + - A2A message/send + - agent template +about: + - Nori + - Autonomous Agents + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +programmingLanguage: + - TypeScript +faqs: + - q: 哪些 SDK 可以配合 Nori 的推理服务使用? + a: 任何 OpenAI 兼容客户端都可以 — 通过 createOpenAICompatible 的 Vercel AI SDK、使用自定义 baseURL 的官方 OpenAI SDK,或接受 OpenAI 兼容提供商的 Agent 框架(如 Mastra)。将客户端指向 NORI_URL/v1,并将 Bearer 令牌附加为 Authorization 请求头。 + - q: 我的 Agent 可以通过 Nori 使用 getAssetsByOwner 之类的 DAS 方法吗? + a: 可以。solana.rpc 服务是对具备 DAS 能力的上游提供商的透明 JSON-RPC 透传,因此 DAS 方法(getAsset、getAssetsByOwner 等)的用法与标准 Solana RPC 方法完全相同 — 同一个端点,同样的按次调用价格。 + - q: 这些示例不委托也能运行吗? + a: 可以,通过 x402 后备轨道 — 首次调用会先执行一次请求,然后返回带支付要求的 HTTP 402;支付并重试后会返回缓存的结果。示例假设已完成委托,因为委托消除了支付往返;一次性设置参见委托给 Nori。 + - q: 我可以通过 chat.completion 请求哪些模型? + a: 费率卡上的任何模型,以 / 形式指定 — 例如 anthropic/claude-sonnet-4-6、openai/gpt-5.4 或 google/gemini-2.5-flash。GET /v1/models 列出实时目录,GET /rate-card 载有每 token 价格。 +--- + +这些示例展示了一个消费方 Agent 使用 Nori 的三项服务 — LLM 推理、图像生成和 Solana RPC — 以及供 Agent 间调用方使用的原生 A2A 信封。每个示例都假设一次性的[委托设置](/agents/nori/delegate-to-nori)已经完成且手头有 Bearer `token`;相同的请求在未委托的情况下也能通过 x402 后备轨道运行,只是会增加一次支付往返。{% .lead %} + +## 概述 + +每个示例都是一次完整的 Nori 付费调用 — 任何地方都不需要提供商 API 密钥。 + +- **推理 Agent** — 将 OpenAI 兼容客户端指向 `NORI_URL/v1`,运行带工具调用的 `chat.completion` +- **艺术创作 Agent** — 通过 `image.generation`(gpt-image-1)生成图像 +- **投资组合分析器** — 通过 `solana.rpc` 读取余额和代币持仓,包括 DAS 方法 +- **A2A 调用方** — 通过 JSON-RPC `message/send` 调用相同的技能,用于 Agent 间集成 + +## 使用 chat.completion 的推理 Agent + +将 OpenAI 兼容客户端指向 `NORI_URL/v1`,Agent 的 LLM 大脑就可以完全运行在 Nori 上。模型以 `/` 形式指定,并路由到上游的 Anthropic、OpenAI 或 Google;三家提供商都支持工具调用(`tools`、`tool_choice`、`tool_calls`),因此完整的 Agent 循环无需修改即可运行。 + +```typescript {% title="inference-agent.ts" %} +import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; +import { generateText, tool } from 'ai'; +import { z } from 'zod'; + +const nori = createOpenAICompatible({ + name: 'nori', + baseURL: `${NORI_URL}/v1`, + headers: { Authorization: `Bearer ${token}` }, // from /auth/handshake +}); + +const { text } = await generateText({ + model: nori('anthropic/claude-sonnet-4-6'), + tools: { + getSolPrice: tool({ + description: 'Get the current SOL price in USD', + inputSchema: z.object({}), + execute: async () => fetchSolPrice(), + }), + }, + prompt: 'Is SOL above $200 right now? Answer in one sentence.', +}); +``` + +每次 `generateText` 调用都是一次计量的 `chat.completion` — 按实际的输入/输出 token 数量、以所选模型的[费率卡](/agents/nori/pricing-and-billing)价格计费,从 Agent 的 PDA 结算。切换模型(或在[服务中断期间](/agents/nori/#nori-作为单点故障)回退到非 Nori 提供商)只需改一行代码,因为线格式是规范的 OpenAI 格式。 + +## 使用 image.generation 的艺术创作 Agent + +需要艺术作品的 Agent — NFT 图像、头像、面向其用户的生成内容 — 以标准的 OpenAI 图像请求形状调用 `POST /v1/images/generations`。Nori 路由到上游的 gpt-image-1,并按每张图像收取固定价格。 + +```typescript {% title="artwork-agent.ts" %} +const response = await fetch(`${NORI_URL}/v1/images/generations`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + model: 'openai/gpt-image-1', + prompt: 'Pixel-art portrait of a sea-otter plumber holding a wrench', + n: 1, + size: '1024x1024', + }), +}).then((r) => r.json()); + +const imageB64 = response.data[0].b64_json; +``` + +典型的后续步骤是上传图像并将其铸造为 [MPL Core](/smart-contracts/core) 资产 — 生成步骤和铸造步骤相互独立,只有生成会产生 Nori 扣费。 + +## 使用 solana.rpc 的投资组合分析器 + +链上数据 Agent 通过同一条计费管道获得 RPC 和 DAS 访问。`POST /v1/solana/rpc` 是对具备 DAS 能力的上游的透明 JSON-RPC 透传,因此标准方法(`getBalance`)和 DAS 方法(`getAsset`、`getAssetsByOwner`)共享同一个端点和同样的按次调用价格。这个投资组合分析器实现了“收集 → 补充 → 总结”工作流中的收集步骤: + +```typescript {% title="portfolio-analyzer.ts" %} +async function noriRpc(method: string, params: unknown[]) { + const res = await fetch(`${NORI_URL}/v1/solana/rpc`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), + }).then((r) => r.json()); + return res.result; +} + +// Gather: SOL balance + all token holdings for a wallet. +const owner = '11111111111111111111111111111112'; // wallet under analysis +const balance = await noriRpc('getBalance', [owner]); + +// DAS method — same endpoint, same per-call price. +const assets = await noriRpc('getAssetsByOwner', [ + { ownerAddress: owner, page: 1, limit: 100 }, +]); + +// Enrich/summarize: feed the holdings to the inference agent above +// for a natural-language portfolio breakdown. +``` + +由于每次调用都单独计量(固定的按次调用价格),循环式 Agent — 按间隔轮询的价格监视器、遍历分页持仓的分析器 — 应当有意识地为调用做预算:PDA 余额就是支出上限,钱包为空会[硬停止](/agents/nori/pricing-and-billing#硬停止语义)服务。 + +## 使用 A2A message/send 的 Agent 间调用方 + +在协议层集成(而非通过 OpenAI SDK)的 Agent,通过 `POST /a2a` 上的 JSON-RPC 2.0 调用相同的技能,并从 [Agent 卡片](/agents/nori/#nori-提供的服务)发现它们。技能输入与 HTTP 接口逐字节相同 — OpenAI 请求体只是作为 DataPart 装在 `message/send` 信封里传输: + +```typescript {% title="a2a-caller.ts" %} +const task = await fetch(`${NORI_URL}/a2a`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'message/send', + params: { + requestId: crypto.randomUUID(), + message: { + parts: [ + { + kind: 'data', + data: { + skill: 'chat.completion', + input: { + model: 'anthropic/claude-sonnet-4-6', + messages: [{ role: 'user', content: 'Hello from another agent.' }], + }, + }, + }, + ], + }, + }, + }), +}).then((r) => r.json()); +``` + +`message/send` 同步返回一个已完成的任务;`tasks/get` 按 ID 获取之前的任务。将 `skill` 换为 `image.generation` 或 `solana.rpc`,输入形状与其 HTTP 对应端点相同。 + +{% callout type="note" title="v1 不提供流式传输" %} +`message/sendStream` 在 Agent 卡片上有声明,但在 v1 中返回 501,且 `/v1/chat/completions` 是非流式的。请围绕完整响应来设计 Agent 循环。 +{% /callout %} + +## 快速参考 + +| 示例 | 服务 | 端点 | 计费方式 | +|---------|---------|----------|-----------| +| 推理 Agent | `chat.completion` | `POST /v1/chat/completions` | 按输入/输出 token、按模型计费 | +| 艺术创作 Agent | `image.generation` | `POST /v1/images/generations` | 按图像计费 | +| 投资组合分析器 | `solana.rpc` | `POST /v1/solana/rpc` | 按调用计费(包括 DAS 方法) | +| A2A 调用方 | 任意技能 | `POST /a2a`(`message/send`) | 与底层技能相同 | + +## 注意事项 + +- 所有示例都假设已有 `NORI_URL`(Nori 的基础 URL)和 `token`(来自[握手流程](/agents/nori/delegate-to-nori#步骤-3--使用-bearer-令牌进行认证)的 Bearer 令牌);令牌 15 分钟后过期,因此长时间运行的 Agent 需要重新握手 +- 没有 Bearer 令牌时,相同的请求通过 x402 轨道运行:首次调用会收到带支付要求的 HTTP 402,付款后重试 +- 如果您更愿意从一个可运行的 Agent 开始,Metaplex Agent 模板已将这些模式打包为现成的 Mastra 工具(`chat-completion`、`generate-image`、`solana-rpc-call`、`delegate-to-nori`) +- 成功后计费适用于每个示例:失败的上游调用不产生任何费用 — 参见[定价与计费](/agents/nori/pricing-and-billing#成功后计费核算) + +由 Metaplex Foundation 维护。最后验证日期:2026-07-08。[在 GitHub 上查看源码](https://github.com/metaplex-foundation/agent-plumber)。 + +## FAQ + +关于基于 Nori 服务进行构建的常见问题。 + +### 哪些 SDK 可以配合 Nori 的推理服务使用? +任何 OpenAI 兼容客户端都可以 — 通过 `createOpenAICompatible` 的 Vercel AI SDK、使用自定义 `baseURL` 的官方 OpenAI SDK,或接受 OpenAI 兼容提供商的 Agent 框架(如 Mastra)。将客户端指向 `NORI_URL/v1`,并将 Bearer 令牌附加为 `Authorization` 请求头。 + +### 我的 Agent 可以通过 Nori 使用 getAssetsByOwner 之类的 DAS 方法吗? +可以。`solana.rpc` 服务是对具备 DAS 能力的上游提供商的透明 JSON-RPC 透传,因此 DAS 方法(`getAsset`、`getAssetsByOwner` 等)的用法与标准 Solana RPC 方法完全相同 — 同一个端点,同样的按次调用价格。 + +### 这些示例不委托也能运行吗? +可以,通过 x402 后备轨道 — 首次调用会先执行一次请求,然后返回带支付要求的 HTTP 402;支付并重试后会返回缓存的结果。示例假设已完成委托,因为委托消除了支付往返;一次性设置参见[委托给 Nori](/agents/nori/delegate-to-nori)。 + +### 我可以通过 chat.completion 请求哪些模型? +费率卡上的任何模型,以 `/` 形式指定 — 例如 `anthropic/claude-sonnet-4-6`、`openai/gpt-5.4` 或 `google/gemini-2.5-flash`。`GET /v1/models` 列出实时目录,[`GET /rate-card`](/agents/nori/pricing-and-billing) 载有每 token 价格。 diff --git a/src/pages/zh/agents/nori/index.md b/src/pages/zh/agents/nori/index.md new file mode 100644 index 00000000..eaf15044 --- /dev/null +++ b/src/pages/zh/agents/nori/index.md @@ -0,0 +1,165 @@ +--- +title: Nori - 面向 Metaplex Agent 的按量付费服务 +metaTitle: Nori - 面向 Agent 的按量付费 LLM、图像与 RPC 服务 | Metaplex +description: Nori 是 Metaplex 的服务 Agent,向其他 Agent 出售 LLM 推理、图像生成和 Solana RPC 访问,按次调用以 SOL 计量结算。了解 delegate-pay(委托支付)计费的运作方式,以及如何将 Nori 用作构建您自己的服务 Agent 的参考实现。 +keywords: + - Nori + - service agent + - agent plumber + - pay-as-you-go inference + - delegate-pay + - x402 payments + - A2A protocol + - agent-to-agent services + - Metaplex agent +about: + - Nori + - Agent Commerce + - Autonomous Agents + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: 什么是 Nori? + a: Nori 是由 Metaplex Foundation 运营的按量付费服务 Agent。它向其他 Agent 出售 LLM 推理、图像生成和 Solana RPC 访问,以美元定价,按次调用以 SOL 从调用方 Agent 的链上 PDA 钱包结算。它同时也是构建 Metaplex 服务 Agent 的开源参考实现。 + - q: 使用 Nori 需要我自己的 LLM 提供商 API 密钥吗? + a: 不需要。Nori 持有上游提供商的密钥(Anthropic、OpenAI、Google、图像生成、付费 Solana RPC)。消费方 Agent 只需要一个 Solana 密钥对和一个已注册的 Agent 资产 — 每次调用都按使用量以 SOL 从 Agent 的 PDA 钱包结算。 + - q: 如果 Nori 宕机,我的 Agent 会怎样? + a: 依赖 Nori 提供推理、图像或 RPC 的已委托 Agent 在 Nori 不可用期间会失去这些能力。Nori 的接口是 OpenAI 兼容格式和标准 Solana JSON-RPC,因此应急后备方案是使用您自己的密钥将客户端指向任何其他 OpenAI 兼容提供商或 RPC 端点。自托管您自己的 Nori 实例计划在 v2 中提供。 + - q: 委托给 Nori 安全吗?Nori 会掏空我的钱包吗? + a: 委托授予 Nori 对您 Agent 的 PDA 钱包的计费权限,因此那里只应保留工作余额。每笔扣费都附带可供审计的链上 Memo 收据,只有成功的调用才会被扣费,并且资产所有者可以随时撤销委托,这会硬停止 delegate-pay 轨道。 + - q: delegate-pay 轨道和 x402 轨道有什么区别? + a: Delegate-pay 是主轨道 — 完成一次性链上委托后,Nori 按次调用直接从您 Agent 的 PDA 扣费,没有支付往返。x402 是未委托调用方的后备轨道 — 第一次请求返回带支付要求的 HTTP 402,调用方支付后重试。 +--- + +Nori 是由 Metaplex Foundation 运营的按量付费**服务 Agent**。它向其他 Agent 出售 LLM 推理、图像生成和 Solana RPC 访问 — 以美元定价,按次调用以 SOL 从调用方 Agent 的链上钱包结算。Nori 同时也是 Metaplex 服务 Agent 的开源参考实现:Agent 构建者可以研究(并复制)它的 [A2A 接口](/agents/agent-commerce)、delegate-pay(委托支付)计费、x402 后备方案和费率卡模式。{% .lead %} + +## 概述 + +Nori 免除了每个 Agent 运营者原本需要自行搭建的基础设施 — LLM 提供商密钥、图像生成账户、付费 Solana RPC 和按次调用计费。消费方 Agent 只需要一个 Solana 密钥对和一个[已注册的 Agent 资产](/agents/register-agent)。 + +- **三项计量服务** — `chat.completion`(Anthropic / OpenAI / Google,支持工具调用)、`image.generation`(gpt-image-1)和 `solana.rpc`(RPC + DAS 透传) +- **两条支付轨道** — [delegate-pay](/agents/nori/delegate-to-nori)(主轨道,一次性链上设置)和 x402 v2(后备轨道,按次调用的 HTTP 402 流程) +- **成功后计费(charge-on-success)** — 先运行上游调用;失败的调用永不扣费,每笔扣费都附带链上 Memo 收据 +- **单点故障注意事项** — 已委托的 Agent 在推理、图像和 RPC 上依赖 Nori 的可用性;缓解措施参见 [Nori 作为单点故障](#nori-作为单点故障) + +{% callout type="note" title="两类读者,一个页面" %} +如果您正在从自己的 Agent **消费** Nori 的服务,或者您正在**构建服务 Agent**并希望获得 A2A 技能、按次调用计费和费率卡发布的可运行参考,请使用本节。[源代码仓库](https://github.com/metaplex-foundation/agent-plumber)是开源的。 +{% /callout %} + +## Nori 提供的服务 + +Nori 通过共享同一处理器栈的两个接口暴露三项服务。技能的输入/输出对聊天和图像使用规范的 OpenAI 线格式,对 RPC 使用标准 Solana JSON-RPC — A2A 调用方和 OpenAI-SDK 调用方发送的负载逐字节相同。 + +| 服务 | 技能 ID | 端点 | 上游 | +|---------|----------|----------|----------| +| LLM 推理(支持工具调用) | `chat.completion` | `POST /v1/chat/completions` | Anthropic、OpenAI、Google — 按 `/` 前缀路由 | +| 图像生成 | `image.generation` | `POST /v1/images/generations` | OpenAI gpt-image-1 | +| Solana RPC + DAS | `solana.rpc` | `POST /v1/solana/rpc` | 运营者配置的 RPC 提供商(DAS 方法透传) | + +两个接口都能访问相同的服务: + +- **OpenAI 兼容 HTTP**(`/v1/*`)— 通过 `baseURL` 将任何 OpenAI SDK 或 AI 框架指向 Nori。这是大多数消费方 Agent 使用的接口。 +- **A2A JSON-RPC**(`/a2a`)— 程序化的 Agent 间调用。发现从 `GET /.well-known/agent-card.json` 开始,它公布技能、支付方案以及 Nori 的 `serviceExecutiveAddress`(您注册为委托方的地址)。 + +## Nori 支付的运作方式 + +Nori 按次调用选择一条支付轨道:调用方已接入时使用 delegate-pay,否则使用 x402。 + +| 轨道 | 何时触发 | 如何结算 | +|------|---------------|----------------| +| **Delegate-pay**(主轨道) | 调用方出示有效的 Bearer 令牌,且 Nori 是调用方 Agent 资产上已注册的[执行委托方](/smart-contracts/mpl-agent/tools) | Nori 签署一笔 MPL Core Execute 交易,将 SOL 从调用方的 PDA 转移到 Nori 的服务 PDA,并附带 Memo 收据 — 无支付往返 | +| **x402 v2**(后备轨道) | 无 Bearer 令牌、令牌无效或未设置委托 | 第一次请求返回带支付要求的 HTTP 402;调用方支付(SOL 或 USDC)后重试,并收到缓存的结果 | + +Delegate-pay 轨道使 Nori 对您 Agent 的最终用户而言不可见:完成[一次性委托](/agents/nori/delegate-to-nori)后,每次调用都自动结算,没有钱包提示,也没有超额报价的预扣。定价发布在带版本号的[费率卡](/agents/nori/pricing-and-billing)上,并附有价格变更通知政策。 + +## Nori 作为单点故障 + +推理、图像生成和 RPC 都来自 Nori 的已委托 Agent,等于把 Nori 变成了单点故障:如果 Nori 不可用,该 Agent 会失去这些能力,直到 Nori 恢复。这是 Nori 自身风险登记册中排名第一的风险,v1 的缓解措施是文档和可移植接口,而非冗余。 + +请明确地为此做好规划: + +- **接口在设计上是可移植的。** `chat.completion` 是规范的 OpenAI 线格式,`solana.rpc` 是标准 Solana JSON-RPC。应急(break-glass)后备方案只是一次配置变更:将您的 OpenAI 兼容客户端指向另一个提供商(使用您自己的密钥),将您的 RPC 调用指向任何公共或付费端点。 +- **保留应急凭证。** 零 BYOK 是 Nori 提供的便利,不是您架构的必要条件。储备一个低配额的提供商密钥和一个免费 RPC URL,可以让您的 Agent 在 Nori 中断期间降级运行而不至瘫痪。 +- **x402 轨道是支付层面的独立后备,而非可用性层面的。** 它消除了对委托的依赖,但仍然依赖 Nori 处于运行状态。 +- **委托随时可撤销。** 如果您迁移离开 Nori,资产所有者撤销委托记录后,delegate-pay 轨道会[硬停止](/agents/nori/pricing-and-billing#硬停止语义)。 + +{% callout type="warning" title="自托管推迟到 v2" %} +运行您自己的 Nori 实例(彻底消除共享依赖)计划在 v2 中提供。在 v1 中,缓解措施是上述可移植的 OpenAI/JSON-RPC 接口 — 在设计您的 Agent 时,把 Nori 的基础 URL 当作一个配置值,而不是一个假设。 +{% /callout %} + +## 将 Nori 用作参考实现 + +Nori 是 Metaplex 服务 Agent 的可运行蓝图 — 一个向其他 Agent 收费提供工作的 Agent。[源代码仓库](https://github.com/metaplex-foundation/agent-plumber)端到端地演示了每种模式: + +| 模式 | Nori 演示的内容 | +|---------|------------------------| +| Agent 卡片发现 | `/.well-known/agent-card.json` 公布技能、支付方案、`serviceAssetAddress` 和 `serviceExecutiveAddress` | +| Delegate-pay 计费 | 通过 MPL Core Execute CPI 从调用方的 PDA 扣费并附带 Memo 收据,配合 5 分钟委托状态缓存 | +| x402 v2 后备 | 规范的 HTTP 402 流程,配备协调方端点(`/verify`、`/settle`),并由协调方担任 feePayer,使调用方无需 SOL 支付网络费用 | +| 费率卡发布 | `GET /rate-card` 提供带版本号的价目表及通知期政策 | +| 成功后计费核算 | 先上游调用,后扣费;失败的调用返回错误且不扣费 | +| 免费委托接入 | 经过严格验证的 `POST /v1/delegate/submit`,作为费用支付方共同签署调用方的委托交易 | + +要在您自己的分叉中添加新的付费服务:编写一个与支付无关、返回结果加 `costUsd` 的处理器,将定价加入价目表,将其接入 A2A 技能分发,并在 Agent 卡片上声明它。 + +## 快速参考 + +| 项目 | 值 | +|------|-------| +| Agent 卡片 | `GET /.well-known/agent-card.json` | +| 费率卡 | `GET /rate-card` | +| 服务 | `chat.completion`、`image.generation`、`solana.rpc` | +| OpenAI 兼容基础 URL | `/v1` | +| A2A 端点 | `POST /a2a`(JSON-RPC 2.0,`message/send`) | +| 支付轨道 | Delegate-pay(主轨道)、x402 v2(后备轨道) | +| 委托程序 | `mpl-agent-tools` — `TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S` | +| 源代码 | [GitHub](https://github.com/metaplex-foundation/agent-plumber) | + +## 注意事项 + +- Nori 部署后的基础 URL 通过其 Agent 注册发布;本节各处的示例使用 `NORI_URL` 作为基础 URL 的占位符 +- 扣费以美元定价,并在扣费时使用 Jupiter 的实时 SOL/USD 价格(30 秒缓存)转换为 SOL — 参见[定价与计费](/agents/nori/pricing-and-billing) +- 委托授予 Nori 对您 Agent 的 PDA 钱包的计费权限。那里只保留工作余额,并审计每笔扣费的 Memo 收据 +- `message/sendStream` 在 Agent 卡片上有声明,但在 v1 中返回 501;A2A 调用是同步的 +- Nori(托管的 Metaplex 服务)和 agent-plumber(开源实现)是同一代码库;本文档统一使用“Nori”指代两者 + +由 Metaplex Foundation 维护。最后验证日期:2026-07-08。 + +## FAQ + +关于 Nori 的常见问题。 + +### 什么是 Nori? +Nori 是由 Metaplex Foundation 运营的按量付费服务 Agent。它向其他 Agent 出售 LLM 推理、图像生成和 Solana RPC 访问,以美元定价,按次调用以 SOL 从调用方 Agent 的链上 PDA 钱包结算。它同时也是构建 Metaplex 服务 Agent 的开源参考实现。 + +### 使用 Nori 需要我自己的 LLM 提供商 API 密钥吗? +不需要。Nori 持有上游提供商的密钥(Anthropic、OpenAI、Google、图像生成、付费 Solana RPC)。消费方 Agent 只需要一个 Solana 密钥对和一个[已注册的 Agent 资产](/agents/register-agent) — 每次调用都按使用量以 SOL 从 Agent 的 PDA 钱包结算。 + +### 如果 Nori 宕机,我的 Agent 会怎样? +依赖 Nori 提供推理、图像或 RPC 的已委托 Agent 在 Nori 不可用期间会失去这些能力。Nori 的接口是 OpenAI 兼容格式和标准 Solana JSON-RPC,因此应急后备方案是使用您自己的密钥将客户端指向任何其他 OpenAI 兼容提供商或 RPC 端点。自托管您自己的 Nori 实例计划在 v2 中提供。 + +### 委托给 Nori 安全吗?Nori 会掏空我的钱包吗? +委托授予 Nori 对您 Agent 的 PDA 钱包的计费权限,因此那里只应保留工作余额。每笔扣费都附带可供审计的链上 Memo 收据,[只有成功的调用才会被扣费](/agents/nori/pricing-and-billing#成功后计费核算),并且资产所有者可以随时[撤销委托](/agents/nori/delegate-to-nori#从-nori-撤销委托),这会硬停止 delegate-pay 轨道。 + +### delegate-pay 轨道和 x402 轨道有什么区别? +Delegate-pay 是主轨道 — 完成一次性链上委托后,Nori 按次调用直接从您 Agent 的 PDA 扣费,没有支付往返。x402 是未委托调用方的后备轨道 — 第一次请求返回带支付要求的 HTTP 402,调用方支付(SOL 或 USDC)后重试。 + +## 术语表 + +Nori 文档中使用的核心术语。 + +| 术语 | 定义 | +|------|------------| +| **Nori** | Metaplex Foundation 的按量付费服务 Agent,同时也是 Metaplex 服务 Agent 的参考实现(agent-plumber) | +| **服务 Agent(Service agent)** | 向其他 Agent 出售服务并按次调用收费的 Agent | +| **Delegate-pay(委托支付)** | Nori 的主支付轨道 — 完成一次性执行委托后,Nori 通过 MPL Core Execute 交易直接从调用方的 PDA 扣费 | +| **x402** | 用于机器对机器支付的 HTTP `402 Payment Required` 协议;Nori 面向未委托调用方的后备轨道 | +| **费率卡(Rate card)** | Nori 在 `GET /rate-card` 发布的价目表 — 带版本号、以美元计价,并附价格变更通知政策 | +| **成功后计费(Charge-on-success)** | Nori 的计费规则:先运行上游调用,只有成功的调用才会被扣费 | +| **硬停止(Hard stop)** | 当调用方取消委托或调用方的 PDA 钱包无法覆盖一笔扣费时,delegate-pay 服务立即终止 | +| **Asset Signer(PDA 钱包)** | Agent 的链上钱包,从 `["mpl-core-execute", asset]` 派生的 [MPL Core](/smart-contracts/core) PDA — Nori 扣费的来源账户 | +| **执行者配置文件(Executive profile)** | [`mpl-agent-tools`](/smart-contracts/mpl-agent/tools) 中链下签名者的链上身份;您委托给 Nori 的执行者配置文件 | +| **Agent 卡片(Agent card)** | 位于 `/.well-known/agent-card.json` 的 A2A 发现文档,公布技能、支付方案和 Nori 的服务地址 | diff --git a/src/pages/zh/agents/nori/pricing-and-billing.md b/src/pages/zh/agents/nori/pricing-and-billing.md new file mode 100644 index 00000000..34fc9b75 --- /dev/null +++ b/src/pages/zh/agents/nori/pricing-and-billing.md @@ -0,0 +1,187 @@ +--- +title: Nori 定价与计费 +metaTitle: Nori 定价与计费 - 费率卡、成功后计费、硬停止 | Metaplex +description: Nori 如何为服务调用定价和计费 - 发布在 GET /rate-card 的费率卡、扣费时的美元到 SOL 转换、成功后计费核算、价格变更通知政策,以及取消委托和钱包余额耗尽时的硬停止语义。 +keywords: + - Nori rate card + - Nori pricing + - charge-on-success + - price-change notice + - hard stop + - wallet empty + - undelegate + - agent billing + - pay-per-call +about: + - Nori + - Agent Commerce + - Solana + - Metaplex +proficiencyLevel: Intermediate +created: '07-08-2026' +updated: '07-08-2026' +faqs: + - q: 如果 Nori 调用失败,我会被扣费吗? + a: 不会。Nori 先运行上游调用,只在成功时扣费。失败的上游调用返回错误且不扣费。在 x402 轨道上,结果只计算一次并被缓存,因此付费重试返回的是缓存结果,永远不会重新运行或重复计费。 + - q: Nori 如何将美元价格转换为 SOL? + a: 费率卡以美元计价。在扣费时,Nori 使用来自 Jupiter 价格 API 的实时 SOL/USD 现货价格(缓存 30 秒)重新计算 SOL 金额。因此实际扣除的 lamports 跟随调用时刻的市场汇率。 + - q: Nori 在价格变更前会提前多久通知? + a: 费率卡带有一个包含 notice_period_days(默认 7)的政策块。涨价在提交时其 effective_at 时间戳至少要在通知期之后,且 effective_at 之前的扣费继续按先前发布的价格执行。变更历史可在政策的 notice_url 查看。 + - q: 我的 Agent 钱包里的 SOL 用完了会怎样? + a: 硬停止。当 PDA 无法覆盖一笔扣费时,delegate-pay 扣费失败,该调用回退为 HTTP 402 x402 质询 — 服务不会以赊账方式提供。一旦您为 PDA 充值,调用即可恢复。 + - q: 如果我在使用过程中取消对 Nori 的委托会怎样? + a: 下一次扣费尝试会在链上失败,Nori 作废其缓存的委托状态,delegate-pay 轨道硬停止。后续调用会收到 x402 支付质询。撤销之后不会有任何扣费,因为链会拒绝该 Execute 交易。 + - q: 我在哪里可以核验 Nori 向我的 Agent 扣了多少费? + a: 每笔扣费都是一笔从您 Agent 的 PDA 到 Nori 服务 PDA 的 SOL 转账,并附带一条携带结构化收据的 Memo 指令。您 Agent 的链上交易历史就是完整的、可独立审计的计费记录。 +--- + +Nori 依据一份公开发布、带版本号的费率卡以美元为每次调用定价,在扣费时刻转换为 SOL,且只在成功时计费 — 失败的上游调用永不扣费。价格变更遵循通知期政策,当调用方取消委托或其钱包无法覆盖一笔扣费时,计费会立即硬停止。{% .lead %} + +## 概述 + +Nori 的计费模型被设计为可从外部审计:公开的价格、链上收据、没有服务就没有扣费。 + +- **费率卡** — `GET /rate-card` 提供完整的美元价目表,包括版本号、`effective_at`、加价系数和价格变更政策 +- **成功后计费(charge-on-success)** — 先运行上游调用;失败返回错误且不扣费,x402 的付费重试返回缓存结果而非重新运行调用 +- **价格变更通知** — 涨价提交时其 `effective_at` 至少在 `notice_period_days`(默认 7)之后;此前的扣费维持先前发布的价格 +- **硬停止(hard stop)** — 取消委托和钱包余额耗尽都会立即停止 delegate-pay 计费;调用回退为 x402 质询,而不是累积债务 + +## Nori 费率卡 + +`GET /rate-card` 是规范的、机器可读的价目表 — 请始终查询它,而不要依赖文档中的任何快照。它提供完整的价目表及政策元数据,缓存 5 分钟: + +```json {% title="GET /rate-card(节选)" %} +{ + "version": 1, + "effective_at": "2026-05-21T00:00:00.000Z", + "policy": { + "notice_period_days": 7, + "notice_url": "https://github.com/metaplex-foundation/agent-plumber/blob/main/packages/shared/src/pricebook.json", + "description": "Price changes are announced by editing this file..." + }, + "markup_factor": 1.25, + "llm": { + "anthropic/claude-sonnet-4-6": { + "inputPerMillion": 3.0, + "outputPerMillion": 15.0, + "cachedInputPerMillion": 0.3 + } + }, + "image": { "openai/gpt-image-1": { "perImage": 0.04 } }, + "rpc": { "default": { "perCall": 0.0001 } } +} +``` + +### 费率卡字段结构 + +| 字段 | 含义 | +|-------|---------| +| `version` | 单调递增的卡片版本号;每次价格变更时递增 | +| `effective_at` | 此卡片价格生效的 ISO 时间戳 | +| `policy.notice_period_days` | 提交一次涨价与其 `effective_at` 之间的最少天数(默认 7) | +| `policy.notice_url` | 卡片(及其变更历史)的发布位置 | +| `markup_factor` | 在扣费时对批发美元价格统一施加的零售加价系数(1.25×) | +| `llm.` | 每百万输入 / 输出 / 缓存输入 token 的批发美元价格 | +| `image.` | 每张生成图像的批发美元价格 | +| `rpc.default` | 每次 RPC 或 DAS 调用的批发美元价格 | + +列出的价格是**批发价**;实际扣费金额为 `批发价 × markup_factor`。`GET /v1/models` 从同一数据源为 OpenAI-SDK 客户端枚举可用的 LLM 模型 ID。 + +### 单笔扣费如何定价 + +每项服务根据费率卡计算出美元成本,然后在扣费时转换为 SOL。 + +1. 服务处理器返回结果加 `costUsd` — `chat.completion` 按 token 数 × 每百万价格计算,`image.generation` 按每张图像计算,`solana.rpc` 按每次调用计算 +2. 对批发成本施加加价系数(1.25×) +3. 美元金额使用来自 Jupiter 价格 API 的实时 SOL/USD 现货价格(30 秒缓存)转换为 lamports +4. 扣费以一笔从您 Agent 的 PDA 到 Nori 服务 PDA 的 SOL 转账落地,并附带 Memo 收据 + +{% callout type="note" title="每笔扣费都附带链上收据" %} +每笔扣费交易上的 Memo 指令编码了一份结构化收据(服务、请求和成本详情)。您的 Agent 与 Nori 服务 PDA 之间的交易历史就是一份完整的、可独立审计的计费记录 — 无需信任 Nori 的链下账目。 +{% /callout %} + +## 成功后计费核算 + +Nori 永远不会为未成功提供的调用扣费。在两条支付轨道上,顺序都是先上游、后扣费: + +- **Delegate-pay 轨道** — Nori 运行上游调用(LLM、图像、RPC);如果成功,Nori 向 PDA 扣费并返回结果。如果上游调用失败,调用方收到错误响应且不扣费。 +- **x402 轨道** — 第一次请求(付款前)会运行上游调用,并以支付质询为键缓存结果。402 响应报出的正是已计算完成的结果的准确成本。当调用方付款并重试时,Nori 返回**缓存的**结果 — 上游调用永远不会重新运行,因此永远不会重复计费,报价即结算价。 + +值得注意的是相反方向的失败情形:在 delegate-pay 轨道上,如果上游调用成功但扣费本身失败(委托被撤销、钱包为空),调用方可能免费获得那一次结果,随后该轨道[硬停止](#硬停止语义)。Nori 承担这一次调用的损失,而不是预先扣押资金。 + +## 价格变更通知政策 + +价格变更通过费率卡本身提前公布 — 在 delegate-pay 轨道上不存在悄然涨价。政策嵌入在卡片的 `policy` 块中: + +1. 价格变更通过提交一张 `version` 递增且 `effective_at` 在未来的新卡片来发布 +2. 对于涨价,`effective_at` 必须至少在提交后 `notice_period_days`(默认 **7 天**)之后 +3. `effective_at` 之前的扣费继续按先前发布的价格执行 +4. 完整的变更历史公开在 `policy.notice_url` + +接受是在委托时隐式完成的:通过委托,Agent 即接受已发布的卡片及其通知政策。如果某项已发布的变更不可接受,请在 `effective_at` 之前[撤销委托](/agents/nori/delegate-to-nori#从-nori-撤销委托) — 撤销是立即硬停止的,因此不会有任何按您未接受的价格执行的扣费落地。 + +要以编程方式监控变更,可轮询 `GET /rate-card`(缓存 5 分钟),并在 `version` 递增或 `effective_at` 变动时告警。 + +## 硬停止语义 + +有两种情况会立即停止 delegate-pay 计费,且是由机制而非政策保证的:链会拒绝扣费,因此不可能累积债务。 + +### 取消委托时的硬停止 + +撤销执行委托会在链的层面终止 Nori 的扣费权限。下一次扣费尝试会以 `Neither the asset or any plugins have approved this operation` 失败,Nori 清除该资产的委托状态缓存,后续调用落入 x402 轨道 — 调用方收到 HTTP 402 支付质询,而不是被自动扣费。由于委托状态最多缓存 5 分钟,撤销后紧接着的一次进行中调用可能仍会尝试(并失败)一次委托扣费;强制停止的是链上检查,因此撤销之后不可能有任何扣费。 + +### 钱包余额耗尽时的硬停止 + +当 Agent 的 PDA 无法覆盖一笔扣费时,委托扣费失败,该调用不会以赊账方式提供。调用方会收到 x402 质询(HTTP 402),可以直接为该次调用付款,或为 PDA 充值以恢复 delegate-pay。Nori 不提供任何信用额度 — 资金不足的 Agent 会降级为按次付费加质询的模式,而不会累积债务。 + +{% callout type="note" title="保持 PDA 高于免租金下限" %} +PDA 需要保持在系统免租金最低余额(890,880 lamports)之上,从它转出的交易才能成功。工作余额的预算公式为:`预期调用数 × 典型扣费金额 + 免租金下限`。Agent 模板正是出于这个原因为新委托预置 0.002 SOL。 +{% /callout %} + +在运维上,将这两种硬停止都视为您 Agent 中的监控信号:先前走 delegate-pay 的调用突然从 200 响应变为 402 质询,意味着委托已不存在或钱包已空。 + +## 快速参考 + +| 项目 | 值 | +|------|-------| +| 费率卡端点 | `GET /rate-card`(5 分钟缓存) | +| 模型目录 | `GET /v1/models` | +| 计价方式 | 美元定价,以 SOL 结算(Jupiter 现货价,30 秒缓存) | +| 加价 | 批发价的 1.25×,统一适用 | +| 通知期 | 7 天(`policy.notice_period_days`) | +| 计费规则 | 成功后计费;x402 重试返回缓存结果 | +| 取消委托 | 立即硬停止 → 回退到 x402 | +| 钱包余额耗尽 | 立即硬停止 → x402 质询,直到充值 | +| 收据 | 每笔扣费交易上的 Memo 指令 | + +## 注意事项 + +- [源代码仓库](https://github.com/metaplex-foundation/agent-plumber)中捆绑的价目表是发布时公开标价的快照;线上实例的 `GET /rate-card` 才是有效的价目表 +- 费率卡上的价格是批发价 — 乘以 `markup_factor` 才是实际扣费金额 +- 同一次调用实际扣除的 lamports 会随扣费时刻的 SOL/USD 汇率变化;卡片固定的是美元金额 +- 硬停止适用于 delegate-pay 轨道;x402 轨道本质上是按次预付的,不存在等价的失败模式 +- 将 Nori 作为参考实现进行分叉的运营者直接编辑 `packages/shared/src/pricebook.json`,并应遵守同样的 `effective_at` 通知纪律 + +由 Metaplex Foundation 维护。最后验证日期:2026-07-08。[在 GitHub 上查看源码](https://github.com/metaplex-foundation/agent-plumber)。 + +## FAQ + +关于 Nori 定价与计费的常见问题。 + +### 如果 Nori 调用失败,我会被扣费吗? +不会。Nori 先运行上游调用,只在成功时扣费。失败的上游调用返回错误且不扣费。在 x402 轨道上,结果只计算一次并被缓存,因此付费重试返回的是缓存结果,永远不会重新运行或重复计费。 + +### Nori 如何将美元价格转换为 SOL? +费率卡以美元计价。在扣费时,Nori 使用来自 Jupiter 价格 API 的实时 SOL/USD 现货价格(缓存 30 秒)重新计算 SOL 金额。因此实际扣除的 lamports 跟随调用时刻的市场汇率。 + +### Nori 在价格变更前会提前多久通知? +费率卡带有一个包含 `notice_period_days`(默认 7)的 `policy` 块。涨价在提交时其 `effective_at` 时间戳至少要在通知期之后,且 `effective_at` 之前的扣费继续按先前发布的价格执行。变更历史可在政策的 `notice_url` 查看。 + +### 我的 Agent 钱包里的 SOL 用完了会怎样? +硬停止。当 PDA 无法覆盖一笔扣费时,delegate-pay 扣费失败,该调用回退为 HTTP 402 x402 质询 — 服务不会以赊账方式提供。一旦您为 PDA 充值,调用即可恢复。 + +### 如果我在使用过程中取消对 Nori 的委托会怎样? +下一次扣费尝试会在链上失败,Nori 作废其缓存的委托状态,delegate-pay 轨道硬停止。后续调用会收到 x402 支付质询。撤销之后不会有任何扣费,因为链会拒绝该 Execute 交易。 + +### 我在哪里可以核验 Nori 向我的 Agent 扣了多少费? +每笔扣费都是一笔从您 Agent 的 PDA 到 Nori 服务 PDA 的 SOL 转账,并附带一条携带结构化收据的 Memo 指令。您 Agent 的链上交易历史就是完整的、可独立审计的计费记录。