Skip to content

Commit 9d998fb

Browse files
Add SDK support for agent selection and session compaction APIs (#544)
1 parent bce4de0 commit 9d998fb

22 files changed

+2177
-368
lines changed

dotnet/src/Generated/Rpc.cs

Lines changed: 233 additions & 36 deletions
Large diffs are not rendered by default.

dotnet/src/Generated/SessionEvents.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace GitHub.Copilot.SDK;
2222
[JsonDerivedType(typeof(AssistantMessageDeltaEvent), "assistant.message_delta")]
2323
[JsonDerivedType(typeof(AssistantReasoningEvent), "assistant.reasoning")]
2424
[JsonDerivedType(typeof(AssistantReasoningDeltaEvent), "assistant.reasoning_delta")]
25+
[JsonDerivedType(typeof(AssistantStreamingDeltaEvent), "assistant.streaming_delta")]
2526
[JsonDerivedType(typeof(AssistantTurnEndEvent), "assistant.turn_end")]
2627
[JsonDerivedType(typeof(AssistantTurnStartEvent), "assistant.turn_start")]
2728
[JsonDerivedType(typeof(AssistantUsageEvent), "assistant.usage")]
@@ -42,6 +43,7 @@ namespace GitHub.Copilot.SDK;
4243
[JsonDerivedType(typeof(SessionShutdownEvent), "session.shutdown")]
4344
[JsonDerivedType(typeof(SessionSnapshotRewindEvent), "session.snapshot_rewind")]
4445
[JsonDerivedType(typeof(SessionStartEvent), "session.start")]
46+
[JsonDerivedType(typeof(SessionTaskCompleteEvent), "session.task_complete")]
4547
[JsonDerivedType(typeof(SessionTitleChangedEvent), "session.title_changed")]
4648
[JsonDerivedType(typeof(SessionTruncationEvent), "session.truncation")]
4749
[JsonDerivedType(typeof(SessionUsageInfoEvent), "session.usage_info")]
@@ -315,6 +317,18 @@ public partial class SessionCompactionCompleteEvent : SessionEvent
315317
public required SessionCompactionCompleteData Data { get; set; }
316318
}
317319

320+
/// <summary>
321+
/// Event: session.task_complete
322+
/// </summary>
323+
public partial class SessionTaskCompleteEvent : SessionEvent
324+
{
325+
[JsonIgnore]
326+
public override string Type => "session.task_complete";
327+
328+
[JsonPropertyName("data")]
329+
public required SessionTaskCompleteData Data { get; set; }
330+
}
331+
318332
/// <summary>
319333
/// Event: user.message
320334
/// </summary>
@@ -387,6 +401,18 @@ public partial class AssistantReasoningDeltaEvent : SessionEvent
387401
public required AssistantReasoningDeltaData Data { get; set; }
388402
}
389403

404+
/// <summary>
405+
/// Event: assistant.streaming_delta
406+
/// </summary>
407+
public partial class AssistantStreamingDeltaEvent : SessionEvent
408+
{
409+
[JsonIgnore]
410+
public override string Type => "assistant.streaming_delta";
411+
412+
[JsonPropertyName("data")]
413+
public required AssistantStreamingDeltaData Data { get; set; }
414+
}
415+
390416
/// <summary>
391417
/// Event: assistant.message
392418
/// </summary>
@@ -899,6 +925,13 @@ public partial class SessionCompactionCompleteData
899925
public string? RequestId { get; set; }
900926
}
901927

928+
public partial class SessionTaskCompleteData
929+
{
930+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
931+
[JsonPropertyName("summary")]
932+
public string? Summary { get; set; }
933+
}
934+
902935
public partial class UserMessageData
903936
{
904937
[JsonPropertyName("content")]
@@ -955,6 +988,12 @@ public partial class AssistantReasoningDeltaData
955988
public required string DeltaContent { get; set; }
956989
}
957990

991+
public partial class AssistantStreamingDeltaData
992+
{
993+
[JsonPropertyName("totalResponseSizeBytes")]
994+
public required double TotalResponseSizeBytes { get; set; }
995+
}
996+
958997
public partial class AssistantMessageData
959998
{
960999
[JsonPropertyName("messageId")]
@@ -996,10 +1035,6 @@ public partial class AssistantMessageDeltaData
9961035
[JsonPropertyName("deltaContent")]
9971036
public required string DeltaContent { get; set; }
9981037

999-
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
1000-
[JsonPropertyName("totalResponseSizeBytes")]
1001-
public double? TotalResponseSizeBytes { get; set; }
1002-
10031038
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
10041039
[JsonPropertyName("parentToolCallId")]
10051040
public string? ParentToolCallId { get; set; }
@@ -1736,6 +1771,8 @@ public enum SystemMessageDataRole
17361771
[JsonSerializable(typeof(AssistantReasoningDeltaData))]
17371772
[JsonSerializable(typeof(AssistantReasoningDeltaEvent))]
17381773
[JsonSerializable(typeof(AssistantReasoningEvent))]
1774+
[JsonSerializable(typeof(AssistantStreamingDeltaData))]
1775+
[JsonSerializable(typeof(AssistantStreamingDeltaEvent))]
17391776
[JsonSerializable(typeof(AssistantTurnEndData))]
17401777
[JsonSerializable(typeof(AssistantTurnEndEvent))]
17411778
[JsonSerializable(typeof(AssistantTurnStartData))]
@@ -1783,6 +1820,8 @@ public enum SystemMessageDataRole
17831820
[JsonSerializable(typeof(SessionStartData))]
17841821
[JsonSerializable(typeof(SessionStartDataContext))]
17851822
[JsonSerializable(typeof(SessionStartEvent))]
1823+
[JsonSerializable(typeof(SessionTaskCompleteData))]
1824+
[JsonSerializable(typeof(SessionTaskCompleteEvent))]
17861825
[JsonSerializable(typeof(SessionTitleChangedData))]
17871826
[JsonSerializable(typeof(SessionTitleChangedEvent))]
17881827
[JsonSerializable(typeof(SessionTruncationData))]
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
*--------------------------------------------------------------------------------------------*/
4+
5+
using GitHub.Copilot.SDK.Rpc;
6+
using GitHub.Copilot.SDK.Test.Harness;
7+
using Xunit;
8+
using Xunit.Abstractions;
9+
10+
namespace GitHub.Copilot.SDK.Test;
11+
12+
public class AgentAndCompactRpcTests(E2ETestFixture fixture, ITestOutputHelper output)
13+
: E2ETestBase(fixture, "agent_and_compact_rpc", output)
14+
{
15+
[Fact]
16+
public async Task Should_List_Available_Custom_Agents()
17+
{
18+
var customAgents = new List<CustomAgentConfig>
19+
{
20+
new()
21+
{
22+
Name = "test-agent",
23+
DisplayName = "Test Agent",
24+
Description = "A test agent",
25+
Prompt = "You are a test agent."
26+
},
27+
new()
28+
{
29+
Name = "another-agent",
30+
DisplayName = "Another Agent",
31+
Description = "Another test agent",
32+
Prompt = "You are another agent."
33+
}
34+
};
35+
36+
var session = await CreateSessionAsync(new SessionConfig { CustomAgents = customAgents });
37+
38+
var result = await session.Rpc.Agent.ListAsync();
39+
Assert.NotNull(result.Agents);
40+
Assert.Equal(2, result.Agents.Count);
41+
Assert.Equal("test-agent", result.Agents[0].Name);
42+
Assert.Equal("Test Agent", result.Agents[0].DisplayName);
43+
Assert.Equal("A test agent", result.Agents[0].Description);
44+
Assert.Equal("another-agent", result.Agents[1].Name);
45+
}
46+
47+
[Fact]
48+
public async Task Should_Return_Null_When_No_Agent_Is_Selected()
49+
{
50+
var customAgents = new List<CustomAgentConfig>
51+
{
52+
new()
53+
{
54+
Name = "test-agent",
55+
DisplayName = "Test Agent",
56+
Description = "A test agent",
57+
Prompt = "You are a test agent."
58+
}
59+
};
60+
61+
var session = await CreateSessionAsync(new SessionConfig { CustomAgents = customAgents });
62+
63+
var result = await session.Rpc.Agent.GetCurrentAsync();
64+
Assert.Null(result.Agent);
65+
}
66+
67+
[Fact]
68+
public async Task Should_Select_And_Get_Current_Agent()
69+
{
70+
var customAgents = new List<CustomAgentConfig>
71+
{
72+
new()
73+
{
74+
Name = "test-agent",
75+
DisplayName = "Test Agent",
76+
Description = "A test agent",
77+
Prompt = "You are a test agent."
78+
}
79+
};
80+
81+
var session = await CreateSessionAsync(new SessionConfig { CustomAgents = customAgents });
82+
83+
// Select the agent
84+
var selectResult = await session.Rpc.Agent.SelectAsync("test-agent");
85+
Assert.NotNull(selectResult.Agent);
86+
Assert.Equal("test-agent", selectResult.Agent.Name);
87+
Assert.Equal("Test Agent", selectResult.Agent.DisplayName);
88+
89+
// Verify getCurrent returns the selected agent
90+
var currentResult = await session.Rpc.Agent.GetCurrentAsync();
91+
Assert.NotNull(currentResult.Agent);
92+
Assert.Equal("test-agent", currentResult.Agent.Name);
93+
}
94+
95+
[Fact]
96+
public async Task Should_Deselect_Current_Agent()
97+
{
98+
var customAgents = new List<CustomAgentConfig>
99+
{
100+
new()
101+
{
102+
Name = "test-agent",
103+
DisplayName = "Test Agent",
104+
Description = "A test agent",
105+
Prompt = "You are a test agent."
106+
}
107+
};
108+
109+
var session = await CreateSessionAsync(new SessionConfig { CustomAgents = customAgents });
110+
111+
// Select then deselect
112+
await session.Rpc.Agent.SelectAsync("test-agent");
113+
await session.Rpc.Agent.DeselectAsync();
114+
115+
// Verify no agent is selected
116+
var currentResult = await session.Rpc.Agent.GetCurrentAsync();
117+
Assert.Null(currentResult.Agent);
118+
}
119+
120+
[Fact]
121+
public async Task Should_Return_Empty_List_When_No_Custom_Agents_Configured()
122+
{
123+
var session = await CreateSessionAsync();
124+
125+
var result = await session.Rpc.Agent.ListAsync();
126+
Assert.Empty(result.Agents);
127+
}
128+
129+
[Fact]
130+
public async Task Should_Compact_Session_History_After_Messages()
131+
{
132+
var session = await CreateSessionAsync();
133+
134+
// Send a message to create some history
135+
await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2+2?" });
136+
137+
// Compact the session
138+
var result = await session.Rpc.Compaction.CompactAsync();
139+
Assert.NotNull(result);
140+
}
141+
}

dotnet/test/CompactionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public async Task Should_Trigger_Compaction_With_Low_Threshold_And_Emit_Events()
4545
// Send multiple messages to fill up the context window
4646
await session.SendAndWaitAsync(new MessageOptions
4747
{
48-
Prompt = "Tell me a long story about a dragon. Be very detailed."
48+
Prompt = "Tell me a story about a dragon. Be detailed."
4949
});
5050
await session.SendAndWaitAsync(new MessageOptions
5151
{

go/generated_session_events.go

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)