The steps
1
Understand
The agent reads the question together with the conversation so far, detects the language the visitor is writing in, and rewrites the question into two focused search queries: one for knowledge, one for images. The answer will come back in the visitor’s language. A question that is off topic for the business skips retrieval entirely; the agent steers back politely instead of answering it.
2
Select topics and images, at the same time
Two fast model calls run in parallel. One picks which of the agent’s knowledge topics the question touches, choosing from each topic’s description of what it covers. The other picks candidate images from the agent’s registry, from a shortlist of id, kind, orientation and what each image shows. Never a URL. Images already shown in the conversation are excluded in code, not just in the prompt.
3
Synthesize each topic
Each selected topic gets its own synthesis, all in parallel, and each one runs its own retrieval.Retrieval is hybrid. A deterministic topic map and a vector search over the agent’s indexed passages run side by side and their rankings are fused, returning the eight best passages for that topic. The two halves fail differently on purpose: the topic map needs no model, no index and no network, so a page keeps answering when the vector half is unavailable or still warming up.The synthesis distills those passages into a short grounded summary of what the knowledge says about the question. One failed topic never sinks the turn; the builder works with the summaries that made it.
4
Build the answer
A single call composes the whole answer from the grounded summaries and the image shortlist: one to three components from the closed catalog, in order, plus the one-line spoken reply. Building writes copy; it does not go looking for new facts. A build that produces no valid component gets exactly one repair attempt before the turn errors.
5
Validate, sanitize, resolve
Every built component goes through the same pipeline, in that exact order, server-side:
- Validate the component’s props against its schema. Unknown fields are a rejection, not a silently dropped key.
- Sanitize every text field, leaving reference ids untouched.
- Resolve ids into real data: an image id becomes a signed URL from wondeya’s own storage, a link id becomes the URL you registered.
6
Stream
The page receives events over Server-Sent Events as they happen: the conversation id first, then a coarse status and a progress line while the turn is worked out, the written reply, each section exactly once with validated props ready to render, and finally the authoritative list of the sections that made it. There are no loading placeholders: a section appears when it is ready.