Sessions
Sessions
A session represents a continuous interaction between an agent and a customer.
When we want to start a new interaction between a customer and an agent, we create a new session for that. Each customer can have as many different sessions with an agent as is desired, and different agents can interact with the same customers—albeit in different sessions.
Session Storage
Sessions are stored in a database, and you can have as many of them as you'd like. It all depends on your storage capacity—but keep in mind that storing sessions for an extended period of time can be a good way to gather data for later analysis and improvement of the conversation experience.
Session Observability
In addition to the conversational details themselves, a session also stores information pertaining to the generative process of the agent's responses:
- An explanation of how the agent interpreted each stage of the conversation
- The guidelines that were activated for each agent response
- The time it took for the agent to respond
- The breakdown of generative models and tokens used for each response
This additional information serves to make it as simple as possible to understand and optimize an agent's behavior.
By default, an agent's memory about a particular customer is confined to a session. However, we can implement persistent memory for customers using context variables.
Session Events
Think of a session in Parlant as a timeline of everything that happens in a conversation.
Each moment in this timeline—whether it's someone speaking, the agent thinking, or a system update—is captured as an event. These events line up one after another, each with its own position number (called its offset), starting from 0.
From a simplistic perspective, when a conversation unfolds, it creates a sequence of these events. A user might start the session by saying "Hello"—that's event 0. The system then notes that the agent is preparing a response by outputting a status event—that's event 1. The agent's "Hi there!" becomes event 2, and so on. Each event, whether it's a message being exchanged, the agent typing, or even an error occurring, takes its place in this ordered sequence.
Every event in this sequence carries important information: what type of event it is (like a message or a status update), what actually happened (the data), and when it occurred. This creates a complete record of the conversation that helps us understand exactly how things unfolded, making it easier to track the conversation's state, handle any issues that arise, or review the interaction later.
Each event is also associated with a correlation ID. This ID primarily helps to correlate between AI-generated messages and the tool events that fed data into them. This lets us easily fetch and display the data that went into generated messages. A common use case for this is to show "sources" or "footnotes" under agent messages in our frontend.
Event-Driven Communication
Unlike traditional LLM APIs where you send a prompt and wait for a direct response, Parlant agents operate more like real conversation partners.
Much like a human service representative, they process information and decide when and how to respond based on their understanding of the context. This means we need to approach communication with them differently.
Instead of the familiar request-response pattern of completion APIs, Parlant uses an event-driven model. When you send a message to an agent, you're really adding an event to their conversation stream. The agent then processes this independently, potentially generating multiple events in response—they might acknowledge receipt, indicate they're thinking, ask for clarification, or provide a full response.
This more natural conversation flow requires us to listen for events—ideally in asynchronous fashion—rather than waiting for an immediate response.
Here's a simple, synchronous example of how this looks in practice:
- Python
- TypeScript
from parlant.client import ParlantClient
client = ParlantClient(base_url=SERVER_ADDRESS)
# Post customer message
customer_message_event = client.sessions.create_event(
session_id=SESSION_ID,
kind="message",
source="customer",
message=MESSAGE,
)
# Wait for and get the agent's reply
agent_message_event = client.sessions.list_events(
session_id=SESSION_ID,
kinds="message",
source="ai_agent",
min_offset=customer_message_event.offset,
wait_for_data=60, # wait for up to 60 seconds for an answer
)[0]
# Print the agent's reply
print(agent_message_event.data)
# Inspect the details of the message generation process
agent_message_trace = client.sessions.inspect_event(
SESSION_ID,
agent_message_event.id,
).trace
import { ParlantClient } from 'parlant-client';
const client = new ParlantClient({ environment: SERVER_ADDRESS });
// Post customer message
const customerMessageEvent = await client.sessions.createEvent(SESSION_ID, {
kind: "message",
source: "customer",
message: MESSAGE,
});
// Wait for and get the agent's reply
const [agentMessageEvent] = (await client.sessions.listEvents(SESSION_ID, {
kinds: "message",
source: "ai_agent",
minOffset: customerMessageEvent.offset,
waitForData: 60 // wait for up to 60 seconds for an answer
}));
// Print the agent's reply
const { message } = agentMessageEvent.data as { message: string };
console.log(message);
// Inspect the details of the message generation process
const { trace } = await client.sessions.inspectEvent(
SESSION_ID,
agentMessageEvent.id
);
Event Kinds
There are two kinds of events you really need to know: message
and status
.
Message Event
A message event, as its name suggests, represents a message written by someone. There are several possible sources for a message within Parlant:
"customer"
: The message came from a customer (using some frontend application)"ai_agent"
: The message was auto-generated by an AI agent"human_agent"
: The message came from a human agent who took over the session"human_agent_on_behalf_of_ai_agent"
: The message came from a human message, but for all intents and purposes (both within Parlant and to the customer) appears to have come from an AI agent
Message Event Structure
{
id: EVENT_ID,
kind: "message",
source: EVENT_SOURCE,
offset: N,
correlation_id: CORRELATION_ID,
data: {
message: MESSAGE,
participant={
id: PARTICIPANT_ID,
display_name: PARTICIPANT_DISPLAY_NAME
}
}
}
Status Event
A status event represents an update on the status of the AI agent, and currently always has the source "ai_agent"
.
Status events are great for displaying conversational updates during a chat with a customer. For example, you can have your frontend indicate when the agent is thinking or typing. There are 6 kinds of status events that you can make use of:
"acknowledged"
: The agent has acknowledged the customer's message and started working on a reply"cancelled"
: The agent has cancelled its reply in the middle, normally because new data was added to the session"processing"
: The agent is evaluating the session in preparation for generating an appropriate reply"typing"
: The agent has finished evaluating the session and is currently generating a message"ready"
: The agent is idle and ready to receive new events"error"
: The agent encountered an error while trying to generate a reply
Status Event Structure
{
id: EVENT_ID,
kind: "status",
source: "ai_agent",
offset: N,
correlation_id: CORRELATION_ID,
data: {
status: STATUS_KIND,
data: OPTIONAL_DATA
}
}
API Highlights
Creating a new session
- CLI
- Python
- TypeScript
$ parlant session create \
--agent-id AGENT_ID \
--customer-id CUSTOMER_ID \
--title TITLE
from parlant.client import ParlantClient
client = ParlantClient(base_url=SERVER_ADDRESS)
session = client.sessions.create(
agent_id=AGENT_ID,
customer_id=CUSTOMER_ID, # Optional: defaults to the guest customer's ID
title=SESSION_TITLE, # Optional: session can be untitled
allow_greeting=False, # Optional: allow the agent to actively start the chat
)
import { ParlantClient } from 'parlant-client';
const client = new ParlantClient({ environment: SERVER_ADDRESS });
const session = await client.sessions.create({
agentId: AGENT_ID,
customerId: CUSTOMER_ID, // Optional: defaults to the guest customer's ID
title: SESSION_TITLE, // Optional: session can be untitled
allowGreeting: false, // Optional: allow the agent to actively start the chat
});
Listing status events
- CLI
- Python
- TypeScript
$ parlant session view \
--id SESSION_ID \
from parlant.client import ParlantClient
client = ParlantClient(base_url=SERVER_ADDRESS)
status_events = client.sessions.list_events(
session_id=SESSION_ID,
min_offset=MIN_OFFSET,
kinds="status",
)
import { ParlantClient } from 'parlant-client';
const client = new ParlantClient({ environment: SERVER_ADDRESS });
const statusEvents = await client.sessions.list_events(SESSION_ID, {
minOffset: MIN_OFFSET,
kinds: "status",
});
Listing sessions
- CLI
- Python
- TypeScript
$ parlant session list \
--agent-id AGENT_ID \
--customer-id CUSTOMER_ID
from parlant.client import ParlantClient
client = ParlantClient(base_url=SERVER_ADDRESS)
sessions = client.sessions.list(
agent_id=AGENT_ID, # Optional: filter by agent ID
customer_id=CUSTOMER_ID, # Optional: filter by agent ID
)
import { ParlantClient } from 'parlant-client';
const client = new ParlantClient({ environment: SERVER_ADDRESS });
const sessions = await client.sessions.list({
agentId: AGENT_ID, // Optional: filter by agent ID
customerId: CUSTOMER_ID, // Optional: filter by customer ID
});