Persistence
Thread persistence keeps conversations alive across page refreshes, browser restarts, and server deployments. This guide covers configuring checkpointers on the Python side and wiring up thread management in your Angular components with injectAgent().
LangGraph checkpoints agent state at every super-step. Each checkpoint is keyed by a thread ID. injectAgent() connects to these checkpoints automatically, so your users resume exactly where they left off — even if your server restarted between sessions.
"Restore a prior thread's messages when the user switches to it" is a behavior the @threadplane/langgraph adapter implements because the LangGraph protocol exposes per-thread checkpoint history. The runtime-neutral Agent contract in @threadplane/chat doesn't require this — adapters built on event-stream protocols (like @threadplane/ag-ui) typically can't offer it. If you're writing your own adapter, the Writing an Adapter guide covers the design choice.
#Python: Checkpointer Setup
Every LangGraph agent needs a checkpointer to persist state between invocations. The checkpointer you choose depends on your environment.
MemorySaver is for development only — all state vanishes when the process exits. For anything users depend on, use PostgresSaver. SqliteSaver is a middle ground for prototypes and single-server deployments where you need persistence without a database.
#Python: Thread IDs in Graph Invocation
The thread ID is how LangGraph associates a conversation with its checkpoint history. Pass it in the configurable dict every time you invoke the graph:
Use stable, user-scoped identifiers for thread IDs. A common pattern is f"{user_id}_{session_id}" — this prevents cross-user data leaks and lets one user have multiple conversations.
#Angular: Basic Thread Persistence
Save the thread ID to localStorage so conversations survive page refreshes. injectAgent() handles thread creation and restoration automatically; the configuration lives in your root provideAgent({...}) call.
#Angular: Thread-List Component
A real chat application needs a sidebar showing all conversations. Here is a full thread-list component that manages multiple threads alongside your chat singleton. The active-thread signal is held in shared state and wired into provideAgent({...}) at bootstrap; the component reads back through injectAgent().
#Reactive Thread Switching
When you pass a Signal as threadId to provideAgent({...}), injectAgent() reacts to every change. Set the signal and the conversation switches automatically — no imperative calls needed.
Use the isThreadLoading() signal to show a skeleton UI while injectAgent() fetches checkpoint state from the server. This avoids a flash of empty content when switching threads.
#Manual Thread Switching
Use switchThread() for imperative thread changes. This is useful when you want to explicitly control when the switch happens — for example, after an animation completes or a modal closes.
#Checkpoint Recovery
When a connection drops mid-stream, joinStream() reconnects to an in-progress run without restarting the agent. This prevents duplicate work and lost tokens.
In most cases injectAgent() handles reconnection internally. Use joinStream() directly only when you need explicit control — for example, when restoring a run ID from a URL parameter after a full page reload.
#Thread Lifecycle
injectAgent() reads the threadId signal. If it contains a value, the existing thread's checkpoint is fetched from the server.
If threadId is null, injectAgent() creates a new thread via the LangGraph API and fires onThreadId with the new ID.
Each super-step is checkpointed server-side. The messages() signal updates in real time as events arrive.
Setting the threadId signal (or calling switchThread()) loads the target thread's latest checkpoint. All signals update to reflect the restored state.
joinStream() reconnects to the in-progress run. The agent does not restart — streaming resumes from the last received event.
#What's Next
Pause agent execution and wait for human approval before continuing.
Preserve long-term context across sessions with LangGraph's memory store.
Stream token-by-token responses and tool progress in real time.
Test thread persistence and switching deterministically with MockAgentTransport.