docs: add UI, query API, and validation design
Design for Sessions/Run views, three new query-api endpoints, and schema validation at ingest-gateway. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,228 @@
|
|||||||
|
# UI, Query API, and Schema Validation Design
|
||||||
|
|
||||||
|
Date: 2026-01-17
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This design covers three related improvements to agentmon:
|
||||||
|
|
||||||
|
1. **Web UI** — Sessions list, session detail, and run detail views
|
||||||
|
2. **Query API** — New endpoints to support the UI
|
||||||
|
3. **Schema Validation** — Required field validation at ingest-gateway
|
||||||
|
|
||||||
|
## URL Structure
|
||||||
|
|
||||||
|
| URL | View | Description |
|
||||||
|
|-----|------|-------------|
|
||||||
|
| `/` | Redirect | Redirects to `/sessions` |
|
||||||
|
| `/sessions` | Sessions List | Recent sessions, filterable |
|
||||||
|
| `/sessions/:session_id` | Session Detail | Runs within a session |
|
||||||
|
| `/runs/:run_id` | Run Detail | Spans within a run |
|
||||||
|
|
||||||
|
Query parameters for filtering:
|
||||||
|
|
||||||
|
- `/sessions?from=2026-01-17&to=2026-01-18` — time range
|
||||||
|
- `/sessions?framework=opencode` — filter by framework
|
||||||
|
- `/sessions?host=willlaptop` — filter by host
|
||||||
|
- Parameters combine: `/sessions?framework=claude-code&host=willlaptop`
|
||||||
|
|
||||||
|
## Query API Endpoints
|
||||||
|
|
||||||
|
### GET /v1/sessions
|
||||||
|
|
||||||
|
List sessions with filters.
|
||||||
|
|
||||||
|
Query params:
|
||||||
|
|
||||||
|
- `from`, `to` — ISO timestamps (default: last 24h)
|
||||||
|
- `framework` — filter by source framework
|
||||||
|
- `host` — filter by source host
|
||||||
|
- `limit` — max results (default 50, max 200)
|
||||||
|
- `cursor` — pagination token (opaque, timestamp-based)
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessions": [
|
||||||
|
{
|
||||||
|
"session_id": "s1",
|
||||||
|
"started_at": "2026-01-17T08:00:00Z",
|
||||||
|
"ended_at": "2026-01-17T09:30:00Z",
|
||||||
|
"framework": "claude-code",
|
||||||
|
"host": "willlaptop",
|
||||||
|
"run_count": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"next_cursor": "..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /v1/sessions/:session_id
|
||||||
|
|
||||||
|
Session detail with runs.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"session": {
|
||||||
|
"session_id": "...",
|
||||||
|
"started_at": "...",
|
||||||
|
"ended_at": "...",
|
||||||
|
"framework": "...",
|
||||||
|
"host": "..."
|
||||||
|
},
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"run_id": "r1",
|
||||||
|
"started_at": "...",
|
||||||
|
"ended_at": "...",
|
||||||
|
"status": "success",
|
||||||
|
"span_count": 12
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### GET /v1/runs/:run_id
|
||||||
|
|
||||||
|
Run detail with spans.
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"run": {
|
||||||
|
"run_id": "...",
|
||||||
|
"session_id": "...",
|
||||||
|
"started_at": "...",
|
||||||
|
"ended_at": "...",
|
||||||
|
"status": "..."
|
||||||
|
},
|
||||||
|
"spans": [
|
||||||
|
{
|
||||||
|
"span_id": "sp1",
|
||||||
|
"name": "Bash",
|
||||||
|
"kind": "tool",
|
||||||
|
"started_at": "...",
|
||||||
|
"duration_ms": 1234,
|
||||||
|
"status": "success",
|
||||||
|
"payload": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI Views
|
||||||
|
|
||||||
|
### Sessions List
|
||||||
|
|
||||||
|
Default view showing last 24 hours, most recent first.
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
|
||||||
|
- Filter bar: time range (from/to), framework dropdown, host dropdown
|
||||||
|
- Table columns: Session ID, Framework, Host, Run Count, Time (relative)
|
||||||
|
- Click row to navigate to session detail
|
||||||
|
- "Load more" button for pagination
|
||||||
|
|
||||||
|
### Session Detail
|
||||||
|
|
||||||
|
Shows session metadata and all runs within it.
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
|
||||||
|
- Header: Session ID, framework, host, start time, total duration
|
||||||
|
- Back link to sessions list
|
||||||
|
- Runs table: Run ID, Status, Span Count, Duration, Start Time
|
||||||
|
- Click row to navigate to run detail
|
||||||
|
|
||||||
|
Status indicators:
|
||||||
|
|
||||||
|
- Green checkmark for success
|
||||||
|
- Red X for error
|
||||||
|
- Yellow circle for running/unknown
|
||||||
|
|
||||||
|
### Run Detail
|
||||||
|
|
||||||
|
Shows run metadata and all spans within it.
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
|
||||||
|
- Header: Run ID, status, start time, duration
|
||||||
|
- Back link to session detail
|
||||||
|
- Spans table: Name, Kind, Status, Duration
|
||||||
|
- Click row to expand/collapse details
|
||||||
|
|
||||||
|
Expanded span shows:
|
||||||
|
|
||||||
|
- Model name, tokens, cost (for LLM spans)
|
||||||
|
- Error details (for failed spans)
|
||||||
|
- Raw payload JSON
|
||||||
|
|
||||||
|
## Schema Validation
|
||||||
|
|
||||||
|
Validation performed at ingest-gateway before publishing to NATS.
|
||||||
|
|
||||||
|
### Required Fields
|
||||||
|
|
||||||
|
All events must include:
|
||||||
|
|
||||||
|
```
|
||||||
|
schema.name = "agentmon.event"
|
||||||
|
schema.version = 1
|
||||||
|
event.id — non-empty string
|
||||||
|
event.type — one of: session.start, session.end, run.start,
|
||||||
|
run.end, span.start, span.end, error, metric.snapshot
|
||||||
|
event.ts — valid timestamp (RFC3339 or unix-ms)
|
||||||
|
event.source.framework — non-empty string
|
||||||
|
event.source.client_id — non-empty string
|
||||||
|
event.source.host — non-empty string
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Responses
|
||||||
|
|
||||||
|
| Scenario | HTTP | WebSocket |
|
||||||
|
|----------|------|-----------|
|
||||||
|
| Valid | 202 Accepted | `{"ack": {"seq": N}}` |
|
||||||
|
| Missing field | 400 + error | `{"error": "missing_field", "field": "..."}` |
|
||||||
|
| Invalid type | 400 + error | `{"error": "invalid_type", "value": "..."}` |
|
||||||
|
| Unknown fields | Allow | Allow |
|
||||||
|
|
||||||
|
Non-strict mode: unknown fields in `correlation`, `attributes`, and `payload` are stored as-is.
|
||||||
|
|
||||||
|
## Frontend Implementation
|
||||||
|
|
||||||
|
Technology: Vanilla JavaScript (no framework, no build step).
|
||||||
|
|
||||||
|
File structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd/web-ui/static/
|
||||||
|
├── index.html # Shell + router
|
||||||
|
├── app.js # Router + page loader
|
||||||
|
├── pages/
|
||||||
|
│ ├── sessions.js
|
||||||
|
│ ├── session.js
|
||||||
|
│ └── run.js
|
||||||
|
└── style.css
|
||||||
|
```
|
||||||
|
|
||||||
|
Routing: History API with catch-all handler serving index.html for all routes.
|
||||||
|
|
||||||
|
Data fetching: Native fetch() to query-api endpoints via /api proxy.
|
||||||
|
|
||||||
|
## Implementation Order
|
||||||
|
|
||||||
|
1. Query API endpoints (sessions, session detail, run detail)
|
||||||
|
2. Schema validation at ingest-gateway
|
||||||
|
3. Frontend pages (sessions list, session detail, run detail)
|
||||||
|
4. Rebuild and deploy
|
||||||
|
|
||||||
|
## Future Considerations
|
||||||
|
|
||||||
|
- Waterfall visualization for spans (SVG/canvas)
|
||||||
|
- Token/cost aggregations in session/run summaries
|
||||||
|
- Free-text search across sessions
|
||||||
|
- Real-time updates via WebSocket subscription
|
||||||
Reference in New Issue
Block a user