Implement ClientIO interaction support on Agent-Server#2178
Merged
GeorgeNgMsft merged 14 commits intomainfrom Apr 10, 2026
Merged
Implement ClientIO interaction support on Agent-Server#2178GeorgeNgMsft merged 14 commits intomainfrom
GeorgeNgMsft merged 14 commits intomainfrom
Conversation
Proposes converting the blocking askYesNo, proposeAction, and popupQuestion callbacks to a non-blocking deferred-promise pattern modeled on the existing requestChoice/respondToChoice mechanism. Covers protocol changes, DisplayLog schema extensions, pending interaction management, replay/reconnection strategy, and a phased implementation plan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cks (Phases 1-8) Convert askYesNo, proposeAction, and popupQuestion from blocking RPC callbacks to a non-blocking deferred-promise pattern with correlation IDs, enabling multi-client broadcast and resilient disconnect handling. - Define PendingInteractionRequest/Response types and discriminated union for askYesNo, proposeAction, popupQuestion interaction types - Add PendingInteractionManager with create/resolve/cancel lifecycle, per-connection cleanup, and timeout support - Extend DisplayLog with logPendingInteraction and logInteractionResolved for interaction persistence and replay - Add requestInteraction/interactionResolved fire-and-forget methods to ClientIO interface and wire through RPC client/server layers - Add respondToInteraction to Dispatcher interface with RPC support - Rewrite SharedDispatcher to use deferred promises instead of blocking callbacks, with broadcast to all clients and first-responder resolution - Add requestInteraction/interactionResolved stubs to all ClientIO implementations (shell, CLI, browser extension, console, MCP, tests) - Add @typeagent/dispatcher-types dependency to agent-server and protocol Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…b.com/microsoft/TypeAgent into dev/georgeng/async-clientio-callbacks
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces an async “deferred interaction” mechanism for ClientIO prompts in agent-server mode, so server-side command execution is no longer coupled to a single blocking RPC invoke call and can survive disconnect/reconnect scenarios.
Changes:
- Adds new dispatcher-types for pending interaction requests/responses and extends
ClientIO/DispatcherAPIs to supportrequestInteraction+respondToInteraction. - Implements server-side tracking/logging of pending interactions via
PendingInteractionManagerand newDisplayLogentry types. - Wires new RPC surface area and propagates pending interactions to clients on session join.
Reviewed changes
Copilot reviewed 29 out of 30 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| ts/pnpm-lock.yaml | Adds workspace dependency links for @typeagent/dispatcher-types. |
| ts/packages/shell/src/renderer/src/main.ts | Adds ClientIO stubs for deferred interaction events (currently no-op). |
| ts/packages/dispatcher/types/src/pendingInteraction.ts | New shared types for pending interaction request/response payloads. |
| ts/packages/dispatcher/types/src/index.ts | Re-exports pending interaction types. |
| ts/packages/dispatcher/types/src/displayLogEntry.ts | Adds pending-interaction and interaction-resolved log entry types. |
| ts/packages/dispatcher/types/src/dispatcher.ts | Adds respondToInteraction to the Dispatcher interface. |
| ts/packages/dispatcher/types/src/clientIO.ts | Adds requestInteraction and interactionResolved to ClientIO. |
| ts/packages/dispatcher/rpc/src/dispatcherTypes.ts | Exposes respondToInteraction through dispatcher RPC invoke functions. |
| ts/packages/dispatcher/rpc/src/dispatcherServer.ts | Implements RPC server handler for respondToInteraction. |
| ts/packages/dispatcher/rpc/src/dispatcherClient.ts | Implements RPC client call for respondToInteraction. |
| ts/packages/dispatcher/rpc/src/clientIOTypes.ts | Adds new ClientIO call-function typings for deferred interactions. |
| ts/packages/dispatcher/rpc/src/clientIOServer.ts | Wires new ClientIO call handlers on the RPC server side. |
| ts/packages/dispatcher/rpc/src/clientIOClient.ts | Wires new ClientIO call senders on the RPC client side. |
| ts/packages/dispatcher/nodeProviders/test/provider.spec.ts | Updates test ClientIO stub to satisfy the extended interface. |
| ts/packages/dispatcher/dispatcher/src/internal.ts | Exposes PendingInteractionManager via internal exports. |
| ts/packages/dispatcher/dispatcher/src/helpers/console.ts | Adds no-op stubs for deferred interactions in console ClientIO. |
| ts/packages/dispatcher/dispatcher/src/displayLog.ts | Adds logging helpers for pending interactions and their resolution. |
| ts/packages/dispatcher/dispatcher/src/dispatcher.ts | Adds base respondToInteraction method (throws by default). |
| ts/packages/dispatcher/dispatcher/src/context/pendingInteractionManager.ts | New manager to store deferred promises and handle cancel/resolve. |
| ts/packages/dispatcher/dispatcher/src/context/interactiveIO.ts | Updates nullClientIO to include the new methods. |
| ts/packages/commandExecutor/src/commandServer.ts | Updates MCP ClientIO stub to include the new methods. |
| ts/packages/cli/src/enhancedConsole.ts | Adds no-op stubs for deferred interactions in CLI ClientIO. |
| ts/packages/agentServer/server/src/sharedDispatcher.ts | Implements deferred interaction flow in server shared dispatcher. |
| ts/packages/agentServer/server/src/sessionManager.ts | Returns pending interactions on session join. |
| ts/packages/agentServer/server/src/server.ts | Includes pending interactions in join-session response payload. |
| ts/packages/agentServer/server/package.json | Adds dependency on @typeagent/dispatcher-types. |
| ts/packages/agentServer/protocol/src/protocol.ts | Extends JoinSessionResult with optional pendingInteractions. |
| ts/packages/agentServer/protocol/package.json | Adds dependency on @typeagent/dispatcher-types. |
| ts/packages/agentServer/docs/async-clientio-design.md | Adds design documentation for the deferred interaction pattern. |
| ts/packages/agents/browser/src/extension/serviceWorker/dispatcherConnection.ts | Adds no-op stubs for deferred interactions in extension ClientIO. |
Files not reviewed (1)
- ts/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ts/packages/dispatcher/dispatcher/src/context/pendingInteractionManager.ts
Show resolved
Hide resolved
…b.com/microsoft/TypeAgent into dev/georgeng/async-clientio-callbacks
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 31 out of 32 changed files in this pull request and generated 10 comments.
Files not reviewed (1)
- ts/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Async ClientIO Callbacks: Non-Blocking Deferred-Promise Pattern
Three ClientIO methods — askYesNo, proposeAction, and popupQuestion — were previously implemented as blocking RPC invoke calls in the agent server. This meant the server-side command processing was tied to a specific client connection: a disconnect would permanently hang the operation, reconnecting clients couldn't recover pending questions, and popupQuestion was entirely disabled in server mode.
This PR converts all three to a non-blocking deferred-promise pattern:
The server generates a unique interactionId, logs the pending interaction to the DisplayLog, stores a deferred Promise in a new PendingInteractionManager, and sends a fire-and-forget requestInteraction notification to the client(s). Command processing suspends at await as before, but is no longer coupled to the connection.
The client responds via a new respondToInteraction dispatcher method, which resolves the deferred promise and resumes processing exactly where it left off.
On client disconnect, pending interactions owned by that connection are cancelled (rejecting their promises), and all callers treat this as a cancellation of the operation.
popupQuestion is now fully supported in server mode via broadcast to all connected clients, with first-responder resolution.
Pending interactions are logged to DisplayLog so they can be replayed to reconnecting or newly joining clients.
Existing callers (askYesNoWithContext, confirmTranslation, sessionContext.popupQuestion) required no changes — the ClientIO interface signatures are unchanged.