Skip to main content
By the end of this guide you’ll have a conversational support agent that can answer questions, search the web for fresh info, escalate sensitive actions for human approval, and remember context across turns.
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 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.
See 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.
Three approval modes:
  • AUTO_RUN — fires immediately.
  • LET_AGENT_DECIDE — the model picks whether to ask.
  • REQUIRES_APPROVAL — always pauses for session.respond(...).
See tool-approval-config example for variations.
3

Start a session and stream the reply

Conversational agents run inside a 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).
Filter 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 session_id — no Agent object needed.
Useful for long-lived chats (email, SMS, async support tickets). See the session-resume example.

Operational tips

  • Pick approval mode per tool. Use REQUIRES_APPROVAL for anything that mutates customer data; AUTO_RUN for read-only retrieval; LET_AGENT_DECIDE only 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 with Session(session_id=...). See Session errors.
  • Log every session.respond decision. 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.