Skip to content

feat(dashboard): surface system events as quiet inline dividers#1650

Merged
esengine merged 1 commit into
mainfrom
feat/dashboard-system-events
May 24, 2026
Merged

feat(dashboard): surface system events as quiet inline dividers#1650
esengine merged 1 commit into
mainfrom
feat/dashboard-system-events

Conversation

@esengine

Copy link
Copy Markdown
Owner

Summary

Layer 1 follow-up to #1649 (CompactionCard). Before this, every loop warning fell through eventize.classifyWarning's default branch and became an error event — Dashboard rendered compaction notices and storm-stuck interrupts as alarming red error cards. And every chatty warning (per-iter "repeated tool call" nudges, storm-suppressed counters) joined the flood.

This PR ships the tiered design we agreed on:

  • High-signal warnings → quiet inline divider in the thread (compaction, abort, rate-limit, storm-stuck).
  • Low-signal warnings → dropped at the kernel boundary (UI never sees them).
  • Existing classified warnings (policy.escalated, policy.budget.*) keep their dedicated event types.

Severity tiering

Added EventSeverity = \"low\" | \"high\" to LoopEvent. Default is high so newly-added warning sites are visible by default (safer for future contributions). Only two sites currently tagged \"low\":

Site Reason
repeatToolCallWarning (loop.ts:904) Fires every iter the model repeats — stormStuck handles the real-bad case
stormSuppressed counter (loop.ts:917 when !allSuppressed) Counter message, no actionable info

Event flow

  • Eventizer.classifyWarning now returns Event | null. Low-severity → null → dropped from kernel stream entirely. High-severity → typed WarningEvent (not the old errorEvent masquerade).
  • New WarningEvent in both src/core/events.ts (kernel) and dashboard/src/protocol.ts (transport).
  • Dashboard SPA adds warning kind to ChatMessage, reducer case in applyIncoming (gates on severity === \"high\"), and a .sys-event-row render — single dim line at ~0.7 opacity flanked by hairlines. Visually weak so several through a long session don't crowd the conversation.

Test plan

  • npm run verify — 262 files / 3598 tests pass (3 new in tests/eventize.test.ts)
  • New cases cover: low-severity dropped, high-severity emit typed warning (not error), unmarked default to high

Follow-ups (not in this PR)

  • Desktop bridge equivalent — Tauri IPC + Tauri-side event types so the desktop window also gets quiet inline dividers (currently it goes through the same eventize path but the renderer + protocol need parallel changes).
  • Settings toggle "Show system events in thread" — for users who want a fully clean conversation, with hidden events still accessible via session log inspection.

… chatty ones

Layer 1 follow-up to #1649 (CompactionCard). Before this, every loop
warning fell through eventize.classifyWarning's default branch and
became an "error" event — Dashboard rendered compaction notices and
storm-stuck interrupts as alarming red error cards. Chatty warnings
(per-iter repeat-tool nudges, storm-suppressed counters) flooded the
thread.

- Add EventSeverity ("low" | "high") to LoopEvent. Tag the two known
  chatty sites in loop.ts (repeatToolCallWarning, stormSuppressed
  counter) as "low"; everything else is "high" by default — safer for
  new emit sites added later.
- Add a typed WarningEvent to the kernel + dashboard protocol.
  Eventize.classifyWarning now: drops low-severity entirely, emits a
  proper warning event (not an error) for high-severity. Existing
  policy.escalated / policy.budget classification still wins for those
  patterns.
- Dashboard SPA: add warning kind to ChatMessage, reducer case in
  applyIncoming (filters anything not "high"), render as a quiet
  inline divider (.sys-event-row) — single line, dim, ~0.7 opacity,
  flanked by hairline rules. Visually weak so several can stack
  through a long session without crowding the conversation.

Tests: low-severity warnings dropped, high-severity emit typed warning
(not error), unmarked warnings default to high.

Follow-ups not in this PR:
- Desktop bridge equivalent (Tauri IPC + Tauri-side event types).
- Settings toggle to fully hide system events for users who want a
  cleaner thread.
@esengine esengine merged commit 5a9a5db into main May 24, 2026
4 checks passed
@esengine esengine deleted the feat/dashboard-system-events branch May 24, 2026 04:52
esengine pushed a commit that referenced this pull request May 24, 2026
Desktop equivalent of #1650. The kernel WarningEvent (added in #1650
for high-severity warnings) already flows through eventize → desktop
sidecar → webview as a Tauri event, but desktop's protocol type and
App reducer didn't know about it — the event reached the renderer and
was silently dropped.

- Add WarningEvent to desktop/src/protocol.ts (matches the dashboard
  shape exactly: type, id, ts, turn, text, severity).
- ChatMessage union grows a "warning" kind; reducer adds a case that
  gates on severity === "high" (low-severity already dropped at
  eventize; defense-in-depth here in case future emit sites use the
  field differently).
- Thread renderer adds the warning branch — same .sys-event-row inline
  divider styling as dashboard (single dim line, 11px, opacity 0.7,
  flanked by hairline rules). Visually weak so several through a long
  session don't crowd the conversation.

Stacked on top of #1650 — desktop and dashboard now have feature parity
for compaction / abort / rate-limit / storm-stuck visibility without
the alarmist red error cards.

Follow-up not in this PR:
- Settings toggle "Show system events in thread" with config persistence,
  for users who want to fully hide them. Severity filter (high-only)
  already keeps the visible set to ~1-3 per session, so this is a
  preference, not a noise mitigation.
esengine added a commit that referenced this pull request May 24, 2026
Follow-up to #1650. Completes the system-event surfacing work:

1. Desktop bridge — the kernel WarningEvent (added in #1650) already
   flowed through eventize → desktop sidecar → webview as a Tauri
   event, but desktop's protocol type and App reducer didn't know
   about it. Add WarningEvent to desktop/src/protocol.ts (matches
   dashboard shape), grow ChatMessage with a "warning" kind, reducer
   gated on severity === "high", thread renderer adds the
   .sys-event-row inline divider (same styling as dashboard).

2. Settings toggle — new config field thread.showSystemEvents
   (default true) with load/saveShowSystemEvents helpers in
   src/config.ts. Desktop sidecar pushes it in $settings and handles
   it in settings_save. Both SPAs grow Settings/SettingsEvent/
   SettingsPatch, reducer stores it, warning render gates on
   settings.showSystemEvents !== false. Settings panel adds a
   seg-ctrl row in the Behavior section, en + zh-CN strings.

Default remains "shown" — severity filter (high-only) already caps
visible events to ~1-3 per session, so this is a preference, not a
noise mitigation.
esengine pushed a commit that referenced this pull request May 24, 2026
…moved, persisted usage stats, plan dispatch gate

Headline themes:
- Desktop: bundle the CLI-hosted React dashboard, retire Tauri+Preact duplicate (#1418)
- Config: drop preset abstraction; flash/pro are direct model selections (#1657, #1630)
- Stats: persist cumulative usage to session meta + auto-restore on startup (#1667, #1680, #1643, #1628)
- Plans: editMode="plan" enforced at the ToolRegistry dispatch gate (#1681); step advance fix (#1629)
- Context: fold once at turn start, drop pre-flight + byte-ceiling (#1642, #1646); collapsible compacted card (#1649)
- Subagents: per-skill flash/pro override + Settings UI (#1632)
- Desktop polish: sidebar drag-resize (#1688), responsive collapse (#1585), copy/edit overlay + msg-history nav (#1645), Esc closes modal not turn (#1685), QQ tab isolation (#1672), DiffCard for edits (#1662), theme-aware highlighting (#1655), system events toggle (#1654/#1650), macOS TCC inheritance (#1614), dashboard.enabled (#1612)
- Dashboard polish: persistent session URL (#1586, #1589, #1599), theme-aware highlighting (#1664), IME confirm-enter guard (#1689), code-fence lang fix (#1677), vendor chunk split (#1587), markdown table h-scroll (#1562)
- TUI: Alt+S input stash/recall; static history isolated from input rerenders (#1635); legacy mouse drop (#1637, #1648); multi-edit gated in review (#1647)
- Diff: SplitDiff column border holds under CJK (#1686)
- MCP: workspace roots passed to servers (#1625); codeCommand honors mcpServers (#1603)
- Config plumbing: (baseUrl, apiKey) resolved as a tuple (#1658); stale model id self-heal (#1663)

See CHANGELOG for the full list.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant