Skip to content

Commit b00ce0a

Browse files
stephentoubCopilot
andcommitted
Add unit tests for IncludeSubAgentStreamingEvents across all SDKs
- .NET: Clone test assertions for SessionConfig and ResumeSessionConfig - Node.js: Wire payload tests for session.create and session.resume - Python: Payload capture tests for create_session and resume_session - Go: JSON marshal tests for createSessionRequest and resumeSessionRequest Each language tests both the default (true) and explicit false paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent adfd29f commit b00ce0a

4 files changed

Lines changed: 272 additions & 0 deletions

File tree

dotnet/test/CloneTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public void SessionConfig_Clone_CopiesAllProperties()
8686
ExcludedTools = ["tool3"],
8787
WorkingDirectory = "/workspace",
8888
Streaming = true,
89+
IncludeSubAgentStreamingEvents = false,
8990
McpServers = new Dictionary<string, McpServerConfig> { ["server1"] = new McpStdioServerConfig { Command = "echo" } },
9091
CustomAgents = [new CustomAgentConfig { Name = "agent1" }],
9192
Agent = "agent1",
@@ -104,6 +105,7 @@ public void SessionConfig_Clone_CopiesAllProperties()
104105
Assert.Equal(original.ExcludedTools, clone.ExcludedTools);
105106
Assert.Equal(original.WorkingDirectory, clone.WorkingDirectory);
106107
Assert.Equal(original.Streaming, clone.Streaming);
108+
Assert.Equal(original.IncludeSubAgentStreamingEvents, clone.IncludeSubAgentStreamingEvents);
107109
Assert.Equal(original.McpServers.Count, clone.McpServers!.Count);
108110
Assert.Equal(original.CustomAgents.Count, clone.CustomAgents!.Count);
109111
Assert.Equal(original.Agent, clone.Agent);
@@ -243,6 +245,7 @@ public void Clone_WithNullCollections_ReturnsNullCollections()
243245
Assert.Null(clone.SkillDirectories);
244246
Assert.Null(clone.DisabledSkills);
245247
Assert.Null(clone.Tools);
248+
Assert.True(clone.IncludeSubAgentStreamingEvents);
246249
}
247250

248251
[Fact]
@@ -272,4 +275,27 @@ public void ResumeSessionConfig_Clone_CopiesAgentProperty()
272275

273276
Assert.Equal("test-agent", clone.Agent);
274277
}
278+
279+
[Fact]
280+
public void ResumeSessionConfig_Clone_CopiesIncludeSubAgentStreamingEvents()
281+
{
282+
var original = new ResumeSessionConfig
283+
{
284+
IncludeSubAgentStreamingEvents = false,
285+
};
286+
287+
var clone = original.Clone();
288+
289+
Assert.False(clone.IncludeSubAgentStreamingEvents);
290+
}
291+
292+
[Fact]
293+
public void ResumeSessionConfig_Clone_PreservesIncludeSubAgentStreamingEventsDefault()
294+
{
295+
var original = new ResumeSessionConfig();
296+
297+
var clone = original.Clone();
298+
299+
Assert.True(clone.IncludeSubAgentStreamingEvents);
300+
}
275301
}

go/client_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,80 @@ func TestResumeSessionRequest_RequestElicitation(t *testing.T) {
861861
})
862862
}
863863

864+
func TestCreateSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
865+
t.Run("defaults to true when nil", func(t *testing.T) {
866+
req := createSessionRequest{
867+
IncludeSubAgentStreamingEvents: Bool(true),
868+
}
869+
data, err := json.Marshal(req)
870+
if err != nil {
871+
t.Fatalf("Failed to marshal: %v", err)
872+
}
873+
var m map[string]any
874+
if err := json.Unmarshal(data, &m); err != nil {
875+
t.Fatalf("Failed to unmarshal: %v", err)
876+
}
877+
if m["includeSubAgentStreamingEvents"] != true {
878+
t.Errorf("Expected includeSubAgentStreamingEvents to be true, got %v", m["includeSubAgentStreamingEvents"])
879+
}
880+
})
881+
882+
t.Run("preserves explicit false", func(t *testing.T) {
883+
req := createSessionRequest{
884+
IncludeSubAgentStreamingEvents: Bool(false),
885+
}
886+
data, err := json.Marshal(req)
887+
if err != nil {
888+
t.Fatalf("Failed to marshal: %v", err)
889+
}
890+
var m map[string]any
891+
if err := json.Unmarshal(data, &m); err != nil {
892+
t.Fatalf("Failed to unmarshal: %v", err)
893+
}
894+
if m["includeSubAgentStreamingEvents"] != false {
895+
t.Errorf("Expected includeSubAgentStreamingEvents to be false, got %v", m["includeSubAgentStreamingEvents"])
896+
}
897+
})
898+
}
899+
900+
func TestResumeSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
901+
t.Run("defaults to true when nil", func(t *testing.T) {
902+
req := resumeSessionRequest{
903+
SessionID: "s1",
904+
IncludeSubAgentStreamingEvents: Bool(true),
905+
}
906+
data, err := json.Marshal(req)
907+
if err != nil {
908+
t.Fatalf("Failed to marshal: %v", err)
909+
}
910+
var m map[string]any
911+
if err := json.Unmarshal(data, &m); err != nil {
912+
t.Fatalf("Failed to unmarshal: %v", err)
913+
}
914+
if m["includeSubAgentStreamingEvents"] != true {
915+
t.Errorf("Expected includeSubAgentStreamingEvents to be true, got %v", m["includeSubAgentStreamingEvents"])
916+
}
917+
})
918+
919+
t.Run("preserves explicit false", func(t *testing.T) {
920+
req := resumeSessionRequest{
921+
SessionID: "s1",
922+
IncludeSubAgentStreamingEvents: Bool(false),
923+
}
924+
data, err := json.Marshal(req)
925+
if err != nil {
926+
t.Fatalf("Failed to marshal: %v", err)
927+
}
928+
var m map[string]any
929+
if err := json.Unmarshal(data, &m); err != nil {
930+
t.Fatalf("Failed to unmarshal: %v", err)
931+
}
932+
if m["includeSubAgentStreamingEvents"] != false {
933+
t.Errorf("Expected includeSubAgentStreamingEvents to be false, got %v", m["includeSubAgentStreamingEvents"])
934+
}
935+
})
936+
}
937+
864938
func TestCreateSessionResponse_Capabilities(t *testing.T) {
865939
t.Run("reads capabilities from session.create response", func(t *testing.T) {
866940
responseJSON := `{"sessionId":"s1","workspacePath":"/tmp","capabilities":{"ui":{"elicitation":true}}}`

nodejs/test/client.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,74 @@ describe("CopilotClient", () => {
9898
spy.mockRestore();
9999
});
100100

101+
it("defaults includeSubAgentStreamingEvents to true in session.create when not specified", async () => {
102+
const client = new CopilotClient();
103+
await client.start();
104+
onTestFinished(() => client.forceStop());
105+
106+
const spy = vi.spyOn((client as any).connection!, "sendRequest");
107+
await client.createSession({ onPermissionRequest: approveAll });
108+
109+
const payload = spy.mock.calls.find((c) => c[0] === "session.create")![1] as any;
110+
expect(payload.includeSubAgentStreamingEvents).toBe(true);
111+
});
112+
113+
it("forwards explicit false for includeSubAgentStreamingEvents in session.create", async () => {
114+
const client = new CopilotClient();
115+
await client.start();
116+
onTestFinished(() => client.forceStop());
117+
118+
const spy = vi.spyOn((client as any).connection!, "sendRequest");
119+
await client.createSession({
120+
onPermissionRequest: approveAll,
121+
includeSubAgentStreamingEvents: false,
122+
});
123+
124+
const payload = spy.mock.calls.find((c) => c[0] === "session.create")![1] as any;
125+
expect(payload.includeSubAgentStreamingEvents).toBe(false);
126+
});
127+
128+
it("defaults includeSubAgentStreamingEvents to true in session.resume when not specified", async () => {
129+
const client = new CopilotClient();
130+
await client.start();
131+
onTestFinished(() => client.forceStop());
132+
133+
const session = await client.createSession({ onPermissionRequest: approveAll });
134+
const spy = vi
135+
.spyOn((client as any).connection!, "sendRequest")
136+
.mockImplementation(async (method: string, params: any) => {
137+
if (method === "session.resume") return { sessionId: params.sessionId };
138+
throw new Error(`Unexpected method: ${method}`);
139+
});
140+
await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll });
141+
142+
const payload = spy.mock.calls.find((c) => c[0] === "session.resume")![1] as any;
143+
expect(payload.includeSubAgentStreamingEvents).toBe(true);
144+
spy.mockRestore();
145+
});
146+
147+
it("forwards explicit false for includeSubAgentStreamingEvents in session.resume", async () => {
148+
const client = new CopilotClient();
149+
await client.start();
150+
onTestFinished(() => client.forceStop());
151+
152+
const session = await client.createSession({ onPermissionRequest: approveAll });
153+
const spy = vi
154+
.spyOn((client as any).connection!, "sendRequest")
155+
.mockImplementation(async (method: string, params: any) => {
156+
if (method === "session.resume") return { sessionId: params.sessionId };
157+
throw new Error(`Unexpected method: ${method}`);
158+
});
159+
await client.resumeSession(session.sessionId, {
160+
onPermissionRequest: approveAll,
161+
includeSubAgentStreamingEvents: false,
162+
});
163+
164+
const payload = spy.mock.calls.find((c) => c[0] === "session.resume")![1] as any;
165+
expect(payload.includeSubAgentStreamingEvents).toBe(false);
166+
spy.mockRestore();
167+
});
168+
101169
it("forwards provider headers in session.create request", async () => {
102170
const client = new CopilotClient();
103171
await client.start();

python/test_client.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,110 @@ async def mock_request(method, params):
594594
finally:
595595
await client.force_stop()
596596

597+
@pytest.mark.asyncio
598+
async def test_create_session_defaults_include_sub_agent_streaming_events_to_true(self):
599+
client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH))
600+
await client.start()
601+
602+
try:
603+
captured = {}
604+
original_request = client._client.request
605+
606+
async def mock_request(method, params):
607+
captured[method] = params
608+
return await original_request(method, params)
609+
610+
client._client.request = mock_request
611+
await client.create_session(
612+
on_permission_request=PermissionHandler.approve_all,
613+
)
614+
assert captured["session.create"]["includeSubAgentStreamingEvents"] is True
615+
finally:
616+
await client.force_stop()
617+
618+
@pytest.mark.asyncio
619+
async def test_create_session_preserves_explicit_false_include_sub_agent_streaming_events(
620+
self,
621+
):
622+
client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH))
623+
await client.start()
624+
625+
try:
626+
captured = {}
627+
original_request = client._client.request
628+
629+
async def mock_request(method, params):
630+
captured[method] = params
631+
return await original_request(method, params)
632+
633+
client._client.request = mock_request
634+
await client.create_session(
635+
on_permission_request=PermissionHandler.approve_all,
636+
include_sub_agent_streaming_events=False,
637+
)
638+
assert captured["session.create"]["includeSubAgentStreamingEvents"] is False
639+
finally:
640+
await client.force_stop()
641+
642+
@pytest.mark.asyncio
643+
async def test_resume_session_defaults_include_sub_agent_streaming_events_to_true(self):
644+
client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH))
645+
await client.start()
646+
647+
try:
648+
session = await client.create_session(
649+
on_permission_request=PermissionHandler.approve_all
650+
)
651+
652+
captured = {}
653+
original_request = client._client.request
654+
655+
async def mock_request(method, params):
656+
captured[method] = params
657+
if method == "session.resume":
658+
return {"sessionId": session.session_id}
659+
return await original_request(method, params)
660+
661+
client._client.request = mock_request
662+
await client.resume_session(
663+
session.session_id,
664+
on_permission_request=PermissionHandler.approve_all,
665+
)
666+
assert captured["session.resume"]["includeSubAgentStreamingEvents"] is True
667+
finally:
668+
await client.force_stop()
669+
670+
@pytest.mark.asyncio
671+
async def test_resume_session_preserves_explicit_false_include_sub_agent_streaming_events(
672+
self,
673+
):
674+
client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH))
675+
await client.start()
676+
677+
try:
678+
session = await client.create_session(
679+
on_permission_request=PermissionHandler.approve_all
680+
)
681+
682+
captured = {}
683+
original_request = client._client.request
684+
685+
async def mock_request(method, params):
686+
captured[method] = params
687+
if method == "session.resume":
688+
return {"sessionId": session.session_id}
689+
return await original_request(method, params)
690+
691+
client._client.request = mock_request
692+
await client.resume_session(
693+
session.session_id,
694+
on_permission_request=PermissionHandler.approve_all,
695+
include_sub_agent_streaming_events=False,
696+
)
697+
assert captured["session.resume"]["includeSubAgentStreamingEvents"] is False
698+
finally:
699+
await client.force_stop()
700+
597701
@pytest.mark.asyncio
598702
async def test_set_model_sends_correct_rpc(self):
599703
client = CopilotClient(SubprocessConfig(cli_path=CLI_PATH))

0 commit comments

Comments
 (0)