When the agent disconnected and reconnected he los...
# ask-ai
p
When the agent disconnected and reconnected he lost the context of the session How to solve this i want the agent to come back with the same previous context
t
Thanks for reaching out, Yassine. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I understand you want the agent to return after a disconnect with the same session context. Short answer: LiveKit does not persist agent session context automatically. You must save the agent's conversation state (for example
session.history
or
session.chat_ctx
) to persistent storage when the agent disconnects, and reload it when the agent reconnects. How to implement this (high level): • Before disconnect (or during shutdown), serialize and save the session state (e.g.,
session.chat_ctx
or
session.history
) to a database or file. You can use a shutdown callback such as
ctx.add_shutdown_callback()
to trigger the save. • On reconnect, load the saved state and pass it into the agent via the
chat_ctx
parameter when constructing the
Agent
(or restore into the agent's session object). • Optionally store any custom per-session state in
userdata
so you can restore application-specific context alongside the chat history. If you’d like, tell me: • which language/runtime you’re using, and • whether you want an example for saving/restoring
session.chat_ctx
to a specific database (Postgres, Redis, etc.), and I’ll provide a concrete code snippet for your environment. Sources: Agents and handoffs | LiveKit docs | External data and RAG | LiveKit docs
p
I'm using python give me an example how to push to the chat and the agent will understand it and start from where he stops before he disconnected
t
Thanks — I’ll show a concise Python example that: • saves
session.chat_ctx
when the agent is about to disconnect, • restores it when the agent reconnects, • demonstrates pushing a new chat message so the agent resumes where it left off. This example uses an async in-memory “store” (replace with Redis/Postgres in production). Adjust the storage calls to your DB.
Copy code
import asyncio
import json
from typing import Any, Dict

# --- Replace these with your actual LiveKit/agent imports ---
# from livekit_agent import Agent, AgentSession, ctx
# ----------------------------------------------------------------

# Simple async key-value store (replace with Redis/Postgres)
_STORE: Dict[str, str] = {}

async def save_to_store(key: str, value: Dict[str, Any]):
    _STORE[key] = json.dumps(value)

async def load_from_store(key: str) -> Dict[str, Any] | None:
    raw = _STORE.get(key)
    return json.loads(raw) if raw else None

# --- Example agent lifecycle handlers ---

async def on_agent_start(room_name: str):
    """
    Called when agent process starts / reconnects.
    Restore chat_ctx if present and create the Agent with it.
    """
    stored = await load_from_store(f"chatctx:{room_name}")
    if stored:
        # Construct agent with restored chat context
        agent = Agent(chat_ctx=stored)  # replace with your Agent class
    else:
        agent = Agent()  # fresh agent

    # Hook to save context on shutdown/disconnect
    async def save_context():
        # session referenced from agent; session.chat_ctx holds context/history
        ctx_to_save = agent.session.chat_ctx
        await save_to_store(f"chatctx:{room_name}", ctx_to_save)

    # Register your shutdown callback with your framework/context
    ctx.add_shutdown_callback(save_context)

    return agent

async def push_user_message(room_name: str, user_id: str, text: str):
    """
    Push a new user chat message into the agent's session so it continues
    from previous context and processes the new message.
    """
    # Load stored chat_ctx and ensure agent has it (if agent not running, you can
    # create a transient Agent instance with restored chat_ctx to process the message)
    stored = await load_from_store(f"chatctx:{room_name}")
    if stored:
        agent = Agent(chat_ctx=stored)
    else:
        agent = Agent()

    # Add the incoming user message into the session history/chat context.
    # How to add depends on your AgentSession API; example:
    agent.session.add_user_message(user_id=user_id, text=text)

    # Now run the agent's processing loop / trigger a response handler
    # This might be a single-step call or an async run depending on your API.
    await agent.process_once()  # replace with actual processing call

    # After processing, save updated chat_ctx back to store
    await save_to_store(f"chatctx:{room_name}", agent.session.chat_ctx)

    # Return agent response (example)
    return agent.session.last_system_message()

# --- Usage example ---
async def example_flow():
    room = "support-room-123"
    # Agent process starts (restore context if exists)
    agent = await on_agent_start(room)

    # Simulate agent disconnect: shutdown callback will fire and save context
    await ctx.shutdown()  # this triggers save_context callback in on_agent_start

    # Later: new user message arrives while agent reconnects
    response = await push_user_message(room, user_id="user_1", text="I still need help with billing.")
    print("Agent responded:", response)

# Run example (in real app, these are event-driven)
# asyncio.run(example_flow())
Notes and places to adapt: • Persist with Redis or Postgres rather than the in-memory
_STORE
. • Use the real Agent constructor and session APIs:
agent.session.chat_ctx
,
agent.session.add_user_message(...)
, and whatever method triggers the agent to process messages in your codebase (
process_once()
is a placeholder). • Ensure
ctx.add_shutdown_callback(save_context)
runs in the agent process to capture context before disconnect. • If your app uses
userdata
, save/restore it the same way as
chat_ctx
. If you tell me which storage you want (Redis or Postgres) and which exact Agent session methods you have available, I’ll produce a complete ready-to-run snippet tailored to those APIs.