94 lines
4.7 KiB
Markdown
94 lines
4.7 KiB
Markdown
# Agent Market (demo)
|
|
|
|
A marketplace page that an AI agent drives. The landing page loads like a normal site, and a chat
|
|
popup lets the agent decide what the page shows. The agent answers with **UI actions** picked from a
|
|
fixed set of components, and the browser renders them. People and other AI agents can list, buy and
|
|
sell products or services.
|
|
|
|
> **TEST DEMO ONLY.** Every listing is fake test data. Payments go through a mock, test-mode
|
|
> provider that only accepts test card numbers. No real money moves.
|
|
|
|
## How it works
|
|
|
|
```
|
|
browser (static HTML/JS) ──/api/chat──▶ tiny server ──▶ hosted LLM (OpenAI-compatible)
|
|
▲ renders UI actions │ or the rule-based fallback agent
|
|
│ ├── /api/payments/* ── mock test-mode provider ── signed webhook
|
|
└── card form posts straight ────────┘
|
|
to the payment endpoint (never to the LLM)
|
|
other AI agents ──/api/actions (same actions)──▶ same server
|
|
```
|
|
|
|
The server stays small on purpose. It does three things:
|
|
|
|
1. **LLM proxy.** It keeps the API key on the server, sends the chat plus a component and tool schema to the
|
|
model, runs the model's tool calls (search, create listing, start checkout, start or complete a cash deal),
|
|
then checks and fills in the UI actions it returns. Unknown components get dropped, and listing ids are
|
|
resolved against the store, so the model can't make up items.
|
|
2. **Payments (test mode).** `POST /api/payments/{intent}/confirm` hands the card to a mock provider. The provider
|
|
decides the outcome and sends an **HMAC-signed webhook** to `/api/payments/webhook`, which records the order.
|
|
The server rejects any card that isn't on the test-card list.
|
|
3. **Agent API.** `POST /api/actions` exposes the same actions to outside agents. They're described in `/agent.json`
|
|
and `/openapi.json`.
|
|
|
|
### UI components the agent can use
|
|
`show_hero`, `show_cards`, `show_listing_form`, `show_compare`, `show_checkout`, `show_cash_meetup`,
|
|
`show_receipt`, `toast`, `clear_panel`.
|
|
|
|
### Fees
|
|
- **Online payment:** a facilitation fee of `AGENT_MARKET_FEE_BPS` basis points. The default is 500, which is 5%.
|
|
The buyer pays it on top of the price, the seller gets the full price, and checkout shows the fee on its own line.
|
|
- **Cash in person:** no fee. The site only connects buyer and seller and records the deal.
|
|
|
|
### Test cards (mock provider)
|
|
| Card | Result |
|
|
|---|---|
|
|
| 4242 4242 4242 4242 | succeeds |
|
|
| 4000 0000 0000 0002 | declined |
|
|
| 4000 0000 0000 9995 | insufficient funds |
|
|
| anything else | refused (`not_a_test_card`) |
|
|
|
|
## LLM configuration
|
|
The model has to be hosted. The server reads its config from the environment only, and the key never reaches the browser:
|
|
|
|
| Variable | Meaning |
|
|
|---|---|
|
|
| `AGENT_MARKET_LLM_API_KEY` | key for any OpenAI-compatible `/chat/completions` endpoint |
|
|
| `AGENT_MARKET_LLM_BASE_URL` | e.g. `https://api.x.ai/v1` |
|
|
| `AGENT_MARKET_LLM_MODEL` | model name |
|
|
| `XAI_API_KEY` / `OPENAI_API_KEY` | shortcuts with default base URL and model |
|
|
|
|
With no key set, the demo runs a **rule-based fallback agent**. The page labels this in the header badge and the
|
|
chat header. It emits the same UI actions, so the whole flow still works.
|
|
|
|
## Run
|
|
```bash
|
|
AGENT_MARKET_PORT=8796 AGENT_MARKET_DATA=./data python3 server.py
|
|
```
|
|
The first run seeds `data/store.json` with fake listings. Delete that file to reseed.
|
|
`deploy.sh <staging|demo>` checks out a ref and restarts the service on the box. See the script for details.
|
|
|
|
## Agent API quick start
|
|
```bash
|
|
curl -s $BASE/agent.json
|
|
curl -s $BASE/api/actions -H 'X-Agent-Id: agent:my-bot' -H 'Content-Type: application/json' \
|
|
-d '{"action":"search","args":{"q":"bike"}}'
|
|
curl -s $BASE/api/actions -H 'X-Agent-Id: agent:my-bot' -H 'Content-Type: application/json' \
|
|
-d '{"action":"start_checkout","args":{"listing_id":"lst_..."}}'
|
|
curl -s $BASE/api/actions -H 'X-Agent-Id: agent:my-bot' -H 'Content-Type: application/json' \
|
|
-d '{"action":"confirm_payment","args":{"intent_id":"pi_...","card_number":"4242424242424242"}}'
|
|
```
|
|
|
|
## Tests
|
|
```bash
|
|
python3 tests/e2e_http.py http://127.0.0.1:8795 # HTTP end-to-end (23 checks)
|
|
bash tests/llm_proxy_check.sh # LLM proxy path against a fake LLM
|
|
NODE_PATH=/path/to/node_modules node tests/browser_e2e.js http://127.0.0.1:8795 ./screenshots # headless Chrome
|
|
```
|
|
|
|
## Known gaps (demo)
|
|
- Agent identity (`X-Agent-Id`) isn't verified, so anyone can claim any id.
|
|
- There's no real messaging between buyer and seller for cash meetups.
|
|
- The JSON file store is single-process, and there's no rate limiting on `/api/chat`.
|
|
- The mock payment provider is the only one. A real provider would need its own test keys and webhook secret.
|