Skip to main content
Who is asking, and what their screen shows.

The picture

An agent that knows neither has to ask. Vendo fills two blocks so it does not have to.
the agent's prompt
Maple's payments page with the panel open, moving $200 to savings without asking which accounts to use
[User] is your server’s assertion about the person, refreshed every request. [Context] is what the browser sends about the page right now — the screen snapshot plus anything useVendoContext publishes — and it lives for one turn only.

Assert facts about the user

Facts ride the auth key you already pass. On a preset, add a facts object beside the display and email your user resolver returns.
app/api/vendo/[...vendo]/route.ts
Values are any JSON, and each fact renders as one key: value line in the [User] block, on every turn.

No preset? Write the same object

auth takes either a preset’s result or an object you write, so a host with no identity vendor gets facts the same way — facts is a sibling of principal, resolved from the same request.
app/api/vendo/[...vendo]/route.ts
Both seams get the same Request, so cache your session decode if it is expensive — the shipped presets memoize theirs per request.
Facts go to the model verbatim. Put nothing in them you would not paste into a chat window: no tokens, no keys, no identifiers you rely on staying private.

The screen rides along already

You wire nothing for this. On every send, the widget snapshots the visible page — its URL and title, then headings, landmarks, links, buttons, table contents, form values, and control states — and attaches it as [Context]. The block is labeled as observation, so page text reads as evidence rather than as instructions to the model.

Publish what the page does not show

A cart total, a selected row id, a wizard step. useVendoContext merges your own data into the same [Context] block and retires it on unmount, so the agent never sees a screen the user has left.
app/checkout/payment-step.tsx
Several mounted callers coexist and merge, and on a repeated key the later one wins.

Keep something out

data-vendo-ignore drops an element and everything under it. Vendo’s own chrome carries it, so the widget never snapshots itself.
To stop page capture entirely, set captureScreen={false} on the provider. Data you publish through useVendoContext still rides.
app/layout.tsx

What actually reaches the model

  • [User] is server-trust. It comes from your resolver, on your server, on every request. The client cannot set it.
  • [Context] is client-trust, one turn only. The browser sends it, so the model reads it as evidence, never as authority — put anything you need trusted in facts. It is never written to the transcript, so the next turn on the same thread carries no context.
  • 8 KB, enforced twice. The client truncates before sending, and the server re-caps whatever arrives by dropping entries past the budget rather than refusing the turn.
  • Nothing can forge a section. Values render as key: value with every continuation line indented, so a fact cannot close its own block and impersonate one of Vendo’s.