Skip to content

feat: session-based conversation reuse for event-triggered automations#118

Draft
malhotra5 wants to merge 1 commit into
mainfrom
feat/session-based-event-routing
Draft

feat: session-based conversation reuse for event-triggered automations#118
malhotra5 wants to merge 1 commit into
mainfrom
feat/session-based-event-routing

Conversation

@malhotra5
Copy link
Copy Markdown
Member

Closes #105

Adds the foundational infrastructure for session-based conversation reuse: related webhook events (e.g. all comments on the same GitHub PR, messages in the same Slack thread) can now be routed to the same running sandbox rather than spawning a fresh sandbox per event.

Changes

schemas.py

  • New SessionConfig model with key_expr (JMESPath expression to extract session key from payload), idle_timeout_seconds, session_timeout_seconds, and on_sandbox_death (queue|restart|drop)
  • EventTrigger.session: SessionConfig | None — opt-in session routing per automation
  • EventResponse.events_queued — count of events routed to existing sessions (backward compatible, defaults to 0)

models.py

  • New SessionStatus enum (ACTIVE, EXPIRED, DEAD)
  • New AutomationSession table — tracks which sandbox owns each session
  • New PendingSessionEvent table — queues events for delivery to the active sandbox

migrations/versions/005_session_tables.py

  • Creates automation_sessions and pending_session_events tables with compound indexes for the primary lookup pattern

utils/session.py (new)

  • extract_session_key(key_expr, payload) — JMESPath key extraction with safe fallback to None
  • get_active_session(automation_id, session_key, session) — DB lookup with expiry check
  • create_session(...) — creates ACTIVE session record
  • queue_pending_event(...) — stores event and bumps session.last_event_at
  • mark_session_dead(run, session) — optimistic-locking transition to DEAD

event_router.py

Session routing in receive_event:

  • For automations with session config: extract the session key and check for an active session
  • If active session found → queue as PendingSessionEvent (no new run created)
  • If no active session → create a new run as before

dispatcher.py

  • After successful dispatch, _maybe_create_session() creates an AutomationSession record when the trigger has session config

watchdog.py

  • After marking a stale run terminal, calls mark_session_dead() so the event router stops routing events to the dead sandbox

tests/test_session.py (new)

30 tests covering SessionConfig validation, EventTrigger with session, extract_session_key edge cases, and EventResponse.events_queued.

Usage Example

// GitHub PR: route all events on the same PR to one session
{
  "trigger": {
    "type": "event",
    "source": "github",
    "on": ["issue_comment.created", "pull_request.synchronize"],
    "filter": "icontains(comment.body, '@openhands')",
    "session": {
      "key_expr": "pull_request.number || issue.number",
      "idle_timeout_seconds": 600,
      "session_timeout_seconds": 7200,
      "on_sandbox_death": "restart"
    }
  }
}

What's NOT yet implemented (follow-up work)

  • Agent-server event queue endpoints (POST/GET/DELETE /api/workspace/events) in OpenHands/software-agent-sdk — required for the SDK to poll pending events from inside the sandbox
  • Preset script session mode loop — the SDK-side polling loop that processes queued events
  • on_sandbox_death = "restart" auto-requeue — watchdog extension to immediately create a new run with queued events

This PR was created by an AI agent (OpenHands) on behalf of the user.

@malhotra5 can click here to continue refining the PR

#105)

Adds session routing infrastructure so related webhook events (e.g.
all comments on the same GitHub PR) can be routed to the same running
sandbox rather than spawning a fresh sandbox per event.

## Changes

### schemas.py
- New  model with  (JMESPath), ,
  , and  (queue|restart|drop)
-  — opt-in per automation
-  — count of events routed to existing sessions

### models.py
- New  enum (ACTIVE, EXPIRED, DEAD)
- New  table — tracks the sandbox owning a session
- New  table — queues events for active/dead sessions

### migrations/versions/005_session_tables.py
- Creates  and  tables with
  appropriate indexes (compound lookup on automation_id + session_key + status)

### utils/session.py (new)
-  — JMESPath extraction with safe fallback
-  — DB lookup
-  — creates ACTIVE session record for a run
-  — stores event and bumps session.last_event_at
-  — optimistic-locking transition to DEAD

### event_router.py
- Session routing: when a matched automation has session config, extract the
  session key and look up an active session. If found, queue as
  PendingSessionEvent; if not, create a new run as before.

### dispatcher.py
- After successful dispatch, calls  which creates an
   record when the trigger has session config.

### watchdog.py
- After marking a stale run terminal, calls  so the event
  router stops routing to the dead sandbox.

### tests/test_session.py (new)
- 30 tests covering  validation,  with session,
   edge cases, and .

## What's NOT yet implemented

- Agent-server event queue endpoints ()
  — these live in the SDK repo (OpenHands/software-agent-sdk) and are
  required for the SDK to poll pending events from the sandbox.
- Preset script session mode loop (SDK-side polling of pending events).
-  auto-requeue logic (watchdog extension).

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions
Copy link
Copy Markdown

Coverage

@github-actions
Copy link
Copy Markdown

🚀 Deploy Preview PR Created/Updated

A deploy preview has been created/updated for this PR.

Deploy PR: https://github.com/OpenHands/deploy/pull/4309
Automation SHA: b57af92dc81bc1de60cff19904f44c59d5a83537
Last updated: May 15, 2026, 03:27:04 PM ET

Once the deploy PR's CI passes, the automation service will be deployed to the feature environment.

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.

Feature: Session-based conversation reuse for event-triggered automations

2 participants