Skip to content

[heartstone] Phase 11 — Session Management + Reconnection#8670

Open
kevinpschaaf wants to merge 4 commits into
mainfrom
heartstone-phase-11
Open

[heartstone] Phase 11 — Session Management + Reconnection#8670
kevinpschaaf wants to merge 4 commits into
mainfrom
heartstone-phase-11

Conversation

@kevinpschaaf
Copy link
Copy Markdown
Collaborator

What

Adds a "Sessions" devtools tab for per-graph session management, session reconnection with event replay, and a unified suspend/resume flow for all input types (inputNode, waitForInput, waitForChoice).

Why

Previously, running a graph created a session with no way to reconnect if the browser tab was closed or the user navigated away. Completed and suspended sessions were invisible. This phase makes sessions first-class: users can view session history, reconnect to running/suspended sessions, and delete old ones — all through the existing devtools panel.

Changes

Backend (opal-backend)

  • Session monitor SSE endpoint (GET /v1beta1/graphSessions?graphId=X): streams the current session list plus live status changes as sessions progress
  • Delete endpoint (DELETE /v1beta1/graphSessions/{id}): removes a session and its graph index entry
  • replayComplete marker: emitted after replaying historical events so the frontend knows when to switch from replay to live mode
  • graph_id made required in GraphSessionStore.create (protocol + impl) — every session must be associated with a graph
  • Access token forwarding through the resume flow for agent authentication

Frontend (visual-editor)

  • SessionHistoryController: signal-backed controller under editor.devtools tracking the active session, connection state, and session list
  • session-actions.ts: SCA actions for connect/disconnect/delete/monitor — connectToSession uses handleInputRequested for the input lifecycle
  • sessions-panel.ts: devtools "Sessions" tab UI showing per-graph session history with status dots, timestamps (now with date), and connect/delete controls
  • GraphRunService extensions: connectSession(), monitorSessions(), deleteSession(), and cancelSession() methods for session lifecycle management
  • Unified handleSuspend: single handler for inputNode, waitForInput, and waitForChoice suspend events, replacing scattered suspend logic
  • consumeSessionEvents extraction: deduplicated the event loop between startBackendRun and connectToSession (~150 lines removed), with shared initRunState setup helper
  • waitForChoice rendering: uses ChoicePresenter + A2UIInteraction to render proper choice buttons instead of falling back to a text input

Tests

  • 8 new handleSuspend tests: covers all three suspend types, early-return guards (no suspendEvent, no console entry, unknown type), schema behavior verification, and abort handling
  • Backend test updates: graph_id now required in all store.create calls across test_graph_session_store.py, test_agent_integration.py, test_headless_mode.py
  • New test_graph_session_router.py: integration tests for session creation, SSE streaming, replay, and the monitor endpoint

Testing

# Backend tests
cd packages/opal-backend
.venv/bin/python -m pytest tests/test_graph_session_store.py tests/test_graph_session_router.py tests/test_agent_integration.py tests/test_headless_mode.py -v

# Frontend tests
cd packages/visual-editor
npm run test:file -- './dist/tsc/tests/sca/actions/run/backend-run-action.test.js'

Manual verification:

  1. Run a graph → sessions tab shows the active session with a green dot
  2. Click a different session → UI replays events and reconnects
  3. Close/reopen the sessions tab → session list persists via SSE monitor
  4. Delete a session → removed from list
  5. Reconnect to a suspended session → input UI appears after replay

…arker

Backend changes for session management:
- GraphSessionStore: added SessionSummary, graph_id tracking, list_sessions(), delete_session()
- InMemoryGraphSessionStore: graph index, optional EventBus for status publishing
- Router: GET / monitor SSE (uniform sessionStatus events), DELETE /{id},
  replayComplete marker in per-session stream, graphId dual-purpose (Drive
  loading vs. session scoping)
- Tests: 17 new tests covering store and router changes
- PROJECT.md: Phase 11 expanded with full design and decisions
Service layer:
- GraphRunEvent: added replayComplete, graphCancelled event types
- SessionStatusEvent: new type for monitor stream
- GraphRunService: createSession now requires graphId, added
  connectSession, monitorSessions, deleteSession methods

Controller layer:
- SessionHistoryController: reactive session map (deep signal),
  activeSessionId, monitor/connection abort controllers
- DevToolsController: wired sessionHistory subcontroller

Action layer:
- session-actions: startSessionMonitor (SSE → controller bridge),
  stopSessionMonitor, deleteSession
- backend-run-action: passes graphId to createSession, handles
  replayComplete and graphCancelled events

UI layer:
- bb-devtools-sessions-panel: session list with status dots,
  timestamps, connect-on-click, delete buttons
- devtools.ts: Sessions tab gated behind enableBackendGraphRunner flag
- Monitor auto-starts on tab connect, stops on disconnect
backend-run-action:
- EventMode type: 'live' (interactive) vs 'replay' (non-blocking)
- processEvent: mode-aware; inputRequired returns 'continue' in replay
- createBridge: mode-aware; shows prompt text but skips input UI in replay
- connectToSession: two-phase stream processing (replay → replayComplete → live)
- startBackendRun: sets activeSessionId after creating session

sessions-panel:
- Session click calls connectToSession directly
- Unified handleSuspend for inputNode/waitForInput/waitForChoice events
- Fixed waitForChoice rendering using ChoicePresenter + A2UIInteraction
- Extracted consumeSessionEvents and initRunState to deduplicate the
  event loop between startBackendRun and connectToSession (~150 lines)
- Made graph_id required in GraphSessionStore.create (protocol + impl)
- Added date display in devtools sessions list
- Added handleSuspend test suite (8 tests covering all branches)
- Exported handleSuspend for testability
- Fixed graph_runner access_token forwarding through resume flow
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