- Guarded tools. Your host actions and connected-account tools, with every call routed through policy, approval, and audit. The pack wraps the same guard-bound registry Vendo’s own loop uses, so no tool reachable from your loop has an unguarded route.
- Generated UI in your chat. A
vendo_create_apptool builds live, interactive apps that render inline in your own chat surface via embed components. - Vendo as a delegate. A
vendo_delegatetool hands Vendo’s agent a whole task and returns the run report.
AI SDK walkthrough
The unmodified Next.js quickstart chatbot plus a four-touch diff.
Mastra walkthrough
The create-mastra weather starter plus the same four touches.
The composition
You runcreateVendo and mount the wire route exactly as the
quickstart describes. What you drop is Vendo’s chat loop and
chat UI. The wire keeps serving apps, approvals, and connected accounts to
the embeds: Vendo minus the conversation.
@vendoai/vendo/ai-sdkexportsvendoTools(vendo, { principal }), an AI SDKToolSetforstreamTextandgenerateText. Built per request, because tool execution needs a principal-scoped context.@vendoai/vendo/mastraexportsvendoMastraTools(vendo), the same pack in MastracreateToolshape forAgent({ tools }). Mastra agent definitions are static, so the caller’s principal resolves per call from Mastra’s request context instead.
The tool pack
Every pack tool is namespacedvendo_* to avoid collisions with your own
tools. A registered host action host_x ships as vendo_host_x; two
built-ins are already prefixed:
include and exclude filter the pack by final (namespaced) tool name,
exact match. include unset means the whole pack; exclude wins over
include.
Approvals in your loop
A guarded call that needs approval does not throw and does not block your loop. The tool returns the approval-ref envelope immediately, so your model sees “pending, the user must approve in the UI”. The pending call parks server-side. When the user approves in<VendoApprovalEmbed>, the wire
executes the parked call and the embed resolves in place to the executed
result. Deny resolves it to “declined” and discards the parked call.
Parked calls expire on a TTL sweep, 60 minutes by default. Tune it with
createVendo({ approvals: { parkedCallTtlMs } }); 0 disables expiry. An
expired call resolves the embed to “expired” and never runs.
Your agent learns the outcome on a later turn if it matters. This is the
same eventual consistency Vendo’s own thread uses for abandoned approvals,
in a new venue.
See Embeds and envelopes for the envelope
contract and the three @vendoai/ui embed components that render it inside
your own chat.
Two models, deliberately
Your agent keeps its own model. Vendo’smodel seam still powers app
generation and the delegate: an explicit createVendo({ model }) wins, and
when you omit it Vendo resolves one through the
dev-mode credential ladder. In the common case that
means zero extra model config.
In-process vs. the MCP door
This seam is for your own agent running in your own backend, in process withcreateVendo. If you want third-party agents (Claude, ChatGPT,
Cursor) to reach your product from outside, that is the
MCP door.