feat: complete phase 4 -- conversation replay API + analytics dashboard
- Replay models: StepType enum, ReplayStep, ReplayPage frozen dataclasses
- Checkpoint transformer: PostgresSaver JSONB -> structured timeline steps
- Replay API: GET /api/conversations (paginated), GET /api/replay/{thread_id}
- Analytics models: AgentUsage, InterruptStats, AnalyticsResult
- Analytics event recorder: Protocol + PostgresAnalyticsRecorder + NoOp
- Analytics queries: resolution_rate, agent_usage, escalation_rate, cost, interrupts
- Analytics API: GET /api/analytics?range=Xd with envelope response
- DB migration: analytics_events table + conversations column additions
- 74 new tests, 399 total passing, 92.87% coverage
This commit is contained in:
@@ -34,6 +34,31 @@ CREATE TABLE IF NOT EXISTS active_interrupts (
|
||||
);
|
||||
"""
|
||||
|
||||
_ANALYTICS_EVENTS_DDL = """
|
||||
CREATE TABLE IF NOT EXISTS analytics_events (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
thread_id TEXT NOT NULL,
|
||||
event_type TEXT NOT NULL,
|
||||
agent_name TEXT,
|
||||
tool_name TEXT,
|
||||
tokens_used INTEGER NOT NULL DEFAULT 0,
|
||||
cost_usd DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||
duration_ms INTEGER,
|
||||
success BOOLEAN,
|
||||
error_message TEXT,
|
||||
metadata JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
"""
|
||||
|
||||
_CONVERSATIONS_MIGRATION_DDL = """
|
||||
ALTER TABLE conversations
|
||||
ADD COLUMN IF NOT EXISTS resolution_type TEXT,
|
||||
ADD COLUMN IF NOT EXISTS agents_used TEXT[],
|
||||
ADD COLUMN IF NOT EXISTS turn_count INTEGER NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS ended_at TIMESTAMPTZ;
|
||||
"""
|
||||
|
||||
|
||||
async def create_pool(settings: Settings) -> AsyncConnectionPool:
|
||||
"""Create an async connection pool with the required psycopg settings."""
|
||||
@@ -55,7 +80,9 @@ async def create_checkpointer(pool: AsyncConnectionPool) -> AsyncPostgresSaver:
|
||||
|
||||
|
||||
async def setup_app_tables(pool: AsyncConnectionPool) -> None:
|
||||
"""Create application-specific tables (conversations, active_interrupts)."""
|
||||
"""Create application-specific tables and apply migrations."""
|
||||
async with pool.connection() as conn:
|
||||
await conn.execute(_CONVERSATIONS_DDL)
|
||||
await conn.execute(_INTERRUPTS_DDL)
|
||||
await conn.execute(_ANALYTICS_EVENTS_DDL)
|
||||
await conn.execute(_CONVERSATIONS_MIGRATION_DDL)
|
||||
|
||||
Reference in New Issue
Block a user