State and Session Management¶
AgentScope provides two levels of state management:
Session (recommended): High-level API for managing state across application runs
State (advanced): Low-level API for fine-grained control
This guide focuses on the Session API, which is the recommended approach for most use cases.
What is a Session?¶
A Session provides persistent storage for stateful components (agents, memories, toolkits) across application runs. It allows you to:
Save and restore complete application state
Resume conversations from where they left off
Manage multiple components together
Migrate state between environments
Quick Start¶
Saving State¶
Use SessionManager to save agent and memory state:
import io.agentscope.core.ReActAgent;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.session.SessionManager;
import java.nio.file.Path;
// Create and use agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.memory(new InMemoryMemory())
.build();
agent.call(msg1).block();
agent.call(msg2).block();
// Save session
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.addComponent(agent)
.saveSession();
Loading State¶
Restore agent from saved session:
// Create agent with same configuration
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.memory(new InMemoryMemory())
.build();
// Load session if exists
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.addComponent(agent)
.loadIfExists();
// Agent continues from where it left off
agent.call(msg3).block();
Multi-Component Sessions¶
Sessions can manage multiple components simultaneously, preserving relationships:
import io.agentscope.core.tool.Toolkit;
// Create components
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.build();
InMemoryMemory memory = new InMemoryMemory();
Toolkit toolkit = new Toolkit();
// Save all components together
SessionManager.forSessionId("conversation-001")
.withJsonSession(Path.of("./sessions"))
.addComponent(agent)
.addComponent(memory)
.addComponent(toolkit)
.saveSession();
// Later, load all components
SessionManager.forSessionId("conversation-001")
.withJsonSession(Path.of("./sessions"))
.addComponent(agent)
.addComponent(memory)
.addComponent(toolkit)
.loadIfExists();
Session Operations¶
Check if Session Exists¶
boolean exists = SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.sessionExists();
if (exists) {
System.out.println("Session found");
}
Load with Error Handling¶
try {
// Throws exception if session doesn't exist
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.addComponent(agent)
.loadOrThrow();
} catch (IllegalArgumentException e) {
System.err.println("Session not found: " + e.getMessage());
}
Conditional Save¶
// Only save if session already exists
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.addComponent(agent)
.saveIfExists();
Delete Session¶
// Delete if exists
boolean deleted = SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.deleteIfExists();
// Or throw exception if doesn't exist
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.deleteOrThrow();
Session Storage¶
JsonSession (Default)¶
JsonSession stores state as JSON files on the filesystem:
Default location:
~/.agentscope/sessions/File format: One JSON file per session (named by session ID)
Features: Automatic directory creation, UTF-8 encoding, pretty printing
import io.agentscope.core.session.SessionManager;
// Use default location (~/.agentscope/sessions/)
SessionManager.forSessionId("user123")
.withDefaultJsonSession()
.addComponent(agent)
.saveSession();
// Use custom location
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("/path/to/sessions"))
.addComponent(agent)
.saveSession();
Custom Session Backends¶
You can implement custom session backends by extending SessionBase:
import io.agentscope.core.session.SessionBase;
// Example: Database-backed session
SessionManager.forSessionId("user123")
.withSession(() -> new DatabaseSession(dbConnection))
.addComponent(agent)
.saveSession();
Component Naming¶
Components are automatically named using their getComponentName() method or class name:
// Automatic naming
SessionManager.forSessionId("user123")
.withJsonSession(Path.of("sessions"))
.addComponent(agent) // Named "reActAgent"
.addComponent(memory) // Named "inMemoryMemory"
.saveSession();
The session file structure:
{
"reActAgent": {
"agentId": "...",
"memory": {...}
},
"inMemoryMemory": {
"messages": [...]
}
}
Advanced: Low-Level State API¶
For fine-grained control, you can use the low-level StateModule interface:
Manual State Management¶
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
// Save state manually
Map<String, Object> state = agent.saveState();
// Serialize to JSON
ObjectMapper mapper = new ObjectMapper();
String jsonState = mapper.writeValueAsString(state);
// Save to file
Files.writeString(Path.of("agent-state.json"), jsonState);
// Load state manually
String jsonState = Files.readString(Path.of("agent-state.json"));
Map<String, Object> state = mapper.readValue(jsonState, Map.class);
// Restore agent
agent.loadState(state);
When to Use Low-Level API¶
Use the low-level API when you need:
Custom serialization formats (not JSON)
Integration with existing storage systems
Partial state updates
State transformation during load/save
Complete Example¶
package io.agentscope.tutorial.task;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.MsgRole;
import io.agentscope.core.message.TextBlock;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.session.JsonSession;
import io.agentscope.core.session.SessionManager;
import java.nio.file.Path;
import java.util.List;
public class SessionExample {
public static void main(String[] args) {
// Session ID (e.g., user ID, conversation ID)
String sessionId = "user-alice-chat-001";
Path sessionPath = Path.of("./sessions");
// Create model
DashScopeChatModel model = DashScopeChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen-plus")
.build();
// Create agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.sysPrompt("You are a helpful assistant. Remember previous conversations.")
.model(model)
.memory(new InMemoryMemory())
.build();
// Try to load existing session
SessionManager.forSessionId(sessionId)
.withSession(new JsonSession(sessionPath))
.addComponent(agent)
.loadIfExists();
// Interact with agent
Msg userMsg = Msg.builder()
.name("user")
.role(MsgRole.USER)
.content(List.of(TextBlock.builder()
.text("Hello! My name is Alice.")
.build()))
.build();
Msg response = agent.call(userMsg).block();
System.out.println("Agent: " + response.getTextContent());
// Save session
SessionManager.forSessionId(sessionId)
.withSession(new JsonSession(sessionPath))
.addComponent(agent)
.saveSession();
System.out.println("Session saved to: " + sessionPath.resolve(sessionId + ".json"));
}
}
Best Practices¶
Use Meaningful Session IDs: Use user IDs, conversation IDs, or other identifiers
// Good SessionManager.forSessionId("user-123-conversation-456") // Avoid SessionManager.forSessionId("session1")
Save Regularly: Persist state after important operations
agent.call(criticalMsg).block(); sessionManager.saveSession(); // Save immediately
Use
loadIfExists()for Graceful Startup: Don’t fail if session doesn’t exist// Graceful - creates new session if not found SessionManager.forSessionId(sessionId) .withJsonSession(path) .addComponent(agent) .loadIfExists();
Clean Up Old Sessions: Delete sessions that are no longer needed
if (userLoggedOut) { SessionManager.forSessionId(sessionId) .withJsonSession(path) .deleteIfExists(); }
Handle Errors: Use try-catch for critical operations
try { SessionManager.forSessionId(sessionId) .withJsonSession(path) .addComponent(agent) .saveOrThrow(); } catch (Exception e) { logger.error("Failed to save session", e); // Handle error (retry, notify user, etc.) }
Troubleshooting¶
Session Not Loading¶
Problem: loadIfExists() doesn’t restore state
Solutions:
Verify session file exists:
sessionManager.sessionExists()Check component names match between save and load
Ensure same component types are used
State Corruption¶
Problem: Session loads but agent behaves unexpectedly
Solutions:
Validate session file format (should be valid JSON)
Check for version mismatches between saved and current code
Delete and recreate session if corrupted
File Permission Errors¶
Problem: Cannot write to session directory
Solutions:
Check directory permissions
Ensure parent directory exists
Use absolute paths instead of relative paths
Next Steps¶
Memory - Understand memory management
Agent - Build stateful agents
Key Concepts - Learn about Session concept