MemberJunction / MemberJunction/MJ

Remote Browser: closing the channel leaves the server-side browser running — there is no per-channel release

Open
#3,919 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.