Prerequisites. Installed SDK · API key set · about 20 minutes. If you already built the RAG end-to-end guide, the KB you ingested there can be added as an
AgentTools lookup tool here.What you’ll build
1
Define the agent
Conversational agents combine an See
LlmInfo, instructions that scope behaviour, and a MemoryConfig so they remember turns within a session. Use type=AgentType.CONVERSATIONAL (functional agents use FUNCTIONAL).AgentTools exposes the platform’s full tool catalogue (exa_ai, google_search, wikipedia, …). The set available to your account depends on which integrations are enabled. exa_ai is the safe default for web search.Agent.new for every parameter and AgentType for the FUNCTIONAL vs CONVERSATIONAL split.2
Add a gated tool
ToolApprovalConfig has three values — pick REQUIRES_APPROVAL for anything sensitive. The fluent agent.add_tool.<name>(...) API lets you append tools after construction.AUTO_RUN— fires immediately.LET_AGENT_DECIDE— the model picks whether to ask.REQUIRES_APPROVAL— always pauses forsession.respond(...).
tool-approval-config example for variations.3
Start a session and stream the reply
Conversational agents run inside a Filter
Session — async context manager, multi-turn, streaming events. Events have direct attributes: event.delta (the token chunk), event.is_complete (turn finished), event.text (the full final reply).listen() with event_types=[...] to skip the noise — but only when you don’t need tool / approval events. The next steps show the full-event listening loop.4
Observe tool events
Subscribe to the unfiltered event stream to see
THINKING, TOOL_CALL, SEARCH_RESULT, and TOOL_RESULT events as the agent works.5
Approve or reject gated tool calls
When the model wants to call a tool gated with
REQUIRES_APPROVAL, the session emits an APPROVAL_REQUEST event and the turn pauses. Resume it with session.respond(event, approved=True | False).session.respond_approval(event, approved=, confirm=, deny_reason=) is the richer form — confirm={...} lets you override the arguments the model proposed, deny_reason="..." is surfaced back to the model when rejecting.6
Multi-turn memory
With
enable_session_memory=True, the agent remembers context across turns within the same session. No glue code required.7
Resume a session later
Sessions are stateful on the server. Disconnect now, resume from any process by Useful for long-lived chats (email, SMS, async support tickets). See the
session_id — no Agent object needed.session-resume example.Operational tips
- Pick approval mode per tool. Use
REQUIRES_APPROVALfor anything that mutates customer data;AUTO_RUNfor read-only retrieval;LET_AGENT_DECIDEonly when you trust the model to ask itself. - Always use
async with. It cleans up the websocket on every exit path, including exceptions. Otherwise you can leak connections on errors. - Catch
SessionDisconnectedError. Websockets drop. Surface to the UI and reconnect withSession(session_id=...). See Session errors. - Log every
session.responddecision. The audit trail for sensitive tools lives in your code, not the agent transcript. - Add a KB tool. If you built RAG end-to-end, wire its pipeline as a tool the agent can call when it needs to answer from your docs.
What’s next
Background batch
For non-conversational long-running work.
Tool approval example
Just the approval-config pattern, isolated.
Agent reference
Every public method on
Agent and Session.