Skip to content

Fix port conflicts for concurrent sessions by dynamically assigning ports#2156

Merged
GeorgeNgMsft merged 15 commits intomainfrom
dev/georgeng/fix_as_easddr_use
Apr 9, 2026
Merged

Fix port conflicts for concurrent sessions by dynamically assigning ports#2156
GeorgeNgMsft merged 15 commits intomainfrom
dev/georgeng/fix_as_easddr_use

Conversation

@GeorgeNgMsft
Copy link
Copy Markdown
Contributor

@GeorgeNgMsft GeorgeNgMsft commented Apr 8, 2026

Goal
Eliminate port conflicts when multiple TypeAgent sessions start concurrently by switching from pre-assigned static ports to OS-assigned dynamic ports. Agents now bind on port 0 and report their actual bound port back to the dispatcher via IPC.

Also cleanup server startup/exit for browser & montage agents.

Summary

  • Agents with localView now bind to port 0 (OS-assigned) instead of a fixed base port
  • The view server process sends { type:"Success", port: } over IPC after starting, and the dispatcher stores the actual port via the new setLocalHostPort() API
  • Added closeAgentContext to browserActionHandler for proper process cleanup on shutdown
  • Fixed montage and markdown agent view process cleanup in closeAgentContext
  • Improved error handling: EADDRINUSE and other server startup errors are now surfaced clearly rather than silently failing
  • Removed portBase option and the nextPortIndex counter from AppAgentManager — no longer needed

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

Note

Copilot was unable to run its full agentic suite in this review.

Improves agent shutdown/startup robustness to reduce port-collision (EADDRINUSE) failures and to better clean up spawned processes/servers.

Changes:

  • Add explicit EADDRINUSE handling when starting the Montage route server and the Browser agent’s BaseServer.
  • Ensure Montage view process is terminated during context close.
  • Add closeAgentContext to the Browser agent to stop the websocket server and kill spawned processes.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
ts/packages/agents/montage/src/route/route.ts Wraps listen() to capture and report EADDRINUSE / server start failures
ts/packages/agents/montage/src/agent/montageActionHandler.ts Kills viewProcess on context close to avoid leakage
ts/packages/agents/browser/src/views/server/core/baseServer.ts Rejects start() on port-in-use instead of silently hanging/never resolving
ts/packages/agents/browser/src/agent/browserActionHandler.mts Adds closeAgentContext to stop websocket server and kill spawned processes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Set exit code instead of calling exit directly.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@GeorgeNgMsft GeorgeNgMsft changed the title Improve cleanup logic for browserActionHandler + montageActionHandler Fix port conflicts for concurrent sessions by dynamically assigning ports Apr 8, 2026
@GeorgeNgMsft GeorgeNgMsft requested a review from Copilot April 9, 2026 00:18
@GeorgeNgMsft GeorgeNgMsft marked this pull request as ready for review April 9, 2026 00:19
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

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

ts/packages/dispatcher/dispatcher/src/context/appAgentManager.ts:529

  • manifest.localView agents now store record.port = 0, which is treated as a real port elsewhere (e.g. activity handling opens http://localhost:0/ when openLocalView is requested). Consider keeping record.port as undefined until the view server reports its actual bound port via setLocalHostPort(), and separately pass 0 only as the requested listen port when initializing/spawning the view server.
        const port = manifest.localView ? 0 : undefined;

        if (port !== undefined) {
            debug(`Dynamic port (OS-assigned) reserved for ${appAgentName}`);
        }

        const record: AppAgentRecord = {
            name: appAgentName,
            provider,
            actions: new Set(),
            schemas: new Set(),
            schemaErrors,
            commands: false,
            manifest,
            port,
        };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@GeorgeNgMsft GeorgeNgMsft deployed to development-fork April 9, 2026 01:00 — with GitHub Actions Active
@GeorgeNgMsft GeorgeNgMsft added this pull request to the merge queue Apr 9, 2026
Merged via the queue into main with commit 42c4963 Apr 9, 2026
21 checks passed
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.

2 participants