address Copilot review: auth-pending unstick, upstream cache eviction, spawn-port bridge fallback, resolver mutex

This commit is contained in:
Connor Peet
2026-05-13 15:45:16 -07:00
parent 979d3176a2
commit ed0ba94d59
4 changed files with 45 additions and 11 deletions
@@ -159,6 +159,21 @@ export function activate(context: vscode.ExtensionContext) {
commandArgs.push('--connection-token', connectionToken);
const agentHostPort = getConfiguration('agentHostPort');
const agentHostBridgePort = getConfiguration('agentHostBridgePort');
if (
typeof agentHostPort === 'number' && agentHostPort > 0 &&
typeof agentHostBridgePort === 'number' && agentHostBridgePort > 0
) {
// `agentHostPort` spawns an agent host inside the server;
// `agentHostBridgePort` bridges the renderer to an
// externally-running one. They contradict each other —
// reject up front so the user notices instead of getting
// two agent hosts and silently confusing failure modes.
throw new Error(
`testResolver: 'agentHostPort' and 'agentHostBridgePort' are mutually exclusive. ` +
`Configure at most one (got port=${agentHostPort}, bridge=${agentHostBridgePort}).`
);
}
if (typeof agentHostPort === 'number' && agentHostPort > 0) {
commandArgs.push('--agent-host-port', String(agentHostPort));
}
@@ -166,7 +181,6 @@ export function activate(context: vscode.ExtensionContext) {
// Bridge to an externally-running agent host (e.g. one started
// by `code agent host`). Mutually exclusive with `agentHostPort`
// — that one spawns its own agent host.
const agentHostBridgePort = getConfiguration('agentHostBridgePort');
if (typeof agentHostBridgePort === 'number' && agentHostBridgePort > 0) {
commandArgs.push('--agent-host-bridge-port', String(agentHostBridgePort));
}
+10
View File
@@ -256,6 +256,16 @@ export class AgentHostChannel<TContext> extends Disposable implements IServerCha
if (!conn) {
conn = this._upstreamFactory(this._endpoint);
this._perCtx.set(ctx, conn);
// If the upstream closes on its own (e.g. agent host restart or
// connection drop), evict it from the cache so the next
// `connect()` call creates a fresh upstream rather than
// returning the stuck-closed one.
const sub = conn.onClose(() => {
sub.dispose();
if (this._perCtx.get(ctx) === conn) {
this._perCtx.delete(ctx);
}
});
}
return conn;
}
+18 -10
View File
@@ -270,17 +270,25 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
disposables.add(instantiationService.createInstance(ServerAgentHostManager, agentHostStarter));
}
// The bridge requires an explicit upstream — we do NOT fall back to
// the spawn port. When `--agent-host-port=0` is used the OS picks a
// port at runtime that this server has no way of learning; in the
// `code tunnel` flow the CLI captures that port from the AH's
// readiness line and passes it back as `--agent-host-bridge-port` on
// the renderer-serving servers. The manager-spawned AH itself never
// serves renderer connections directly, so it doesn't need a bridge.
const bridgePort = args['agent-host-bridge-port'];
const bridgePath = args['agent-host-bridge-path'];
// The bridge upstream defaults to the agent host this server just
// spawned, but ONLY when that endpoint is dialable at configuration
// time — i.e. an explicit non-zero port or a socket path. When
// `--agent-host-port=0` is used the OS picks a port at runtime that
// this server has no way of learning, so we refuse to register a
// bridge against a placeholder `0`; in that case the caller (the CLI
// `code tunnel` flow) is expected to capture the bound port from the
// AH's readiness line and pass it back as `--agent-host-bridge-port`
// on the renderer-serving servers. Explicit `--agent-host-bridge-*`
// always wins over the spawn fallback.
const spawnPortNumber = spawnPort ? parseInt(spawnPort, 10) : NaN;
const hasUsableSpawnPort = Number.isFinite(spawnPortNumber) && spawnPortNumber > 0;
const bridgePort = args['agent-host-bridge-port'] ?? (hasUsableSpawnPort ? spawnPort : undefined);
const bridgePath = args['agent-host-bridge-path'] ?? spawnPath;
const bridgeHost = args['agent-host-bridge-host'] ?? args.host ?? 'localhost';
const bridgeToken = args['agent-host-bridge-connection-token'];
const bridgeToken = args['agent-host-bridge-connection-token']
?? ((bridgePort || bridgePath) && spawnAgentHost && connectionToken.type === ServerConnectionTokenType.Mandatory
? connectionToken.value
: undefined);
if (bridgePort || bridgePath) {
const agentHostBridge = disposables.add(new AgentHostChannel<RemoteAgentConnectionContext>(
socketServer,
@@ -67,10 +67,12 @@ export class EditorRemoteAgentHostServiceClient extends Disposable implements IA
if (!enabled) {
this._logService.info(`${LOG_PREFIX} Disabled via "${AgentHostEnabledSettingId}". Not connecting.`);
this.setAuthenticationPending(false);
return;
}
if (!connection) {
this._logService.warn(`${LOG_PREFIX} No remote agent connection available. Not connecting.`);
this.setAuthenticationPending(false);
return;
}