run(). The Turn it hands
back is awaitable and iterable: run.events is the live feed, and awaiting the
same object gives you the TurnResult at the end.
Vendo’s chat UI is not handed over here, deliberately: this lane gives you an
event stream and a result, and the surface is yours to build. For a chat
surface with no work at all,
handler() plus
useVendoChat is one mount; for Vendo’s own thread,
overlay, and generated screens, see
Vendo’s Full-Stack Agent.The route
app/api/reports/route.ts
run.threadIdis available immediately, before the first event, so the header goes out with the response rather than after it.signal: req.signalties the run to the connection. The browser closes the tab, the request aborts, the run stops.await runafter the loop is the result. Iterating the events does not consume it; the same object is both.
What comes over the wire
run.events yields RunEvents, each tagged by type.
Forward them whole, as above, and branch in your UI. A new event type then
reaches your client the day it ships, instead of being dropped by a server that
only knew five.
Ending on the result
TheTurnResult is the honest close: status, the model’s own text, the
toolCalls it made, threadId, turnId, and usage. One status decides
which of the four screens you draw.
app/reports-client.ts
interrupted, and the cards are on
interruptions. Carrying on is resume(decisions) on the server-side object,
not a fresh run() — the turn picks up from where it stopped.
Run
The result shape, typed output, and the usage you meter on.
Telemetry
The same runs, seen from your Cloud console.