package postgres import ( "context" "encoding/json" "fmt" "time" ) type EventRow struct { EventID string `json:"event_id"` TS time.Time `json:"ts"` Type string `json:"type"` Payload json.RawMessage `json:"payload"` } type EventsFilter struct { Limit int EventType string Framework string ClientID string Since *time.Time // if nil, defaults to 24h ago } func (d *DB) ListRecentEvents(ctx context.Context, f EventsFilter) ([]EventRow, error) { if f.Limit <= 0 { f.Limit = 100 } if f.Limit > 1000 { f.Limit = 1000 } since := f.Since if since == nil { t := time.Now().Add(-24 * time.Hour) since = &t } query := "SELECT event_id, ts, type, payload FROM events WHERE 1=1" args := []any{} argN := 1 query += fmt.Sprintf(" AND ts >= $%d", argN) args = append(args, *since) argN++ if f.EventType != "" { query += fmt.Sprintf(" AND type = $%d", argN) args = append(args, f.EventType) argN++ } if f.Framework != "" { query += fmt.Sprintf(" AND source_framework = $%d", argN) args = append(args, f.Framework) argN++ } if f.ClientID != "" { query += fmt.Sprintf(" AND client_id = $%d", argN) args = append(args, f.ClientID) argN++ } query += fmt.Sprintf(" ORDER BY ts DESC LIMIT $%d", argN) args = append(args, f.Limit) rows, err := d.sql.QueryContext(ctx, query, args...) if err != nil { return nil, err } defer rows.Close() var out []EventRow for rows.Next() { var r EventRow if err := rows.Scan(&r.EventID, &r.TS, &r.Type, &r.Payload); err != nil { return nil, err } out = append(out, r) } return out, rows.Err() } func (d *DB) ListAgentLiveEvents(ctx context.Context, framework, clientID string, limit int) ([]EventRow, error) { if limit <= 0 { limit = 200 } if limit > 1000 { limit = 1000 } rows, err := d.sql.QueryContext(ctx, ` SELECT event_id, ts, type, payload FROM events WHERE source_framework = $1 AND client_id = $2 AND type IN ('session.start', 'session.end', 'run.start', 'run.end', 'span.start', 'span.end', 'error') ORDER BY ts DESC LIMIT $3 `, framework, clientID, limit) if err != nil { return nil, err } defer rows.Close() var out []EventRow for rows.Next() { var r EventRow if err := rows.Scan(&r.EventID, &r.TS, &r.Type, &r.Payload); err != nil { return nil, err } out = append(out, r) } return out, rows.Err() }