|
|
@@ -0,0 +1,104 @@
|
|
|
+# Todo 12 Structured Round Stats Plan
|
|
|
+
|
|
|
+**Status:** done
|
|
|
+
|
|
|
+## Goal
|
|
|
+
|
|
|
+Move round statistics to structured backend events for token counts, cached tokens, TTFT, elapsed time, and per-turn summaries.
|
|
|
+
|
|
|
+## Why
|
|
|
+
|
|
|
+The original requirement calls for chat-window round statistics: token count, cache hits, TTFT, and total elapsed time. The MVP UI calculates TTFT/elapsed in the browser and only displays usage chunks. That is useful visually, but not enough for reproducible Agent debugging. Backend-emitted stats should become part of the WebSocket event stream.
|
|
|
+
|
|
|
+## Scope
|
|
|
+
|
|
|
+This todo covers:
|
|
|
+
|
|
|
+- Backend timing collection inside `DebugRuntime.run()`.
|
|
|
+- Structured `round_stats` WebSocket messages.
|
|
|
+- Usage aggregation from streamed `usage` items.
|
|
|
+- UI rendering from backend `round_stats` events.
|
|
|
+- Tests for deterministic stats using an injectable clock.
|
|
|
+
|
|
|
+This todo does not cover:
|
|
|
+
|
|
|
+- Persistent run history.
|
|
|
+- Multi-run comparison dashboards.
|
|
|
+- Provider-side detailed cache diagnostics beyond available `cached_tokens`.
|
|
|
+- Cost estimation.
|
|
|
+
|
|
|
+## Files
|
|
|
+
|
|
|
+- Modify: `src/agent_lab/application/runtime.py`
|
|
|
+- Modify/add application contracts or domain models only if needed.
|
|
|
+- Modify: `src/agent_lab/presentation/static/app.js`
|
|
|
+- Modify/add tests, preferably `tests/test_debug_runtime.py` and `tests/test_websocket_api.py`.
|
|
|
+- Do not modify: `docs/plans/todos.md`.
|
|
|
+
|
|
|
+## Design
|
|
|
+
|
|
|
+Add an injectable monotonic clock to `DebugRuntime`:
|
|
|
+
|
|
|
+```python
|
|
|
+Clock = Callable[[], float]
|
|
|
+DebugRuntime(chat_client, queues=None, registry=None, clock=time.perf_counter)
|
|
|
+```
|
|
|
+
|
|
|
+Track one `round_index` per ChatAgent call. For each round:
|
|
|
+
|
|
|
+- `started_at = clock()`;
|
|
|
+- first message delta sets `ttft_ms` if unset;
|
|
|
+- usage item updates `prompt_tokens`, `completion_tokens`, `total_tokens`, and `cached_tokens`;
|
|
|
+- after the ChatAgent stream completes, emit:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "type": "round_stats",
|
|
|
+ "round_index": 1,
|
|
|
+ "ttft_ms": 123,
|
|
|
+ "elapsed_ms": 456,
|
|
|
+ "prompt_tokens": 10,
|
|
|
+ "completion_tokens": 20,
|
|
|
+ "total_tokens": 30,
|
|
|
+ "cached_tokens": 5,
|
|
|
+ "had_event": true
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Keep existing `usage` messages for compatibility, but the UI should prefer `round_stats` for the stats panel. If no token arrives, `ttft_ms` can be `null`.
|
|
|
+
|
|
|
+## Steps
|
|
|
+
|
|
|
+1. Add failing runtime tests for:
|
|
|
+ - `round_stats` is emitted after a model turn;
|
|
|
+ - TTFT and elapsed are derived from the injected clock;
|
|
|
+ - usage totals are included;
|
|
|
+ - multi-turn event handoff emits one stats object per ChatAgent call.
|
|
|
+2. Refactor `DebugRuntime` to collect and emit stats through the existing output queue.
|
|
|
+3. Update `app.js` to update stats from `round_stats` messages and keep current browser timing only as a fallback before stats arrives.
|
|
|
+4. Add or update static JS tests/assertions for `round_stats` handling.
|
|
|
+5. Run:
|
|
|
+
|
|
|
+```bash
|
|
|
+uv run pytest tests/test_debug_runtime.py tests/test_websocket_api.py
|
|
|
+uv run pytest
|
|
|
+```
|
|
|
+
|
|
|
+6. If successful, commit implementation files only with:
|
|
|
+
|
|
|
+```bash
|
|
|
+git commit -m "feat: emit structured round stats"
|
|
|
+```
|
|
|
+
|
|
|
+## Verification
|
|
|
+
|
|
|
+Result:
|
|
|
+
|
|
|
+- `uv run pytest tests/test_debug_runtime.py tests/test_websocket_api.py` passed: 23 tests, 1 existing Starlette deprecation warning.
|
|
|
+- `uv run pytest` passed: 28 tests, 1 existing Starlette deprecation warning.
|
|
|
+
|
|
|
+## Evaluation
|
|
|
+
|
|
|
+- Backend emits deterministic `round_stats` messages with round index, TTFT, elapsed time, token totals, cached tokens, and event presence.
|
|
|
+- UI handles backend `round_stats` and keeps browser-side timing as a fallback.
|
|
|
+- The original MVP requirement for chat-window round statistics is covered.
|