.NET: Shrayrastogi/ag UI permission wrapper#4988
Open
ShrayRastogi wants to merge 7 commits intomicrosoft:mainfrom
Open
.NET: Shrayrastogi/ag UI permission wrapper#4988ShrayRastogi wants to merge 7 commits intomicrosoft:mainfrom
ShrayRastogi wants to merge 7 commits intomicrosoft:mainfrom
Conversation
Author
@microsoft-github-policy-service agree |
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.
Motivation and Context
Fixes #4826
When using
GitHubCopilotAgentwithMapAGUIto serve an AG-UI endpoint, MCP tool calls triggered by the Copilot SDK are completely invisible to AG-UI clients. TheOnPermissionRequestcallback fires server-side, but zeroTOOL_CALL_*events reach the SSE stream. This means:PermissionHandler.ApproveAllThis PR adds two independently shippable capabilities:
TOOL_CALL_START/ARGS/END/RESULTAG-UI events for every MCP permission requestCUSTOMevents +POST /approveendpoint enabling any AG-UI client to approve/deny MCP tool calls before executionThe solution is generic to the AG-UI protocol — not tied to any specific frontend framework.
See also: ADR-0021: AG-UI Permission Events for Copilot SDK MCP Tool Calls
Description
Phase 1 — Tool Call Visibility (automatic when
OnPermissionRequestis set):GitHubCopilotAgent.RunCoreStreamingAsync()to create theChannel<AgentResponseUpdate>beforeSessionConfigcopy, enabling theOnPermissionRequestclosure to write to itCopySessionConfigWithPermissionEmitter()wraps the user'sOnPermissionRequestcallback to emitFunctionCallContent(before tool execution) andFunctionResultContent(after permission decision) into the streaming channelAsAGUIEventStreamAsync()pipeline converts these toTOOL_CALL_START/ARGS/END/RESULTSSE events automatically — zero changes needed in the AG-UI layer for Phase 1PermissionRequestsubclasses (PermissionRequestMcp,PermissionRequestShell,PermissionRequestWrite,PermissionRequestRead,PermissionRequestUrl) from Copilot SDK v0.2.0 for rich tool metadataPhase 2 — Human-in-the-Loop Approval:
CUSTOMevent type to the framework (CustomEvent.cs, updatedBaseEventJsonConverter,AGUIJsonSerializerContext) —CUSTOMis an official AG-UI protocol event, not draftPendingApprovalStoreservice withTaskCompletionSource<bool>entries and configurable timeout (AGUIOptions.ApprovalTimeout, default 60s)MapAGUIviaAgentRunOptions.AdditionalProperties), the wrapper blocks the Copilot SDK'sOnPermissionRequeston the TCS until the client responds or timeout expiresCUSTOMevents (tool_approval_requested/tool_approval_completed) emitted alongsideTOOL_CALL_*eventsPOST {pattern}/approveendpoint registered byMapAGUIresolves the TCS with the client's approve/deny decisionFunc<string, Task<bool>>delegate bridgesGitHubCopilotAgentandPendingApprovalStorewithout cross-package dependenciesAdditional fixes:
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]onToolCallStartEvent.ParentMessageIdfor AG-UI spec compliance (optional field should be omitted, not serialized asnull)STATE_DELTAcase toBaseEventJsonConverter.Read()(was missing)CopySessionConfig/CopyResumeSessionConfigwith new v0.2.0 SDK properties (Agent,OnEvent)PermissionRequestResultKindenumFiles changed:
GitHubCopilotAgent.csOnPermissionRequestwrapper, typedPermissionRequestsubclass extractionAGUIEventTypes.csCustom = "CUSTOM"CustomEvent.csCUSTOMevent classBaseEventJsonConverter.csCUSTOM+STATE_DELTAcasesAGUIJsonSerializerContext.csCustomEventfor AOTToolCallStartEvent.csJsonIgnore(WhenWritingNull)onParentMessageIdChatResponseUpdateAGUIExtensions.csCUSTOMevents for approval request/completedAGUIEndpointRouteBuilderExtensions.csPOST /approveendpoint,PendingApprovalStoredelegate wiringPendingApprovalStore.csAGUIOptions.csApprovalTimeoutServiceCollectionExtensions.csPendingApprovalStore+AGUIOptionsDirectory.Packages.propsGitHub.Copilot.SDK0.1.29 → 0.2.0Contribution Checklist