feat: opt-in state.db sync for /insights visibility (#92)
WebUI sessions were invisible to 'hermes /insights' because the WebUI bypasses the gateway and calls AIAgent.run_conversation() directly, never writing to state.db. New 'Sync usage to /insights' setting (default: off) that mirrors WebUI session metadata (tokens, cost, model, title) into state.db after each turn. Uses absolute token counts to avoid double-counting. Components: - api/state_sync.py: bridge module with sync_session_start() and sync_session_usage(). Uses ensure_session() (idempotent) and update_token_counts(absolute=True). All wrapped in try/except. - api/config.py: new 'sync_to_insights' boolean setting - api/streaming.py: calls sync_session_usage() after s.save() - api/routes.py: same for the non-streaming chat path - Settings UI: checkbox toggle with description Default off because: - Writing to state.db while CLI/gateway also writes could cause WAL lock contention on busy systems - Some users may not want WebUI sessions in /insights stats Closes #92 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -309,6 +309,21 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
|
||||
m['attachments'] = attachments
|
||||
break
|
||||
s.save()
|
||||
# Sync to state.db for /insights (opt-in setting)
|
||||
try:
|
||||
from api.config import load_settings as _load_settings
|
||||
if _load_settings().get('sync_to_insights'):
|
||||
from api.state_sync import sync_session_usage
|
||||
sync_session_usage(
|
||||
session_id=s.session_id,
|
||||
input_tokens=s.input_tokens or 0,
|
||||
output_tokens=s.output_tokens or 0,
|
||||
estimated_cost=s.estimated_cost,
|
||||
model=model,
|
||||
title=s.title,
|
||||
)
|
||||
except Exception:
|
||||
pass # never crash the stream for sync failures
|
||||
usage = {'input_tokens': input_tokens, 'output_tokens': output_tokens, 'estimated_cost': estimated_cost}
|
||||
# Include context window data from the agent's compressor for the UI indicator
|
||||
_cc = getattr(agent, 'context_compressor', None)
|
||||
|
||||
Reference in New Issue
Block a user