MemberJunction / MemberJunction/MJ
Remote Browser: closing the channel leaves the server-side browser running — there is no per-channel release
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
Found while implementing #3498 (close one live channel). Filing rather than folding into that PR, because the fix is a server change and #3498 is a UI/session-service change.
## What happens
`RemoteBrowserEngine`'s browser for an agent session is released by the **server-side** `RemoteBrowserChannel` plugin, on `OnSessionClosed` / `Dispose`:
```ts
// packages/AI/RemoteBrowser/Server/src/remote-browser-channel.ts
await RemoteBrowserEngine.Instance.EndSessionForAgentSession(agentSessionID);
```
That is session-scoped. When the CLIENT closes just the Remote Browser channel — the new `RealtimeSessionService.CloseChannel` from #3498 — the client plugin's `Dispose()` stops the screencast and the audio stream, but nothing tells the server that this channel is going away. So the headless Chrome keeps running until the whole session ends.
## Why it matters
It is the cost half of #3498's impact paragraph: a Remote Browser channel nobody wants keeps a browser alive server-side. Closing the channel makes it *invisible* rather than *gone*, which is the worse of the two states — the resource is still billed and still driveable through the server relay, and now nobody is watching it.
It gets sharper with #3531 (multiple browsers per session): a session can hold several, and closing one surface should release exactly that instance.
## Shape of a fix
A mutation meaning "this channel is going away for this session" — e.g. `EndRemoteBrowserSession(agentSessionID, instanceKey)` on `RemoteBrowserActionResolver`, forwarding to `RemoteBrowserEngine.EndSessionForAgentSession(agentSessionID, instanceKey)` behind the same ownership gate every other mutation uses — called from the Remote Browser client plugin's `Dispose()`.
Note that `instanceKey` is what makes this precise rather than a session-wide teardown; it lands in #3915.
More generally this is a missing seam: `BaseRealtimeChannelClient.Dispose()` has no way to say "release my server-side resources", and Remote Browser is simply the first channel that holds an expensive one.
## Related
- #3498 — close one live channel (the client half; merged/open PR notes this as explicitly out of scope)
- #3531 / #3915 — `instanceKey`, which the release call needs to be per-surface
Contributor guide
Research direction
Start with packages/AI/RemoteBrowser/Server/src/remote-browser-channel.ts and trace the existing OnSessionClosed/Dispose release path through RemoteBrowserEngine. Then inspect RemoteBrowserActionResolver and the Remote Browser client plugin's Dispose(), using instanceKey from #3915. Done means closing one channel releases its server-side browser while other browser instances in the session remain available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100