Skip to content

Agents tunnels: auto-reconnect with backoff and wake-triggered retry#310868

Merged
osortega merged 4 commits intomainfrom
osortega/agents-tunnel-reconnect
Apr 17, 2026
Merged

Agents tunnels: auto-reconnect with backoff and wake-triggered retry#310868
osortega merged 4 commits intomainfrom
osortega/agents-tunnel-reconnect

Conversation

@osortega
Copy link
Copy Markdown
Contributor

Summary

Tunnel-backed remote agent hosts previously had no auto-reconnect behavior — on laptop sleep or network drop the tunnel would flip to Disconnected and stay there until the user manually retried. This adds a reconnect loop inside TunnelAgentHostContribution.

Changes

In src/vs/sessions/contrib/remoteAgentHost/browser/tunnelAgentHost.contribution.ts:

  • Detect Connected → Disconnected transitions for still-cached tunnels and schedule an immediate reconnect. Only fires when the entry is explicitly Disconnected — if the entry has been removed from the connection list (e.g. user clicked "Remove Remote"), we honour the removal and do not reconnect.
  • Exponential backoff on consecutive failures: 1s → 30s cap, up to 10 attempts, then pause.
  • Wake-triggered retry (web only): on browser online or tab visibilitychange → visible, resume any paused reconnects. Rate-limited to one resume per 10s so rapid tab toggling can't hammer a permanently broken endpoint with unbounded attempt bursts. Only clears the attempt counter when the address is actually paused, so in-progress backoff sequences aren't short-circuited.
  • State pruning when a tunnel is uncached or the contribution is disposed (all pending setTimeouts cleared).
  • _connectTunnel now resets backoff/pause state on success and re-schedules on failure via _scheduleReconnect.

Related

Pairs with the microsoft/vscode-dev PR that adds offline + long-hidden-resume force-close to the browser tunnel WebSocket.

Risk

  • Scoped to TunnelAgentHostContribution — does not touch the generic IRemoteAgentHostService reconnect machinery (which still explicitly skips tunnel entries in reconnect()).
  • Wake listeners are isWeb-gated.
  • Status UI update is through the existing _updateConnectionStatuses path — no new UI surface.

Follow-ups (not in this PR)

  • Unit tests for the reconnect state machine.
  • Telemetry for reconnect attempts / pause events.
  • A manual "Retry now" action on the provider.

Tunnel-backed remote agent hosts previously had no auto-reconnect
behavior — on laptop sleep / network drop the tunnel would flip to
Disconnected and stay there until the user manually retried.

This adds a reconnect loop inside TunnelAgentHostContribution:

- Detect Connected→Disconnected transitions for still-cached tunnels
  and schedule an immediate reconnect. Only fires when the entry is
  explicitly Disconnected — if the entry has been removed (e.g. user
  clicked "Remove Remote"), we honour the removal and do not reconnect.
- Exponential backoff on consecutive failures: 1s → 30s cap, up to
  10 attempts, then pause.
- Wake-triggered retry: on browser `online` or tab
  `visibilitychange` → visible, resume any paused reconnects.
  Rate-limited to one resume per 10s so rapid tab toggling can't
  hammer a permanently broken endpoint with unbounded attempt bursts.
- Prune all reconnect state when a tunnel is uncached or the
  contribution is disposed.
Copilot AI review requested due to automatic review settings April 16, 2026 23:03
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds auto-reconnect behavior for tunnel-backed remote agent hosts in the Agents window (vs/sessions), improving resilience to sleep/network drops by retrying tunnel connections with exponential backoff and web wake triggers.

Changes:

  • Detects Connected → Disconnected transitions for cached tunnel addresses and schedules reconnect attempts.
  • Implements exponential backoff with a max delay cap and a pause after a fixed number of failures.
  • Adds web-only wake-triggered resume (online, visibilitychange) plus reconnect-state pruning/cleanup.
Show a summary per file
File Description
src/vs/sessions/contrib/remoteAgentHost/browser/tunnelAgentHost.contribution.ts Adds reconnect state machine (tracking statuses, timers, attempts, pause/resume) and web wake listeners to automatically re-establish tunnel connections.

Copilot's findings

Comments suppressed due to low confidence (1)

src/vs/sessions/contrib/remoteAgentHost/browser/tunnelAgentHost.contribution.ts:460

  • _pruneReconnectState clears timeouts/attempts/pause flags for uncached tunnels, but _previousStatuses is only pruned from _handleConnectionChanges (which doesn’t run on tunnel-cache changes). If a tunnel is uncached and later re-cached without a connection-change event, the stale previous status can cause a spurious Connected→Disconnected transition and immediate reconnect scheduling. Consider also pruning _previousStatuses for uncached addresses as part of _pruneReconnectState.
	/** Drop reconnect state for addresses whose tunnel is no longer cached. */
	private _pruneReconnectState(): void {
		const cachedAddresses = new Set(
			this._tunnelService.getCachedTunnels().map(t => `${TUNNEL_ADDRESS_PREFIX}${t.tunnelId}`)
		);
		for (const address of [...this._reconnectTimeouts.keys()]) {
			if (!cachedAddresses.has(address)) {
				this._cancelReconnect(address);
			}
		}
		for (const address of [...this._reconnectAttempts.keys()]) {
			if (!cachedAddresses.has(address)) {
				this._reconnectAttempts.delete(address);
			}
		}
		for (const address of [...this._reconnectPaused]) {
			if (!cachedAddresses.has(address)) {
				this._reconnectPaused.delete(address);
			}
		}
  • Files reviewed: 1/1 changed files
  • Comments generated: 2

Comment thread src/vs/sessions/contrib/remoteAgentHost/browser/tunnelAgentHost.contribution.ts Outdated
Co-authored-by: Copilot <copilot@github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 17, 2026

Screenshot Changes

Base: b3b68311 Current: 5e267b04

Changed (42)

chat/aiCustomizations/aiCustomizationManagementEditor/WelcomePage/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/LocalHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/CliHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/Sessions/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SessionsSkillsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SkillsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/InstructionsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/WelcomePage/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/LocalHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/CliHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/Sessions/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SessionsSkillsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SkillsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/InstructionsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTabNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationWelcomePages/WelcomePage/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PluginsTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpServersTabNarrow/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTabNarrow/Light
Before After
before after
chat/aiCustomizations/aiCustomizationWelcomePages/WelcomePage/Light
Before After
before after
editor/inlineCompletions/other/JumpToHint/Dark
Before After
before after
agentSessionsViewer/CompletedUnread/Dark
Before After
before after
agentSessionsViewer/WithDiffChanges/Dark
Before After
before after
agentSessionsViewer/CompletedUnread/Light
Before After
before after
agentSessionsViewer/WithDiffChanges/Light
Before After
before after

Added (18)

chat/aiCustomizations/aiCustomizationManagementEditor/McpDisabledByUser/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/McpDisabledByPolicy/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/PluginsDisabledByUser/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/PluginsDisabledByPolicy/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/AgentsItemEditor/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/McpServerDetail/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/PluginDetail/Dark

current

chat/aiCustomizations/aiCustomizationManagementEditor/McpDisabledByUser/Light

current

chat/aiCustomizations/aiCustomizationManagementEditor/McpDisabledByPolicy/Light

current

chat/aiCustomizations/aiCustomizationManagementEditor/PluginsDisabledByUser/Light

current

chat/aiCustomizations/aiCustomizationManagementEditor/PluginsDisabledByPolicy/Light

current

chat/aiCustomizations/aiCustomizationManagementEditor/AgentsItemEditor/Light

current

chat/aiCustomizations/aiCustomizationManagementEditor/McpServerDetail/Light

current

chat/aiCustomizations/aiCustomizationManagementEditor/PluginDetail/Light

current

editor/inlineChatZoneWidget/InlineChatZoneWidget/Light

current

editor/inlineChatZoneWidget/InlineChatZoneWidget/Dark

current

editor/inlineChatZoneWidget/InlineChatZoneWidgetTerminated/Dark

current

editor/inlineChatZoneWidget/InlineChatZoneWidgetTerminated/Light

current

osortega and others added 2 commits April 17, 2026 11:30
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
@osortega osortega marked this pull request as ready for review April 17, 2026 18:44
@osortega osortega enabled auto-merge (squash) April 17, 2026 18:59
@osortega osortega merged commit ea6aac9 into main Apr 17, 2026
26 checks passed
@osortega osortega deleted the osortega/agents-tunnel-reconnect branch April 17, 2026 19:07
@vs-code-engineering vs-code-engineering bot added this to the 1.117.0 milestone Apr 17, 2026
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.

3 participants