Files
vscode/cli
5768d37c97 agent host: keep the idle timeout guard for the full websocket session (#330743)
* agent host: keep the idle timeout guard for the full websocket session

The `--idle-timeout` activity guard was released when a connection upgraded to a WebSocket, not
when the client disconnected. `serve_connection_with_upgrades` completes as soon as it hands the
transport to `hyper::upgrade::on`, so the task that held the guard ended a few milliseconds after
a WebSocket started. The idle timer then counted zero clients, armed, and 300 seconds later
stopped a supervisor that was still serving that client. The shutdown calls `kill_tree`, which
also stopped the agent host server and its child processes, so in-flight turns were lost.

Remote hosts showed this as a continuous restart loop. Agent host logs from one report contain 10
process starts in 50 minutes, each 297-299 seconds after its tunnel connection was established,
with no graceful shutdown message and a tool completion as the last line written. Connection
lifetime did not change with traffic: connections that carried 200 and 7,866 messages both ended
at approximately 305 seconds, and local (non-tunnel) connections in the same logs stayed up for
more than 2,900 seconds.

- Adds `idle_timeout::GuardedStream`, which holds the `ClientGuard` in the connection transport
  instead of the task that serves the connection. `hyper::upgrade::Upgraded` keeps the wrapped
  stream, so the guard now lives until the socket closes.
- Uses the wrapper in `AgentHostSidecar::serve` and in `serve_tunnel_connection`, so local and
  tunnel-relayed clients both report activity for their full connection.
- Takes an `Option<ClientGuard>` so callers wrap unconditionally and keep one stream type whether
  or not the idle timeout is enabled.
- Adds a regression test that upgrades a real WebSocket, exchanges a message, and makes sure that
  no disconnect is reported while the session is open and that the disconnect is still reported
  when the socket closes. The existing activity test used a bare TCP connection and could not
  find this problem.

(Commit message generated by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agent host: guard the dev-tunnel-hosted gateway connections

Addresses review feedback: the first change covered `AgentHostSidecar::serve_tunnel_connection`,
which has no call sites. The live `--tunnel` path in `run_supervisor` hands each relayed socket
straight to `serve_agent_host_tunnel_connection`, so those connections were still unguarded.

The gateway's inner dial back into our own listener does not close the gap. It only applies when a
selection resolves to this supervisor. A client that is still deciding what to select, or whose
selection resolves to a different live endpoint or a new dedicated host, never reaches our accept
loop, so the supervisor that owns the tunnel counted zero clients and could stop itself while it
was actively proxying that client.

- Adds `AgentHostSidecar::activity_tracker`, which gives callers that serve connections the
  sidecar did not accept a handle to report activity.
- Wraps each relayed tunnel socket in `run_supervisor` with `idle_timeout::GuardedStream`, so the
  guard survives the WebSocket upgrade and lasts for the full proxied session.
- Corrects the comment that said the inner self-dial was sufficient.
- Adds a regression test that selects a different endpoint through the real tunnel router and
  exchanges frames, which fails if the guard is held by the serving task instead of the transport.
- Adds a persistent echo endpoint helper so a test can tell "session still live" apart from "the
  target hung up".

(Commit message generated by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-13 22:19:00 +00:00
..