Context & Memory for Long Sessions

10 min read Module 3 of 9 Topic 9 of 25

What you'll learn

  • Explain why unbounded context growth is a bigger problem in real-time voice than in text chat
  • Design a sliding-window plus summarization strategy for long conversations
  • Persist session state so a call can survive a network reconnect without losing context
  • Estimate the cost impact of context growth in a per-minute-billed voice session
Building this at your company? For enterprise and company teams taking this to production: book a 30-minute session with our AI engineers for architecture guidance, code review, and a rollout plan for your use case.
Book a Team Session

A voice call doesn’t reset between turns the way a fresh chat session might feel like it does. A caller who mentioned their account number at minute two expects the agent to still know it at minute eleven, and every turn of this course’s pipeline has been built around a latency budget that gets harder to protect the longer a call runs. This final lesson of Module 3 is about the tension between those two facts: conversations need memory, and memory costs both time and money in a system billed and budgeted per turn.

Why context growth hurts more in real-time voice than in text chat

In a text chat product, a growing context window is mostly a cost concern, users tolerate a slightly slower response on message 40 of a long thread without much complaint, since they’re already reading at their own pace. In a voice pipeline, context growth is a latency concern first and a cost concern second, because every extra thousand tokens of conversation history re-sent on each turn adds real, felt milliseconds to time-to-first-token, directly eating into the sub-second budget established back in Lesson 2. A call that opens with 200ms LLM latency on turn one can drift to 600-800ms by turn thirty if context is left to grow unbounded, and that drift happens gradually enough that it’s easy to miss without the tracing infrastructure Module 7 covers.

Cost compounds the same way. Most LLM APIs bill per input token, and re-sending the full conversation history on every turn means a 30-turn call’s total token spend grows roughly quadratically with turn count, not linearly, since each new turn’s request includes every prior turn’s content again. For a high-volume support line handling thousands of calls a day, unmanaged context growth turns a call that should cost a few cents in LLM spend into one that costs several times that, purely from re-transmitted history.

Sliding window plus summarization

The standard fix is a two-tier memory structure: keep the most recent N turns verbatim (they’re the most likely to be referenced directly, and keeping them exact preserves nuance), and compress everything older into a compact running summary that gets prepended to every request instead of the full history.

flowchart TB
    NEW["New caller turn"] --> CTX["Assemble context:\nsummary + last N turns"]
    CTX --> LLM["Dialogue manager\nclaude-sonnet-5 / GPT-5"]
    LLM --> RESP["Response to caller"]
    RESP --> APPEND["Append turn to\nrecent-turns buffer"]
    APPEND --> CHECK{"Buffer exceeds\nN turns?"}
    CHECK -->|yes| SUMMARIZE["Summarize oldest turns\ninto running summary"]
    CHECK -->|no| STORE["Persist state\n(session store)"]
    SUMMARIZE --> STORE

    style NEW fill:#EEF0F7,stroke:#6366F1,color:#0F172A
    style CTX fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style LLM fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style RESP fill:#fff7ed,stroke:#f59e0b,color:#0F172A
    style APPEND fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style CHECK fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style SUMMARIZE fill:#f0fdf9,stroke:#0D9488,color:#0F172A
    style STORE fill:#fff7ed,stroke:#f59e0b,color:#0F172A

The summarization step itself is a small, cheap LLM call (a short prompt like “compress this conversation segment into 2-3 sentences preserving any account details, stated issues, and decisions made”) run off the critical path, typically triggered asynchronously once the buffer crosses its threshold rather than blocking the caller’s next turn. This is the detail that makes the pattern viable in real time: summarization happens in the background between turns, never in the foreground of the turn the caller is waiting on.

MAX_VERBATIM_TURNS = 6

async def assemble_context(session: SessionState) -> list[dict]:
    messages = []
    if session.running_summary:
        messages.append({
            "role": "system",
            "content": f"Conversation so far: {session.running_summary}",
        })
    messages.extend(session.recent_turns[-MAX_VERBATIM_TURNS:])
    return messages


async def maybe_summarize(session: SessionState):
    if len(session.recent_turns) <= MAX_VERBATIM_TURNS:
        return
    to_compress = session.recent_turns[:-MAX_VERBATIM_TURNS]
    session.recent_turns = session.recent_turns[-MAX_VERBATIM_TURNS:]

    summary_response = await llm.messages.create(
        model="claude-sonnet-5",
        max_tokens=150,
        messages=[{
            "role": "user",
            "content": (
                f"Existing summary: {session.running_summary or 'none'}\n"
                f"New turns to fold in: {format_turns(to_compress)}\n\n"
                "Update the summary in 2-3 sentences, preserving any "
                "account details, stated issues, and decisions made."
            ),
        }],
    )
    session.running_summary = summary_response.text
    await session_store.save(session)  # off critical path, fire-and-forget

Losing information by dropping old turns outright, instead of summarizing them, is the failure mode to watch for here. An account number given in turn 3 has to still be recoverable in turn 40, or the caller experiences the single most trust-eroding moment a long support call can produce: being asked to repeat something they already said.

Persisting state across reconnects

Mobile networks drop. A caller’s call can survive a brief network interruption at the transport layer (Module 5 covers reconnect logic for LiveKit and Twilio Media Streams specifically), but only if the conversation’s actual state, the running summary, recent turns, any tool results already gathered, caller or account identifiers, outlives the dropped connection. Keeping session state as an in-memory object tied to a single WebSocket connection means a reconnect is functionally a new, memoryless call; keeping it in an external store (a fast key-value store like Redis, keyed by a stable session or call ID issued at call start) means a reconnected client can rehydrate the exact same context and continue as if nothing happened.

This has a direct cost implication worth planning for: session state needs a retention and cleanup policy, since a support line handling meaningful call volume will otherwise accumulate an unbounded number of stale session records. A time-to-live on the order of the longest realistic hold-and-reconnect window (typically a few minutes) after the last activity on a session is usually enough, paired with a hard cleanup once a call is marked complete.

What this sets up

Everything built across this module, spoken-language prompting, tool calling with filler acknowledgments, and now bounded, persistent memory, forms the complete conversational core the rest of this course assumes is working. Module 4 picks up right where this leaves off, turning the dialogue manager’s streamed text output into natural-sounding, low-latency speech.

Knowledge Check

4 questions to test your understanding

1 A 12-minute support call accumulates a full, unsummarized transcript in the LLM context for every turn. What happens to both latency and cost as the call goes on, and why?

2 A sliding-window strategy keeps only the last N turns verbatim in context and periodically summarizes everything older into a compact running summary. What's the main risk if the summarization step is skipped and older turns are simply dropped instead?

3 A caller's mobile connection drops mid-call and reconnects 8 seconds later. What must the pipeline have in place for the conversation to resume naturally rather than restarting from scratch?

4 Why is a fixed, small context window (e.g. always just the last 3 turns, no summary) usually a poor fit for a long support call, even though it keeps cost and latency low?

Discussion

Questions and notes from learners on this topic

Loading discussion…

Go further with expert guidance

Ready to build production AI?
Talk to our R&D team.

These courses give you the foundation. Our embedded AI teams take you from prototype to production in 30–90 days, with your team, your codebase, your goals. Book a free strategy call to see how we can accelerate your AI initiative.

30 minutes · No obligation · Expert AI engineers, not sales reps

AI Architecture Review

Audit your current stack and identify high-impact improvements

Project Review

Get expert feedback on your AI implementation and codebase

Team Mentoring

Upskill your engineers with hands-on AI coaching sessions

AI Strategy

Define your AI roadmap, prioritization, and implementation plan