Skip to content

[remote-copilot-sdk] Complete + host server-side chat-client transport listener (builds CopilotSdkChatClient from AgentDefinition) #1314

Description

@JoshuaRowePhantom

Part of #1313

Summary

Complete and host the server-side chat-client transport listener so that a REMOTE Phantom.Workspaces user-computer-profile can receive an AgentDefinition on the chat-client channel, construct a CopilotSdkChatClient (or any other executor IChatClient) via AgentFactory, and serve it back to the SOURCE via ChatClientOverTransport. Register the listener in production so this path is reachable.

This is foundational for the docs/design/remote-chat-client-session.md topology (local router + local persistence + remote SDK chat client). Without this, no source AgentChat can obtain a remote CopilotSdkChatClient.

Dependencies

  • None. (Foundational.)

Root Cause / Current State

  • features/Phantom.Workspaces.Transport/Chat/ChatClientTransportListener.cs:12 — the constructor takes a pre-built IChatClient chatClient.
  • ChatClientTransportListener.cs:20-29 — OnChannelOpenAsync delegates every chat-client channel to that single fixed instance. It never reads an AgentDefinition from the wire payload; it cannot per-channel construct an executor client.
  • features/Phantom.Workspaces.Llm.Core/AgentFactory.cs:210, 224, 301 — CreateChatClient / CreateChatClientAsync, with the github-copilot provider dispatch at :278 / :353, and the Copilot-SDK client builder starting at CreateGitHubCopilotClient :814+. These are the intended factories the listener should invoke.
  • features/Phantom.Workspaces.Transport/ReverseHttp/ReverseExecutionDispatcher.cs — the reverse-http transport server dispatch. It does not register a chat-client listener today (see docs/design/unified-transport-production-cutover.md), so even a correctly-implemented listener is not hosted in production.

Net effect: today there is no wire path where the remote instance receives an AgentDefinition and builds a CopilotSdkChatClient per turn; #1313's scenario cannot be reached.

Affected Files

  • features/Phantom.Workspaces.Transport/Chat/ChatClientTransportListener.cs
  • features/Phantom.Workspaces.Transport/ReverseHttp/ReverseExecutionDispatcher.cs
  • Transport host/registry wiring on the server side (whatever registers listeners in production per docs/design/unified-transport-production-cutover.md).
  • (No test-only touches here; test harness lands in sibling sub-items.)

Design / Fix

  1. Extend ChatClientTransportListener (or introduce a companion listener) so OnChannelOpenAsync reads an AgentDefinition from the chat-client open payload and builds the executor IChatClient per channel via AgentFactory.CreateChatClient(AgentDefinition) / CreateChatClientAsync(...) (dispatching through github-copilot at AgentFactory.cs:278 / :353 → Copilot SDK client builder at :814+).
  2. The constructed client's lifetime is scoped to the channel; dispose on channel close.
  3. Register the listener on the transport server / ReverseExecutionDispatcher following the pattern described in docs/design/unified-transport-production-cutover.md. The registration must be reachable in production, not test-only.
  4. Preserve the existing pre-built IChatClient path (used by current tests) as an overload / fallback where the payload omits AgentDefinition, so this change is additive and non-breaking.

Expected Tests

Test Asserts
ChatClientTransportListener_ReceivesAgentDefinition_BuildsChatClientViaAgentFactory Given a chat-client channel opened with a wire-carried AgentDefinition (provider github-copilot), the listener invokes AgentFactory.CreateChatClientAsync (verified via spy/fake factory) and services subsequent chat requests through the resulting IChatClient.
ChatClientTransportListener_PerChannelClientLifetime_DisposesOnChannelClose The IChatClient built for a channel is disposed when the channel closes (verified via disposable spy).
ReverseExecutionDispatcher_RegistersChatClientListener_ServesChatClientChannels With production wiring in place, a chat-client channel open request is dispatched to ChatClientTransportListener (verified against HubRelayHarness or equivalent loopback).
ChatClientTransportListener_LegacyPreBuiltChatClientPath_StillWorks Existing pre-built-IChatClient usage continues to serve channels when the payload omits AgentDefinition (regression guard).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't workingdiagnosedRoot cause identifiedverified-locallyImplementation has been verified locally

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions