AI agents: Reading conversation history
-
AI agent conversations can be read using the
GetConversationMessagesmethod. -
By default, the method returns the whole conversation in one call, oldest first.
A long conversation can be read in fixed-size pages instead, by paging back through earlier history or forward to newer messages. -
Even a long conversation that has been trimmed or summarized over time is returned as a single chronological list of messages.
-
This page covers: reading and paging through a conversation's messages, choosing the level of detail, and inspecting tool calls and sub-conversations.
-
Learn how to create and run a conversation in Managing conversations.
-
In this article:
Get the conversation messages
To read a conversation's messages, call GetConversationMessages (or GetConversationMessagesAsync)
and pass the conversation document ID.
GetConversationMessages returns an AiConversationMessagesResult object that includes a Messages
list, holding the conversation's messages in chronological order, oldest first.
If no conversation with the given ID exists, the method returns null.
Passing only a conversation ID returns the whole conversation in one call: PageSize, the maximum
number of messages in a page, defaults to int.MaxValue, so no page limit applies.
To read the conversation in fixed-size pages, set PageSize and read it a page at a time, as explained in
Page through the conversation.
At the default Simple detail level, the result holds the messages between the user and the LLM.
See Control the level of detail
for the other detail levels and the message types each level includes.
Example: Read a conversation
// Read the whole conversation (Simple view)
AiConversationMessagesResult result =
await store.AI.GetConversationMessagesAsync("Chats/1-A");
// Messages are returned in chronological order (oldest first)
foreach (AiConversationMessage message in result.Messages)
{
Console.WriteLine($"[{message.Role}] {message.Content}");
}
Besides the messages, the result includes, among others:
LastMessageAt
The time the last message was added to the conversation.TotalUsage
The cumulative token usage across the whole conversation.HasMoreMessages
truewhen the conversation holds more messages beyond the returned page.
See GetConversationMessages and AiConversationMessagesResult in the Syntax section.
Page through the conversation
A single call to GetConversationMessages returns one page of messages, up to PageSize.
By default, the page holds the conversation's most recent messages.
To select another page, pass a GetConversationMessagesOptions object instead of a bare conversation ID:
- Set
Beforeto a timestamp to read the page of messages immediately before it. - Set
Afterto a timestamp to read the page of messages immediately after it.
Before and After are mutually exclusive: a call sets one or the other, never both.
The returned page is always ordered oldest to newest. Before, After, and PageSize decide only the messages a page covers, not their order.
Example: Page back through a conversation
// Read the most recent page
var page = await store.AI.GetConversationMessagesAsync(
new GetConversationMessagesOptions
{
ConversationId = "Chats/1-A",
PageSize = 20
});
// Read the previous page
var previousPage = await store.AI.GetConversationMessagesAsync(
new GetConversationMessagesOptions
{
ConversationId = "Chats/1-A",
// the oldest message's Timestamp
Before = page.Messages[0].Timestamp,
PageSize = 20
});
In the example above, Before is set to the Timestamp of the oldest message on the page just
read. However, Before and After accept any DateTime value, not only a message's Timestamp, so a
page can start at any point in time, without first reading a page.
Consecutive pages are contiguous, with no gap and no overlap. On the result, HasMoreMessages is true
when the conversation holds more messages beyond the page just returned. The further messages are
older when Before is set (or when neither Before nor After is set), and newer when
After is set. To read the whole conversation one page at a time, call GetConversationMessages again while
HasMoreMessages is true.
Catch up on new messages
To catch up after new messages arrive, pass the Timestamp of the newest message already retrieved,
using After. GetConversationMessages then returns only the messages added since the last read,
not the whole conversation.
// Read only the messages added after the newest message already retrieved
var newMessages = await store.AI.GetConversationMessagesAsync(
new GetConversationMessagesOptions
{
ConversationId = "Chats/1-A",
After = lastSeenTimestamp
});
See GetConversationMessagesOptions in the Syntax section.
Control the level of detail
Use the DetailLevel option to control the level of detail in the result.
Simple, the default, returns only the messages between the user and the LLM, the visible
part of the conversation.
The higher levels include additional detail: system prompts, tool calls, summaries,
and internal messages.
Raise the level when debugging an agent or inspecting its steps.
Each level includes a different set of messages:
| Detail level | Messages returned |
|---|---|
Simple | User messages (including those that carry only an attachment) and the LLM's messages that have content. System prompts, tool calls, summaries, and internal messages are excluded. |
Detailed | Everything in Simple, plus system prompts and tool calls with their results. Summaries and internal messages are excluded. |
Full | Everything in Detailed, plus summaries and internal messages. Intended for debugging. |
Example: Request the detailed view
// Request the detailed view, e.g. for debugging
var detailed = await store.AI.GetConversationMessagesAsync(
new GetConversationMessagesOptions
{
ConversationId = "Chats/1-A",
DetailLevel = AiConversationDetailLevel.Detailed,
PageSize = 50
});
See AiConversationDetailLevel in the Syntax section.
Inspect tool calls and sub-conversations
At the Detailed or Full detail level, the ToolCalls list of a message from the LLM holds
the tool calls the LLM made. Each entry is an AiToolCallResult object, giving the tool's Name, the
Arguments the LLM passed, and the Result the tool returned.
An agent can hand work to another agent (a sub-agent).
The exchange with a sub-agent is held in its own conversation (a sub-conversation).
When a tool call invoked a sub-agent, the tool call's SubConversationId points to the
resulting sub-conversation. The result's SubConversationIds list gathers every sub-conversation
started during this conversation. Pass any ID from SubConversationIds to GetConversationMessages to read the
matching sub-conversation.
Example: Read tool calls and sub-conversations
// Read the conversation with tool calls included
var trace = await store.AI.GetConversationMessagesAsync(
new GetConversationMessagesOptions
{
ConversationId = "Chats/1-A",
DetailLevel = AiConversationDetailLevel.Detailed,
PageSize = 50
});
foreach (AiConversationMessage message in trace.Messages)
{
if (message.ToolCalls == null)
continue;
foreach (AiToolCallResult toolCall in message.ToolCalls)
{
// Inspect the tool call and the result returned
Console.WriteLine($"{toolCall.Name}({toolCall.Arguments}) -> {toolCall.Result}");
// If the tool call invoked a sub-agent, read the matching sub-conversation
if (toolCall.SubConversationId != null)
{
var subConversation = await store.AI.GetConversationMessagesAsync(
new GetConversationMessagesOptions
{
ConversationId = toolCall.SubConversationId,
DetailLevel = AiConversationDetailLevel.Detailed
});
Console.WriteLine($" sub-conversation with {subConversation.Messages.Count} messages");
}
}
}
See AiConversationMessage
and AiToolCallResult
in the Syntax section.
See Multi-agents for the full sub-agent picture.
Syntax
Methods
Conversation history
- GetConversationMessages
Reads messages from an AI agent conversation.
The conversation-ID overload returns the whole conversation at the default Simple detail level.
The options overload gives full control over paging and the level of detail.
// Async, returns the whole conversation
public Task<AiConversationMessagesResult> GetConversationMessagesAsync(
string conversationId, CancellationToken token = default)
// Async, with paging and detail options
public Task<AiConversationMessagesResult> GetConversationMessagesAsync(
GetConversationMessagesOptions parameters, CancellationToken token = default)
// Sync, returns the whole conversation
public AiConversationMessagesResult GetConversationMessages(string conversationId)
// Sync, with paging and detail options
public AiConversationMessagesResult GetConversationMessages(GetConversationMessagesOptions parameters)
Usage:
var result = await store.AI.GetConversationMessagesAsync("Chats/1-A");
| Parameter | Type | Description |
|---|---|---|
| conversationId | string | The conversation document ID. The overload that takes only this ID returns the whole conversation at the default Simple detail level. |
| parameters | GetConversationMessagesOptions | The Before and After boundaries, page size, and detail level. |
| token | CancellationToken | Optional cancellation token. |
| Return value | |
|---|---|
AiConversationMessagesResult | The conversation's messages, in chronological order, with paging and usage metadata. |
Classes
Conversation history classes
- GetConversationMessagesOptions
- AiConversationMessagesResult
Parameters for reading messages from an AI agent conversation.
class GetConversationMessagesOptions
{
string ConversationId
DateTime? Before
DateTime? After
int PageSize
AiConversationDetailLevel DetailLevel
}
| Property | Type | Description |
|---|---|---|
| ConversationId | string | The conversation document ID. Required. |
| Before | DateTime? | Return messages older than this timestamp (exclusive). Interpreted as UTC. Used to page back to earlier messages. Cannot be combined with After. |
| After | DateTime? | Return messages newer than this timestamp (exclusive). Interpreted as UTC. Used to catch up on new messages. Cannot be combined with Before. |
| PageSize | int | Maximum number of messages to return. Default: int.MaxValue. Must be greater than 0; a value of 0 or less throws an ArgumentOutOfRangeException. |
| DetailLevel | AiConversationDetailLevel | The level of detail to include in the returned messages. Default: Simple. |
The result of reading conversation messages.
class AiConversationMessagesResult
{
string ConversationId
string Agent
Dictionary<string, object> Parameters
AiUsage TotalUsage
DateTime LastMessageAt
List<AiConversationMessage> Messages
bool HasMoreMessages
List<string> SubConversationIds
List<string> Attachments
}
| Property | Type | Description |
|---|---|---|
| ConversationId | string | The conversation document ID. |
| Agent | string | The identifier of the AI agent this conversation belongs to. |
| Parameters | Dictionary<string, object> | The conversation parameters as a name-to-value map. |
| TotalUsage | AiUsage | Cumulative token usage across all turns of the conversation. See AiUsage. |
| LastMessageAt | DateTime | The time the last message was added to the conversation. |
| Messages | List<AiConversationMessage> | The returned messages, in chronological order (oldest first). |
| HasMoreMessages | bool | true when more messages exist beyond the returned page: older messages when Before is set (or neither is set), newer messages when After is set. |
| SubConversationIds | List<string> | IDs of sub-agent conversations spawned during this conversation. Each can be read separately using GetConversationMessages. |
| Attachments | List<string> | Names of all attachments referenced across the conversation. |
- AiConversationMessage
- AiToolCallResult
A single message in a conversation.
class AiConversationMessage
{
AiMessageRole Role
string Content
List<string> Attachments
DateTime Timestamp
List<AiToolCallResult> ToolCalls
AiUsage Usage
string SubConversationId
}
| Property | Type | Description |
|---|---|---|
| Role | AiMessageRole | What the message is: a system prompt, a user message, a message from the LLM, a summary, or an internal message. See AiMessageRole. |
| Content | string | The text content. When the stored message has several text parts, they are joined with line breaks. null for a message from the LLM that only initiated tool calls. |
| Attachments | List<string> | Names of the attachments associated with this message, if any. |
| Timestamp | DateTime | The time the message was recorded (UTC). Unique within the conversation and rising in message order, so a Timestamp value can be used to page through the conversation. |
| ToolCalls | List<AiToolCallResult> | Tool calls initiated by the LLM in this message, with their results inlined. null when the message has no tool calls. |
| Usage | AiUsage | Token usage for this message, or null for messages the LLM did not generate (such as user messages and system prompts).See AiUsage. |
| SubConversationId | string | For an Internal role message, the ID of the sub-conversation the message relates to. |
A tool call made during the conversation, and the result returned.
class AiToolCallResult
{
string Id
string Name
string Arguments
string Result
string SubConversationId
}
| Property | Type | Description |
|---|---|---|
| Id | string | The tool call ID from the LLM. |
| Name | string | The tool name. |
| Arguments | string | The arguments the LLM passed, as a JSON string. |
| Result | string | The tool's response content. null if the tool call is still pending. |
| SubConversationId | string | If the tool call invoked a sub-agent, the ID of the spawned sub-conversation. The sub-conversation can be read separately using GetConversationMessages. |
Enums
Conversation history enums
- AiConversationDetailLevel
- AiMessageRole
Controls the level of detail the returned messages carry.
enum AiConversationDetailLevel
{
Simple,
Detailed,
Full
}
| Value | Description |
|---|---|
| Simple | User messages (including those that carry only an attachment) and the LLM's messages that have content. System prompts, tool calls, summaries, and internal messages are excluded. |
| Detailed | Adds system prompts and tool calls with their results. Summaries and internal messages are excluded. |
| Full | Everything in Detailed, plus summaries and internal messages. Intended for debugging. |
The kind of message in a conversation.
enum AiMessageRole
{
System,
User,
Assistant,
Summary,
Internal
}
| Value | Description |
|---|---|
| System | A system prompt message. |
| User | A message from the user. |
| Assistant | A message from the LLM, which may carry content, tool calls, or both. |
| Summary | A summary produced when the conversation was trimmed. |
| Internal | An internal message that relates to a sub-conversation, linked by its SubConversationId. |