ulysses/routes
Leo 6c15dc7d33
Chat metrics: surface backend generation speed
* Chat metrics: show backend's true generation t/s, not tokens÷wall-clock

The per-message tokens/sec read low and felt wrong because it was computed as
output_tokens / total_duration, where total_duration is wall-clock including
prefill, tool calls, and network — not pure decode time. llama.cpp already
reports the correct gen speed in its stream (timings.predicted_per_second), but
it was being dropped.

- llm_core.py: when parsing the OpenAI-compatible usage chunk, also read the
  sibling `timings` block llama.cpp includes — pass predicted_per_second through
  as gen_tps and prompt_per_second as prefill_tps on the usage event.
- agent_loop.py: capture backend_gen_tps/backend_prefill_tps from usage events;
  in _compute_final_metrics prefer backend_gen_tps over the wall-clock division
  when present (fall back to computed for cloud APIs that omit timings). Tag the
  result with tps_source ("backend" vs "computed") and surface prefill_tps.

Result: the displayed t/s now matches the model's real decode speed and is
stable regardless of prompt length (a long prefill no longer deflates it).

Checks: py_compile passes; verified extraction against a real llama.cpp final
chunk (gen 79 t/s surfaced vs the deflated wall-clock figure shown before).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Chat metrics: surface true t/s on the direct-chat path too

Follow-up to the gen-tps work: the non-agent direct-chat stream path in
chat_routes turned the raw `usage` event straight into a metrics event but only
copied token counts — it never set tokens_per_second or response_time. So simple
(non-tool) replies showed "Speed: n/a" / "Time: undefineds" and the chip fell
back to a bare token count ("27 tok") instead of t/s.

Map the usage event's gen_tps (llama.cpp timings.predicted_per_second, added in
the prior commit) into tokens_per_second here too, tag tps_source=backend, and
set response_time from wall-clock for the stats popup.

Checks: py_compile passes; verified llama.cpp emits usage+timings on the final
stream chunk (gen ~90 t/s) that this path consumes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Tests: backend gen/prefill t/s passthrough and preference

Cover the two pieces of the true-t/s metric so it can be reviewed on its own:
- stream_llm surfaces llama.cpp's timings.predicted_per_second /
  prompt_per_second as gen_tps / prefill_tps on the usage event (captured
  llama.cpp final-chunk fixture), and omits them when the backend reports no
  timings.
- _compute_final_metrics prefers backend_gen_tps over output/wall-clock,
  tags tps_source ("backend" vs "computed"), and surfaces prefill_tps.

Reuses the fake-client stream harness from test_llm_core_streaming.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 20:52:08 +09:00
..
__init__.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
admin_wipe_routes.py Admin: wipe gallery albums with images 2026-06-02 20:35:57 +09:00
api_token_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
assistant_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
auth_routes.py Add explicit open-signup state endpoint 2026-06-02 12:35:54 +09:00
backup_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
calendar_routes.py Fix YEARLY recurring CalDAV events only showing on DTSTART year (#179) 2026-06-01 13:42:44 +09:00
chat_helpers.py feat(ai): add OpenRouter and Ollama Cloud providers (#231) 2026-06-01 14:26:10 +09:00
chat_routes.py Chat metrics: surface backend generation speed 2026-06-02 20:52:08 +09:00
cleanup_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
compare_routes.py feat(ai): add OpenRouter and Ollama Cloud providers (#231) 2026-06-01 14:26:10 +09:00
contacts_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
cookbook_helpers.py Cookbook: surface pip install failures in logs 2026-06-02 20:34:52 +09:00
cookbook_routes.py Fix Cookbook dependency install completion state 2026-06-02 12:59:29 +09:00
diagnostics_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
document_helpers.py Harden PDF document markers against cross-owner upload access (#445) 2026-06-01 22:38:14 +09:00
document_routes.py Documents: strip PDF marker without corrupting text 2026-06-02 20:35:27 +09:00
editor_draft_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
email_helpers.py Email: add explicit SMTP security mode 2026-06-02 13:15:06 +09:00
email_pollers.py Scope email calendar extraction to account owner 2026-06-01 23:12:32 +09:00
email_routes.py Email: add explicit SMTP security mode 2026-06-02 13:15:06 +09:00
embedding_routes.py chore: use running event loop in async helpers (#821) 2026-06-02 12:28:05 +09:00
emoji_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
font_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
gallery_helpers.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
gallery_routes.py Gallery: match image endpoint URLs with exact v1 suffix 2026-06-02 20:34:05 +09:00
history_routes.py fix(history): scope topic analysis to authenticated owner only (#744) 2026-06-02 11:36:01 +09:00
hwfit_routes.py Cookbook serve profiles and engine filter 2026-06-02 12:34:42 +09:00
mcp_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
memory_routes.py feat: allow memory import without session (#493) 2026-06-01 22:32:17 +09:00
model_routes.py Models: avoid hidden models in default fallback 2026-06-02 20:37:14 +09:00
note_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
personal_routes.py Scope personal RAG uploads by owner (#446) 2026-06-01 22:36:53 +09:00
prefs_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
preset_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
research_routes.py fix(auth): honor AUTH_ENABLED=false on owner-scoped endpoints (no /login loop) (#880) 2026-06-02 12:26:26 +09:00
search_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
session_routes.py Sessions: allow deleting memory-only ghost sessions 2026-06-02 20:51:26 +09:00
shell_routes.py Fix Cookbook dependency install completion state 2026-06-02 12:59:29 +09:00
signature_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
skills_routes.py Skills: delete owner-scoped skills with owner 2026-06-02 20:28:36 +09:00
stt_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
task_routes.py Polish email tasks and window controls 2026-06-01 20:56:46 +09:00
tts_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
upload_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
vault_routes.py fix(security): stop leaking the vault master password via process argv (#879) 2026-06-02 12:25:43 +09:00
webhook_routes.py Security: owner-scope v1 chat endpoint fallback 2026-06-02 20:31:35 +09:00