README: look & layout control, guardrails
This commit is contained in:
parent
2fdd46af9d
commit
a47bd648ac
37
README.md
37
README.md
@ -35,6 +35,38 @@ The server stays small on purpose. It does three things:
|
||||
`show_hero`, `show_cards`, `show_listing_form`, `show_compare`, `show_checkout`, `show_cash_meetup`,
|
||||
`show_receipt`, `toast`, `clear_panel`.
|
||||
|
||||
### Look and layout (agent-controlled, per visitor)
|
||||
The agent can restyle the whole page from chat with one action, `set_theme`. Its payload is a JSON theme spec:
|
||||
design tokens applied as CSS variables. The model never sends raw HTML or JS. The server checks every value
|
||||
(`market/theme.py`), and the browser applies the result (`static/theme.js`).
|
||||
|
||||
| Area | Spec keys |
|
||||
|---|---|
|
||||
| Background | `background.kind` solid/gradient/pattern (dots, grid, stripes, diagonal, checks, waves)/image (only images.unsplash.com, picsum.photos, upload.wikimedia.org), `colors`, `angle` |
|
||||
| Colours | `mode` light/dark, `palette.{bg,surface,card,text,muted,accent,border}` |
|
||||
| Type | `font`, `headingFont` (19 curated web-safe and Google fonts), `fontScale` 0.75 to 1.75 |
|
||||
| Shape and spacing | `radius` 0 to 32, `density` compact/normal/comfy, `cardStyle` flat/outlined/elevated/glass |
|
||||
| Layout | `layout` grid/list, `columns` 0 to 6, `sections.order` / `sections.hidden` (hero, chips, bullets, results, footer) |
|
||||
| Copy | `copy.{logo,headline,subhead,footer,chips[],bullets[]}` |
|
||||
| Chat | `chat.{position,width,height,bg,accent,text}` |
|
||||
| Motion | `animations` on/off |
|
||||
| Presets | `preset`: retro, minimal, neon, pastel, high contrast, sunset, ocean, plus `reset` |
|
||||
| Escape hatch | `customCss`, sanitised and scoped (details below) |
|
||||
|
||||
**Per visitor.** The theme lives in the browser's `localStorage`. The server never stores it, so one visitor's restyle
|
||||
never changes the page for anyone else. **Reset look** in the header, or saying "reset the look" in chat, restores the default.
|
||||
|
||||
**Guardrails.**
|
||||
- `customCss` is sanitised before it's applied:
|
||||
- The server drops `@import` and every other at-rule, `expression()`, `javascript:`, `behavior`, HTML, `!important`, custom properties, and negative margins.
|
||||
- It neutralises `url()` pointing anywhere outside the image allowlist.
|
||||
- Only an allowlist of properties survives. Positioning, z-index, `content` and transforms aren't on it.
|
||||
- Rules are scoped under `#page`, and the browser checks them again.
|
||||
- The CSS uses cascade layers in the order `base < user < protected`. The TEST DEMO banner, the agent badge, and the checkout, cash and receipt panels (fee lines, totals, the test-card notice and the card inputs) live in `protected`. No theme can hide, recolour or shrink them.
|
||||
- Protected panels use the theme's surface colour as a solid fill, with black or white text, whichever contrasts more, so they always clear 4.5:1. The banner and badge use fixed high-contrast colours.
|
||||
- Text sitting directly on the page background switches to readable ink. If no ink clears 4.5:1 against every gradient stop, it gets a scrim behind it.
|
||||
- If the model is unavailable, the built-in agent understands the common look commands: presets, light/dark, background colours, gradients and patterns, accent and text colour, fonts, bigger or smaller text, corners, density, card style, list/grid, columns, chat position and size, hiding or showing sections, headline, logo and subtitle, animations, and reset.
|
||||
|
||||
### 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.
|
||||
@ -106,6 +138,8 @@ curl -s $BASE/api/actions -H 'X-Agent-Id: agent:my-bot' -H 'Content-Type: applic
|
||||
python3 tests/e2e_http.py http://127.0.0.1:8795 # HTTP end-to-end (23 checks)
|
||||
bash tests/llm_proxy_check.sh # fake LLM: 429 chain, cooldown, fallback, key handling, rate limit
|
||||
python3 tests/nl_check.py http://127.0.0.1:8795 # real model: 6 natural-language prompts
|
||||
python3 tests/test_theme.py # theme spec + customCss sanitiser
|
||||
NODE_PATH=... node tests/theme_check.js BASE ./screenshots # chat restyles, guardrail contrast, fresh session, reset (REQUIRE_LLM=1 to insist on the model)
|
||||
NODE_PATH=/path/to/node_modules node tests/browser_e2e.js http://127.0.0.1:8795 ./screenshots # headless Chrome
|
||||
```
|
||||
|
||||
@ -113,5 +147,6 @@ NODE_PATH=/path/to/node_modules node tests/browser_e2e.js http://127.0.0.1:8795
|
||||
- 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 rate limits live in memory, so a restart resets them.
|
||||
- Free OpenRouter models have small daily request caps and get rate-limited upstream. Once those run out, the rule-based agent answers.
|
||||
- Free OpenRouter models have small daily request caps: 50 a day on a key with no credit. They also get rate-limited upstream. When the daily cap hits,
|
||||
the server parks the whole model chain until OpenRouter's reset time, and the built-in agent answers, labelled as such.
|
||||
- The mock payment provider is the only one. A real provider would need its own test keys and webhook secret.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user