@bnbagent/studio-cli 0.0.6-alpha.1 → 0.0.6-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bag.js +743 -121
- package/dist/{chunk-M3ODFCA7.js → chunk-6EYSXRFD.js} +78 -14
- package/dist/{deployCli-N6TPN6XA.js → deployCli-3U2FESF4.js} +1 -1
- package/package.json +2 -2
- package/recipes/agent/code/{{PKG}}/signing.ts.tmpl +12 -1
- package/skills/bnbagent-studio.md +13 -4
- package/skills/references/bnbagent-studio-adding-to-project.md +16 -0
- package/skills/references/bnbagent-studio-buying-via-8183.md +19 -3
- package/skills/references/bnbagent-studio-operating.md +19 -0
- package/skills/references/bnbagent-studio-scaffolding-agent.md +18 -3
- package/skills/references/bnbagent-studio-selling-via-8183.md +20 -0
- package/skills/references/bnbagent-studio-selling-via-b402.md +41 -17
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +3 -2
- package/skills/references/bnbagent-studio-using-altana-wallet.md +5 -4
|
@@ -293,6 +293,44 @@ function mb(n) {
|
|
|
293
293
|
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
+
// src/cli/_x402SellerConfig.ts
|
|
297
|
+
var DEFAULT_B402_PRICE_USD = "0.01";
|
|
298
|
+
var PRICE_USD_RE = /^(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
299
|
+
var ZERO_PRICE_USD_RE = /^0(?:\.0+)?$/;
|
|
300
|
+
function x402SellerPricingState(seller) {
|
|
301
|
+
const raw = seller.price_usd;
|
|
302
|
+
const priceUsd = raw === void 0 ? DEFAULT_B402_PRICE_USD : typeof raw === "string" ? raw : "";
|
|
303
|
+
if (!PRICE_USD_RE.test(priceUsd)) {
|
|
304
|
+
return { kind: "invalid", value: String(raw ?? "") };
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
kind: ZERO_PRICE_USD_RE.test(priceUsd) ? "free" : "paid",
|
|
308
|
+
priceUsd
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function normalizeB402PriceUsd(value) {
|
|
312
|
+
const normalized = value.trim();
|
|
313
|
+
if (!PRICE_USD_RE.test(normalized)) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
`B402 price must be a non-negative decimal USD string; got ${JSON.stringify(value)}.`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
return normalized;
|
|
319
|
+
}
|
|
320
|
+
function x402SellerUsesB402(cfg) {
|
|
321
|
+
const payments = table2(cfg.payments);
|
|
322
|
+
const seller = table2(payments.x402_seller);
|
|
323
|
+
return seller.enabled === true && x402SellerPricingState(seller).kind === "paid";
|
|
324
|
+
}
|
|
325
|
+
function x402SellerIsFree(cfg) {
|
|
326
|
+
const payments = table2(cfg.payments);
|
|
327
|
+
const seller = table2(payments.x402_seller);
|
|
328
|
+
return seller.enabled === true && x402SellerPricingState(seller).kind === "free";
|
|
329
|
+
}
|
|
330
|
+
function table2(value) {
|
|
331
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
332
|
+
}
|
|
333
|
+
|
|
296
334
|
// src/cli/exit.ts
|
|
297
335
|
var CliExit = class extends Error {
|
|
298
336
|
constructor(code) {
|
|
@@ -597,10 +635,10 @@ var B402_RUNTIME_KEYS = [
|
|
|
597
635
|
"B402_PRIVATE_KEY_B64"
|
|
598
636
|
];
|
|
599
637
|
function commerceRails(cfg) {
|
|
600
|
-
const payments =
|
|
638
|
+
const payments = table3(cfg.payments);
|
|
601
639
|
return {
|
|
602
640
|
erc8183: isTable(payments.erc8183),
|
|
603
|
-
x402:
|
|
641
|
+
x402: table3(payments.x402_seller).enabled === true
|
|
604
642
|
};
|
|
605
643
|
}
|
|
606
644
|
function b402Credentials(agentRoot) {
|
|
@@ -633,15 +671,36 @@ function loadDeployConfig(root) {
|
|
|
633
671
|
function x402DeploySummary(root, destination, publicUrl) {
|
|
634
672
|
const { agentRoot, cfg } = loadDeployConfig(root);
|
|
635
673
|
if (!commerceRails(cfg).x402) return "";
|
|
674
|
+
const seller = table3(table3(cfg.payments).x402_seller);
|
|
675
|
+
const pricing = x402SellerPricingState(seller);
|
|
636
676
|
const credentials = b402Credentials(agentRoot);
|
|
637
677
|
const activation = "run the bnbagent-studio-selling-via-b402 skill, fill the four B402_* variables in .studio/.env.local, then redeploy.";
|
|
638
|
-
|
|
639
|
-
return `x402 rail is DORMANT. To activate: ${activation}`;
|
|
640
|
-
}
|
|
641
|
-
const runtime = String(table2(cfg.stack).runtime ?? "agentcore");
|
|
678
|
+
const runtime = String(table3(cfg.stack).runtime ?? "agentcore");
|
|
642
679
|
if (destination !== "platform" && runtime !== "agentcore") {
|
|
643
680
|
return `x402 rail is FORCED DORMANT: the ${runtime} runtime has no x402 path. Deploy to AgentCore (managed platform or self-hosted) to activate the rail.`;
|
|
644
681
|
}
|
|
682
|
+
if (pricing.kind === "invalid") {
|
|
683
|
+
return "x402 rail is DORMANT: price_usd is invalid; run `bag doctor`.";
|
|
684
|
+
}
|
|
685
|
+
if (pricing.kind === "free") {
|
|
686
|
+
if (destination !== "platform") {
|
|
687
|
+
return [
|
|
688
|
+
"x402 rail is ACTIVE in FREE mode (self-hosted AgentCore).",
|
|
689
|
+
"B402 verify/settle is bypassed; no credentials, token payment, or settlement audit is used.",
|
|
690
|
+
"This target has no anonymous public URL; expose /x402 with your own HTTP front.",
|
|
691
|
+
'The front reaches the agent by wrapping each request as envelope-v1 JSON \u2014 {"v":1,"method":"POST","path":"/x402","headers":{...},"body":"<base64>"} \u2014 inside a SigV4-signed (or JWT bearer) InvokeAgentRuntime call. Limits: 1 MiB request, 5 MiB response, no streaming.'
|
|
692
|
+
].join("\n");
|
|
693
|
+
}
|
|
694
|
+
const url2 = publicUrl ?? "<available after the platform agentId is assigned>";
|
|
695
|
+
return [
|
|
696
|
+
"x402 rail is ACTIVE in FREE mode.",
|
|
697
|
+
`Anonymous FREE URL: ${url2}`,
|
|
698
|
+
"B402 verify/settle is bypassed; no credentials, token payment, or settlement audit is used."
|
|
699
|
+
].join("\n");
|
|
700
|
+
}
|
|
701
|
+
if (!credentials.complete) {
|
|
702
|
+
return `x402 rail is DORMANT. To activate: ${activation}`;
|
|
703
|
+
}
|
|
645
704
|
const settlement = [
|
|
646
705
|
"B402 settlement runs inside every paid request and normally adds 10\u201345 s; buyer timeout must be at least 120 s.",
|
|
647
706
|
"Settlement happens before work. If work later fails, the payment is retained and is not refunded automatically."
|
|
@@ -663,7 +722,7 @@ function x402DeploySummary(root, destination, publicUrl) {
|
|
|
663
722
|
...settlement
|
|
664
723
|
].join("\n");
|
|
665
724
|
}
|
|
666
|
-
function
|
|
725
|
+
function table3(value) {
|
|
667
726
|
return isTable(value) ? value : {};
|
|
668
727
|
}
|
|
669
728
|
function isTable(value) {
|
|
@@ -735,14 +794,14 @@ function deployCommand(environment = process.env) {
|
|
|
735
794
|
}
|
|
736
795
|
return ["bunx", "--bun", DEPLOY_CLI_PACKAGE];
|
|
737
796
|
}
|
|
738
|
-
function providerPassthrough(studio,
|
|
739
|
-
const raw = tableOf(studio, "deploy")[
|
|
797
|
+
function providerPassthrough(studio, table4) {
|
|
798
|
+
const raw = tableOf(studio, "deploy")[table4];
|
|
740
799
|
if (raw === void 0 || raw === null) {
|
|
741
800
|
return {};
|
|
742
801
|
}
|
|
743
802
|
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
744
803
|
throw new Error(
|
|
745
|
-
`studio.toml [deploy.${
|
|
804
|
+
`studio.toml [deploy.${table4}] must be a TOML table of deploy-spec keys`
|
|
746
805
|
);
|
|
747
806
|
}
|
|
748
807
|
return { ...raw };
|
|
@@ -835,10 +894,10 @@ function buildDeploySpec(root, opts) {
|
|
|
835
894
|
}
|
|
836
895
|
doc.foundry = foundry;
|
|
837
896
|
} else {
|
|
838
|
-
for (const
|
|
839
|
-
if (Object.keys(providerPassthrough(studio,
|
|
897
|
+
for (const table4 of ["agentcore", "foundry"]) {
|
|
898
|
+
if (Object.keys(providerPassthrough(studio, table4)).length > 0) {
|
|
840
899
|
printErr(
|
|
841
|
-
`note: the bnb/trial platform does not allow custom provider configuration; [deploy.${
|
|
900
|
+
`note: the bnb/trial platform does not allow custom provider configuration; [deploy.${table4}] ignored`
|
|
842
901
|
);
|
|
843
902
|
}
|
|
844
903
|
}
|
|
@@ -848,7 +907,7 @@ function buildDeploySpec(root, opts) {
|
|
|
848
907
|
if (opts.inlineSecrets) {
|
|
849
908
|
Object.assign(env, opts.inlineSecrets);
|
|
850
909
|
}
|
|
851
|
-
if (opts.target === "bnb/trial" && tableOf(studio, "deploy").destination === "platform" && (!hasProtocolsArray || hasX402Face(faces)) && commerceRails(studio).x402 && b402Credentials(agentRoot).complete) {
|
|
910
|
+
if (opts.target === "bnb/trial" && tableOf(studio, "deploy").destination === "platform" && (!hasProtocolsArray || hasX402Face(faces)) && commerceRails(studio).x402 && (x402SellerIsFree(studio) || b402Credentials(agentRoot).complete)) {
|
|
852
911
|
doc.x402 = {
|
|
853
912
|
publicPaths: ["/x402"],
|
|
854
913
|
tunnel: "http-envelope-v1"
|
|
@@ -1019,6 +1078,11 @@ export {
|
|
|
1019
1078
|
entryStemOf,
|
|
1020
1079
|
devPortOf,
|
|
1021
1080
|
recipeModeOf,
|
|
1081
|
+
DEFAULT_B402_PRICE_USD,
|
|
1082
|
+
x402SellerPricingState,
|
|
1083
|
+
normalizeB402PriceUsd,
|
|
1084
|
+
x402SellerUsesB402,
|
|
1085
|
+
x402SellerIsFree,
|
|
1022
1086
|
whichBin,
|
|
1023
1087
|
agentcoreFlavor,
|
|
1024
1088
|
checkDocker,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bnbagent/studio-cli",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.2",
|
|
4
4
|
"description": "The `bag` CLI: scaffold, run, deploy, and monetize a single seller agent on BNB Chain (ERC-8004 identity, ERC-8183 commerce, x402 payments).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"tar": "^7.4.0",
|
|
38
38
|
"viem": "^2.54.0",
|
|
39
39
|
"yaml": "^2.9.0",
|
|
40
|
-
"@bnbagent/studio-runtime": "0.0.6-alpha.
|
|
40
|
+
"@bnbagent/studio-runtime": "0.0.6-alpha.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@a2a-js/sdk": "^0.3.14",
|
|
@@ -111,6 +111,17 @@ function defaultNetworkName(): string {
|
|
|
111
111
|
return String(((cfg.network ?? {}) as TomlTable).default ?? "bsc-testnet");
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Bind provider_sig to the same Commerce deployment used by the runtime
|
|
116
|
+
* client. QA/custom stacks override the canonical SDK registry via env.
|
|
117
|
+
*/
|
|
118
|
+
export function commerceVerifyingContract(
|
|
119
|
+
chainId: number,
|
|
120
|
+
): `0x${string}` {
|
|
121
|
+
const override = process.env.ERC8183_COMMERCE_ADDRESS?.trim();
|
|
122
|
+
return (override || deployedAddresses(chainId).commerceProxy) as `0x${string}`;
|
|
123
|
+
}
|
|
124
|
+
|
|
114
125
|
/**
|
|
115
126
|
* Return `[minPrice, maxPrice]` in raw wei from studio.toml.
|
|
116
127
|
*
|
|
@@ -182,7 +193,7 @@ function getHandler(): NegotiationHandlerLike {
|
|
|
182
193
|
...negotiationSignerOptions(wallet),
|
|
183
194
|
quoteTtlSeconds: ttl,
|
|
184
195
|
chainId: network.chainId,
|
|
185
|
-
verifyingContract:
|
|
196
|
+
verifyingContract: commerceVerifyingContract(network.chainId),
|
|
186
197
|
});
|
|
187
198
|
}
|
|
188
199
|
return handler;
|
|
@@ -33,8 +33,9 @@ bounded operations — **`negotiate`** (rule-based price clamp + EIP-191 sign;
|
|
|
33
33
|
**no LLM touches money**) and **`notify_funded`** (verify the funded job →
|
|
34
34
|
produce the deliverable → submit on-chain; A2A acks then delivers in the
|
|
35
35
|
background, MCP delivers synchronously in the tool call). The optional x402
|
|
36
|
-
rail adds an anonymous
|
|
37
|
-
before
|
|
36
|
+
rail adds an anonymous HTTP request at `/x402`; positive prices settle through
|
|
37
|
+
B402 before work, while explicit zero is FREE passthrough and bypasses the
|
|
38
|
+
facilitator. It does not expose a general signing tool. Read-only chain
|
|
38
39
|
tools remain available. ALL signing is fixed entrypoint code in
|
|
39
40
|
`app/agent/src/signing.ts` or the runtime's bounded x402 payment handler, never
|
|
40
41
|
an LLM-callable tool. The encrypted keystore lives at the workspace root
|
|
@@ -55,7 +56,7 @@ not answer from memory.
|
|
|
55
56
|
| Add wallet / the single seller runtime to an existing TypeScript agent | `references/bnbagent-studio-adding-to-project.md` |
|
|
56
57
|
| Run / debug / dev / doctor / RPC / balance / incident triage | `references/bnbagent-studio-operating.md` |
|
|
57
58
|
| Implement what the Agent sells, tune pricing, publish over A2A and/or MCP, defend disputes (seller flow) | `references/bnbagent-studio-selling-via-8183.md` |
|
|
58
|
-
| Sell one paid HTTP request through the B402-backed x402 rail (merchant application, RSA key, credentials, IP allowlist, activation) | `references/bnbagent-studio-selling-via-b402.md` |
|
|
59
|
+
| Sell one paid or FREE HTTP request through the B402-backed x402 rail (pricing choice; paid merchant application, RSA key, credentials, IP allowlist, activation) | `references/bnbagent-studio-selling-via-b402.md` |
|
|
59
60
|
| Deploy / redeploy / status / logs / destroy | Run `bag deploy` and explicitly choose a provider. Non-interactive deploy requires `--provider bnb\|aws\|azure --yes` (and `--allow-multiple` when keeping another provider active). Read `references/bnbagent-studio-use-bnb-trial.md`, `references/bnbagent-studio-use-aws-agentcore.md`, or `references/bnbagent-studio-use-azure-foundry.md` for the selected provider. `bag deploy status` lists every recorded provider; multi-deployment logs/verify/destroy require `--provider`. |
|
|
60
61
|
| Wire chain-read tools into the Agent's LLM (AI SDK `tool()` wrappers, or any TS agent framework) | `references/bnbagent-studio-wiring-llm-tools.md` |
|
|
61
62
|
| Buy a service from another ERC-8183 seller via CLI — incl. testing your own seller from the buyer side (v2/internal — NOT the v1 seller product flow) | `references/bnbagent-studio-buying-via-8183.md` |
|
|
@@ -84,10 +85,18 @@ must NOT be added to the description — see docs/design/decisions.md §14. -->
|
|
|
84
85
|
|
|
85
86
|
1. **Agent project code is user-owned** — recipe-emitted files are theirs to edit; studio doesn't auto-rewrite them.
|
|
86
87
|
2. **Private keys live in a user-controlled environment, never transmitted to studio or third parties** — the encrypted keystore lives at the workspace root, outside the deploy codeLocation (no packaging path can bundle it). Altana keeps its admin keystore there and gives local runtime only a bounded session; deployment is blocked. Other supported deploy paths inject only their required wallet material into the selected runtime secret channel. (Scoped, consented exception: provider `bnb`, the 48h testnet trial — testnet-forced, throwaway wallet recommended.)
|
|
87
|
-
3. **Signing is fixed handler code, never an LLM-callable tool** — the ERC-8183 rail exposes bounded `negotiate` / `notify_funded` flows and the x402 rail exposes a bounded
|
|
88
|
+
3. **Signing is fixed handler code, never an LLM-callable tool** — the ERC-8183 rail exposes bounded `negotiate` / `notify_funded` flows and the x402 rail exposes a bounded request handler; raw/arbitrary signing is never exposed. Read-only chain queries remain read-only tools.
|
|
88
89
|
4. **SDK protocol layer stays pure** — studio's opinions don't pollute `bnbagent-sdk`.
|
|
89
90
|
5. **The user can jump ship at any point** — emitted code is theirs to edit / fork / migrate; studio depends on no closed SaaS. Emitted code imports from `@bnbagent/studio-runtime` and depends on that runtime lib (not the CLI), so uninstalling the `@bnbagent/studio-cli` package never breaks a deployed agent.
|
|
90
91
|
|
|
92
|
+
Treat ERC-8183 amounts as decimal strings at CLI/config boundaries and
|
|
93
|
+
`bigint` internally. `price = "0"` is an explicit FREE choice, not a missing
|
|
94
|
+
value; it requires all three contract-address overrides from one verified
|
|
95
|
+
zero-price-compatible stack.
|
|
96
|
+
Treat B402 `price_usd` as a decimal string too. `"0"` is explicit anonymous
|
|
97
|
+
FREE passthrough: B402 verify/settle and secret injection are skipped. Positive
|
|
98
|
+
prices retain the paid merchant flow.
|
|
99
|
+
|
|
91
100
|
## CLI groups at a glance
|
|
92
101
|
|
|
93
102
|
`init`, `scan`, `recipe`, `skills`, `wallet`, `erc8004`, `erc8183`, `x402`, `agents`, `config`, `env`, `dev`, `doctor`, `audit`, `deploy`, `platform`, `llm`, `bundle`, `budget` — see `bag --help` for details. `bag deploy [--provider bnb\|aws\|azure]` is the primary deploy command; `prepare`, `verify`, `status`, `info`, `destroy`, `logs`, `fix-gitignore`, and `provision-cognito` remain lifecycle subcommands (`deploy agent` is a deprecated compatibility alias). Provider deploy/status/logs/destroy and deploy-time credential validation are delegated to pinned `@bnbagent/deploy-cli@0.4.14`.
|
|
@@ -131,6 +131,22 @@ the configured list price, clamps it to `[min_price, max_price]`, then
|
|
|
131
131
|
from the request *before* clamping — the LLM still never sets the price. The
|
|
132
132
|
buyer anchors the signed envelope on-chain via `createJob` + `fund`.
|
|
133
133
|
|
|
134
|
+
Use `bag config set payments.erc8183.price 0` only for an explicit FREE
|
|
135
|
+
product decision. Studio stores ERC-8183 amounts as decimal strings and reports
|
|
136
|
+
FREE in `bag doctor`. Zero funding also requires commerce, router, and policy
|
|
137
|
+
from one compatible stack: set all three `ERC8183_*_ADDRESS` overrides, then
|
|
138
|
+
require `bag doctor` and `bag deploy prepare` to pass. The buyer still runs
|
|
139
|
+
`setBudget(0)` and `fund(0)`, but no ERC-20 approval or token escrow occurs.
|
|
140
|
+
|
|
141
|
+
For an X402 face, choose its request price independently. Use
|
|
142
|
+
`bag config set payments.x402_seller.price_usd 0` only when the existing agent
|
|
143
|
+
is intentionally becoming an unrestricted anonymous FREE API. This path
|
|
144
|
+
bypasses B402 verify/settle, payment, and settlement audit; it needs no merchant
|
|
145
|
+
credentials and Studio will not synchronize any configured B402 secrets.
|
|
146
|
+
Positive prices retain the paid B402 onboarding and settle-before-work flow.
|
|
147
|
+
Verify the choice with `bag x402 sell status`, `bag doctor`, and
|
|
148
|
+
`bag deploy prepare`.
|
|
149
|
+
|
|
134
150
|
## Step 4c — LLM credit continuity (automatic, NOT an LLM tool)
|
|
135
151
|
|
|
136
152
|
For Pieverse projects, the Agent's `buildModel()` factory in the emitted
|
|
@@ -56,13 +56,17 @@ flow now auto-adds dispute_window).
|
|
|
56
56
|
## Preconditions
|
|
57
57
|
|
|
58
58
|
- `bag doctor` is clean (or only warns on LLM key)
|
|
59
|
-
-
|
|
59
|
+
- For a paid job, the wallet has ≥ 0.05 tBNB (gas) and enough U for the budget
|
|
60
|
+
plus slack. On BSC testnet the
|
|
60
61
|
ERC-8183 kernel writes (`createJob` / `fund` deposit / `settle` …) are
|
|
61
62
|
gas-sponsored via the SDK's MegaFuel paymaster, so you spend far less tBNB than
|
|
62
63
|
that — but **not zero**: `fund` sends an ERC-20 `approve` (a token call, not
|
|
63
64
|
sponsored) when the token allowance is too low — typically just the first fund,
|
|
64
65
|
since studio approves a floored cap that later jobs reuse. Keep a little tBNB for
|
|
65
|
-
it. (Mainnet is never sponsored.)
|
|
66
|
+
it. (Mainnet is never sponsored.) For a FREE job, use `--budget-u 0`: no U
|
|
67
|
+
balance, ERC-20 approval, or token escrow is needed, but the ERC-8183 writes
|
|
68
|
+
still need the selected gas/paymaster path and a zero-price-compatible
|
|
69
|
+
commerce/router/policy stack.
|
|
66
70
|
- You know the **provider's wallet address** (the seller agent's address)
|
|
67
71
|
- The seller is **reachable** (its A2A agent is deployed somewhere); discoverable
|
|
68
72
|
via the provider's `bag erc8004 resolve <agent_id>` endpoint URI
|
|
@@ -110,6 +114,13 @@ bag erc8183 buy --provider <provider_addr> "<task description>" \
|
|
|
110
114
|
# `--agent-id` resolves the endpoint + negotiates first.
|
|
111
115
|
```
|
|
112
116
|
|
|
117
|
+
For a signed FREE quote:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
bag erc8183 buy --provider <provider_addr> "<task description>" \
|
|
121
|
+
--budget-u 0 --deadline-min 30 --network bsc-testnet
|
|
122
|
+
```
|
|
123
|
+
|
|
113
124
|
> **Task can be passed two ways** (both accepted): as a positional argument
|
|
114
125
|
> `bag erc8183 buy --provider <addr> "<task>"` OR via the flag
|
|
115
126
|
> `bag erc8183 buy --provider <addr> --task "<task>"`. Pass it once — supplying
|
|
@@ -120,7 +131,8 @@ The 4 on-chain steps run sequentially:
|
|
|
120
131
|
1. `createJob(provider, expiredAt, description)` → returns `job_id`
|
|
121
132
|
2. `registerJob(jobId)`
|
|
122
133
|
3. `setBudget(jobId, rawBudget)`
|
|
123
|
-
4. `fund(jobId, rawBudget, approveFloor=rawBudget)` — auto-approves U
|
|
134
|
+
4. `fund(jobId, rawBudget, approveFloor=rawBudget)` — auto-approves U only
|
|
135
|
+
when the positive budget needs allowance; budget 0 skips approval and escrow
|
|
124
136
|
|
|
125
137
|
Output prints 4 tx hashes + `job_id`. Note the `job_id` for later.
|
|
126
138
|
|
|
@@ -212,6 +224,10 @@ bag erc8183 status $JOB
|
|
|
212
224
|
bag erc8183 settle $JOB --action dispute
|
|
213
225
|
```
|
|
214
226
|
|
|
227
|
+
For the FREE regression, change the budget to `0` and confirm the compatible
|
|
228
|
+
contract job still reaches `FUNDED` and `SUBMITTED` without an ERC-20 approval
|
|
229
|
+
or balance change.
|
|
230
|
+
|
|
215
231
|
This is the exact end-to-end flow used to validate real-chain buying. See the
|
|
216
232
|
references below for the canonical picture.
|
|
217
233
|
|
|
@@ -32,6 +32,7 @@ the file when the topic comes up — don't answer from memory:
|
|
|
32
32
|
- `bnbagent-studio-extending-signing.md` — `PolicyViolation` / `X402PolicyError` diagnosis + extending the EIP-712 allowlist
|
|
33
33
|
- `bnbagent-studio-adding-to-project.md` — adding the seller runtime to an existing TypeScript project
|
|
34
34
|
- `bnbagent-studio-buying-via-8183.md` — buyer flow (find provider → buy → fetch → settle)
|
|
35
|
+
- `bnbagent-studio-selling-via-b402.md` — inbound x402 pricing mode, paid merchant setup, and B402 settlement operations
|
|
35
36
|
|
|
36
37
|
This playbook covers **generic ops**: dev / doctor / balances / RPC / incident triage.
|
|
37
38
|
For seller job-lifecycle decisions (settle / submit / dispute defense), read
|
|
@@ -49,6 +50,7 @@ For seller job-lifecycle decisions (settle / submit / dispute defense), read
|
|
|
49
50
|
| "how much have I approved 0x... for?" | ⚠️ **v0.2 backlog — `bag erc20 allowance` does not exist in v0.0.x** |
|
|
50
51
|
| "is my agent registered?" | `bag erc8004 show` (note: registration is normally automatic at `bag deploy verify` — manual `bag erc8004 register` only if you need an identity before deploy) |
|
|
51
52
|
| "what's the status of job X?" | `bag erc8183 status <id>` (read-only — neutral) |
|
|
53
|
+
| "is `/x402` paid or free?" | `bag x402 sell status` (`Rail state: paid` probes B402 unless `--no-probe`; `free` skips B402) |
|
|
52
54
|
| "settle job X" | `bag erc8183 settle <id> --action approve\|reject\|dispute` (default `approve`) — **seller's manual step** after the dispute window; deeper context in `bnbagent-studio-selling-via-8183.md` (same directory) |
|
|
53
55
|
| "submit work for job X" | **seller action** — read `bnbagent-studio-selling-via-8183.md` (same directory) for the submit/dispute flow |
|
|
54
56
|
| "tx not confirming" | Read BscScan link from prior tx output + check `eth_getTransactionCount` |
|
|
@@ -158,6 +160,19 @@ The `--all` form is the right move when `app/agent/studio.toml`'s
|
|
|
158
160
|
testnet U pays ERC-8183 jobs, mainnet U pays the Pieverse LLM auto-renew.
|
|
159
161
|
Same wallet address on both chains.
|
|
160
162
|
|
|
163
|
+
`bag doctor` prints ERC-8183 pricing as `PAID` or `FREE`. FREE is not ready on
|
|
164
|
+
the canonical contract stack: select one zero-price-compatible QA/custom stack
|
|
165
|
+
by setting `ERC8183_COMMERCE_ADDRESS`, `ERC8183_ROUTER_ADDRESS`, and
|
|
166
|
+
`ERC8183_POLICY_ADDRESS` together. A partial set fails because it can mix
|
|
167
|
+
incompatible commerce, router, and policy deployments.
|
|
168
|
+
|
|
169
|
+
For the inbound x402 seller rail, `bag doctor` also prints `PAID` or `FREE`.
|
|
170
|
+
PAID requires the complete B402 merchant credential set and an `evm-local` or
|
|
171
|
+
`twak` payout wallet. Explicit zero is anonymous FREE passthrough: it does not
|
|
172
|
+
read B402 credentials, call the facilitator, settle a payment, or apply the
|
|
173
|
+
paid-mode payout-wallet allowlist. Confirm the same state with
|
|
174
|
+
`bag x402 sell status`.
|
|
175
|
+
|
|
161
176
|
> ⚠️ **v0.2 backlog — not in v0.0.x.** There is **no** `bag wallet transfer`,
|
|
162
177
|
> no `bag erc20 approve/allowance` group, and no `bag wallet balance --address`
|
|
163
178
|
> / `--token` flag in v0.0.x — running any of them errors with
|
|
@@ -201,6 +216,10 @@ covered in `bnbagent-studio-selling-via-8183.md` (same directory).
|
|
|
201
216
|
| `notify_funded` replies `{"status":"rejected","reason":...}` | `verifySignedJob` failed synchronously in the ack — a **permanent** failure | `reason` names it: not our signature / tampered terms / underfunded / expired (or `error` for a malformed `job_id`). The job is refused outright; re-fund/re-notify with a correct, fully-funded job |
|
|
202
217
|
| Job stays `FUNDED`, never reaches `SUBMITTED` after an `accepted` ack | Background delivery failed (`runWork` / `submitResult` raised) — **not** visible in the A2A reply | The ack only confirms verify passed; delivery runs in the background. Observe the failure via the chain (job never leaves `FUNDED`) + CloudWatch logs; a later `notify_funded` re-attempts it via the sweep |
|
|
203
218
|
| `ERC8183JobOps` has no such export from `@bnbagent/sdk` | package.json pinned an old `@bnbagent/sdk` (missing class) | Bump the dependency and reinstall |
|
|
219
|
+
| FREE price fails doctor/prepare on canonical contracts | `price = "0"` is selected without a zero-price-compatible stack | Set all three `ERC8183_*_ADDRESS` overrides from the current apex-contracts `bscTestnetQa` entry, then rerun `bag doctor` and `bag deploy prepare` |
|
|
220
|
+
| ERC-8183 contract override is incomplete | Only one or two of commerce/router/policy were selected | Set or remove all three together; never mix stacks |
|
|
221
|
+
| `/x402` is public without a 402 challenge | `payments.x402_seller.price_usd = "0"` selected anonymous FREE passthrough | If payment is intended, set a positive decimal price, configure the complete B402 credential set, rerun `bag doctor`, and redeploy |
|
|
222
|
+
| B402 credentials are missing but x402 reports FREE | Expected: FREE bypasses B402 and does not synchronize its secrets | No credential fix is needed; change to a positive price only when the route should charge |
|
|
204
223
|
| `OPENROUTER_API_KEY env var is required` | Loading the entrypoint triggers the emitted `buildModel()` factory | Set the env var even for `bag dev --help` smoke |
|
|
205
224
|
| RPC `limit exceeded` | Public RPC throttle | Retry, or set `STUDIO_BSC_TESTNET_RPC=<private rpc>` |
|
|
206
225
|
|
|
@@ -117,6 +117,8 @@ The fields (give the user all of them at once):
|
|
|
117
117
|
| 7 | **LLM model** | provider catalogue; for `pieverse-llm` the default `auto/free` runs at $0/token | `auto/free` |
|
|
118
118
|
| 8 | **Auto-topup** | `enable` / `disable` — lets the Agent auto-pay $U from the wallet when LLM credits run low | deferred (non-interactive `bag init` records no `[budget]`; enable later with `bag budget enable`) |
|
|
119
119
|
| 9 | **Scaffold destination** (`--destination`) | `self` (prepare the AgentCore scaffold for **your own** AWS account; runtime material stays under your cloud-account control) / `platform` (prepare for a 48h **testnet-only** trial on the BNB Chain managed platform — runs the *same* agent in the **operator's** AWS, so a wallet key **leaves your control**; it hard-forces `[network].default = bsc-testnet`, pins runtime=`agentcore`, packages an artifact, and auth is GitHub device flow. Use a **throwaway** `bag wallet new`, never your main wallet). This is scaffold intent only; deploy still explicitly selects `--provider`. | `platform` while the trial campaign runs (bare init falls back to `self` once it ends, or when `--network bsc-mainnet` / a non-agentcore `--runtime` is passed) |
|
|
120
|
+
| 10 | **ERC-8183 price** (`--erc8183-price`) | non-negative integer string in token base units; `0` explicitly selects FREE | `100000000000000000` (0.1 U) |
|
|
121
|
+
| 11 | **B402/x402 price** (`--b402-price`, when the b402 rail is selected) | non-negative decimal USD string; `0` explicitly selects anonymous FREE passthrough and bypasses B402 | `0.01` |
|
|
120
122
|
|
|
121
123
|
v1 is **seller-only** — there is no role to choose. `bag init` scaffolds the
|
|
122
124
|
single seller agent under `app/agent/` (serves the selected public faces,
|
|
@@ -215,7 +217,7 @@ Step 6b when `storage=ipfs`):
|
|
|
215
217
|
> keep steps 3/4/6 below. Pass `--no-onboard` to `bag init` to make this
|
|
216
218
|
> explicit and deterministic regardless of how the shell wires stdin.
|
|
217
219
|
|
|
218
|
-
1. `bag init <name> --llm-provider <p> --network <n> --storage-provider <s> --wallet-kind <k> --no-onboard`
|
|
220
|
+
1. `bag init <name> --llm-provider <p> --network <n> --storage-provider <s> --wallet-kind <k> --rails <8183|b402|both> [--erc8183-price <base-units>] [--b402-price <usd>] --no-onboard`
|
|
219
221
|
— scaffold the v0.0.1 workspace. **`<name>` must start with a letter and be
|
|
220
222
|
≤23 chars after sanitizing** — `bag init` auto-drops `-`/`_` for the
|
|
221
223
|
AgentCore name (printing what it used) but errors if the alphanumeric form
|
|
@@ -229,7 +231,16 @@ Step 6b when `storage=ipfs`):
|
|
|
229
231
|
faces (omit for A2A default; `--protocol <one>` is only a legacy alias), add
|
|
230
232
|
`--model <m>` only if the user overrode the provider default, and
|
|
231
233
|
`--enable-auto-topup` / `--no-auto-topup` only if they made an explicit
|
|
232
|
-
choice (otherwise omit — consent stays deferred).
|
|
234
|
+
choice (otherwise omit — consent stays deferred). Pass
|
|
235
|
+
`--erc8183-price 0` only when the user explicitly chose FREE; omitting the
|
|
236
|
+
flag preserves the paid 0.1 U default. FREE additionally requires all three
|
|
237
|
+
`ERC8183_COMMERCE_ADDRESS`, `ERC8183_ROUTER_ADDRESS`, and
|
|
238
|
+
`ERC8183_POLICY_ADDRESS` values from one zero-price-compatible QA/custom
|
|
239
|
+
stack; set them with `bag env set` after scaffolding. For B402, pass
|
|
240
|
+
`--b402-price 0` only after the user explicitly accepts an unrestricted
|
|
241
|
+
anonymous FREE `/x402` endpoint. FREE bypasses B402 verify/settle and needs
|
|
242
|
+
no merchant credentials; a positive price keeps the `$0.01` default and
|
|
243
|
+
requires the paid onboarding playbook. **Destination:** while the
|
|
233
244
|
trial campaign runs, bare `bag init` (no `--destination`) defaults to
|
|
234
245
|
`platform` — so pass `--destination self` **explicitly** whenever the user
|
|
235
246
|
chose their own AWS, otherwise studio.toml silently records `platform` and the
|
|
@@ -344,7 +355,11 @@ Step 6b when `storage=ipfs`):
|
|
|
344
355
|
brand-new seller can scaffold, run `bag dev`, and deploy with an empty
|
|
345
356
|
wallet. `bag doctor` and `bag deploy` only **WARN** (never block) on zero
|
|
346
357
|
balance. Funding is needed later only for: a paid LLM model, on-chain
|
|
347
|
-
settle,
|
|
358
|
+
settle, paying positive-price ERC-8183 job buys, or buying/smoking a PAID
|
|
359
|
+
B402 request. A FREE ERC-8183 buy needs no U
|
|
360
|
+
escrow or ERC-20 approval, but still needs the ERC-8183 state-changing calls
|
|
361
|
+
and their gas/paymaster path. A FREE B402/x402 request needs neither token
|
|
362
|
+
funding nor a facilitator call. When funding is needed, the wallet uses
|
|
348
363
|
**TWO distinct U balances on TWO chains** (same wallet address, same private
|
|
349
364
|
key, different chains):
|
|
350
365
|
|
|
@@ -106,6 +106,26 @@ quote_ttl_seconds = 300
|
|
|
106
106
|
default_estimated_completion_seconds = 600
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
An explicit `price = "0"` opts into free jobs when the selected ERC-8183
|
|
110
|
+
contract supports zero-price funding. Keep `currency` configured because it
|
|
111
|
+
remains part of the signed quote.
|
|
112
|
+
|
|
113
|
+
Prefer the CLI so the zero-price choice is visible and remains a decimal
|
|
114
|
+
string:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
bag config set payments.erc8183.price 0
|
|
118
|
+
bag env set ERC8183_COMMERCE_ADDRESS <qa-commerce-proxy>
|
|
119
|
+
bag env set ERC8183_ROUTER_ADDRESS <qa-router-proxy>
|
|
120
|
+
bag env set ERC8183_POLICY_ADDRESS <qa-policy>
|
|
121
|
+
bag doctor
|
|
122
|
+
bag deploy prepare
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Take all three addresses from the same apex-contracts `bscTestnetQa` entry.
|
|
126
|
+
Doctor/prepare reject canonical or partial contract selection for FREE and
|
|
127
|
+
announce `zero token escrow` only when the complete custom/QA stack is selected.
|
|
128
|
+
|
|
109
129
|
## Stage 3 — LLM credit continuity (Pieverse projects only)
|
|
110
130
|
|
|
111
131
|
If `[llm].provider = "pieverse-llm"`, the Agent's emitted
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bnbagent-studio-selling-via-b402
|
|
3
|
-
description: When the user wants a bnbagent-studio agent to sell paid HTTP requests through the B402-backed x402 rail. Owns per-agent merchant onboarding, RSA key preparation, egress-IP allowlisting, sandbox/production separation, B402 environment setup, seller status checks, and activation by redeploy (managed platform or self-hosted AgentCore).
|
|
3
|
+
description: When the user wants a bnbagent-studio agent to sell paid or FREE HTTP requests through the B402-backed x402 rail. Owns the explicit pricing choice and, for PAID mode, per-agent merchant onboarding, RSA key preparation, egress-IP allowlisting, sandbox/production separation, B402 environment setup, seller status checks, and activation by redeploy (managed platform or self-hosted AgentCore).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
> **Reference file** of the `bnbagent-studio` router skill — installed at
|
|
@@ -9,24 +9,46 @@ description: When the user wants a bnbagent-studio agent to sell paid HTTP reque
|
|
|
9
9
|
|
|
10
10
|
# Sell via B402
|
|
11
11
|
|
|
12
|
-
Use this playbook to activate the x402 seller rail for one agent.
|
|
13
|
-
credentials are per agent and per
|
|
14
|
-
|
|
12
|
+
Use this playbook to activate the x402 seller rail for one agent. First choose
|
|
13
|
+
PAID or FREE explicitly. B402 merchant credentials are per agent and per
|
|
14
|
+
environment and are needed only for PAID. Never reuse a merchant record across
|
|
15
|
+
agent wallets, or mix sandbox and production values.
|
|
15
16
|
|
|
16
17
|
## Preconditions
|
|
17
18
|
|
|
18
|
-
- The agent wallet already exists.
|
|
19
|
+
- The agent wallet already exists. In PAID mode its address receives U.
|
|
19
20
|
- The project targets the managed platform or self-hosted AgentCore
|
|
20
21
|
(azure-foundry cannot activate the rail).
|
|
21
|
-
-
|
|
22
|
+
- PAID managed platform only: a platform bearer token is available for reading the
|
|
22
23
|
platform egress IPs — the GitHub-login access token from
|
|
23
24
|
`bag platform login`, or a `bnbk_…` API token minted once by
|
|
24
25
|
`bag platform token`.
|
|
25
26
|
- `[payments.x402_seller]` exists. If not, run
|
|
26
27
|
`bag x402 sell init`.
|
|
27
28
|
|
|
28
|
-
The application uses the **agent wallet address**, not a developer
|
|
29
|
-
buyer wallet, or platform wallet.
|
|
29
|
+
The PAID application uses the **agent wallet address**, not a developer
|
|
30
|
+
treasury, buyer wallet, or platform wallet.
|
|
31
|
+
|
|
32
|
+
## Choose PAID or FREE
|
|
33
|
+
|
|
34
|
+
Use one of these explicit boundaries:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bag init <name> --rails b402 --b402-price 0
|
|
38
|
+
bag x402 sell init --price-usd 0
|
|
39
|
+
bag config set payments.x402_seller.price_usd 0
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`"0"` means anonymous FREE passthrough. The runtime returns work directly and
|
|
43
|
+
does not issue a 402 challenge, call B402 `/supported`/verify/settle, transfer
|
|
44
|
+
U, or write an `x402_sell` settlement audit. B402 credentials are ignored and
|
|
45
|
+
not synchronized. Run `bag x402 sell status`, `bag doctor`, and
|
|
46
|
+
`bag deploy prepare`; all must label the route FREE.
|
|
47
|
+
|
|
48
|
+
This is unrestricted public access. Confirm that intent before continuing.
|
|
49
|
+
Managed platform still publishes the route through its gateway; self-hosted
|
|
50
|
+
AgentCore still needs an envelope-v1 front; Azure Foundry remains unsupported.
|
|
51
|
+
If FREE is the selected product, skip the merchant/RSA/IP sections below.
|
|
30
52
|
|
|
31
53
|
## Generate the agent's RSA material
|
|
32
54
|
|
|
@@ -146,7 +168,7 @@ exactly one private-key form; do not set both.
|
|
|
146
168
|
|
|
147
169
|
## Verify and activate
|
|
148
170
|
|
|
149
|
-
|
|
171
|
+
For PAID mode, check names and presence without exposing values:
|
|
150
172
|
|
|
151
173
|
```bash
|
|
152
174
|
bag x402 sell status --no-probe
|
|
@@ -163,7 +185,7 @@ For a sandbox/trial agent, it must find exact/eip3009 U on `eip155:97`. For
|
|
|
163
185
|
production it must find the mainnet environment expected by the project. A
|
|
164
186
|
network mismatch is not safe to ignore.
|
|
165
187
|
|
|
166
|
-
Run the deployment gate, then redeploy to activate the
|
|
188
|
+
Run the deployment gate, then redeploy to activate the selected mode:
|
|
167
189
|
|
|
168
190
|
```bash
|
|
169
191
|
bag deploy prepare
|
|
@@ -171,11 +193,12 @@ bag deploy --provider bnb # managed platform
|
|
|
171
193
|
bag deploy --provider aws # self-hosted AgentCore
|
|
172
194
|
```
|
|
173
195
|
|
|
174
|
-
On the managed platform the deploy summary must say `x402 rail is ACTIVE`
|
|
175
|
-
print the anonymous `/x402` URL. On a self-hosted
|
|
176
|
-
`x402 rail is ACTIVE (self-hosted AgentCore)
|
|
177
|
-
|
|
178
|
-
|
|
196
|
+
On the managed platform the deploy summary must say `x402 rail is ACTIVE` (or
|
|
197
|
+
`ACTIVE in FREE mode`) and print the anonymous `/x402` URL. On a self-hosted
|
|
198
|
+
AgentCore deploy it says `x402 rail is ACTIVE (self-hosted AgentCore)` or
|
|
199
|
+
`ACTIVE in FREE mode (self-hosted AgentCore)`: the rail runs in-process, but
|
|
200
|
+
there is no anonymous URL — operate your own HTTP front that relays envelope-v1
|
|
201
|
+
JSON over SigV4-signed `InvokeAgentRuntime` calls (see
|
|
179
202
|
`docs/guides/x402-selling.md`, "Self-hosted AgentCore access"). A dormant or
|
|
180
203
|
forced-dormant summary means the rail was not activated; fix the named
|
|
181
204
|
credential, runtime, network, or tunnel condition and redeploy.
|
|
@@ -190,5 +213,6 @@ credential, runtime, network, or tunnel condition and redeploy.
|
|
|
190
213
|
does not trigger an automatic refund.
|
|
191
214
|
- The rail activates on AgentCore targets only (managed platform or
|
|
192
215
|
self-hosted); azure-foundry stays forced dormant.
|
|
193
|
-
-
|
|
194
|
-
|
|
216
|
+
- PAID payout wallets must use `wallet.kind` `evm-local` or `twak`; FREE has
|
|
217
|
+
no payout and does not apply this B402-specific allowlist.
|
|
218
|
+
- Never describe FREE as a zero-value B402 settlement. It bypasses B402.
|
|
@@ -197,8 +197,9 @@ bag deploy destroy --provider aws --execute # delegated teardown (add --purge)
|
|
|
197
197
|
## Reference
|
|
198
198
|
|
|
199
199
|
- b402/x402 selling on self-hosted AgentCore: the rail activates in-process
|
|
200
|
-
|
|
201
|
-
your own HTTP front that
|
|
200
|
+
with complete B402 credentials for PAID, or without them when explicit zero
|
|
201
|
+
selects FREE. There is no anonymous URL — operate your own HTTP front that
|
|
202
|
+
relays envelope-v1 over `InvokeAgentRuntime`. See
|
|
202
203
|
`bnbagent-studio-selling-via-b402` and `docs/guides/x402-selling.md`.
|
|
203
204
|
- `bag deploy --help` / `bag deploy <command> --help` (authoritative for commands + flags)
|
|
204
205
|
- `agentcore/agentcore.json` — name (resource naming continuity), protocol, authorizer, envVars
|
|
@@ -58,10 +58,11 @@ x402 buying remains separate and exact-bounded:
|
|
|
58
58
|
bag wallet session x402-setup --allowance-u <U> --yes
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Altana cannot be the b402 **seller** payout wallet
|
|
62
|
-
`evm-local` and `twak` only); init, `bag x402 sell init`, and
|
|
63
|
-
readiness reject
|
|
64
|
-
is
|
|
61
|
+
Altana cannot be the b402 **seller** payout wallet for a positive price (paid
|
|
62
|
+
mode allows `evm-local` and `twak` only); init, `bag x402 sell init`, and
|
|
63
|
+
deploy readiness reject that paid combination. Explicit
|
|
64
|
+
`price_usd = "0"` is allowed because FREE passthrough performs no payout and
|
|
65
|
+
bypasses B402. The outbound buying authority above remains a separate feature.
|
|
65
66
|
|
|
66
67
|
For troubleshooting, run `bag doctor` and `bag wallet session status`. Do not
|
|
67
68
|
print, parse, or copy the `signer` portion of the serialized session, and never
|