messages.create yourself and you
handle the tool turns yourself.
One method gives you that loop’s half of the door.
agent.ts
door.tools is already the shape
messages.create takes, and door.results already returns the shape you push
back.
Who the agent acts as
Pass the incoming request and Vendo reads the signed-in user off its session cookie, through the same seam the door authenticates with. Pass a user id instead — one of your ids, spelled the way your product spells it — and the agent acts as that person from a cron or a queue worker.jobs/nightly.ts
null, undefined — is refused here rather than acting as a
user nobody is.
One door per conversation
Open it once and keep it for the whole conversation. The session it holds is what a parked approval resumes on, so an agent that opens a new door per tool call parks forever. Inside that conversation, nothing else is yours to manage. A ten-minute badge that runs out, or a session the door has forgotten, is re-established on the next call and the call goes through.Approvals
door.results never throws for a guarded call. If your policy parks one, the
result block carries the sentence the model should read —
This action needs approval. Approval apr_… is waiting in Maple’s Vendo
approvals queue — resolve it there, then retry.
— and door.embeds grows a typed vendo/approval-ref@1 for your own code:
<VendoApproval>, with the wire the decision is spent on:
app/chat.tsx
Long calls
Generating a screen withvendo_make runs longer than a stock 60-second tool
call, and door.results waits for it — the door beats progress frames and this
client has no deadline of its own to give up on.
Under the hood
The door is a stock MCP server over streamable HTTP, andagentTools is a
client for it: it mints a short-lived user-bound token with
vendo.tokenFor, opens one MCP session at
/api/vendo/mcp, lists tools, and calls them. If you would rather hold that
client yourself — your own MCP SDK, your own session policy, a language that is
not TypeScript — tokenFor is the only Vendo-shaped part and the rest is the
protocol: