@bnbagent/studio-cli 0.0.6-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.
- package/DISCLAIMER.md +48 -0
- package/LICENSE +201 -0
- package/dist/_agentcoreName-DZDWEYD3.js +7 -0
- package/dist/_twak-5XQMOFUC.js +25 -0
- package/dist/bag.js +19358 -0
- package/dist/chunk-7RAKL4AS.js +172 -0
- package/dist/chunk-M3ODFCA7.js +1053 -0
- package/dist/chunk-U7IDQ3K5.js +14 -0
- package/dist/deployCli-N6TPN6XA.js +40 -0
- package/package.json +64 -0
- package/recipes/agent/code/{{PKG}}/signing.ts.tmpl +287 -0
- package/recipes/agent/recipe.toml +35 -0
- package/recipes/providers/pieverse-llm/recipe.toml +16 -0
- package/recipes/providers/pieverse-llm/skills/funding-pieverse-llm.md +203 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/.dockerignore.tmpl +8 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/Dockerfile.tmpl +50 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/agentCard.ts.tmpl +135 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/dualMain.ts.tmpl +402 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/executor.ts.tmpl +147 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/main.ts.tmpl +344 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/mcpMain.ts.tmpl +677 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/model.ts.tmpl +117 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/sellerCore.ts.tmpl +503 -0
- package/recipes/runtimes/agentcore/code/{{PKG}}/tools.ts.tmpl +157 -0
- package/recipes/runtimes/agentcore/recipe.toml +97 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/.dockerignore.tmpl +8 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/Dockerfile.tmpl +47 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/agentCard.ts.tmpl +131 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/executor.ts.tmpl +504 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/foundryMain.ts.tmpl +300 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/main.ts.tmpl +196 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/mcpMain.ts.tmpl +562 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/model.ts.tmpl +117 -0
- package/recipes/runtimes/azure-foundry/code/{{PKG}}/tools.ts.tmpl +157 -0
- package/recipes/runtimes/azure-foundry/recipe.toml +88 -0
- package/recipes/tools-chain/code/{{PKG}}/chainTools.ts.tmpl +166 -0
- package/recipes/tools-chain/recipe.toml +11 -0
- package/recipes/wallet/recipe.toml +20 -0
- package/recipes/x402-buyer/code/{{PKG}}/x402Buyer.ts.tmpl +175 -0
- package/recipes/x402-buyer/recipe.toml +15 -0
- package/skills/bnbagent-studio.md +107 -0
- package/skills/references/bnbagent-studio-adding-to-project.md +241 -0
- package/skills/references/bnbagent-studio-buying-from-bazaar.md +169 -0
- package/skills/references/bnbagent-studio-buying-via-8183.md +222 -0
- package/skills/references/bnbagent-studio-extending-signing.md +227 -0
- package/skills/references/bnbagent-studio-operating.md +211 -0
- package/skills/references/bnbagent-studio-scaffolding-agent.md +536 -0
- package/skills/references/bnbagent-studio-selling-via-8183.md +271 -0
- package/skills/references/bnbagent-studio-selling-via-b402.md +194 -0
- package/skills/references/bnbagent-studio-use-aws-agentcore.md +208 -0
- package/skills/references/bnbagent-studio-use-azure-foundry.md +164 -0
- package/skills/references/bnbagent-studio-use-bnb-trial.md +92 -0
- package/skills/references/bnbagent-studio-using-altana-wallet.md +68 -0
- package/skills/references/bnbagent-studio-using-twak-wallet.md +260 -0
- package/skills/references/bnbagent-studio-wiring-llm-tools.md +338 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bnbagent-studio-using-twak-wallet
|
|
3
|
+
description: When the user's project has [wallet].kind = "twak" (a fully-supported wallet kind, opt in with `--wallet-kind twak`) — creating the Trust Wallet Agent Kit wallet, anchoring its address, funding it, SIWE-binding for Pieverse, deploying it as a container, and working around its known limitations.
|
|
4
|
+
---
|
|
5
|
+
|
|
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.
|
|
7
|
+
|
|
8
|
+
# bnbagent-studio-using-twak-wallet
|
|
9
|
+
|
|
10
|
+
Procedure for setting up and operating the **twak** wallet kind (Trust Wallet
|
|
11
|
+
Agent Kit CLI) in a bnbagent-studio project. twak is a **fully-supported**
|
|
12
|
+
wallet kind — opt in at scaffold with `bag init <name> --wallet-kind twak`
|
|
13
|
+
(`evm-local`, a local keystore, is the default). The wallet is a **self-custody,
|
|
14
|
+
AES-256-GCM-encrypted mnemonic** the user controls (not a hosted service),
|
|
15
|
+
living by default in a **project-dedicated** home `.studio/twak`
|
|
16
|
+
(`[wallet].twak_home`), isolated from your main `~/.twak`. The default kind is
|
|
17
|
+
`evm-local` (local keystore); re-scaffold with `--wallet-kind twak` to use twak.
|
|
18
|
+
|
|
19
|
+
## 1. Install the CLI
|
|
20
|
+
|
|
21
|
+
Needs Node ≥ 20:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install -g @trustwallet/cli@0.20.0
|
|
25
|
+
twak --version
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
studio requires **>= 0.20.0** (the SDK forwards `--paymaster-url` on sponsored
|
|
29
|
+
bsc-testnet writes — the flag first shipped in v0.20.0; older CLIs reject it
|
|
30
|
+
with "unknown option"); `bag doctor` and `bag deploy prepare` verify the floor.
|
|
31
|
+
|
|
32
|
+
## 2. Create the wallet — one time, in YOUR terminal
|
|
33
|
+
|
|
34
|
+
studio can't create it for you (the twak CLI takes the password on argv, upstream
|
|
35
|
+
S-8, and studio never puts secrets on argv). Do these steps yourself.
|
|
36
|
+
|
|
37
|
+
**Every twak command is prefixed with the dedicated home.** Without `HOME=$DH`,
|
|
38
|
+
twak uses your real `~/.twak` (your MAIN wallet) and macOS pops a login-keychain
|
|
39
|
+
password prompt. Set it once:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
DH=<workspace>/.studio/twak # e.g. ~/proj/.studio/twak
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**1. Get Trust Wallet NaaS API credentials** (one time; account-level, NOT
|
|
46
|
+
wallet-specific). Make an app at https://portal.trustwallet.com/dashboard/apps
|
|
47
|
+
→ copy its Access ID + HMAC secret. (`twak wallet create` fails with "No API
|
|
48
|
+
credentials found" without them.)
|
|
49
|
+
|
|
50
|
+
**2. Run the setup wizard** — writes the credentials into the dedicated home:
|
|
51
|
+
```bash
|
|
52
|
+
HOME="$DH" twak setup
|
|
53
|
+
```
|
|
54
|
+
- **Step 1 (API credentials):** paste the Access ID + HMAC secret.
|
|
55
|
+
WalletConnect Project ID → leave blank, ENTER.
|
|
56
|
+
- **Step 2 ("which harnesses to wire up"): SELECT NONE — press ENTER** on the
|
|
57
|
+
empty list (do NOT press SPACE or `a`). 🔒 This would register twak's
|
|
58
|
+
signing MCP into Claude Code / Cursor / etc., handing wallet+signing power
|
|
59
|
+
to your AI assistant (and any prompt-injection reaching it) — studio forbids
|
|
60
|
+
that: signing is fixed `signing.ts` code, the LLM only receives read-only
|
|
61
|
+
chain tools, and the deployed agent never calls twak via MCP.
|
|
62
|
+
- **Step 3 (Wallet "Pick one"): choose `3) Skip for now`** (you create it in
|
|
63
|
+
the next step). NOT `2) Use WalletConnect with my existing wallet` (binds
|
|
64
|
+
your main/real wallet).
|
|
65
|
+
|
|
66
|
+
**3. Create the wallet** (password UPPER + lower + digit, e.g. `Mypasswd01`;
|
|
67
|
+
`mypasswd01` is rejected). **RECOMMENDED — let studio drive it with the
|
|
68
|
+
password OFF argv** (it resolves the project home from studio.toml, so no
|
|
69
|
+
`HOME=` juggling):
|
|
70
|
+
```bash
|
|
71
|
+
bag wallet twak-init # interactive hidden prompt
|
|
72
|
+
printf %s "$PW" | bag wallet twak-init --password-stdin # CI / scripts
|
|
73
|
+
bag wallet twak-init --password-file pw.txt # file must be chmod 600
|
|
74
|
+
```
|
|
75
|
+
It wraps `twak wallet create --no-keychain` (password reaches twak via env +
|
|
76
|
+
piped stdin only), tightens `wallet.json` to mode 600, and adopts the
|
|
77
|
+
address into studio.toml in one go — so steps 5's `bag wallet new` is
|
|
78
|
+
already done.
|
|
79
|
+
|
|
80
|
+
Manual alternative (password lands on argv → `ps` / shell history;
|
|
81
|
+
acceptable only for a throwaway hot wallet):
|
|
82
|
+
```bash
|
|
83
|
+
HOME="$DH" twak wallet create --password '<StrongPw>' --no-keychain
|
|
84
|
+
```
|
|
85
|
+
`--no-keychain` keeps the password OUT of the OS keychain — it lives only in
|
|
86
|
+
`TWAK_WALLET_PASSWORD` (step 4), so creation triggers **no macOS keychain
|
|
87
|
+
prompt**. Expect: "Agent wallet created successfully / Wallet registered with backend /
|
|
88
|
+
Generated addresses for 25 chains". (twak then prints "Restart your harness… /
|
|
89
|
+
Try a sample query…" — that's for MCP users; ignore it, studio doesn't use
|
|
90
|
+
twak's MCP.)
|
|
91
|
+
|
|
92
|
+
> **Already have a wallet here?** If twak says `Wallet already exists. Back up
|
|
93
|
+
> … then delete it`, the wallet is already created — do **NOT** follow the
|
|
94
|
+
> literal "delete it". `wallet.json` is the ONLY copy of your AES-256-GCM
|
|
95
|
+
> encrypted mnemonic; deleting it without the mnemonic backed up loses the funds
|
|
96
|
+
> **forever**. Confirm it's yours (`HOME="$DH" twak wallet addresses`), skip
|
|
97
|
+
> create, and go straight to step 5 — `bag wallet new` just ADOPTS the existing
|
|
98
|
+
> address (idempotent, never destructive). Only recreate if you've safely backed
|
|
99
|
+
> up the mnemonic, and then `mv` `wallet.json` to a `.bak` rather than deleting.
|
|
100
|
+
|
|
101
|
+
> **CI / scripts:** use `bag wallet twak-init --password-stdin` /
|
|
102
|
+
> `--password-file` above — it is the supported non-interactive path and
|
|
103
|
+
> works on headless runners (no keychain involved). Avoid the older
|
|
104
|
+
> `TWAK_NONINTERACTIVE=1 TWAK_SETUP_WALLET=create … twak setup` route: it
|
|
105
|
+
> has no `--no-keychain` equivalent, stores the password in the OS
|
|
106
|
+
> keychain, and aborts with `STORAGE_ERROR` on headless / Docker runners.
|
|
107
|
+
|
|
108
|
+
**4. Put the unlock password in `.env.local`** — **YOU edit the file** (never
|
|
109
|
+
through the chat, never `bag env set <literal>` — the password must not reach
|
|
110
|
+
the assistant or argv). Same value as Step 3:
|
|
111
|
+
```
|
|
112
|
+
# .studio/.env.local
|
|
113
|
+
TWAK_WALLET_PASSWORD=<StrongPw>
|
|
114
|
+
```
|
|
115
|
+
studio AND the deployed runtime unlock via this env — the keychain copy is
|
|
116
|
+
local-only and never deploys, so this line is mandatory or deploy can't sign.
|
|
117
|
+
|
|
118
|
+
**5. Anchor + activate** — back in a NORMAL shell (**no `HOME=` prefix**; studio
|
|
119
|
+
resolves the home from `[wallet].twak_home` itself, and `bag wallet new`
|
|
120
|
+
ADOPTS the address — it does not create a second wallet):
|
|
121
|
+
```bash
|
|
122
|
+
cd <workspace>/app/agent
|
|
123
|
+
bag wallet new # writes the NEW address into studio.toml [wallet].address — confirm it's the new wallet, not your main one
|
|
124
|
+
bag llm activate # zero-deposit Pieverse key
|
|
125
|
+
bag doctor # all PASS (zero balance is a WARN, fine)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### macOS keychain — bypassed by default
|
|
129
|
+
|
|
130
|
+
With `--no-keychain` (step 3) the wallet password lives ONLY in
|
|
131
|
+
`TWAK_WALLET_PASSWORD` (step 4) — twak never reads or writes the OS keychain, so
|
|
132
|
+
both creation and signing trigger **no macOS password prompt**. studio and the
|
|
133
|
+
deployed runtime unlock via that env, so nothing is lost by skipping the keychain.
|
|
134
|
+
|
|
135
|
+
> **Safety net (you normally never see it):** for the rare case you create a wallet
|
|
136
|
+
> WITHOUT `--no-keychain`, `bag init` (and `bag wallet new`) also auto-creates an
|
|
137
|
+
> isolated, **empty-password** keychain under `$DH/Library/Keychains` —
|
|
138
|
+
> secret-free, scoped to `$DH` (your real login keychain untouched), never
|
|
139
|
+
> deployed. With `--no-keychain` twak doesn't touch any keychain at all.
|
|
140
|
+
|
|
141
|
+
> ⚠️ **If you omitted `--no-keychain` and a macOS prompt LOOPS** (or a bare `twak
|
|
142
|
+
> setup` prompted against your **main** login keychain and rejects every password):
|
|
143
|
+
> **Do NOT click "Reset Default Keychain"** — it erases your Wi-Fi passwords, SSH
|
|
144
|
+
> passphrases, and saved app secrets. Quit it with `pkill -9 -f twak`, then
|
|
145
|
+
> recreate the wallet **disk-only**:
|
|
146
|
+
> ```bash
|
|
147
|
+
> HOME="$DH" twak wallet create --password '<StrongPw>' --no-keychain
|
|
148
|
+
> ```
|
|
149
|
+
> and rely on `TWAK_WALLET_PASSWORD` (step 4) to unlock — same end state, no
|
|
150
|
+
> keychain involved.
|
|
151
|
+
|
|
152
|
+
### Other wallet placements
|
|
153
|
+
|
|
154
|
+
`bag init` always writes a project-dedicated `[wallet].twak_home`; the flow above
|
|
155
|
+
is the default (a brand-new dedicated wallet). Alternatives:
|
|
156
|
+
- **Reuse an existing wallet** across agents → `bag init --twak-home <path>`
|
|
157
|
+
(that wallet's HOME-style dir, containing `.twak/wallet.json`). Same flow:
|
|
158
|
+
create with `--no-keychain`, unlock via `TWAK_WALLET_PASSWORD`.
|
|
159
|
+
- **Your main `~/.twak`** (DISCOURAGED — real funds / bound identities) → opt-in
|
|
160
|
+
only via `bag init --twak-home ~`, or "yes" to the warned prompt (default "no")
|
|
161
|
+
when a machine wallet is detected. Recorded as `[wallet].twak_home = <$HOME>`.
|
|
162
|
+
|
|
163
|
+
Each wallet is its own address → its own ERC-8004 identity, Pieverse SIWE
|
|
164
|
+
binding, and secret bundle; `bag doctor` / `bag deploy` resolve the right one via
|
|
165
|
+
`[wallet].twak_home`.
|
|
166
|
+
|
|
167
|
+
## 3. Fund it — and keep it a HOT wallet
|
|
168
|
+
|
|
169
|
+
Two assets, two different rules:
|
|
170
|
+
|
|
171
|
+
- **U (payment token)** — the principal for x402 topups (LLM credit) and what
|
|
172
|
+
buyers pay you. x402 payments are **GASLESS** (EIP-3009, the facilitator
|
|
173
|
+
settles), so topping up burns no BNB. A twak wallet is also a supported
|
|
174
|
+
b402 **seller** payout wallet (`bag init --wallet-kind twak --rails b402`);
|
|
175
|
+
receiving needs no signature or gas either.
|
|
176
|
+
- **BNB (gas)** — **testnet: none needed; mainnet: a little for ERC-8183.**
|
|
177
|
+
Testnet: the SDK forwards MegaFuel's testnet paymaster (`--paymaster-url`,
|
|
178
|
+
twak >= 0.20.0), so x402 topups (already gasless) plus **all** 8004/8183
|
|
179
|
+
writes are sponsored — a little tBNB (~0.007) is only a fallback in case
|
|
180
|
+
sponsorship declines a tx. Mainnet: x402 stays gasless and `bag 8004
|
|
181
|
+
register` is gas-sponsored by twak internally (Trust gateway — studio
|
|
182
|
+
passes no paymaster flag), but **`8183 settle` / `fund` self-pay gas**, so
|
|
183
|
+
keep ~0.007 BNB on the wallet for them.
|
|
184
|
+
|
|
185
|
+
> ⚠️ **MegaFuel testnet relay reliability (BUG-029).** The bsctestnet relay
|
|
186
|
+
> has been observed accepting a sponsored write, returning a tx hash, and
|
|
187
|
+
> then never broadcasting it — the hash is unverifiable on every public
|
|
188
|
+
> RPC and the wallet nonce never moves (reproduced 2026-07-24 and
|
|
189
|
+
> 2026-07-28 with raw `twak erc8183 create-job --paymaster-url …`). Do NOT
|
|
190
|
+
> treat raw `twak erc8183` sponsored bsctestnet writes as a stable PASS
|
|
191
|
+
> path for tests/CI. Drive the write through studio (`bag erc8004 …`,
|
|
192
|
+
> `bag erc8183 …`) or the SDK's `TWAKProvider` instead: those classify the
|
|
193
|
+
> failure (`RelaySubmissionUnverifiedError` = relay swallowed it, never
|
|
194
|
+
> persist the hash as pending; `TransactionPendingError` = the tx IS
|
|
195
|
+
> visible, wait) instead of a bare receipt timeout. Self-pay escape
|
|
196
|
+
> hatches: `--no-paymaster` on studio 8004 writes, or
|
|
197
|
+
> `BNBAGENT_USE_PAYMASTER=0` for any studio/SDK call.
|
|
198
|
+
|
|
199
|
+
**Hot-wallet rule**: fund only a few days of spend. The Agent wallet is an
|
|
200
|
+
operational hot wallet, not a treasury — the on-chain balance is the one
|
|
201
|
+
spending limit nothing can bypass. Studio's daily caps
|
|
202
|
+
(`[budget].max_per_day_usd`) are in-process guardrails: real across CLI runs
|
|
203
|
+
(persisted to `.studio/spend-ledger.json`), best-effort in the deployed
|
|
204
|
+
runtime (in-memory, resets on cold start).
|
|
205
|
+
|
|
206
|
+
Testnet faucet: https://www.bnbchain.org/en/testnet-faucet (tBNB, fallback only).
|
|
207
|
+
Mainnet: U via PancakeSwap (BNB not needed — gas is sponsored).
|
|
208
|
+
|
|
209
|
+
## 4. SIWE binding (Pieverse) — ALWAYS bind before paying
|
|
210
|
+
|
|
211
|
+
Pieverse attributes x402 topups to the **SIWE-bound payer address** (the paid
|
|
212
|
+
call carries no session header on the twak path). `bag llm activate` performs
|
|
213
|
+
the SIWE login (an EIP-191 `sign_message`, which twak supports) before any
|
|
214
|
+
payment, so the normal flow is safe. If you ever top up through a custom
|
|
215
|
+
path: bind first, pay second — an unbound payment cannot be attributed.
|
|
216
|
+
|
|
217
|
+
## 5. Local dev (no Docker) vs deploy (Container image)
|
|
218
|
+
|
|
219
|
+
**Local dev needs no Docker.** `bag dev` runs the agent **in-process** by
|
|
220
|
+
default (the TS entrypoint, no Docker) — the keystore/twak materialize hooks are
|
|
221
|
+
no-ops locally, so in-process exercises the same code path as the deployed
|
|
222
|
+
container minus the image. Use `bag dev --container` only if you want the
|
|
223
|
+
AgentCore dev container for full image parity (that mode runs via `agentcore
|
|
224
|
+
dev` and needs Docker / Podman / Finch); it is **not** required to develop or
|
|
225
|
+
test the twak agent locally.
|
|
226
|
+
|
|
227
|
+
**Deploy ships a Container image.** The managed AgentCore image can't host the
|
|
228
|
+
twak CLI toolchain, so a twak Agent deploys as a **custom container** (Node ≥ 20
|
|
229
|
+
+ the twak CLI). `bag init` already configured everything: `agentcore.json`
|
|
230
|
+
registers a `Container` runtime and `app/agent/Dockerfile` builds the image
|
|
231
|
+
(linux/arm64 — an x86 machine needs docker buildx for cross-build).
|
|
232
|
+
|
|
233
|
+
- Local Docker is **required** for `bag deploy --provider aws`: the pinned
|
|
234
|
+
`bnbagent-deploy` (to which Studio delegates all cloud execution
|
|
235
|
+
to) builds the image locally (linux/arm64) and pushes it to ECR — there is
|
|
236
|
+
no remote-build fallback, so the Docker daemon must be running.
|
|
237
|
+
- Wallet material reaches the runtime ONLY via AWS Secrets Manager
|
|
238
|
+
(`TWAK_WALLET_JSON` / `TWAK_CREDENTIALS_JSON` / `TWAK_WALLET_PASSWORD`),
|
|
239
|
+
never inside the image. `bag deploy prepare` verifies all of this.
|
|
240
|
+
|
|
241
|
+
## 6. Known limitations (upstream twak CLI v0.20.0)
|
|
242
|
+
|
|
243
|
+
| Limitation | Upstream ref | What you see |
|
|
244
|
+
|---|---|---|
|
|
245
|
+
| ~~Seller `submit` unavailable~~ | ~~REQ-1~~ RESOLVED in v0.19.0 | `submit --opt-params` works — verified on-chain. |
|
|
246
|
+
| ~~Seller `quote` signing broken~~ | ~~S-11 regression in v0.19.0~~ RESOLVED in v0.19.1 | v0.19.0 hex-decoded `0x…` messages and signed the bytes, so provider_sig never verified (testnet also rejected `sign-message --chain bsctestnet`). v0.19.1 signs the literal text (EIP-191): `sign_quote` works on both wallet kinds. |
|
|
247
|
+
| ~~Testnet intent writes self-pay gas~~ | ~~REQ-2~~ RESOLVED in v0.20.0 | twak accepts `--paymaster-url`; the SDK forwards MegaFuel's testnet endpoint on every sponsored write, so testnet 8004/8183 writes are gasless too (the relay itself is flaky — see the BUG-029 warning in §3). Mainnet stays twak-internal (no flag passed). The CLI floor is now **0.20.0** — `bag doctor` / `bag deploy prepare` reject older. |
|
|
248
|
+
| No generic EIP-712 signing | P0 (won't fix) | `[wallet.signing]` is ignored; payments go through the delegated payer's own prechecks + `--max-payment`. Endpoints needing an `Authorization` header *and* x402 are unavailable (e.g. `bag llm key new --initial-usd > 0` — use `--initial-usd 0` + topup + allocate instead, same end state). |
|
|
249
|
+
| No wallet import | S-6 | Switching wallet kinds changes your address → re-run `bag 8004 register` (new on-chain identity). |
|
|
250
|
+
| Programmatic wallet creation forces password onto argv | S-8 | Bridged by `bag wallet twak-init` (password via stdin / 0600 file / hidden prompt — never argv); the manual twak commands remain a fallback. |
|
|
251
|
+
| CLI has no daily/monthly caps | — | Studio's policy layer (`[budget].max_per_day_usd`, host allowlist, per-request caps) is the spend authority for both wallet kinds. |
|
|
252
|
+
|
|
253
|
+
## 7. Quick health checks
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
bag doctor # [wallet] twak CLI / wallet / address-anchor checks
|
|
257
|
+
bag wallet show # describe(): address, key_location, capabilities
|
|
258
|
+
bag wallet balance # BNB + U via RPC (works on testnet too)
|
|
259
|
+
bag deploy prepare # container/Dockerfile/secret checks before deploy
|
|
260
|
+
```
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bnbagent-studio-wiring-llm-tools
|
|
3
|
+
description: When the user wants their agent's LLM to call read-only chain queries (wallet balance, ERC-8004 agent info, ERC-8183 job status, etc.) — exposes the 15 functions in `@bnbagent/studio-runtime/tools` as LLM tools via AI SDK `tool()` wrappers, or any other TS agent framework.
|
|
4
|
+
---
|
|
5
|
+
|
|
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.
|
|
7
|
+
|
|
8
|
+
# bnbagent-studio-wiring-llm-tools
|
|
9
|
+
|
|
10
|
+
Wire `bnbagent-studio`'s 15 chain readonly functions into the user's agent so
|
|
11
|
+
the LLM can autonomously query wallet, balance, ERC-8004 identity, ERC-8183
|
|
12
|
+
jobs, etc. Studio ships the pure functions plus two emitted wrapper files: the
|
|
13
|
+
runtime recipe's curated default (`app/agent/src/tools.ts`, `LLM_READ_TOOLS`)
|
|
14
|
+
and the full-inventory `tools-chain` recipe
|
|
15
|
+
(`tools-chain/code/{{PKG}}/chainTools.ts.tmpl`, emitted as
|
|
16
|
+
`app/agent/src/chainTools.ts`); for a non-AI-SDK framework you (Claude Code)
|
|
17
|
+
write a thin wrapping file in the Agent sub-project.
|
|
18
|
+
|
|
19
|
+
In v1 the workspace contains one sub-project, `app/agent/` — the single
|
|
20
|
+
selected-faces seller runtime. LLM tools always live in
|
|
21
|
+
**`app/agent/src/tools.ts`**. The `{{PKG}}` recipe variable resolves to the
|
|
22
|
+
agent's `src/` dir, so the emit target is `app/agent/src/tools.ts` — its
|
|
23
|
+
meaning is "source dir of the agent sub-project", not "package inside a
|
|
24
|
+
single-root project".
|
|
25
|
+
|
|
26
|
+
## Audience
|
|
27
|
+
|
|
28
|
+
Claude Code (or another agent) editing the user's workspace. The user has run
|
|
29
|
+
`bag init` and wants their Agent sub-project to expose read-only chain queries
|
|
30
|
+
to its LLM (`app/agent/src/tools.ts`). These are READ-ONLY — the Agent's
|
|
31
|
+
signing always stays in `app/agent/src/signing.ts` (fixed code), never an LLM
|
|
32
|
+
tool.
|
|
33
|
+
|
|
34
|
+
## When to use this skill
|
|
35
|
+
|
|
36
|
+
- The user says "let my agent query its balance" / "agent should know about its
|
|
37
|
+
on-chain jobs" / "give the LLM access to chain state"
|
|
38
|
+
- The user wants to wire chain tools into a **non-AI-SDK** stack (LangChain.js,
|
|
39
|
+
a bare OpenAI/Anthropic SDK tool loop, custom)
|
|
40
|
+
- The user wants to **customize** which chain queries their LLM sees
|
|
41
|
+
- The user uses `bag init` but wants to extend / re-emit the tool list
|
|
42
|
+
|
|
43
|
+
## When NOT to use this skill
|
|
44
|
+
|
|
45
|
+
- The user wants the Agent to **sign transactions / pay** — in the single seller
|
|
46
|
+
model all signing (quote-sign, submit, settle) is FIXED code
|
|
47
|
+
in `app/agent/src/signing.ts` (called by A2A's `SellerAgentExecutor` or MCP's
|
|
48
|
+
`src/mcpMain.ts` tools), **never** an
|
|
49
|
+
LLM-callable tool. The LLM only produces work text after a job is verified
|
|
50
|
+
funded; fixed code prices, clamps, signs, and submits. There is no "wire a
|
|
51
|
+
signing tool into the LLM" path in v1.
|
|
52
|
+
- The user is doing dev-time debugging via Claude Code — that's the `bag` CLI
|
|
53
|
+
read commands (`bag wallet`, `bag erc8183 status/list`, …), not LLM tools.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## The 15 functions
|
|
58
|
+
|
|
59
|
+
All in `@bnbagent/studio-runtime/tools`. Each returns a plain object (or
|
|
60
|
+
string); the wire-format keys stay snake_case (the tool contract shared with
|
|
61
|
+
LLMs and MCP clients).
|
|
62
|
+
|
|
63
|
+
### Wallet & chain basics — always safe
|
|
64
|
+
|
|
65
|
+
| Function | Reads | Dependency |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `walletInfo()` | active wallet address + source + keystore dir | none |
|
|
68
|
+
| `walletAddress()` | active wallet address (alias of walletInfo) | none |
|
|
69
|
+
| `walletList()` | all configured keystore addresses | dev concern |
|
|
70
|
+
| `balanceNative(address?, network?)` | BNB / tBNB balance | none |
|
|
71
|
+
| `balanceU(address?, network?)` | U token balance | `[u_token]` |
|
|
72
|
+
| `networkInfo(network?)` | chain id, RPC host, contract addresses | none |
|
|
73
|
+
| `txStatus(txHash, network?)` | tx receipt + revert reason | none |
|
|
74
|
+
|
|
75
|
+
### LLM provider — Pieverse-specific
|
|
76
|
+
|
|
77
|
+
| Function | Reads | Dependency |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `pieverseUsage(days=7)` | LLM spend on Pieverse | `[llm.provider=pieverse-llm]` |
|
|
80
|
+
|
|
81
|
+
Note: `pieverseUsage` does a SIWE EIP-191 personal_sign (no on-chain effect,
|
|
82
|
+
domain-locked). Other functions are pure RPC reads.
|
|
83
|
+
|
|
84
|
+
### ERC-8004 identity
|
|
85
|
+
|
|
86
|
+
| Function | Reads | Dependency |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `agentInfo(agentId, network?)` | on-chain ERC-8004 record by ID | `[erc8004]` |
|
|
89
|
+
| `agentByAddress(address, network?)` | look up agent by owner address | `[erc8004]` |
|
|
90
|
+
|
|
91
|
+
### ERC-8183 jobs
|
|
92
|
+
|
|
93
|
+
| Function | Reads | Dependency |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `jobStatus(jobId, network?)` | job state, client, provider, budget | `[erc8183]` |
|
|
96
|
+
| `jobList(limit=10, mine=false, provider?, network?)` | recent jobs | `[erc8183]` |
|
|
97
|
+
| `jobCount(network?)` | network-wide inflight job count | `[erc8183]` |
|
|
98
|
+
|
|
99
|
+
### Advanced / footguns
|
|
100
|
+
|
|
101
|
+
| Function | Reads | Why footgun |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `blockInfo(block?, network?)` | block summary | usually noise for LLM |
|
|
104
|
+
| `contractCallView(address, functionSignature, args?, outputTypes?, network?)` | arbitrary `eth_call` | accepts **any** ABI — LLM can be prompt-injected into calling attacker contracts |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Step 1 — Confirm the user has run `bag init`
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# from workspace root:
|
|
112
|
+
ls app/agent/studio.toml && (ls app/agent/src/main.ts 2>/dev/null || ls app/agent/src/mcpMain.ts)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
If `app/agent/src/tools.ts` already exists, the user has the AI SDK form
|
|
116
|
+
already. Skip to Step 4 if they want to customize.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Step 2 — Identify the stack
|
|
121
|
+
|
|
122
|
+
Look at `app/agent/src/main.ts` or `app/agent/src/mcpMain.ts` imports /
|
|
123
|
+
`app/agent/package.json`:
|
|
124
|
+
|
|
125
|
+
| Sign in code | Stack |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `import { tool, generateText } from "ai"` | **AI SDK** (use stock recipe) |
|
|
128
|
+
| `from "langchain"` / `from "@langchain/core"` | **LangChain.js** |
|
|
129
|
+
| `openai.chat.completions.create({ tools: ... })` | **bare OpenAI SDK loop** |
|
|
130
|
+
| `anthropic.messages.create({ tools: ... })` | **bare Anthropic SDK loop** |
|
|
131
|
+
|
|
132
|
+
If AI SDK: emit the stock recipe and stop.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
bag recipe code tools-chain > app/agent/src/chainTools.ts # full inventory + CHAIN_READ_TOOLS
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Then in the protocol entrypoint (`app/agent/src/main.ts` for A2A,
|
|
139
|
+
`app/agent/src/mcpMain.ts` for MCP), pass the tool set into the generate call:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { LLM_READ_TOOLS } from "./tools.js";
|
|
143
|
+
// inside runWork:
|
|
144
|
+
const { text } = await generateText({ model, tools: LLM_READ_TOOLS, prompt });
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
For non-AI-SDK stacks, continue.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Step 3 — Write a framework-specific wrapper
|
|
152
|
+
|
|
153
|
+
Studio doesn't ship adapters for non-AI-SDK stacks (commitment: "agent code
|
|
154
|
+
the user owns"). You write a wrapper file in the user's project. Pattern:
|
|
155
|
+
import the pure functions, wrap each with the framework's tool primitive.
|
|
156
|
+
|
|
157
|
+
### LangChain.js
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
// app/agent/src/tools.ts
|
|
161
|
+
import { tool } from "@langchain/core/tools";
|
|
162
|
+
import { z } from "zod";
|
|
163
|
+
import * as cr from "@bnbagent/studio-runtime/tools";
|
|
164
|
+
|
|
165
|
+
export const LLM_READ_TOOLS = [
|
|
166
|
+
tool(async () => cr.walletInfo(), {
|
|
167
|
+
name: "wallet_info",
|
|
168
|
+
description: "Describe the agent's active wallet.",
|
|
169
|
+
schema: z.object({}),
|
|
170
|
+
}),
|
|
171
|
+
tool(async ({ address, network }) => cr.balanceNative(address ?? null, network),
|
|
172
|
+
{
|
|
173
|
+
name: "balance_native",
|
|
174
|
+
description: "Native BNB balance of an address (defaults to the agent's wallet).",
|
|
175
|
+
schema: z.object({ address: z.string().optional(), network: z.string().optional() }),
|
|
176
|
+
}),
|
|
177
|
+
// balanceU (requires [u_token]), networkInfo, txStatus,
|
|
178
|
+
// pieverseUsage (requires [llm.provider=pieverse-llm]),
|
|
179
|
+
// agentInfo / agentByAddress (require [erc8004]),
|
|
180
|
+
// jobStatus / jobList (require [erc8183]) — same pattern.
|
|
181
|
+
// ⚠️ contractCallView accepts any ABI — keep it out unless deliberate.
|
|
182
|
+
];
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Wire into the agent (e.g. `createReactAgent({ llm, tools: LLM_READ_TOOLS })`).
|
|
186
|
+
|
|
187
|
+
### Bare OpenAI / Anthropic tool loop
|
|
188
|
+
|
|
189
|
+
For a hand-rolled tool loop, declare each function in the provider's tool JSON
|
|
190
|
+
format and dispatch on the tool name:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
// app/agent/src/tools.ts
|
|
194
|
+
import * as cr from "@bnbagent/studio-runtime/tools";
|
|
195
|
+
|
|
196
|
+
export const CHAIN_READ_FUNCTIONS: Record<string, (args: any) => Promise<unknown>> = {
|
|
197
|
+
wallet_info: async () => cr.walletInfo(),
|
|
198
|
+
balance_native: async (a) => cr.balanceNative(a.address ?? null, a.network),
|
|
199
|
+
balance_u: async (a) => cr.balanceU(a.address ?? null, a.network), // requires [u_token]
|
|
200
|
+
network_info: async (a) => cr.networkInfo(a.network),
|
|
201
|
+
tx_status: async (a) => cr.txStatus(a.tx_hash, a.network),
|
|
202
|
+
// pieverse_usage, // requires [llm.provider=pieverse-llm]
|
|
203
|
+
// agent_info, agent_by_address, // require [erc8004]
|
|
204
|
+
// job_status, job_list, // require [erc8183]
|
|
205
|
+
// contract_call_view, block_info, wallet_list, wallet_address,
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Generic
|
|
210
|
+
|
|
211
|
+
For any framework that accepts a typed function + description, the pattern is
|
|
212
|
+
identical — wrap each `cr.*` function in the framework's tool primitive and
|
|
213
|
+
assemble a list. The emitted AI SDK files (`tools.ts` / `chainTools.ts`)
|
|
214
|
+
already carry per-tool descriptions and zod input schemas you can copy from.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Step 4 — Customize what the LLM sees
|
|
219
|
+
|
|
220
|
+
The recipe gives a sensible default; the user owns the file. Common edits:
|
|
221
|
+
|
|
222
|
+
**Remove tools** the agent doesn't need (smaller LLM context = better focus):
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
export const LLM_READ_TOOLS: ToolSet = {
|
|
226
|
+
balance_u: CHAIN_READ_TOOLS.balance_u, // only thing this agent really needs
|
|
227
|
+
tx_status: CHAIN_READ_TOOLS.tx_status,
|
|
228
|
+
};
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Uncomment Pieverse usage** if the user's `[llm].provider = "pieverse-llm"`:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
pieverse_usage: ..., // requires [llm.provider=pieverse-llm]
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Uncomment 8004 / 8183 reads** if the user added those sections to
|
|
238
|
+
`studio.toml` after `bag init` (e.g., ran `bag erc8004 register` later).
|
|
239
|
+
|
|
240
|
+
**Never uncomment** `contract_call_view` without thinking — it accepts any ABI
|
|
241
|
+
signature and an LLM jailbreak / prompt injection can drain via reads from
|
|
242
|
+
malicious contracts (or hammer expensive RPC). Keep commented unless the
|
|
243
|
+
agent has a specific debug / introspection job and the user has read the
|
|
244
|
+
tool description.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Step 5 — Write operations live in fixed code, NOT LLM tools
|
|
249
|
+
|
|
250
|
+
Read tools (this skill) are safe-ish — worst case the LLM gives wrong info.
|
|
251
|
+
**Write operations** (quote-sign, submit, settle) are the whole point of the
|
|
252
|
+
single seller model's signing boundary: they live as FIXED code in
|
|
253
|
+
`app/agent/src/signing.ts`, are dispatched by A2A's `SellerCore` (in
|
|
254
|
+
`app/agent/src/sellerCore.ts`, which `SellerAgentExecutor` inherits) or MCP's
|
|
255
|
+
server tools (`negotiate`/`notify_funded`; `settle` is the manual `bag erc8183 settle`),
|
|
256
|
+
and are **never** put in the LLM's `tools` set. The quote price is rule-based
|
|
257
|
+
(fixed code reads the list `price`, clamps it to `[min,max]`, then signs — the
|
|
258
|
+
LLM never touches the price); the LLM only PRODUCES the work text in `notify_funded` delivery —
|
|
259
|
+
money never flows through a tool call.
|
|
260
|
+
|
|
261
|
+
The one automatic signing path outside `signing.ts` is the budget-gated
|
|
262
|
+
model-wrapper LLM-credit auto-renew hook (in the emitted
|
|
263
|
+
`app/agent/src/model.ts`'s `buildModel()` factory, backed by
|
|
264
|
+
`@bnbagent/studio-runtime/pieverse` `PieverseCreditEnsurer`) — also automatic,
|
|
265
|
+
also **not** an LLM tool.
|
|
266
|
+
|
|
267
|
+
The x402 buyer kernel (`@bnbagent/studio-runtime/x402`, the payment signer) is
|
|
268
|
+
**not** an LLM tool either — in v1 it is reachable only as the Agent's
|
|
269
|
+
automatic model-wrapper LLM-credit auto-renew (above), driven by fixed code,
|
|
270
|
+
never the LLM. Do not wire it into the Agent's `tools` set. The SDK's
|
|
271
|
+
`SigningPolicy` is the second-layer gate on every signature regardless.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Common questions
|
|
276
|
+
|
|
277
|
+
**Q: Why isn't `app/agent/src/tools.ts` auto-synced with `app/agent/studio.toml` changes?**
|
|
278
|
+
|
|
279
|
+
A: The recipe is emitted once at `bag init` time; the file is the user's. To
|
|
280
|
+
refresh after configuring new features (e.g., enabling `[erc8183]` later):
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
bag recipe code tools-chain > app/agent/src/chainTools.ts.new
|
|
284
|
+
diff app/agent/src/chainTools.ts app/agent/src/chainTools.ts.new
|
|
285
|
+
# manually merge — preserves any user customizations
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Q: Does this work in AgentCore deployment?**
|
|
289
|
+
|
|
290
|
+
A: Yes. The functions only need `@bnbagent/studio-runtime` (already a
|
|
291
|
+
dependency of the Agent sub-project via `app/agent/package.json`). No
|
|
292
|
+
subprocess, no MCP transport — pure in-process calls. The deploy artifact
|
|
293
|
+
ships the built `tools.ts` as part of the Agent that serves its selected
|
|
294
|
+
A2A/MCP faces on AgentCore.
|
|
295
|
+
|
|
296
|
+
**Q: Is this the same as `bag init --protocols MCP`?**
|
|
297
|
+
|
|
298
|
+
A: No. `bag init --protocols MCP` selects an **external seller face**
|
|
299
|
+
(streamable-HTTP `/mcp` for buyers). This skill wires read-only chain queries
|
|
300
|
+
into the Agent's own LLM as in-process tools. v0.0.1 doesn't ship
|
|
301
|
+
MCP-for-agent (the agent runtime consuming a subprocess MCP server as its LLM
|
|
302
|
+
tools). MCP here is instead an *external seller face* (`bag init --protocols
|
|
303
|
+
MCP` or `--protocols A2A,MCP`) — see `docs/design/decisions.md`. For
|
|
304
|
+
now: in-process is simpler, faster, and matches commitment "agent code the
|
|
305
|
+
user owns".
|
|
306
|
+
|
|
307
|
+
**Q: How do I know if my `app/agent/src/tools.ts` is up to date?**
|
|
308
|
+
|
|
309
|
+
A: Re-emit with `bag recipe code tools-chain > app/agent/src/chainTools.ts.new`
|
|
310
|
+
and diff against your current file. If studio added new tools in a newer
|
|
311
|
+
version, they'll appear in the emit; you decide whether to adopt.
|
|
312
|
+
|
|
313
|
+
**Q: Can I reuse a Pieverse API key I created with a DIFFERENT wallet (BYOK)?**
|
|
314
|
+
|
|
315
|
+
A: Yes, for inference — with one caveat. The LLM-credit auto-renew hook
|
|
316
|
+
(`PieverseCreditEnsurer`) authenticates to Pieverse with the **agent's signing
|
|
317
|
+
wallet** and can only inspect/allocate keys **that wallet owns**. If you set
|
|
318
|
+
`[llm.pieverse].key_hash` to a key created by another wallet (the owner is your
|
|
319
|
+
day-to-day wallet, not the agent's throwaway signer), the hook can't see it: it
|
|
320
|
+
detects the owner mismatch, prints one warning, **disables itself for that
|
|
321
|
+
session, and lets inference run on the key's existing Bearer credit**. It does
|
|
322
|
+
not crash the agent and does not repeat the check.
|
|
323
|
+
|
|
324
|
+
Recommended BYOK setup — do NOT hand the owner wallet's private key to the
|
|
325
|
+
agent (that would violate the "keys stay in the user's environment" boundary):
|
|
326
|
+
|
|
327
|
+
1. Put the key in the agent env: `PIEVERSE_LLM_API_KEY=sk-pv-…` in
|
|
328
|
+
`.studio/.env.local`, plus `[llm.pieverse].key_hash = "0x…"` and `network`
|
|
329
|
+
in `studio.toml`.
|
|
330
|
+
2. Turn off auto-renew so the hook doesn't try to allocate a key it can't own:
|
|
331
|
+
`bag llm auto-renew llm off`.
|
|
332
|
+
3. Top the key up yourself in the Pieverse portal (or from the owner wallet)
|
|
333
|
+
when it runs low — the agent will 402 upstream if the Bearer credit is
|
|
334
|
+
exhausted.
|
|
335
|
+
|
|
336
|
+
If you instead want the agent to auto-allocate/topup, activate a key the
|
|
337
|
+
**agent's own** signing wallet owns with `bag llm activate` (zero-deposit is
|
|
338
|
+
fine) and keep auto-renew on.
|