You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ensure that when the REMOTE CopilotSdkChatClient self-invokes its built-in shell/powershell tool (root AgentId == null), the resulting ToolExecutionStartEvent / ToolExecutionCompleteEvent pair survives the transport hop and, on the SOURCE, is written to the root/session sink (no ParentToolCallIdPropertyName) and appears as children of the SDK session node in AgentChat history — not lost, not attributed to a sub-agent.
This sub-item covers node hierarchy / placement + the assertion. It relies on #1312 (the CopilotSdkStreamAdapter switch dropping unmapped events, no default arm) being fixed so unknown/future kinds are not silently discarded.
CopilotSdkStreamAdapter.cs:113 — ToolExecutionStartEvent is mapped into a ChatResponseUpdate, tagged with event.AgentId.
CopilotSdkStreamAdapter.cs:121 — ToolExecutionCompleteEvent mapping, likewise tagged with event.AgentId.
features/Phantom.Workspaces.Llm.Core/CopilotSubAgentRouter.cs:27-40 — items with a non-null ParentToolCallId route to the correct sub-agent sink; root-tagged items (no ParentToolCallIdPropertyName) go to the SDK session node's root sink.
features/Phantom.Workspaces.Llm.Core/CopilotSubAgentRouter.cs — root-vs-sub-agent sink routing at :27-40.
Test additions (unit-level) under features/Phantom.Workspaces.Llm.Core.Tests/ (e.g. CopilotSdkStreamAdapterTests.cs, CopilotSubAgentRouterTests.cs).
No transport code changes here; the transport-hop assertion is a scenario in sub-item S6.
Design / Fix
Node hierarchy contract. For events with AgentId == null (root), the emitted ChatResponseUpdate MUST NOT carry CopilotSdkStreamAdapter.ParentToolCallIdPropertyName. Confirm this is already the behavior of the :113 / :121 mappings; add unit coverage that pins it. For events with a non-null AgentId (sub-agent), the property MUST be set so CopilotSubAgentRouter routes them.
SDK session node placement. Root-tagged tool-execution items must land on the SDK session node's root sink so they render as children of that node in AgentChat history. Add coverage against CopilotSubAgentRouter that root items reach the root sink and are not attributed to any sub-agent.
Out of scope: the transport hop and full source-side history assertion (covered by S6).
Expected Tests
Follow the Subject_Scenario_ExpectedOutcome convention. Mirror existing tests in features/Phantom.Workspaces.Llm.Core.Tests/CopilotSdkChatClientTests.cs (naming style) and any existing CopilotSdkStreamAdapterTests / CopilotSubAgentRouterTests.
End-of-turn AgentChat history places root shell/powershell tool-execution items as children of the SDK session node (structural assertion using the same in-memory AgentChat used in existing tests).
Part of #1313
Summary
Ensure that when the REMOTE
CopilotSdkChatClientself-invokes its built-in shell/powershell tool (rootAgentId == null), the resultingToolExecutionStartEvent/ToolExecutionCompleteEventpair survives the transport hop and, on the SOURCE, is written to the root/session sink (noParentToolCallIdPropertyName) and appears as children of the SDK session node inAgentChathistory — not lost, not attributed to a sub-agent.This sub-item covers node hierarchy / placement + the assertion. It relies on #1312 (the
CopilotSdkStreamAdapterswitch dropping unmapped events, nodefaultarm) being fixed so unknown/future kinds are not silently discarded.Dependencies
CopilotSdkStreamAdapter.TranslateCopilotSdkSessionEventsswitch has nodefaultarm; unmappedSessionEvents are silently dropped). This sub-item asserts hierarchy correctness for events that ARE mapped and requires the drop-fix so nearby/related events are not lost mid-stream.Root Cause / Current State
features/Phantom.Workspaces.Llm.Core/CopilotSdkStreamAdapter.cs:93— the outerswitch (sessionEvent)has nodefaultarm; unmapped kinds are silently dropped. This is Copilot SDK adapter silently drops unhandled SDK session events (no default arm; self-invoke bypasses framework tool loop) #1312.CopilotSdkStreamAdapter.cs:113—ToolExecutionStartEventis mapped into aChatResponseUpdate, tagged withevent.AgentId.CopilotSdkStreamAdapter.cs:121—ToolExecutionCompleteEventmapping, likewise tagged withevent.AgentId.features/Phantom.Workspaces.Llm.Core/CopilotSubAgentRouter.cs:27-40— items with a non-nullParentToolCallIdroute to the correct sub-agent sink; root-tagged items (noParentToolCallIdPropertyName) go to the SDK session node's root sink.AgentIdshell/powershell tool-execution pair round-trips over the transport and lands on the root/session sink of the SOURCE, appearing as children of the SDK session node. The adapter's fragility (Copilot SDK adapter silently drops unhandled SDK session events (no default arm; self-invoke bypasses framework tool loop) #1312) compounds the risk.Affected Files
features/Phantom.Workspaces.Llm.Core/CopilotSdkStreamAdapter.cs— hierarchy correctness around:113/:121; assumes Copilot SDK adapter silently drops unhandled SDK session events (no default arm; self-invoke bypasses framework tool loop) #1312 lands thedefaultarm.features/Phantom.Workspaces.Llm.Core/CopilotSubAgentRouter.cs— root-vs-sub-agent sink routing at:27-40.features/Phantom.Workspaces.Llm.Core.Tests/(e.g.CopilotSdkStreamAdapterTests.cs,CopilotSubAgentRouterTests.cs).Design / Fix
AgentId == null(root), the emittedChatResponseUpdateMUST NOT carryCopilotSdkStreamAdapter.ParentToolCallIdPropertyName. Confirm this is already the behavior of the:113/:121mappings; add unit coverage that pins it. For events with a non-nullAgentId(sub-agent), the property MUST be set soCopilotSubAgentRouterroutes them.AgentChathistory. Add coverage againstCopilotSubAgentRouterthat root items reach the root sink and are not attributed to any sub-agent.defaultarm, add a unit test that an unknown/futureSessionEventsubclass produces at least a diagnostic (not a silent drop). This sub-item does not itself change the adapter'sswitch; it consumes the fix.Expected Tests
Follow the
Subject_Scenario_ExpectedOutcomeconvention. Mirror existing tests infeatures/Phantom.Workspaces.Llm.Core.Tests/CopilotSdkChatClientTests.cs(naming style) and any existingCopilotSdkStreamAdapterTests/CopilotSubAgentRouterTests.CopilotSdkStreamAdapter_ToolExecutionStartEventRootAgentId_EmitsUpdateWithoutParentToolCallIdPropertyToolExecutionStartEventwithAgentId == nullmaps (at:113) to aChatResponseUpdatethat does NOT carryParentToolCallIdPropertyName.CopilotSdkStreamAdapter_ToolExecutionCompleteEventRootAgentId_EmitsUpdateWithoutParentToolCallIdPropertyToolExecutionCompleteEventat:121.CopilotSdkStreamAdapter_ToolExecutionEventsWithAgentId_SetParentToolCallIdPropertyCopilotSubAgentRouter_RootTaggedToolExecutionItems_RouteToRootSessionSinkCopilotSubAgentRouter(:27-40) delivers them to the root/session sink, NOT to any sub-agent sink.CopilotSubAgentRouter_SubAgentTaggedToolExecutionItems_RouteToMatchingSubAgentSinkParentToolCallId(regression guard).AgentChatHistory_RootShellToolExecutionItems_AppearAsChildrenOfSdkSessionNodeAgentChathistory places root shell/powershell tool-execution items as children of the SDK session node (structural assertion using the same in-memoryAgentChatused in existing tests).