Session Management
MinimalAgent provides built-in session management to maintain conversation context and track reasoning across multiple interactions.
Quick Start
Enable session support with just one parameter:
agent = Agent(use_session_memory=True)
# First interaction
response1 = agent.run("What's the weather in Seattle?", session_id="user123")
# Later interaction (remembers context)
response2 = agent.run("What about tomorrow?", session_id="user123")
What Sessions Provide
- Conversation Memory: Agent remembers previous messages and context
- Reasoning Storage: Track the agent's thinking process over time
- Persistence: Data stored in DynamoDB with automatic TTL
Configuration Options
agent = Agent(
# Basic session settings
use_session_memory=True, # Enable session persistence
session_ttl=3600, # Session TTL in seconds (default: 1 hour)
# Advanced settings
session_table_name="my-sessions", # Custom DynamoDB table name
real_time_reasoning=True, # Update reasoning during execution
memory_region="us-east-1", # AWS region for DynamoDB
)
Retrieving Reasoning and Tool Invocation History
A key benefit of session management is the ability to retrieve detailed reasoning and tool usage history. This is particularly valuable for debugging, monitoring, or analyzing how the agent performed complex multi-step tasks:
# Get the most recent reasoning data for a session
reasoning = agent.get_reasoning("user123")
print(f"Query: {reasoning.query}")
print(f"Response: {reasoning.final_response}")
# Examine tool usage from the most recent interaction
print(f"The agent took {reasoning.total_steps} steps to answer")
for step in reasoning.steps:
print(f"\nStep {step.step_number} thinking: {step.thinking}")
# Analyze all tools used in this step
for tool in step.tools:
print(f"Tool used: {tool.name}")
print(f"Tool inputs: {tool.inputs}")
print(f"Tool result: {tool.result}")
# Get complete reasoning history across all interactions
reasoning_history = agent.get_reasoning_history("user123")
print(f"Found {len(reasoning_history)} interactions in this session")
# Analyze all tool invocations across all interactions
for i, interaction in enumerate(reasoning_history):
print(f"\nInteraction {i+1}: {interaction.query}")
print(f"Total steps: {interaction.total_steps}")
for step in interaction.steps:
for tool in step.tools:
print(f"Tool: {tool.name}, Inputs: {tool.inputs}")
Note: get_reasoning_history() retrieves reasoning objects with complete tool invocation data, allowing you to track exactly what tools were called, with what parameters, and what results they returned across an entire session.
Real-Time Reasoning and Tool Tracking
Enable real-time reasoning to track the agent's thinking process and tool invocations as they happen:
With real-time updates, each thinking step and tool use is written to DynamoDB immediately, enabling:
- Live Tool Monitoring: See tools being called in real-time with their parameters and results
- Complex Task Tracking: Monitor multi-step processes that might take significant time
- External Monitoring: Build dashboards or monitoring systems by polling the database
Example: Monitoring Long-Running Operations
This is especially valuable for applications with long-running operations:
# In your application
agent = Agent(
tools=[long_running_tool, search_database, complex_analysis],
use_session_memory=True,
real_time_reasoning=True
)
# Start a complex operation
agent.run("Analyze the latest data and generate a comprehensive report", session_id="report-task")
# In a separate monitoring application
import time
def monitor_progress(session_id):
while True:
reasoning = agent.get_reasoning(session_id)
# Show completed steps
print(f"Completed {len(reasoning.steps)} of {reasoning.total_steps} steps")
# Show tools used so far
for step in reasoning.steps:
for tool in step.tools:
print(f"Tool used: {tool.name} with inputs: {tool.inputs}")
print(f"Result: {tool.result}")
time.sleep(5) # Poll every 5 seconds
Session Storage Details
Sessions are stored in DynamoDB with:
- Automatic table creation
- TTL-based expiration
- Partition key: messages#{session_id} or reasoning#{session_id}
- Sort key: Timestamp
DynamoDB Table Structure
MinimalAgent uses a single-table design with the following structure:
| Attribute | Type | Description |
|---|---|---|
pk |
String | Partition key with prefix: messages#{session_id} or reasoning#{session_id} |
sk |
Number | Sort key using timestamp (Unix epoch) |
expiration_time |
Number | TTL attribute for automatic deletion |
messages |
String | JSON string of messages (only in message items) |
reasoning |
String | JSON string of reasoning data (only in reasoning items) |
Bring Your Own DynamoDB Table
You can use your own pre-created DynamoDB table instead of having MinimalAgent create one for you. This is useful for:
- Infrastructure-as-code deployments
- Custom resource controls (provisioned capacity, encryption, etc.)
- Shared tables across multiple applications
- Custom backup policies
To use your own table, it must follow this schema:
# AWS SAM/CloudFormation example
Resources:
AgentSessionTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-custom-session-table
BillingMode: PAY_PER_REQUEST # Or use provisioned capacity
AttributeDefinitions:
- AttributeName: pk
AttributeType: S # String type
- AttributeName: sk
AttributeType: N # Number type
KeySchema:
- AttributeName: pk
KeyType: HASH # Partition key
- AttributeName: sk
KeyType: RANGE # Sort key
TimeToLiveSpecification:
AttributeName: expiration_time
Enabled: true
Then, tell the agent to use your custom table:
agent = Agent(
tools=[...],
use_session_memory=True,
session_table_name="my-custom-session-table", # Your custom table name
)
AWS CloudFormation/SAM Example
Here's a CloudFormation/SAM template for creating just the DynamoDB table:
AWSTemplateFormatVersion: '2010-09-09'
Resources:
AgentSessionTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-agent-sessions # Choose your table name
BillingMode: PAY_PER_REQUEST # Or use provisioned capacity
AttributeDefinitions:
- AttributeName: pk
AttributeType: S # String type for partition key
- AttributeName: sk
AttributeType: N # Number type for sort key
KeySchema:
- AttributeName: pk
KeyType: HASH # Partition key
- AttributeName: sk
KeyType: RANGE # Sort key
TimeToLiveSpecification:
AttributeName: expiration_time
Enabled: true
# Optional: Add point-in-time recovery
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
# Optional: Add tags
Tags:
- Key: Project
Value: MinimalAgent
Outputs:
AgentTableName:
Description: Session DynamoDB Table Name
Value: !Ref AgentSessionTable
To use this table with MinimalAgent, simply reference its name:
from minimalagent import Agent, tool
@tool
def example_tool(param: str) -> dict:
"""Example tool functionality."""
return {"result": f"Processed {param}"}
agent = Agent(
tools=[example_tool],
use_session_memory=True,
session_table_name="my-agent-sessions" # Match the table name from CloudFormation
)
Best Practices
- Use consistent session IDs for related interactions
- Set appropriate TTL based on expected conversation duration
- Monitor DynamoDB usage if running at scale
Complete Example
Here's a complete example of session management:
from minimalagent import Agent, tool
import uuid
@tool
def answer_question(question: str) -> dict:
"""Answer a simple question."""
return {"answer": f"The answer to '{question}' is 42."}
# Create agent with sessions enabled
agent = Agent(
tools=[answer_question],
use_session_memory=True,
show_reasoning=True,
)
# Generate session ID (or use a user ID in a real application)
session_id = str(uuid.uuid4())
# First interaction
response1, reasoning1 = agent.run(
"What is the meaning of life?",
session_id=session_id
)
# Second interaction (referencing the first)
response2, reasoning2 = agent.run(
"Can you elaborate on that?",
session_id=session_id
)
# Retrieve the reasoning history
history = agent.get_reasoning_history(session_id)
print(f"Found {len(history)} interactions in this session")