Repository navigation
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
[Feature Request] Support sessionID Filter for SSE Event Subscription
Summary
Add support for sessionID query parameter in the /event SSE endpoint to allow clients to subscribe to events for specific sessions only, rather than receiving all events and filtering client-side.
Problem Statement
Currently, the /event endpoint broadcasts all events to all subscribers. Clients must filter events by sessionID on their own. This design causes significant issues in multi-session and multi-node deployment scenarios.
Current Behavior
GET /event?directory=/path/to/project
Returns: ALL events from all sessions in that directory.
Evidence from Source Code
Even OpenCode's internal code filters by sessionID on the client side:
packages/opencode/src/tool/task.ts:111-112
const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
if (evt.properties.part.sessionID !== session.id) return // Client-side filtering
// ...
})packages/opencode/src/cli/cmd/github.ts:840-841
Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
if (evt.properties.part.sessionID !== session.id) return // Client-side filtering
// ...
})packages/opencode/src/server/server.ts:475
const unsub = Bus.subscribeAll(async (event) => { // Subscribes to ALL events
await stream.writeSSE({
data: JSON.stringify(event),
})
})Use Cases
1. Cloud SaaS Deployment
┌─────────────────────────────────┐
│ Load Balancer (Nginx) │
└───────────────┬─────────────────┘
┌───────┬───────────┼───────────┬───────┐
▼ ▼ ▼ ▼ ▼
Backend Backend Backend Backend Backend
Node 1 Node 2 Node 3 Node 4 Node 5
└───────┴───────────┴───────────┴───────┘
│
▼
OpenCode Server
Problems:
- Each backend node needs its own SSE connection
- All nodes receive ALL events (massive bandwidth waste)
- Each node must filter events for its sessions
- Linear scaling of connections and data transfer
2. Multi-Session Web IDE
A web-based IDE with multiple sessions open simultaneously:
// User has 3 sessions open
// Current: Must subscribe once and filter ALL events
const events = await fetch('/event?directory=/project');
// For each event, check which session it belongs to
if (event.properties.part.sessionID === 'ses_session1') { /* update UI 1 */ }
if (event.properties.part.sessionID === 'ses_session2') { /* update UI 2 */ }
if (event.properties.part.sessionID === 'ses_session3') { /* update UI 3 */ }3. Backend Service (Telegram Bot, Slack Bot, etc.)
As described in Issue #6573:
A Node.js service uses the @opencode-ai/sdk to interact with OpenCode via REST API, polling session status and streaming responses back to users. Sessions hang indefinitely when the LLM uses the Task tool to spawn subagents, because subagent events come through the same subscription.
Proposed Solution
Option A: Add sessionID Query Parameter (Recommended)
GET /event?sessionID=ses_xxx
GET /event?directory=/path/to/project&sessionID=ses_xxx
Benefits:
- Simple and straightforward
- Backward compatible (existing
/eventbehavior unchanged) - Reduces bandwidth waste significantly
- Enables proper multi-node deployment
Implementation Suggestion:
// packages/opencode/src/server/server.ts
.get("/event", async (c) => {
const sessionID = c.req.query("sessionID");
return streamSSE(c, async (stream) => {
stream.writeSSE({
data: JSON.stringify({ type: "server.connected", properties: {} }),
});
const unsub = Bus.subscribeAll(async (event) => {
// If sessionID filter is specified, only send matching events
if (sessionID) {
const eventSessionID =
event.properties?.part?.sessionID ||
event.properties?.info?.sessionID ||
event.properties?.info?.id ||
event.properties?.sessionID;
if (eventSessionID && eventSessionID !== sessionID) {
return; // Skip events for other sessions
}
}
await stream.writeSSE({ data: JSON.stringify(event) });
});
// ... rest of the handler
});
})Option B: Support Multiple Session Subscription
GET /event?sessionIDs=ses_xxx,ses_yyy,ses_zzz
Option C: WebSocket with Dynamic Subscription
const ws = new WebSocket('/ws/events');
// Subscribe to specific sessions
ws.send(JSON.stringify({
type: 'subscribe',
sessionIDs: ['ses_xxx', 'ses_yyy']
}));
// Dynamically add/remove subscriptions
ws.send(JSON.stringify({
type: 'unsubscribe',
sessionIDs: ['ses_xxx']
}));Performance Impact
Current (Without sessionID Filter)
With 100 concurrent sessions and 10 backend nodes:
| Metric | Value |
|---|---|
| SSE Connections | 10 (one per node) |
| Events Transferred | 10x (every event sent to all nodes) |
| Client CPU | High (filtering 100 sessions worth of events) |
| Network Bandwidth | 10x waste |
Proposed (With sessionID Filter)
| Metric | Value |
|---|---|
| SSE Connections | 100 (one per session, distributed across nodes) |
| Events Transferred | 1x (each event sent once to correct subscriber) |
| Client CPU | Minimal (no filtering needed) |
| Network Bandwidth | Optimal |
Related Issues
- #6573 - Sessions hang indefinitely when Task tool spawns subagents via REST API - Root cause is mixed events from parent and child sessions
- #6142 - Add sessionID to experimental.chat.system.transform hook - Related sessionID tracking request
- #2168 - API documentation - Questions about session event handling
Current Workaround
We currently use Redis Pub/Sub as middleware to handle session-specific event routing:
OpenCode Server
↓ (1 SSE connection)
Dedicated Subscriber Service
↓ (Parse sessionID, publish to channel)
Redis Pub/Sub (channel per session)
↓ (Subscribe by channel)
Backend Nodes (N instances)
This works but adds significant architectural complexity and operational overhead.
Environment
- OpenCode Version: 1.1.27
- Deployment: Multi-node (4+ instances behind load balancer)
- Use Case: Cloud SaaS Platform with multiple concurrent users
Additional Context
I have verified through source code analysis that:
- The current Bus implementation broadcasts all events (
Bus.subscribeAll) - Even OpenCode's own internal code filters by sessionID client-side
- The SSE endpoint in
server.ts:475simply forwards all Bus events without filtering
I am willing to contribute a PR for this feature if the approach is approved.
Labels: enhancement, api, sse, multi-tenant
Activity
github-actions commentedon Jan 20, 2026
This issue might be a duplicate of existing issues. Please check:
servedeployments #5784: MCP auth configuration for multi-tenantservedeployments (Related multi-tenant concern)Feel free to ignore if none of these address your specific case.
dammitpogi commentedon Mar 1, 2026
+1 on session-scoped SSE filtering — we're about to need this for our Jules integration.
We're adding Google Jules support (it's a session-based agent that uses polling), and we want the IDE experience to feel native. Our plan is to emit normalized jules.* Bus events — things like jules.run.created, status, plan, activity, artifact — and have the UI consume them through /event.
The problem is that /event currently broadcasts every bus event to every subscriber. For long-running agent sessions, that gets noisy fast. A simple /event?sessionID=... filter would help us:
On our end, we'll always include openCodeSessionID in the properties field of every jules.* event, so client-side routing works right away. Server-side filtering would just let us drop irrelevant events earlier in the pipeline.
github-actions commentedon May 1, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.