feat(market): /market command + agent_talent tool to hire marketplace skills#83
Open
Zambala108 wants to merge 8 commits into
Open
feat(market): /market command + agent_talent tool to hire marketplace skills#83Zambala108 wants to merge 8 commits into
Zambala108 wants to merge 8 commits into
Conversation
… skills Add a buyer surface for the BlockRun agent marketplace (business.blockrun.ai): a catalog of paid AI skills, each runnable for ONE standard single-leg `exact` x402 USDC payment on Base. Two surfaces over one payment path (src/market/client.ts): - `/market` slash command — a human browses (`/market`, `/market <keyword>`), inspects (`/market info <slug>`), and hires (`/market run <slug> <input>`). Browsing is a free GET; run pays one x402 from the wallet. - `agent_talent` tool — the agent discovers (`action:"list"`) and hires (`action:"run"`) talent autonomously mid-task, charged only on success. The marketplace speaks standard x402, so Franklin pays it with the same EVM wallet and the same `@blockrun/llm` signer it already uses for the gateway — the only deltas from the BlockRun gateway primitive are the `x-payment` header name and the base URL (env BLOCKRUN_MARKET_URL, default business.blockrun.ai). Base-only: a hire always pays from the EVM wallet. Regression test (test/market.local.mjs) drives the client against a mock marketplace and asserts Franklin signs the EXACT advertised price — the invariant the live route enforces with `signedValueMicro === totalMicro`. This caught a real bug: a `Run — <skill>` description with an em-dash made @blockrun/llm's btoa-based payload encoding throw "Invalid character" on any non-Latin1 skill name; the description is now ASCII-stripped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extend the regression suite from the client-only checks to the two buyer surfaces: agent_talent (list / list+query / empty / run / missing slug+input / failed-hire-no-charge / unknown action / concurrency safety) and the /market command dispatch (browse / search / info / info-usage / run / run-usage / run-failure-no-charge), plus limit clamping and formatSkillCard. 22 market tests, 470/470 in the full suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename the user-facing catalog heading from "Agent marketplace" to "Agent talents" (consistent with the agent_talent tool + the talent panel), in both the /market command and the tool's list output. Default browse shows the top 12 by popularity; when more exist the heading now reads "top 12 of <total>" instead of silently capping. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…search
Broaden the tool description so the model reliably routes a plain-language
"find / search / recommend an agent for <domain>" request to
agent_talent{action:"list", query}, not only the agent's own sub-task needs.
Verified live (Anthropic Haiku 4.5) among Franklin's real toolset: NL requests
in English and Chinese route to agent_talent list with a sensible query, the
model picks it over WebSearch for "find me an agent", and an unrelated question
triggers no marketplace call.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
agent_talent run spends USDC from the wallet with no refund, so it now goes through the permission prompt (behavior "ask") like the other paid, irreversible tools (VoiceCall, BuyPhoneNumber) — previously it fell through to the generic default that dumped raw args. The prompt now reads: Hire 'yield-radar' from the agent marketplace — pays from your wallet (USDC on Base), charged only on a successful run. action="list" (browse/search) is a free read, so it auto-allows with no prompt. In --trust mode both still auto-allow, matching the existing policy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lugs whole
The list rows hard-sliced the description to 40 chars, cutting mid-word
("Live stablecoin yields ranked across cha"). Truncate at the last word
boundary with an ellipsis instead ("...across…"), and stop slicing the slug —
it is the identifier the user types into `/market run <slug>`, so a cut slug
was unusable. Same bug class, fixed in both spots; short descriptions and short
slugs are unaffected and columns still align.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the "N runs" stat from the /market list rows, the /market info card, and the agent_talent list output. The catalog is still ordered by popularity (the discovery API sorts by run_count server-side) — the count is just no longer shown. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The catalog's ordering contract on every surface (the /market list, the agent_talent tool, the future web panel) is most-called-first. The discovery API already sorts by run_count desc, but the CLI takes a top-N slice, so make the ordering explicit and self-contained: fetchCatalog stable-sorts by run_count desc before slicing/filtering. Regression test locks it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A buyer surface for the BlockRun agent marketplace (business.blockrun.ai) — a catalog of paid AI skills published by other creators, each runnable for ONE standard single-leg
exactx402 USDC payment on Base. Two surfaces over one shared payment path (src/market/client.ts):/marketcommand/market(browse top),/market <keyword>(search),/market info <slug>(detail card),/market run <slug> <input>(hire)agent_talenttool{action:"list", query?}(free discovery),{action:"run", slug, input}(hire, paid)Browsing/search/info are free GETs against the public catalog;
runanswers a 402 with one wallet-signed payment.Why
The marketplace speaks standard x402, so Franklin pays it with the same EVM wallet and the same
@blockrun/llmsigner it already uses for the gateway. The only deltas from the existing BlockRun gateway primitive (src/tools/blockrun.ts) are thex-paymentheader name and the base URL (BLOCKRUN_MARKET_URL, defaulthttps://business.blockrun.ai). This makes Franklin a first-class buyer of marketplace talent — the agent can hire a specialized skill (live data, a domain analysis) for a sub-task it can't do well itself, charged only on success.Note on naming: Franklin's
skillRegistryalready owns the word "skill" (localSKILL.mdslash commands), so the marketplace gets its own namespace (/market,agent_talent) to avoid collision.How it pays
src/market/client.tsis the single payment path shared by both surfaces:POST /api/v1/skills/<slug>/run→ 402 with the standard challenge body{ accepts:[{amount, payTo, network, …}] }.extractPaymentDetails+createPaymentPayload(@blockrun/llm) sign one EIP-3009exactauthorization for exactly the advertised amount.x-paymentheader → result. Fails closed (the route settles only on success, so any non-2xx = no charge).Receipts
Regression test (
test/market.local.mjs, innpm test) drives the built client against a mock marketplace and asserts Franklin signs the EXACT advertised price — the invariant the live route enforces withsignedValueMicro === totalMicro— plus the discovery parse, keyword filter, and fail-closed-no-charge path. It caught a real bug: aRun — <skill>payment description with an em-dash made@blockrun/llm'sbtoa-based payload encoding throwInvalid characteron any non-Latin1 skill name; the description is now ASCII-stripped before signing.Live E2E vs. real Coinbase CDP (Base mainnet). Franklin's built
distclient (bothrunMarketSkilland theagent_talenttool) ran against a shim wired to business.blockrun.ai's realverifyPayment+ real CDP/verify:This closes the one untested real-world link: CDP accepts the signature
@blockrun/llmproduces, and it clears the route's strict exact-price gate. The remaining legs (on-chain settle + instant creator payout) are proven on Base mainnet in the business repo: settle0x1cea9dcdd2eff4e4474f1d504acf217d7c6ac85bca27432ce3dc476a6565e4da, payout0xc0d971c3501cf4624e5c2601ec4bc77f0d2380e76fc0ee5091dcd61f8f18a066.Tests / gates
npx tsc --noEmit✓ ·npm run build✓ ·node dist/index.js --help✓npm test→ 453/453 pass (incl. the new 5 market tests and the English-only source gate)Notes
agent_talentis registered inallCapabilities;/marketis registered in/helpand command discovery.🤖 Generated with Claude Code