Sessions & Memory

Multi-turn chat with persistent sessions, conversation forking, and long-term memory for shipit_agent.Agent.

2 min read
8 sections
Edit this page

Plain Agent.run is stateless: it sends the prompt + the agent's configured history to the LLM and returns the result. To build a chat experience that remembers earlier turns, you have two orthogonal building blocks:

Building blockLives atLifetimeUse it for
SessionSessionStoreone conversationMulti-turn chat history (user/assistant messages)
MemoryMemoryStoreacross conversationsLong-term facts the agent should remember

The two compose: a long-running chat is a session that also writes to memory.


1. Multi-turn chat with chat_session()

agent.chat_session(session_id=...) returns an AgentChatSession bound to a specific session id. Each send() / stream() call appends to that session's history.

python
from shipit_agent import Agent
from shipit_agent.stores import InMemorySessionStore

agent = Agent.with_builtins(
    llm=llm,
    session_store=InMemorySessionStore(),
)

session = agent.chat_session(session_id="user-42")

session.send("Remember that I work in EU/Berlin time.")
session.send("Schedule a 30-minute meeting next Tuesday at 10am my time.")
# The agent has both turns in context — it knows "my time" means EU/Berlin.

session.history() returns the full message list at any point.


2. Persistent sessions across restarts

Swap InMemorySessionStore for FileSessionStore and your sessions survive process restarts:

python
from shipit_agent.stores import FileSessionStore

agent = Agent.with_builtins(
    llm=llm,
    session_store=FileSessionStore(root="~/.shipit/sessions"),
)
session = agent.chat_session(session_id="user-42")

Each session is one JSON file under ~/.shipit/sessions/. The store implements the simple SessionStore protocol — implement your own to back sessions on Postgres, Redis, DynamoDB, etc.


3. Streaming inside a session

python
for event in session.stream("What did I ask earlier?"):
    print(f"[{event.type}] {event.message}")

Identical to agent.stream(...) — every event flows through, the only extra step is that the new turn is also persisted to the session store.


4. Conversation forking and resuming

SessionManager (in shipit_agent.session_manager) layers fork/archive/resume on top of any SessionStore:

python
from shipit_agent import SessionManager
from shipit_agent.stores import FileSessionStore

manager = SessionManager(store=FileSessionStore(root="~/.shipit/sessions"))

# Create a fresh session
session_id = manager.create()

# Fork from an existing session at the third message
fork_id = manager.fork(parent_id=session_id, from_message=3)

# Archive a session (soft-delete)
manager.archive(session_id)

# List all live sessions
for record in manager.list_sessions():
    print(record.session_id, len(record.messages))

Forking is great for "what if" branches: a user's main thread plus half a dozen exploratory branches that all share the first few messages.


5. Long-term memory

AgentMemory is a unified facade over three memory types:

Memory typeStoresRetrieves by
ConversationMemoryturn history with strategies (buffer / window / token / summary)recency
SemanticMemoryembedded factsvector similarity
EntityMemorystructured (entity, attribute, value) triplesentity name
python
from shipit_agent import Agent, AgentMemory

memory = AgentMemory.default(llm=llm, embedding_fn=my_embed_fn)

agent = Agent.with_builtins(
    llm=llm,
    memory_store=memory.knowledge,        # backs the runtime's memory tool
)

# Run 1
agent.run("My favourite colour is teal.")
memory.add_fact("user_favourite_colour=teal")

# Run 2 — same agent, fresh prompt; memory is still there
agent.run("What's my favourite colour?")

See the Advanced memory guide for the full set of strategies, retrieval knobs, and persistence backends.


6. Combining sessions + memory

The pattern most production chat features use:

python
from shipit_agent import Agent, AgentMemory
from shipit_agent.stores import FileSessionStore

memory = AgentMemory.default(llm=llm, embedding_fn=my_embed_fn)

agent = Agent.with_builtins(
    llm=llm,
    session_store=FileSessionStore(root="~/.shipit/sessions"),
    memory_store=memory.knowledge,
)

session = agent.chat_session(session_id="user-42")
session.send("Remember that I prefer concise answers.")
# session_store has the message history; memory_store has the fact.

# A week later, in a different process:
session = agent.chat_session(session_id="user-42")
session.send("Tell me about Python's GIL.")
# The agent has both: the conversation history AND the long-term fact.

7. Hooks for observability

Subscribe to events as they happen via add_event_callback or add_packet_callback:

python
def on_event(event):
    print(f"[{event.type}] {event.message}")

session.add_event_callback(on_event)

for _ in session.stream("Search the docs"):
    pass

For a JSON-friendly callback (useful for logging and analytics) use add_packet_callback — packets are SSE/WebSocket-shaped dicts.


See also