Skip to main content

Chat — client.chat

:::info Requires bessai ≥ 0.2.0 The chat namespace ships in SDK version 0.2.0pip install --upgrade bessai (check with bessai.__version__). :::

Deploy the same agents you use for voice — prompt, LLM, tools, skills, knowledge bases, MCP — as text chat, over a synchronous REST transport or a realtime LiveKit text room. Chat sessions are a separate resource from calls (no CallResponse/calls row is involved).

create(**params) → ChatSession

POST /v1/chat/sessions — create a chat session for a published agent.

ParamTypeRequiredDefaultDescription
agent_idstryesUUID of the published agent.
transportstrno"rest""rest" (reply via send_message()) or "livekit" (text-only room).
channel_typestrno"api""api", "web_widget", or "dashboard_test".
dynamic_variablesdict[str,str]noNoneValues injected into the system prompt.
external_user_keystrnoNoneYour end-user's stable id — threads their sessions together.

transport="rest" sessions carry the agent's opening line in session.greeting (None if the agent has no greeting configured) — reply via send_message(). transport="livekit" sessions return session.access_token / session.room_url / session.room_name for a text-only LiveKit room instead — connect with the LiveKit JS/Web SDK and exchange text over the lk.chat topic; greeting is None there (the chat worker sends it over the room).

session = client.chat.create(agent_id="ag_abc123", external_user_key="visitor-42")
print(session.greeting.content) # "Hi! How can I help you today?"

create_test_session(**params) → ChatSession

POST /v1/chat/test — mirror of call.create_test_call(): accepts draft agents and a temp_config dict of non-persisted overrides. REST transport only — the fastest loop for iterating on a prompt. Params: agent_id, temp_config, dynamic_variables.

send_message(session_id, content) → ChatTurnResult

POST /v1/chat/sessions/{id}/messages — send a user message on a REST-transport session and get the assistant's reply (synchronous JSON). Raises on livekit-transport sessions (409) — those talk over the room's lk.chat text stream instead. content is 1–4,000 characters.

ChatTurnResult fields: session_id, assistant_content, tool_calls (list of {"name","arguments","output"}), tokens_in, tokens_out, session_closed (bool — true if this turn closed the session), close_reason (agent_end_chat | message_cap | insufficient_credits | explicit_close | None), user_message_id, assistant_message_id.

reply = client.chat.send_message(session.session_id, "Do you have a table for 4 tonight?")
print(reply.assistant_content, reply.session_closed)

retrieve(session_id, skip=0, limit=50) → ChatSessionDetail

GET /v1/chat/sessions/{id} — session detail plus the paginated message thread (oldest first). Extends ChatSession with dynamic_variables, session_metadata, and messages (list[ChatMessage]).

list(skip=0, limit=20, agent_id=None, status=None, channel_type=None, from_date=None, to_date=None) → list[ChatSession]

GET /v1/chat/sessions — your org's sessions, newest first. statusactive|idle|closed; channel_typeapi|web_widget|dashboard_test.

close(session_id) → ChatSessionCloseResult

POST /v1/chat/sessions/{id}/close — explicitly close a session; queues the post-chat pipeline (summary/sentiment/automation). Raises if already closed.

ChatSession fields: session_id, organization_id, agent_id, agent_version, channel_type, widget_id, external_user_key, status (activeidleclosed), livekit_room_name, message_count, agent_reply_count, total_tokens_in, total_tokens_out, summary, sentiment, session_cost, processing_status, started_at, last_message_at, closed_at, created_at, plus greeting/access_token/room_url/room_name on the create() response only. ChatMessage fields: message_id, session_id, role (user|assistant|tool|system), content, tool_calls, tokens_in, tokens_out, created_at.

Full turn loop (Python):

session = client.chat.create(agent_id="ag_abc123", external_user_key="visitor-42")
if session.greeting:
print("agent:", session.greeting.content)

for user_msg in ["Hi, do you have a table for 4?", "Tonight at 8pm works great."]:
print("user:", user_msg)
reply = client.chat.send_message(session.session_id, user_msg)
print("agent:", reply.assistant_content)
if reply.session_closed:
break

client.chat.close(session.session_id)

Cost & limits: chat is billed per agent reply (use agent_reply_count / total_tokens_in/total_tokens_out to reconcile); input messages are capped at 4,000 characters; output is capped by the agent's max_completion_tokens; each turn sends the last 30 messages of history to the LLM. See the Partner API Guide's rate/cost notes for the full picture, including the credit-sufficiency gate.