Portal Community

Session Lifecycle

1

Session Start

A new ConversationComposite is created when a user sends their first message. The session ID is either provided by the client (for resuming) or generated fresh.

2

Active Turns

Each user message + agent response pair adds to Messages. Tool calls are recorded in ToolCalls. Working memory context is rebuilt on each turn.

3

Session End

The session ends via explicit close (user ends chat), timeout (configurable idle timeout), or agent decision. At close, the full conversation is persisted as an episode.

4

Episode Persisted

The episodic memory store saves the full message history. The episode is indexed for future semantic search if embedding is enabled.

Message Types in the Conversation

RoleWhen AddedContent
systemSession startAssembled system prompt from AgentComposite
contextBefore each user turnInjected semantic + episodic memory results
userEach user messageThe user's text input
assistantEach LLM responseAgent's response text or tool call directive
toolAfter tool executionTool execution result fed back to LLM

Context Preservation Across Turns

The WorkingMemoryManager rebuilds the context window on every turn. It reads from the ConversationComposite's message list and prunes as needed to stay within the token budget:

public class WorkingMemoryManager
{
    public async Task<IReadOnlyList<LLMMessage>> BuildContextAsync(
        ConversationComposite conversation,
        AgentComposite agent,
        string newUserMessage)
    {
        var budget = agent.MemoryConfig.MaxWorkingMemoryTokens;
        var messages = new List<LLMMessage>();

        // 1. System prompt (always first, always included)
        messages.Add(new LLMMessage(Role.System, agent.SystemPrompt));

        // 2. Semantic memory retrieval
        var retrieved = await _semanticStore.SearchAsync(
            agent.Id, newUserMessage, agent.MemoryConfig.SemanticTopK);
        if (retrieved.Any())
            messages.Add(new LLMMessage(Role.Context, FormatRetrieved(retrieved)));

        // 3. Message history (with pruning)
        var history = PruneToFit(conversation.Messages, budget - CountTokens(messages));
        messages.AddRange(history);

        // 4. Current user message
        messages.Add(new LLMMessage(Role.User, newUserMessage));

        return messages;
    }
}

Tool Call Recording

Every tool call made during a conversation is recorded in the ToolCalls collection. This serves two purposes: audit trail and context for subsequent turns.

public class ToolCallRecord
{
    public Guid Id { get; init; }
    public string ToolName { get; set; }
    public JsonDocument Input { get; set; }
    public JsonDocument? Output { get; set; }
    public bool Succeeded { get; set; }
    public string? ErrorMessage { get; set; }
    public DateTimeOffset CalledAt { get; init; }
    public TimeSpan Duration { get; set; }
}

Multi-Session Context

When a user returns for a new session, the new ConversationComposite does not automatically have the history of past sessions. Past context arrives through episodic memory retrieval — the MemoryOrchestrator searches past episodes for semantically relevant content and injects it as context messages.

Session ID Strategy

For web chat: session ID is stored in the browser session. For embedded widgets: the host application can provide a stable session ID to allow resuming. For API callers: pass sessionId in the request body. If omitted, a new session is always created.