Skip to content

feat(events): emit trigger.fired + memory.changed, event-drive those stores (closes #93, #101)#118

Merged
imran31415 merged 1 commit into
mainfrom
feat/sse-triggers-memory
Jun 17, 2026
Merged

feat(events): emit trigger.fired + memory.changed, event-drive those stores (closes #93, #101)#118
imran31415 merged 1 commit into
mainfrom
feat/sse-triggers-memory

Conversation

@umi-appcoder

@umi-appcoder umi-appcoder Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

What

Finishes the SSE migration — extends the event surface beyond tasks so the Triggers and Memory views are also real-time. Closes #93 (SSE event stream) and the polling-unification half of #101.

Backend (server.py)

  • trigger.fired — published from _fire_webhook (webhook received) and handle_cron_fire (k8s CronJob pod fires), {trigger_type, trigger_id, task_id}.
  • memory.changed — published from the memory upsert / delete / link handlers, {op, namespace, key}.

SPA

  • api/events.tstrigger.fired / memory.changed added to the subscribed event types.
  • store/triggers.ts + store/memory.ts — subscribe to the stream; a coalesced refresh fires on their event. The interval becomes a safety net: normal cadence when the stream is down, ~45s heartbeat when it's up.
    • The memory poll keeps its heartbeat on purpose: MCP-authored writes (from a Claude task) happen in a separate process and don't emit here, so the safety poll still catches them within ~45s.

Pure addition — behavior is unchanged when SSE is unavailable.

Verification

  • tsc clean; events.test.ts gains a trigger.fired/memory.changed dispatch case (7 tests); full SPA suite 119 passing.
  • Python suite 466 passing (emits are additive); yarn build OK.

Net result

All three live views (Build, Triggers, Memory) now update via push in <1s, with graceful poll fallbacks. The steady background polling is suppressed while the stream is healthy.

Closes #93
Closes #101

🤖 Generated with Claude Code

…stores

Completes the SSE migration (#93) and the polling-unification half of
#101 by extending the event surface beyond tasks.

Backend (server.py):
- trigger.fired — published from _fire_webhook (webhook received) and
  handle_cron_fire (k8s CronJob pod fires).
- memory.changed — published from the memory upsert / delete / link
  handlers ({op, namespace, key}).

SPA:
- api/events.ts: add trigger.fired / memory.changed to the subscribed
  event types.
- store/triggers.ts + store/memory.ts: subscribe to the stream and
  refresh (coalesced) on their event; the existing interval becomes a
  safety-net — it polls normally when the stream is down and slows to a
  ~45s heartbeat when it's up. The memory poll deliberately keeps the
  heartbeat because MCP-authored writes happen in a separate process and
  so don't emit here; the safety poll still catches them.

Behavior is unchanged when SSE is unavailable (pure addition).

Tests: events.test.ts gains a new-event-types dispatch case (7 total);
full SPA suite 119 passing; Python suite 466 passing; build OK.

Closes #93
Closes #101
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@imran31415 imran31415 merged commit 0fdc0b9 into main Jun 17, 2026
7 checks passed
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.

perf(spa): lazy-load routes + D3/marked, unify polling on usePoll feat: SSE event stream (/api/events) + background reconcile to replace polling

1 participant