@bnbagent/studio-cli 0.0.10 → 0.0.11-alpha.1

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.
Files changed (36) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +2 -2
  3. package/dist/_agentcoreName-DZDWEYD3.js +0 -0
  4. package/dist/_twak-4XF4H5PL.js +0 -0
  5. package/dist/bag.js +317 -124
  6. package/dist/chunk-RO726HJG.js +0 -0
  7. package/dist/{chunk-YFEM4564.js → chunk-TTPOH453.js} +79 -37
  8. package/dist/chunk-U7IDQ3K5.js +0 -0
  9. package/dist/{deployCli-NJFCWBSF.js → deployCli-K55GXDVO.js} +1 -1
  10. package/package.json +11 -12
  11. package/recipes/runtimes/agentcore/code/{{PKG}}/Dockerfile.tmpl +20 -21
  12. package/recipes/runtimes/agentcore/code/{{PKG}}/executor.ts.tmpl +36 -0
  13. package/recipes/runtimes/agentcore/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
  14. package/recipes/runtimes/agentcore/recipe.toml +3 -3
  15. package/recipes/runtimes/azure-foundry/code/{{PKG}}/Dockerfile.tmpl +25 -23
  16. package/recipes/runtimes/azure-foundry/code/{{PKG}}/agentCard.ts.tmpl +16 -12
  17. package/recipes/runtimes/azure-foundry/code/{{PKG}}/executor.ts.tmpl +72 -393
  18. package/recipes/runtimes/azure-foundry/code/{{PKG}}/mcpMain.ts.tmpl +160 -43
  19. package/recipes/runtimes/azure-foundry/code/{{PKG}}/sellerCore.ts.tmpl +504 -0
  20. package/recipes/runtimes/azure-foundry/code/{{PKG}}/unifiedMain.ts.tmpl +620 -0
  21. package/recipes/runtimes/azure-foundry/recipe.toml +19 -11
  22. package/recipes/x402-buyer/code/{{PKG}}/x402Buyer.ts.tmpl +6 -4
  23. package/skills/bnbagent-studio.md +2 -2
  24. package/skills/references/bnbagent-studio-adding-to-project.md +1 -1
  25. package/skills/references/bnbagent-studio-buying-from-bazaar.md +1 -1
  26. package/skills/references/bnbagent-studio-operating.md +4 -4
  27. package/skills/references/bnbagent-studio-scaffolding-agent.md +4 -4
  28. package/skills/references/bnbagent-studio-selling-via-8183.md +3 -3
  29. package/skills/references/bnbagent-studio-selling-via-b402.md +2 -2
  30. package/skills/references/bnbagent-studio-use-aws-agentcore.md +1 -1
  31. package/skills/references/bnbagent-studio-use-azure-foundry.md +3 -3
  32. package/skills/references/bnbagent-studio-use-bnb-trial.md +1 -1
  33. package/skills/references/bnbagent-studio-wiring-llm-tools.md +3 -3
  34. package/recipes/runtimes/agentcore/code/{{PKG}}/main.ts.tmpl +0 -347
  35. package/recipes/runtimes/azure-foundry/code/{{PKG}}/foundryMain.ts.tmpl +0 -422
  36. package/recipes/runtimes/azure-foundry/code/{{PKG}}/main.ts.tmpl +0 -196
@@ -6,8 +6,10 @@
6
6
  * trusted via `bag x402 trust` (`[payments.x402.merchants.*]` — e.g. the
7
7
  * Binance Bazaar shelf: CMC market data).
8
8
  *
9
- * Wire into the agent (main.ts / mcpMain.ts) signing stays fixed code,
10
- * these tools only *fetch with payment* inside the config fences:
9
+ * Wire into the agent (main.ts / mcpMain.ts on agentcore; foundryMain.ts on
10
+ * azure-foundry each carries this hint on its `tools:` line) — signing
11
+ * stays fixed code, these tools only *fetch with payment* inside the config
12
+ * fences:
11
13
  *
12
14
  * import { X402_BUYER_TOOLS } from "./x402Buyer.js";
13
15
  * ...
@@ -150,8 +152,8 @@ export const X402_BUYER_TOOLS: ToolSet = {
150
152
  // only produces text.
151
153
  //
152
154
  // In `sellerCore.ts` `doWorkAndSubmit` (you own that file) — or the
153
- // azure-foundry `executor.ts` equivalent — replace the generic prompt with a
154
- // pre-fetch:
155
+ // azure-foundry equivalent, `foundryMain.ts` `buildRunWork` — replace the
156
+ // generic prompt with a pre-fetch:
155
157
  //
156
158
  // import { buyWithX402 } from "./x402Buyer.js";
157
159
  //
@@ -11,7 +11,7 @@ Invoked as `/bnbagent-studio <ask>`? Treat `<ask>` as the user's intent and rout
11
11
 
12
12
  ## The single seller runtime model (the invariants)
13
13
 
14
- One deployed runtime, one signer: a single valuable Agent serves the selected faces (A2A `src/main.ts` on `:9000`, MCP `src/mcpMain.ts` on `:8000/mcp`, or A2A-native `src/dualMain.ts` on `:9000` with tunneled `/mcp`), holds the key, and signs in-process. The ERC-8183 rail exposes exactly two bounded operations - **`negotiate`** (rule-based price clamp + EIP-191 sign; **no LLM touches money**) and **`notify_funded`** (verify the funded job → produce the deliverable → submit on-chain; A2A acks then delivers in the background, MCP delivers synchronously in the tool call). The optional x402 rail adds an anonymous HTTP request at `/x402`; positive prices settle through B402 before work, while explicit zero is FREE passthrough and bypasses the facilitator. It does not expose a general signing tool. Read-only chain tools remain available. ALL signing is fixed entrypoint code in `app/agent/src/signing.ts` or the runtime's bounded x402 payment handler, never an LLM-callable tool. The encrypted keystore lives at the workspace root `.studio/wallets/`, outside the deploy codeLocation, and is injected only via the selected provider's delegated secret channel. `settle` is manual (`bag erc8183 settle`). Full layout and lifecycle details live in the references below - read them before acting.
14
+ One deployed runtime, one signer: a single valuable Agent serves the selected faces (A2A `src/unifiedMain.ts` on `:9000`, MCP `src/mcpMain.ts` on `:8000/mcp`, or A2A-native `src/dualMain.ts` on `:9000` with tunneled `/mcp`), holds the key, and signs in-process. The ERC-8183 rail exposes exactly two bounded operations - **`negotiate`** (rule-based price clamp + EIP-191 sign; **no LLM touches money**) and **`notify_funded`** (verify the funded job → produce the deliverable → submit on-chain; A2A acks then delivers in the background, MCP delivers synchronously in the tool call). The optional x402 rail adds an anonymous HTTP request at `/x402`; positive prices settle through B402 before work, while explicit zero is FREE passthrough and bypasses the facilitator. It does not expose a general signing tool. Read-only chain tools remain available. ALL signing is fixed entrypoint code in `app/agent/src/signing.ts` or the runtime's bounded x402 payment handler, never an LLM-callable tool. The encrypted keystore lives at the workspace root `.studio/wallets/`, outside the deploy codeLocation, and is injected only via the selected provider's delegated secret channel. `settle` is manual (`bag erc8183 settle`). Full layout and lifecycle details live in the references below - read them before acting.
15
15
 
16
16
  ## Decision tree - which reference to read next
17
17
 
@@ -53,7 +53,7 @@ Treat ERC-8183 amounts as decimal strings at CLI/config boundaries and `bigint`
53
53
 
54
54
  ## CLI groups at a glance
55
55
 
56
- `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] [--backend aws\|azure]` is the primary deploy command; `--backend` is valid only for provider `bnb` and confirms the recipe-derived managed backend. `prepare`, `verify`, `status`, `info`, `destroy`, `logs`, and `fix-gitignore` 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.5.4`.
56
+ `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] [--backend aws\|azure]` is the primary deploy command; `--backend` is valid only for provider `bnb` and confirms the recipe-derived managed backend. `prepare`, `verify`, `status`, `info`, `destroy`, `logs`, and `fix-gitignore` 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.5.10`.
57
57
 
58
58
  ## Tool surface
59
59
 
@@ -55,7 +55,7 @@ bag scan
55
55
 
56
56
  ## Step 3 - Emit the agent
57
57
 
58
- A seller is the single Agent serving the selected protocol. `bag init` already composes it from recipes - `agent` (the fixed-code `src/signing.ts`) and `runtimes/agentcore` (A2A: `src/main.ts` (the express + A2A entrypoint) + `src/sellerCore.ts` (the protocol-neutral core; executor inherits it) + `src/executor.ts` + `src/agentCard.ts`; MCP: `src/mcpMain.ts`; shared `src/tools.ts` + `src/model.ts`; a `Dockerfile` is added only for a container deployment path such as TWAK). Use `bag recipe code` to inspect or re-emit a piece:
58
+ A seller is the single Agent serving the selected protocol. `bag init` already composes it from recipes - `agent` (the fixed-code `src/signing.ts`) and `runtimes/agentcore` (A2A: `src/unifiedMain.ts` (the express + A2A entrypoint, one code set for both deploy clouds) + `src/sellerCore.ts` (the protocol-neutral core; executor inherits it) + `src/executor.ts` + `src/agentCard.ts`; MCP: `src/mcpMain.ts`; shared `src/tools.ts` + `src/model.ts`; a `Dockerfile` is added only for a container deployment path such as TWAK). Use `bag recipe code` to inspect or re-emit a piece:
59
59
 
60
60
  ```bash
61
61
  bag recipe code agent > /dev/null # inspect; bag init writes app/agent/src/signing.ts for you
@@ -57,7 +57,7 @@ Hard-stop cases: a reviewed merchant whose live payTo drifts from the studio pin
57
57
  bag recipe code x402-buyer # emits src/x402Buyer.ts (next to src/tools.ts)
58
58
  ```
59
59
 
60
- Then wire the set into the agent's LLM in `src/main.ts` (A2A) or `src/mcpMain.ts` (MCP) - the scaffold's `tools:` line carries this exact hint in a comment:
60
+ Then wire the set into the agent's LLM in `src/unifiedMain.ts` (A2A — one entrypoint deployed to both clouds) or `src/mcpMain.ts` (MCP) - the scaffold's `tools:` line carries this exact hint in a comment:
61
61
 
62
62
  ```ts
63
63
  import { X402_BUYER_TOOLS } from "./x402Buyer.js";
@@ -7,7 +7,7 @@ description: When the user wants to run, debug, diagnose, or operate a bnbagent-
7
7
 
8
8
  # bnbagent-studio-operating
9
9
 
10
- Procedure for **day-to-day operation** of an existing bnbagent-studio project. Audience: Claude Code in a current TypeScript workspace (thin root with the `agentcore/` config dir + the workspace-root `.studio/wallets/` + funded wallet, plus the single sub-project `app/agent/` holding `studio.toml` + `src/main.ts` / `src/sellerCore.ts` / `src/executor.ts` / `src/agentCard.ts` / `src/signing.ts`). Most commands run from the workspace root; the current project-root fallback locates the `app/agent/` sub-project automatically for wallet/LLM/budget ops.
10
+ Procedure for **day-to-day operation** of an existing bnbagent-studio project. Audience: Claude Code in a current TypeScript workspace (thin root with the `agentcore/` config dir + the workspace-root `.studio/wallets/` + funded wallet, plus the single sub-project `app/agent/` holding `studio.toml` + `src/unifiedMain.ts` / `src/sellerCore.ts` / `src/executor.ts` / `src/agentCard.ts` / `src/signing.ts`). Most commands run from the workspace root; the current project-root fallback locates the `app/agent/` sub-project automatically for wallet/LLM/budget ops.
11
11
 
12
12
  **Different from**:
13
13
 
@@ -63,7 +63,7 @@ bag dev # A2A agent on :9000, MCP on :8000/mcp (same for any dest
63
63
  bag dev --port 9100 # override the port
64
64
  ```
65
65
 
66
- `bag dev` sets `STORAGE_LOCAL_PATH=~/.bag/deliverables/<workspace-name>/` for the agent subprocess and runs it **without** Cognito env, so the local endpoint is reachable without a token (Cognito is mandatory only on the deployed AgentCore runtime). For A2A projects, the agent (`app/agent/src/main.ts`) exposes `/.well-known/agent-card.json` + JSON-RPC `message/send` + `GET /ping` on `:9000`. Smoke-test the card with curl:
66
+ `bag dev` sets `STORAGE_LOCAL_PATH=~/.bag/deliverables/<workspace-name>/` for the agent subprocess and runs it **without** Cognito env, so the local endpoint is reachable without a token (Cognito is mandatory only on the deployed AgentCore runtime). For A2A projects, the agent (`app/agent/src/unifiedMain.ts`) exposes `/.well-known/agent-card.json` + JSON-RPC `message/send` + `GET /ping` on `:9000`. Smoke-test the card with curl:
67
67
 
68
68
  ```bash
69
69
  curl http://localhost:9000/.well-known/agent-card.json
@@ -106,12 +106,12 @@ Returns a rich table of checks across the `app/agent/` sub-project:
106
106
  | Check | What FAIL means | Fix |
107
107
  | --- | --- | --- |
108
108
  | app/agent/studio.toml parseable | Missing or syntax error | `bag init` to regenerate, or hand-fix TOML |
109
- | Agent entrypoint imports | Protocol entrypoint raises on load (`src/main.ts` for A2A, `src/mcpMain.ts` for MCP) | Fix the error printed by the check (often a missing env var or a broken import) |
109
+ | Agent entrypoint imports | Protocol entrypoint raises on load (`src/unifiedMain.ts` for A2A, `src/mcpMain.ts` for MCP) | Fix the error printed by the check (often a missing env var or a broken import) |
110
110
  | wallet keystore | No `<workspace>/.studio/wallets/*.json` | `bag wallet new` (writes to the workspace root keystore dir) |
111
111
  | WALLET_PASSWORD env | Not in `.studio/.env.local` / not exported | Edit the owner-only `.studio/.env.local`; never pass the password on argv |
112
112
  | LLM provider key | API key env not set | Edit `.studio/.env.local` or export the right `*_API_KEY` |
113
113
  | Network reachable | RPC down/wrong URL | Override via `STUDIO_BSC_TESTNET_RPC=...` (testnet) / `STUDIO_BSC_RPC=...` (mainnet) - per-network env vars read by `@bnbagent/studio-runtime/networks` `getNetwork` |
114
- | Wallet tBNB balance | 0 tBNB | Faucet: testnet.bnbchain.org/faucet-smart |
114
+ | Wallet tBNB balance | 0 tBNB | Message https://t.me/bnbchain_official_bot: `I would like to get tBNB to my wallet <address>` (more options: docs.bnbchain.org/bnb-smart-chain/developers/faucet/) |
115
115
  | Wallet U balance | 0 U | Transfer from holder, or ask for sponsor U |
116
116
  | 8004 registered | Not registered | Normally registered automatically at `bag deploy verify`. Manual: `bag erc8004 register --endpoint <url>` (only if you need an on-chain identity before deploy). WARN-only in `bag doctor` - it doesn't block local dev. |
117
117
 
@@ -36,7 +36,7 @@ Procedure for **greenfield** seller creation. Audience: Claude Code (or another
36
36
  ├── tsconfig.json builds src/ → dist/ (the deployed entrypoint is dist/*.js)
37
37
  ├── studio.toml wallet / llm / budget / payments.erc8183 bounds / payments.x402 / storage
38
38
  ├── Dockerfile container deploy path only (for example, twak)
39
- └── src/ main.ts / mcpMain.ts / dualMain.ts / sellerCore.ts / executor.ts / agentCard.ts / signing.ts / tools.ts / model.ts
39
+ └── src/ unifiedMain.ts / mcpMain.ts / dualMain.ts / sellerCore.ts / executor.ts / agentCard.ts / signing.ts / tools.ts / model.ts
40
40
  ```
41
41
 
42
42
  - **The Agent (`<name>/app/agent/`, → AWS Bedrock AgentCore).** ONE valuable agent (memory / tools / skills / KB / LLM) that **serves the selected faces** (A2A: `0.0.0.0:9000`; MCP: `0.0.0.0:8000/mcp`; A2A+MCP: A2A-native `dualMain.ts` on `:9000` with `/mcp` tunneled), holds the key, and signs **in-process**. Its outward surface is two fixed-code commerce operations (A2A skills on `SellerAgentExecutor`, or MCP tools on the MCP server):
@@ -112,7 +112,7 @@ Will create (single seller agent):
112
112
  (twak is fully supported too - opt in with --wallet-kind twak)
113
113
  storage: local (offline dev; switch to ipfs - needs a pinning endpoint + key - before deploy)
114
114
  fixed: stack=AI SDK (model factory + tools), runtime=agentcore (AWS Bedrock AgentCore)
115
- protocol: A2A (src/main.ts on 0.0.0.0:9000; local 127.0.0.1:9000)
115
+ protocol: A2A (src/unifiedMain.ts on 0.0.0.0:9000; local 127.0.0.1:9000)
116
116
  or MCP (src/mcpMain.ts on 0.0.0.0:8000/mcp; local localhost:8000/mcp)
117
117
  destination: platform (campaign default while the trial runs - 48h testnet on the operator's AWS; key leaves your machine, use a throwaway wallet)
118
118
  or self (prepare for your own AWS Bedrock AgentCore; runtime material stays in your account - pass --destination self)
@@ -138,7 +138,7 @@ Build a TodoWrite list. The shape depends on the `wallet kind`. The canonical 8-
138
138
 
139
139
  > **Onboarding note.** On a human TTY, `bag init` runs steps 3, 4 and 6 automatically (it prompts once for the wallet password, runs `bag wallet new`, zero-deposit-activates Pieverse, and prints faucet URLs). **You (Claude Code) drive `bag init` non-interactively**, so that auto-flow does NOT fire - keep steps 3/4/6 below. Pass `--no-onboard` to `bag init` to make this explicit and deterministic regardless of how the shell wires stdin.
140
140
 
141
- 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` - scaffold the current workspace. **`<name>` must start with a letter, use ASCII letters and digits only, and be at most 23 characters.** `bag init` rejects `-`, `_`, `.`, and overlong names instead of renaming them. Pass `--wallet-kind evm-local` (default) or `--wallet-kind twak` (twak is fully supported - pass the flag to opt in), and `--storage-provider local` (default) or `ipfs`, per the Stage-1 choices; for twak, add `--twak-home <path>` ONLY if the user wants to reuse an existing wallet (otherwise omit - a project-dedicated `.studio/twak` is the safe default). add `--protocols <comma-list>` when the user chose non-default or multiple faces (omit for A2A default; `--protocol <one>` is only a legacy alias), add `--model <m>` only if the user overrode the provider default, and `--enable-auto-topup` / `--no-auto-topup` only if they made an explicit choice (otherwise omit - consent stays deferred). Pass `--erc8183-price 0` only when the user explicitly chose FREE; omitting the flag preserves the paid 0.1 U default. The canonical stack supports FREE; if a custom deployment is selected, set all three `ERC8183_COMMERCE_ADDRESS`, `ERC8183_ROUTER_ADDRESS`, and `ERC8183_POLICY_ADDRESS` values from that same stack. For B402, pass `--b402-price 0` only after the user explicitly accepts an unrestricted anonymous FREE `/x402` endpoint. FREE bypasses B402 verify/settle and needs no merchant credentials; a positive price keeps the `$0.01` default and requires the paid onboarding playbook. **Destination:** while the trial campaign runs, bare `bag init` (no `--destination`) defaults to `platform` - so pass `--destination self` **explicitly** whenever the user chose their own AWS, otherwise studio.toml silently records `platform` and the confirmation block you echoed no longer matches what was written. Omit `--destination` only when the user actually wants the `platform` 48h testnet trial (the campaign default) - do NOT treat that default as a mistake or re-confirm it; it is the intended behavior while the campaign is open. (Bare init also resolves to `self` once the campaign ends, or when `--network bsc-mainnet` / a non-agentcore `--runtime` is passed.) On the `platform` path `bag init` hard-forces `bsc-testnet`, pins `--runtime agentcore` + packages an artifact (a zip for the default evm-local and altana wallets, a container for twak). For evm-local a wallet key will later leave your machine, so pair it with a throwaway `bag wallet new`; for altana only the bounded session ships - do NOT create a new wallet (full flow: `docs/guides/platform-deploy.md`). Defaults `--runtime agentcore` (the only advertised runtime; the Preview `azure-foundry` runtime remains explicitly selectable but is outside this playbook; there is no `--framework` flag because the AI SDK model/tools story is part of the runtime templates). Creates `<name>/` workspace root + `<name>/app/agent/` (the single sub-project: A2A emits `src/main.ts` (the express + A2A entrypoint) + `src/sellerCore.ts` (the protocol-neutral core; executor inherits it) + `src/executor.ts` + `src/agentCard.ts`; MCP emits `src/mcpMain.ts`; both include `src/signing.ts` + `src/tools.ts` + `src/model.ts` + their own `studio.toml` + `package.json` + `tsconfig.json`) + `<name>/agentcore/` (`agentcore.json` + `aws-targets.json`, self-rendered - no agentcore CLI needed at init). The workspace root holds the `agentcore/` deploy descriptor, the `.studio/wallets/` keystore, a thin `package.json` + `pnpm-workspace.yaml`, README, and `.gitignore`. (v1 is seller-only - no `--role`.)
141
+ 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` - scaffold the current workspace. **`<name>` must start with a letter, use ASCII letters and digits only, and be at most 23 characters.** `bag init` rejects `-`, `_`, `.`, and overlong names instead of renaming them. Pass `--wallet-kind evm-local` (default) or `--wallet-kind twak` (twak is fully supported - pass the flag to opt in), and `--storage-provider local` (default) or `ipfs`, per the Stage-1 choices; for twak, add `--twak-home <path>` ONLY if the user wants to reuse an existing wallet (otherwise omit - a project-dedicated `.studio/twak` is the safe default). add `--protocols <comma-list>` when the user chose non-default or multiple faces (omit for A2A default; `--protocol <one>` is only a legacy alias), add `--model <m>` only if the user overrode the provider default, and `--enable-auto-topup` / `--no-auto-topup` only if they made an explicit choice (otherwise omit - consent stays deferred). Pass `--erc8183-price 0` only when the user explicitly chose FREE; omitting the flag preserves the paid 0.1 U default. The canonical stack supports FREE; if a custom deployment is selected, set all three `ERC8183_COMMERCE_ADDRESS`, `ERC8183_ROUTER_ADDRESS`, and `ERC8183_POLICY_ADDRESS` values from that same stack. For B402, pass `--b402-price 0` only after the user explicitly accepts an unrestricted anonymous FREE `/x402` endpoint. FREE bypasses B402 verify/settle and needs no merchant credentials; a positive price keeps the `$0.01` default and requires the paid onboarding playbook. **Destination:** while the trial campaign runs, bare `bag init` (no `--destination`) defaults to `platform` - so pass `--destination self` **explicitly** whenever the user chose their own AWS, otherwise studio.toml silently records `platform` and the confirmation block you echoed no longer matches what was written. Omit `--destination` only when the user actually wants the `platform` 48h testnet trial (the campaign default) - do NOT treat that default as a mistake or re-confirm it; it is the intended behavior while the campaign is open. (Bare init also resolves to `self` once the campaign ends, or when `--network bsc-mainnet` / a non-agentcore `--runtime` is passed.) On the `platform` path `bag init` hard-forces `bsc-testnet`, pins `--runtime agentcore` + packages an artifact (a zip for the default evm-local and altana wallets, a container for twak). For evm-local a wallet key will later leave your machine, so pair it with a throwaway `bag wallet new`; for altana only the bounded session ships - do NOT create a new wallet (full flow: `docs/guides/platform-deploy.md`). Defaults `--runtime agentcore` (the only advertised runtime; the Preview `azure-foundry` runtime remains explicitly selectable but is outside this playbook; there is no `--framework` flag because the AI SDK model/tools story is part of the runtime templates). Creates `<name>/` workspace root + `<name>/app/agent/` (the single sub-project: A2A emits `src/unifiedMain.ts` (the express + A2A entrypoint, one code set for both deploy clouds) + `src/sellerCore.ts` (the protocol-neutral core; executor inherits it) + `src/executor.ts` + `src/agentCard.ts`; MCP emits `src/mcpMain.ts`; both include `src/signing.ts` + `src/tools.ts` + `src/model.ts` + their own `studio.toml` + `package.json` + `tsconfig.json`) + `<name>/agentcore/` (`agentcore.json` + `aws-targets.json`, self-rendered - no agentcore CLI needed at init). The workspace root holds the `agentcore/` deploy descriptor, the `.studio/wallets/` keystore, a thin `package.json` + `pnpm-workspace.yaml`, README, and `.gitignore`. (v1 is seller-only - no `--role`.)
142
142
  > **Altana + custom contracts:** Altana sessions remain bound to the canonical ERC-8183 targets. Use `evm-local` for a custom Commerce/Router/Policy stack; doctor and deploy readiness reject this unsupported combination when the ERC-8183 rail is active.
143
143
 
144
144
  2. `cd <name>`, then make sure the dependencies are installed. `bag init` already runs the install by default (skip only if it was scaffolded with `--no-install`); the manual equivalent from the workspace root is:
@@ -186,7 +186,7 @@ Build a TodoWrite list. The shape depends on the `wallet kind`. The canonical 8-
186
186
  - **evm-local** (default): `bag wallet new` creates the encrypted keystore. To import an existing key, the user pastes it and you immediately run `bag wallet new --private-key <pk>` (the key is written only into the keystore, nowhere else on disk).
187
187
 
188
188
  5. **Fund the wallet - OPTIONAL; do NOT block on it.** The default `auto/free` LLM model runs at $0 and AgentCore deploy consumes no wallet balance, so a brand-new seller can scaffold, run `bag dev`, and deploy with an empty wallet. `bag doctor` and `bag deploy` only **WARN** (never block) on zero balance. Funding is needed later only for: a paid LLM model, on-chain settle, paying positive-price ERC-8183 job buys, or buying/smoking a PAID B402 request. A FREE ERC-8183 buy needs no U escrow or ERC-20 approval, but still needs the ERC-8183 state-changing calls and their gas/paymaster path. A FREE B402/x402 request needs neither token funding nor a facilitator call. When funding is needed, the wallet uses **TWO distinct U balances on TWO chains** (same wallet address, same private key, different chains):
189
- - **tBNB (gas)** on BSC testnet: https://testnet.bnbchain.org/faucet-smart - paste address
189
+ - **tBNB (gas)** on BSC testnet: message the official Telegram bot https://t.me/bnbchain_official_bot with `I would like to get tBNB to my wallet <address>` (up to 0.3 tBNB/day; replies with the tx hash). More options: https://docs.bnbchain.org/bnb-smart-chain/developers/faucet/
190
190
  - **BSC mainnet U** (`0xcE24439F2D9C6a2289F741120FE202248B666666`) - for Pieverse LLM topup. Minimum **0.2 U** recommended (0.1 for activate + slack). Pieverse runs **only on mainnet chainId=56**; testnet U cannot pay for LLM credits. Acquire via PancakeSwap. Wallet-funded renewal stays off unless the operator explicitly enables it with `bag budget enable`; otherwise refill Account Balance with `bag llm topup` as needed.
191
191
  - **BSC testnet U** (`0xc70B8741B8B07A6d61E54fd4B20f22Fa648E5565`) - for ERC-8183 job payments if `[network].default = bsc-testnet`. Faucet: https://united-coin-u.github.io/u-faucet/ (paste the agent wallet address; see also `docs/guides/U-token-testnet.md`).
192
192
 
@@ -33,7 +33,7 @@ A v1 seller ships as **one runtime**: a single valuable Agent on AWS Bedrock Age
33
33
 
34
34
  - `bag doctor` is clean (or only warns on optional checks) - run from workspace root
35
35
  - Wallet has ≥ 0.05 tBNB (gas to submit deliverables) and ≥ 0 U (sellers receive U, don't spend)
36
- - The agent sub-project is emitted (`<workspace>/app/agent/src/main.ts` for A2A or `src/mcpMain.ts` for MCP, plus `src/signing.ts`). If not, run `bag init` or read the `bnbagent-studio-adding-to-project.md` reference first.
36
+ - The agent sub-project is emitted (`<workspace>/app/agent/src/unifiedMain.ts` for A2A or `src/mcpMain.ts` for MCP, plus `src/signing.ts`). If not, run `bag init` or read the `bnbagent-studio-adding-to-project.md` reference first.
37
37
  - For LLM-using sellers: `[llm].provider` configured in `app/agent/studio.toml` + (if Pieverse) `bag llm activate` has been run
38
38
 
39
39
  ## Stage 1 - Implement the `notify_funded` value (the `runWork` hook)
@@ -73,9 +73,9 @@ Tune the clamp in `<workspace>/app/agent/studio.toml`:
73
73
  # app/agent/studio.toml
74
74
  [payments.erc8183]
75
75
  currency = "0x..." # $U token - prefilled by `bag init` from [network].default; rarely changed
76
- price = "0" # raw wei - the asking list price the quote signs
76
+ price = "100000000000000000" # raw wei - the asking list price the quote signs (scaffold default 0.1 U; U has 18 decimals)
77
77
  min_price = "0" # raw wei - clamp floor
78
- max_price = "0" # raw wei - clamp ceiling (set > 0 to enforce)
78
+ max_price = "" # raw wei - clamp ceiling; empty = unbounded (a "0" ceiling clamps every paid quote to 0)
79
79
  quote_ttl_seconds = 300
80
80
  default_estimated_completion_seconds = 600
81
81
  ```
@@ -152,7 +152,7 @@ bag deploy --provider bnb # managed platform
152
152
  bag deploy --provider aws # self-hosted AgentCore
153
153
  ```
154
154
 
155
- On the managed platform the deploy summary must say `x402 rail is ACTIVE` (or `ACTIVE in FREE mode`) and print the anonymous `/x402` URL. On a self-hosted AgentCore deploy it says `x402 rail is ACTIVE (self-hosted AgentCore)` or `ACTIVE in FREE mode (self-hosted AgentCore)`: the rail runs in-process, but there is no anonymous URL. Operate your own HTTP front that relays envelope-v1 JSON through an authenticated AgentCore invocation. The default Bag self-deploy uses Cognito OAuth over raw HTTPS; AWS SDK/SigV4 is only for a runtime deliberately configured with IAM authorization. PAID also needs your own fixed-egress B402 Relay or equivalent network path. The complete gateway wrapper, response parser, Relay example, and direct-invocation fallback are in the [self-hosted x402 gateway guide](https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/guides/self-hosted-x402-gateway.md). A dormant or forced-dormant summary means the rail was not activated; fix the named credential, runtime, network, or tunnel condition and redeploy.
155
+ On the managed platform the deploy summary must say `x402 rail is ACTIVE` (or `ACTIVE in FREE mode`) and print the anonymous `/x402` URL. On a self-hosted AgentCore deploy it says `x402 rail is ACTIVE (self-hosted AgentCore)` or `ACTIVE in FREE mode (self-hosted AgentCore)` (self-hosted Azure Foundry prints the same summary with its own label): the rail runs in-process, but there is no anonymous URL. Operate your own HTTP front that relays envelope-v1 JSON through an authenticated AgentCore invocation. The default Bag self-deploy uses Cognito OAuth over raw HTTPS; AWS SDK/SigV4 is only for a runtime deliberately configured with IAM authorization. PAID also needs your own fixed-egress B402 Relay or equivalent network path. The complete gateway wrapper, response parser, Relay example, and direct-invocation fallback are in the [self-hosted x402 gateway guide](https://github.com/bnb-chain/bnbagent-studio/blob/main/docs/guides/self-hosted-x402-gateway.md). A dormant or forced-dormant summary means the rail was not activated; fix the named credential, runtime, network, or tunnel condition and redeploy.
156
156
 
157
157
  ## Hard rules
158
158
 
@@ -161,6 +161,6 @@ On the managed platform the deploy summary must say `x402 rail is ACTIVE` (or `A
161
161
  - Never replay a paid HTTP request whose outcome is unknown. Follow `docs/guides/x402-selling.md` and reconcile `(nonce, network, payer)` first.
162
162
  - Binance `/settle` is asynchronous. A parseable `success: false` response with a transaction is pending and requires an idempotent poll with the same settlement payload. Studio v0.0.6 and the latest `@bnb-chain/b402@0.1.0` do not yet perform that poll; they classify pending as unknown. Do not claim current mainnet readiness until this is updated.
163
163
  - Settlement happens before work. A later work failure retains the payment and does not trigger an automatic refund.
164
- - The rail activates on AgentCore targets only (managed platform or self-hosted); azure-foundry stays forced dormant.
164
+ - The rail activates on AgentCore and Azure Foundry targets (managed platform or self-hosted); self-hosted targets have no anonymous URL and need an operator-run envelope-v1 front.
165
165
  - PAID B402 payout wallets must use `wallet.kind` `evm-local` (private-key wallet stored as an encrypted keystore) or `twak`. Altana is unsupported. FREE x402 bypasses B402, has no payout, and must not be described as Altana B402 support.
166
166
  - Never describe FREE as a zero-value B402 settlement. It bypasses B402.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: bnbagent-studio-use-aws-agentcore
3
- description: When the user wants to deploy or operate a bnbagent-studio project on AWS Bedrock AgentCore - deploy with `bag deploy --provider aws` (all cloud lifecycle mutations are delegated to pinned `@bnbagent/deploy-cli@0.5.4`), inspect with `bag deploy status` / `logs --provider aws` / `verify --provider aws`, and tear down with `bag deploy destroy --provider aws --execute [--purge]`. Also covers AWS credential prerequisites, the optional read-only quota probe, and the runtime-secret channel.
3
+ description: When the user wants to deploy or operate a bnbagent-studio project on AWS Bedrock AgentCore - deploy with `bag deploy --provider aws` (all cloud lifecycle mutations are delegated to pinned `@bnbagent/deploy-cli@0.5.10`), inspect with `bag deploy status` / `logs --provider aws` / `verify --provider aws`, and tear down with `bag deploy destroy --provider aws --execute [--purge]`. Also covers AWS credential prerequisites, the optional read-only quota probe, and the runtime-secret channel.
4
4
  ---
5
5
 
6
6
  > **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: bnbagent-studio-use-azure-foundry
3
- description: When the user wants to deploy or operate a bnbagent-studio project on Azure AI Foundry Hosted Agents - scaffold with `bag init --runtime azure-foundry`, deploy either to the managed platform with `bag deploy --provider bnb --backend azure` or directly with `bag deploy --provider azure`; all cloud lifecycle execution is delegated to pinned `@bnbagent/deploy-cli@0.5.4`. Native MCP is not supported on Azure; use AgentCore for MCP.
3
+ description: When the user wants to deploy or operate a bnbagent-studio project on Azure AI Foundry Hosted Agents - scaffold with `bag init --runtime azure-foundry`, deploy either to the managed platform with `bag deploy --provider bnb --backend azure` or directly with `bag deploy --provider azure`; all cloud lifecycle execution is delegated to pinned `@bnbagent/deploy-cli@0.5.10`. Native MCP is not supported on Azure; use AgentCore for MCP.
4
4
  ---
5
5
 
6
6
  > **Reference file** of the `bnbagent-studio` router skill - installed at `bnbagent-studio/references/` and loaded on demand (not a standalone skill). Route here via the router's decision tree.
@@ -13,7 +13,7 @@ Procedure for deploying and operating the seller Agent on **Azure AI Foundry Hos
13
13
 
14
14
  ```
15
15
  <workspace>/
16
- ├── app/agent/ # the deployed code (src/foundryMain.ts host + Dockerfile here)
16
+ ├── app/agent/ # the deployed code (src/unifiedMain.ts host + Dockerfile here)
17
17
  │ ├── studio.toml # [azure] block: location / account_name / subdomain / project_name / agent_endpoint
18
18
  │ └── Dockerfile # the container image bnbagent-deploy builds + pushes
19
19
  └── .studio/ # secrets + wallets (workspace root - never in the image)
@@ -47,7 +47,7 @@ Procedure for deploying and operating the seller Agent on **Azure AI Foundry Hos
47
47
 
48
48
  > The encrypted keystore (`.studio/wallets/`) stays at the workspace root and rides only that secret channel - never baked into the image.
49
49
 
50
- Provider-native overrides go in the optional `studio.toml [deploy.foundry]` table (verbatim deploy-spec keys; deploy-cli 0.5.4 consumes `account`, `cpu`, `location`, `memory`, `project`, `projectEndpoint`, `protocol`, `registry` and warns about anything else). The `[azure]` block's `account_name` / `project_name` / `project_endpoint` / `location` win over conflicting `[deploy.foundry]` keys.
50
+ Provider-native overrides go in the optional `studio.toml [deploy.foundry]` table (verbatim deploy-spec keys; deploy-cli 0.5.10 consumes `account`, `cpu`, `location`, `memory`, `project`, `projectEndpoint`, `protocol`, `registry` and warns about anything else). The `[azure]` block's `account_name` / `project_name` / `project_endpoint` / `location` win over conflicting `[deploy.foundry]` keys.
51
51
 
52
52
  ## Typical workflow
53
53
 
@@ -9,7 +9,7 @@ description: Use when deploying or operating a bnbagent-studio seller on the BNB
9
9
 
10
10
  Treat this provider as a temporary testnet sandbox. Require a throwaway wallet, keep `bsc-testnet`, and explain that the runtime signing material is transmitted to the operator's managed secret store for the trial. Never use a mainnet key. Exception: `wallet.kind='altana'` ships only the bounded, budget-limited, revocable session - the throwaway-wallet advice does not apply; tighten the session instead (`bag wallet session grant --force --budget-u <small> --expiry-days <short>`) and never run `bag wallet new` on an altana project (it breaks the session's `[wallet].address` anchor).
11
11
 
12
- All auth and cloud lifecycle work must cross the pinned `@bnbagent/deploy-cli@0.5.4` boundary. Do not call a cloud CLI or platform REST routes directly. The managed backend is recipe-derived: `agentcore` uses AWS; `azure-foundry` uses Azure. For headless managed Azure, confirm with `bag deploy --provider bnb --backend azure --yes`; never treat `--backend` as a cross-cloud recipe converter.
12
+ All auth and cloud lifecycle work must cross the pinned `@bnbagent/deploy-cli@0.5.10` boundary. Do not call a cloud CLI or platform REST routes directly. The managed backend is recipe-derived: `agentcore` uses AWS; `azure-foundry` uses Azure. For headless managed Azure, confirm with `bag deploy --provider bnb --backend azure --yes`; never treat `--backend` as a cross-cloud recipe converter.
13
13
 
14
14
  ## Select and authenticate
15
15
 
@@ -81,7 +81,7 @@ Note: `pieverseUsage` does a SIWE EIP-191 personal_sign (no on-chain effect, dom
81
81
 
82
82
  ```bash
83
83
  # from workspace root:
84
- ls app/agent/studio.toml && (ls app/agent/src/main.ts 2>/dev/null || ls app/agent/src/mcpMain.ts)
84
+ ls app/agent/studio.toml && (ls app/agent/src/unifiedMain.ts 2>/dev/null || ls app/agent/src/mcpMain.ts)
85
85
  ```
86
86
 
87
87
  If `app/agent/src/tools.ts` already exists, the user has the AI SDK form already. Skip to Step 4 if they want to customize.
@@ -90,7 +90,7 @@ If `app/agent/src/tools.ts` already exists, the user has the AI SDK form already
90
90
 
91
91
  ## Step 2 - Identify the stack
92
92
 
93
- Look at `app/agent/src/main.ts` or `app/agent/src/mcpMain.ts` imports / `app/agent/package.json`:
93
+ Look at `app/agent/src/unifiedMain.ts` or `app/agent/src/mcpMain.ts` imports / `app/agent/package.json`:
94
94
 
95
95
  | Sign in code | Stack |
96
96
  | --- | --- |
@@ -105,7 +105,7 @@ If AI SDK: emit the stock recipe and stop.
105
105
  bag recipe code tools-chain > app/agent/src/chainTools.ts # full inventory + CHAIN_READ_TOOLS
106
106
  ```
107
107
 
108
- Then in the protocol entrypoint (`app/agent/src/main.ts` for A2A, `app/agent/src/mcpMain.ts` for MCP), pass the tool set into the generate call:
108
+ Then in the protocol entrypoint (`app/agent/src/unifiedMain.ts` for A2A, `app/agent/src/mcpMain.ts` for MCP), pass the tool set into the generate call:
109
109
 
110
110
  ```ts
111
111
  import { LLM_READ_TOOLS } from "./tools.js";
@@ -1,347 +0,0 @@
1
- /**
2
- * Single A2A seller agent entrypoint. Generated by `bag recipe code agent`.
3
- *
4
- * This is the VALUABLE agent AND the SOLE key-holder/signer. It serves its
5
- * two ERC-8183 seller skills DIRECTLY over the A2A protocol on AWS Bedrock
6
- * AgentCore (`--protocol A2A`): an `@a2a-js/sdk` express app exposes the
7
- * agent card at `/.well-known/agent-card.json` + JSON-RPC `message/send` on
8
- * `0.0.0.0:9000` (`AGENT_PORT` overrides locally), plus `GET /ping` for the
9
- * AgentCore liveness contract. There is no separate forwarding service — the
10
- * agent IS the seller (see executor.ts + agentCard.ts).
11
- *
12
- * A2A skills (executor.ts):
13
- *
14
- * negotiate → read the FIXED list price → CLAMP to [min,max] → EIP-191 SIGN
15
- * the offer (no LLM, no tools) → return the signed offer (or reject)
16
- * notify_funded → re-verify the funded job on-chain (fast) → ACK accepted at once,
17
- * then in the BACKGROUND: LLM work → manifest → storage →
18
- * submitResult (SIGN + broadcast). The buyer polls the chain for
19
- * the deliverable. Each notify also sweeps other FUNDED jobs
20
- * (buyer-push fallback). While background work is in flight the
21
- * `/ping` handler reports HEALTHY_BUSY so AgentCore keeps the
22
- * scale-to-zero runtime warm until it lands.
23
- *
24
- * Buyers reach this endpoint with an OAuth2 (Cognito) bearer — AgentCore A2A
25
- * mandates inbound auth (see agentCard.ts + `bag deploy provision-cognito`).
26
- *
27
- * ## Boundaries (do NOT cross — they are the whole point)
28
- *
29
- * - The agent does ALL deterministic SIGNING (quote-sign + submit + settle +
30
- * automatic Pieverse LLM-credit auto-renew). ALL signing is FIXED code in
31
- * `signing.ts` — NEVER an LLM-callable tool (money never in the LLM).
32
- * - The price is a FIXED list price from studio.toml (clamped before
33
- * signing) — the LLM never prices; it only PRODUCES the work text in the
34
- * delivery step.
35
- * - Chain access for the LLM is READ-ONLY tools only (`tools.ts`).
36
- * - `settle` (claim payment after the dispute window) is operator-driven —
37
- * run `bag erc8183 settle <job_id>`; it is deliberately NOT an A2A skill.
38
- */
39
-
40
- import { createHash } from "node:crypto";
41
- import { pathToFileURL } from "node:url";
42
- import {
43
- GetSecretValueCommand,
44
- SecretsManagerClient,
45
- } from "@aws-sdk/client-secrets-manager";
46
- import { DefaultRequestHandler, InMemoryTaskStore } from "@a2a-js/sdk/server";
47
- import {
48
- agentCardHandler,
49
- jsonRpcHandler,
50
- UserBuilder,
51
- } from "@a2a-js/sdk/server/express";
52
- import {
53
- loadStudioToml,
54
- type TomlTable,
55
- } from "@bnbagent/studio-runtime/config";
56
- import {
57
- ensureAltanaSessionLoaded,
58
- ensureKeystoreMaterialized,
59
- ensureTwakMaterialized,
60
- getWallet,
61
- } from "@bnbagent/studio-runtime/wallet";
62
- import {
63
- createEnvelopeMiddleware,
64
- X402_SELL_PATH,
65
- type X402HttpRequest,
66
- type X402RunWork,
67
- X402Seller,
68
- } from "@bnbagent/studio-runtime/x402";
69
- import { generateText, stepCountIs } from "ai";
70
- import express from "express";
71
- import { buildAgentCard } from "./agentCard.js";
72
- import { SellerAgentExecutor } from "./executor.js";
73
- import { buildModel } from "./model.js";
74
- import type { RunWork } from "./sellerCore.js";
75
- import { LLM_READ_TOOLS } from "./tools.js";
76
-
77
- const APP_NAME = "agent";
78
-
79
- /**
80
- * Deliverable `generator` label: this seller's own name, read from
81
- * studio.toml `[project].name` (minus the `-agent` suffix) so each delivered
82
- * manifest is self-identifying. Best-effort — falls back to `APP_NAME` if
83
- * the config can't be read.
84
- */
85
- function generatorTag(): string {
86
- let name = "";
87
- try {
88
- const cfg = loadStudioToml();
89
- name = String(((cfg.project ?? {}) as Record<string, unknown>).name ?? "");
90
- } catch {
91
- // a metadata label must never break delivery
92
- return APP_NAME;
93
- }
94
- return name.endsWith("-agent")
95
- ? name.slice(0, -"-agent".length)
96
- : name || APP_NAME;
97
- }
98
-
99
- // ── Runtime secrets ───────────────────────────────────────────────────────────
100
- // Keep plaintext secrets OUT of agentcore.json. When BNBAGENT_RUNTIME_SECRET_ID
101
- // is set (deployed runtime), pull a JSON {ENV_NAME: value} blob from AWS
102
- // Secrets Manager into the process env BEFORE anything reads it (keystore
103
- // unlock, provider key, buildModel, Cognito OAuth env). No-op locally, where
104
- // .env.local already populated the environment. In a deployed runtime the
105
- // managed secret bundle is authoritative and replaces any stale spec-level
106
- // value left by an earlier runtime revision.
107
- async function loadRuntimeSecrets(): Promise<void> {
108
- const secretId = process.env.BNBAGENT_RUNTIME_SECRET_ID;
109
- if (!secretId) {
110
- return;
111
- }
112
- const resp = await new SecretsManagerClient({}).send(
113
- new GetSecretValueCommand({ SecretId: secretId }),
114
- );
115
- const bundle = JSON.parse(resp.SecretString ?? "{}") as Record<
116
- string,
117
- unknown
118
- >;
119
- for (const [key, value] of Object.entries(bundle)) {
120
- process.env[key] = String(value);
121
- }
122
- const pieverseKey = process.env.PIEVERSE_LLM_API_KEY;
123
- if (pieverseKey) {
124
- const fingerprint = createHash("sha256")
125
- .update(pieverseKey, "utf-8")
126
- .digest("hex")
127
- .slice(0, 12);
128
- console.info(
129
- `[runtime-secrets] PIEVERSE_LLM_API_KEY source=secretsmanager sha256=${fingerprint}…`,
130
- );
131
- }
132
- }
133
-
134
- /** studio.toml `[network].default` (best-effort; used by the funded sweep). */
135
- function defaultNetwork(): string {
136
- try {
137
- const cfg = loadStudioToml();
138
- return String(
139
- ((cfg.network ?? {}) as Record<string, unknown>).default ?? "bsc-testnet",
140
- );
141
- } catch {
142
- return "bsc-testnet";
143
- }
144
- }
145
-
146
- // ── One-shot LLM helper (the executor's delivery work hook) ──────────────────
147
- // LLM credit auto-renew (Pieverse path): `buildModel()` (in model.ts) returns
148
- // a model wrapped with a middleware that auto-tops up the active Pieverse key
149
- // before each generate call when [llm.auto_renew] is enabled. That top-up is
150
- // the ONLY automatic signing path outside signing.ts — it is budget-gated and
151
- // is NOT an LLM tool. It rides transparently into the delivery step.
152
- //
153
- // The LLM runs only in an authorized value step: verified ERC-8183 delivery
154
- // or x402 work after its payment/free gate. `negotiate` is rule-based and
155
- // never touches the LLM. The read-only chain tools are
156
- // attached so the work can read on-chain context if it needs to — drop them
157
- // from `tools.ts` if your work doesn't read chain. Signing / settle are NEVER
158
- // tools — they are fixed code in signing.ts, triggered by the A2A skills,
159
- // never callable by the LLM. (The one deliberate exception: the x402-buyer
160
- // recipe's PAID fetch tools — see the `tools:` note below — the LLM picks the
161
- // URL, but who gets paid and the per-call/daily caps stay locked in
162
- // studio.toml.)
163
- export function buildRunWork(): RunWork {
164
- // The model is resolved LAZILY on first delivery, not at boot: a seller
165
- // with no provider key yet must still serve negotiate (which never calls
166
- // the LLM) — missing-key errors surface at notify_funded delivery time.
167
- let model: ReturnType<typeof buildModel> | undefined;
168
- return async (prompt, { abortSignal }) => {
169
- model ??= buildModel(); // managed model with the auto-renew hook (delivery only)
170
- const result = await generateText({
171
- model,
172
- system:
173
- "You are a seller agent. The runtime has already authorized this task " +
174
- "through its configured commerce rail. Complete the user's task now; " +
175
- "do not ask for a job ID or additional payment. " +
176
- "Be concrete and concise. Use the read-only chain tools when on-chain " +
177
- "context helps. If a paid-data tool such as `buy_with_x402` is available " +
178
- "to you, USE IT to fetch the data a task needs — those merchants (e.g. " +
179
- "CoinMarketCap) charge via on-chain wallet payment, NOT an API key; never " +
180
- "reply that you cannot complete the task for lack of an API key.",
181
- prompt,
182
- // LLM_READ_TOOLS = read-only chain tools (wallet, balances,
183
- // ERC-8004/8183 queries). Edit `tools.ts` to add/remove. These are
184
- // READ-ONLY — the agent never signs via a tool; all signing is in
185
- // signing.ts (fixed code).
186
- // To let the agent BUY paid data at work time (e.g. CMC market data
187
- // after `bag x402 trust cmc` + `bag recipe code x402-buyer`), spread
188
- // the emitted tool set — payee + per-call/daily caps stay locked in
189
- // studio.toml:
190
- // import { X402_BUYER_TOOLS } from "./x402Buyer.js";
191
- // tools: { ...LLM_READ_TOOLS, ...X402_BUYER_TOOLS },
192
- tools: LLM_READ_TOOLS,
193
- stopWhen: stepCountIs(8), // bounded tool-call loop, then final text
194
- abortSignal,
195
- });
196
- return result.text.trim();
197
- };
198
- }
199
-
200
- function hasErc8183Rail(cfg: TomlTable): boolean {
201
- const payments = asTable(cfg.payments);
202
- return asTable(payments?.erc8183) !== null;
203
- }
204
-
205
- function asTable(value: unknown): TomlTable | null {
206
- return value !== null && typeof value === "object" && !Array.isArray(value)
207
- ? (value as TomlTable)
208
- : null;
209
- }
210
-
211
- function flatHeaders(
212
- headers: Record<string, string | string[] | undefined>,
213
- ): Record<string, string> {
214
- const out: Record<string, string> = {};
215
- for (const [name, value] of Object.entries(headers)) {
216
- if (typeof value === "string") out[name] = value;
217
- else if (value !== undefined) out[name] = value[0] ?? "";
218
- }
219
- return out;
220
- }
221
-
222
- function flatQuery(query: Record<string, unknown>): Record<string, string> {
223
- const out: Record<string, string> = {};
224
- for (const [name, value] of Object.entries(query)) {
225
- if (typeof value === "string") out[name] = value;
226
- }
227
- return out;
228
- }
229
-
230
- function x402Work(runWork: RunWork): X402RunWork {
231
- return ({ prompt }) => runWork(prompt, { sessionId: "x402" });
232
- }
233
-
234
- // ── serving ───────────────────────────────────────────────────────────────────
235
-
236
- async function main(): Promise<void> {
237
- await loadRuntimeSecrets();
238
-
239
- // Wallet material is NEVER bundled into the deploy artifact. `bag deploy`
240
- // injects it via Secrets Manager and these calls (run once at cold start,
241
- // before any signing) materialize it on disk. Each is a no-op for the
242
- // other wallet kind and locally, where the wallet already lives on disk:
243
- // - evm-local: WALLET_KEYSTORE_JSON → keystore file (unlocked with WALLET_PASSWORD)
244
- // - twak: TWAK_WALLET_JSON / TWAK_CREDENTIALS_JSON → $TMPDIR/twak-home/.twak
245
- // (exported as TWAK_HOME_DIR; twak reads TWAK_WALLET_PASSWORD itself)
246
- ensureKeystoreMaterialized();
247
- ensureTwakMaterialized();
248
- await ensureAltanaSessionLoaded();
249
-
250
- const cfg = loadStudioToml();
251
- const rails = { erc8183: hasErc8183Rail(cfg) };
252
- const host = process.env.AGENT_BIND_HOST || "0.0.0.0";
253
- const port = Number(process.env.AGENT_PORT || "9000");
254
- const runWork = buildRunWork();
255
-
256
- // The executor backs the seller skills with signing.ts fixed code (NEVER an
257
- // LLM tool). The express app hosts the agent card + JSON-RPC message/send
258
- // on 0.0.0.0:9000 and GET /ping for AgentCore's liveness probe.
259
- const executor = new SellerAgentExecutor({
260
- runWork,
261
- generator: generatorTag(),
262
- network: defaultNetwork(),
263
- commerceSkills: rails.erc8183,
264
- });
265
- const agentCard = buildAgentCard({ commerceSkills: rails.erc8183 });
266
- const seller = await X402Seller.create({
267
- cfg,
268
- runWork: x402Work(runWork),
269
- walletAddress: getWallet().address,
270
- resourceUrl: `${
271
- process.env.AGENTCORE_RUNTIME_URL ?? `http://localhost:${port}`
272
- }${X402_SELL_PATH}`,
273
- });
274
-
275
- const handler = new DefaultRequestHandler(
276
- agentCard,
277
- new InMemoryTaskStore(),
278
- executor,
279
- );
280
-
281
- const app = express();
282
-
283
- // GET /ping status fed to AgentCore: HEALTHY_BUSY while a background
284
- // delivery is in flight, else HEALTHY.
285
- //
286
- // notify_funded acks immediately and runs the slow work (LLM + on-chain
287
- // submit) in the background. Reporting HEALTHY_BUSY tells AgentCore the
288
- // runtime is still working, so the scale-to-zero runtime is NOT reaped on
289
- // idle before delivery lands (bounded by the session max-lifetime; ≤8h).
290
- app.get("/ping", (_req, res) => {
291
- res.json({ status: executor.isBusy() ? "HEALTHY_BUSY" : "HEALTHY" });
292
- });
293
-
294
- if (seller.state !== "disabled") {
295
- app.all(
296
- X402_SELL_PATH,
297
- express.text({ type: "*/*", limit: "1mb" }),
298
- async (req, res) => {
299
- const request: X402HttpRequest = {
300
- method: req.method,
301
- path: req.path,
302
- query: flatQuery(req.query),
303
- headers: flatHeaders(req.headers),
304
- body:
305
- typeof req.body === "string"
306
- ? req.body
307
- : JSON.stringify(req.body ?? ""),
308
- };
309
- const out = await seller.handle(request);
310
- res.status(out.status).set(out.headers).send(out.body);
311
- },
312
- );
313
- }
314
-
315
- app.use(express.json({ limit: "8mb" }));
316
- app.use(createEnvelopeMiddleware({ port }));
317
-
318
- app.use(
319
- "/.well-known/agent-card.json",
320
- agentCardHandler({ agentCardProvider: handler }),
321
- );
322
- app.use(
323
- jsonRpcHandler({
324
- requestHandler: handler,
325
- userBuilder: UserBuilder.noAuthentication,
326
- }),
327
- );
328
-
329
- // AgentCore's A2A contract is 0.0.0.0:9000. Do not honor the HTTP
330
- // protocol's $PORT=8080 convention here; AGENT_PORT is the local-dev /
331
- // rendered-container override.
332
- app.listen(port, host, () => {
333
- console.log(`[seller-agent] A2A serving on ${host}:${port}`);
334
- });
335
- }
336
-
337
- // Run only as an entrypoint (`node main.js` / the AgentCore runtime), never
338
- // on import — tests import the builders above without starting a server.
339
- const isMain =
340
- process.argv[1] !== undefined &&
341
- import.meta.url === pathToFileURL(process.argv[1]).href;
342
- if (isMain) {
343
- main().catch((e) => {
344
- console.error("[seller-agent] fatal:", e);
345
- process.exit(1);
346
- });
347
- }