- Comprehensive API documentation - Migration examples (before/after) - Specialized manager patterns - Next steps for agent refactoring Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.8 KiB
SessionManager Usage Guide
Overview
The SessionManager<T> class provides a generic, reusable way to manage agent sessions with D1 database. It eliminates duplicated CRUD code across all 4 agents (Domain, Deposit, Server, Troubleshoot).
Features
- CRUD Operations: get, save, delete, has
- Expiry Management: Automatic TTL handling
- Message Management: Add messages with automatic trimming (max limit)
- Type Safety: Full TypeScript support with generics
- Extensible: Specialized managers for agents with extra fields
Basic Usage
1. For Simple Sessions (Deposit, Troubleshoot)
import { SessionManager } from '../utils/session-manager';
import type { DepositSession } from '../types';
// Create manager instance
const depositSessionManager = new SessionManager<DepositSession>({
tableName: 'deposit_sessions',
ttlMs: 30 * 60 * 1000, // 30 minutes
maxMessages: 20
});
// Get or create session
let session = await depositSessionManager.get(db, userId);
if (!session) {
session = depositSessionManager.create(userId, 'collecting_amount');
}
// Add message
depositSessionManager.addMessage(session, 'user', userMessage);
// Save session
await depositSessionManager.save(db, session);
// Delete session
await depositSessionManager.delete(db, userId);
// Check if session exists
const hasSession = await depositSessionManager.has(db, userId);
2. For Sessions with Extra Fields (Domain, Server)
import { DomainSessionManager } from '../utils/session-manager';
import type { DomainSession } from '../types';
// Use specialized manager
const domainSessionManager = new DomainSessionManager({
tableName: 'domain_sessions',
ttlMs: 60 * 60 * 1000, // 1 hour
maxMessages: 20
});
// Create with additional fields
const session = domainSessionManager.create(userId, 'gathering', {
target_domain: 'example.com'
});
// The manager handles target_domain serialization automatically
await domainSessionManager.save(db, session);
Specialized Managers
DomainSessionManager
Handles target_domain field for Domain Agent.
export class DomainSessionManager extends SessionManager<DomainSession> {
protected parseAdditionalFields(result: Record<string, unknown>): Partial<DomainSession> {
return {
target_domain: result.target_domain as string | undefined,
};
}
protected getAdditionalColumns(session: DomainSession): Record<string, unknown> {
return {
target_domain: session.target_domain || null,
};
}
}
ServerSessionManager
Handles last_recommendation field for Server Agent.
export class ServerSessionManager extends SessionManager<ServerSession> {
protected parseAdditionalFields(result: Record<string, unknown>): Partial<ServerSession> {
return {
last_recommendation: result.last_recommendation
? JSON.parse(result.last_recommendation as string)
: undefined,
};
}
protected getAdditionalColumns(session: ServerSession): Record<string, unknown> {
return {
last_recommendation: session.last_recommendation
? JSON.stringify(session.last_recommendation)
: null,
};
}
}
API Reference
Constructor
constructor(config: SessionManagerConfig)
Parameters:
config.tableName: D1 table name (e.g., 'domain_sessions')config.ttlMs: Session TTL in millisecondsconfig.maxMessages: Maximum messages to keep in session
Methods
get(db, userId)
Get session from D1. Returns null if not found or expired.
async get(db: D1Database, userId: string): Promise<T | null>
save(db, session)
Save session to D1 (insert or replace). Automatically updates updated_at and expires_at.
async save(db: D1Database, session: T): Promise<void>
delete(db, userId)
Delete session from D1.
async delete(db: D1Database, userId: string): Promise<void>
has(db, userId)
Check if active session exists (lightweight query).
async has(db: D1Database, userId: string): Promise<boolean>
create(userId, status, additionalFields?)
Create a new session object (not saved to DB yet).
create(userId: string, status: string, additionalFields?: Partial<T>): T
isExpired(session)
Check if session is expired.
isExpired(session: T): boolean
addMessage(session, role, content)
Add message to session with automatic trimming.
addMessage(session: T, role: 'user' | 'assistant', content: string): void
getOrCreate(db, userId, initialStatus)
Get existing session or create new one (convenience method).
async getOrCreate(db: D1Database, userId: string, initialStatus: string): Promise<T>
Migration Guide
Before (domain-agent.ts)
// 160 lines of duplicated CRUD code
async function getDomainSession(db: D1Database, userId: string): Promise<DomainSession | null> {
// ... 40 lines
}
async function saveDomainSession(db: D1Database, session: DomainSession): Promise<void> {
// ... 30 lines
}
async function deleteDomainSession(db: D1Database, userId: string): Promise<void> {
// ... 10 lines
}
function createDomainSession(userId: string, status: DomainSessionStatus): DomainSession {
// ... 10 lines
}
function isSessionExpired(session: DomainSession): boolean {
// ... 5 lines
}
function addMessageToSession(session: DomainSession, role: 'user' | 'assistant', content: string): void {
// ... 15 lines
}
async function hasDomainSession(db: D1Database, userId: string): Promise<boolean> {
// ... 10 lines
}
After (with SessionManager)
import { DomainSessionManager } from '../utils/session-manager';
const sessionManager = new DomainSessionManager({
tableName: 'domain_sessions',
ttlMs: 60 * 60 * 1000,
maxMessages: 20
});
// All CRUD operations now use the manager
const session = await sessionManager.get(db, userId);
sessionManager.addMessage(session, 'user', message);
await sessionManager.save(db, session);
Result: ~160 lines → ~10 lines per agent = ~600 lines saved across 4 agents!
Next Steps
- Task 19: Refactor
domain-agent.tsto useDomainSessionManager - Task 20: Refactor
server-agent.tsto useServerSessionManager - Task 21: Refactor
deposit-agent.tsto useSessionManager<DepositSession> - Task 22: Refactor
troubleshoot-agent.tsto useSessionManager<TroubleshootSession>
Notes
- The base
SessionManager<T>works for simple sessions (Deposit, Troubleshoot) - Specialized managers (
DomainSessionManager,ServerSessionManager) handle extra fields - All session operations are logged with structured logging
- Expired sessions are automatically filtered out in
get()method - Message trimming prevents memory bloat (configurable
maxMessages)