Skip to content

Commit ca93613

Browse files
stephentoubCopilot
andauthored
Enhance C# generator with richer typing and data annotations (#1067)
* Enhance C# generator with richer typing and data annotations - integer -> long, number -> double (was double for both) - format: date-time -> DateTimeOffset, uuid -> Guid, duration -> TimeSpan - Add MillisecondsTimeSpanConverter for TimeSpan JSON serialization - Emit [Range], [RegularExpression], [Url], [MinLength], [MaxLength] - Emit [StringSyntax(Uri)], [StringSyntax(Regex)], [Base64String] - Change all public collections from concrete to interface types (List<T> -> IList<T>, Dictionary<K,V> -> IDictionary<K,V>) - Lazy-initialize collection properties via field ??= pattern Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update ListSessionsAsync return type in docs to IList Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix clone comparer preservation and byok doc example Preserve dictionary comparer in SessionConfig/ResumeSessionConfig Clone() by checking for Dictionary<> and passing its Comparer. Fix byok.md to use Task.FromResult<IList<ModelInfo>>() for the updated delegate signature. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: Range(Type,string,string) for long, add SDK using to Rpc Use Range(typeof(long), ...) overload since RangeAttribute has no long constructor. Add 'using GitHub.Copilot.SDK' to Rpc.cs header so MillisecondsTimeSpanConverter resolves when duration fields exist. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix Go doc example: type-assert SessionEventData to AssistantMessageData The Go SDK uses per-event-type data structs, so response.Data is a SessionEventData interface. Access Content by type-asserting to *copilot.AssistantMessageData. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unnecessary using GitHub.Copilot.SDK from Rpc.cs generator Rpc.cs is in namespace GitHub.Copilot.SDK.Rpc, a child of GitHub.Copilot.SDK, so types from the parent namespace resolve automatically without an explicit using directive. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 70b7721 commit ca93613

File tree

13 files changed

+258
-105
lines changed

13 files changed

+258
-105
lines changed

docs/auth/byok.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ using GitHub.Copilot.SDK;
426426

427427
var client = new CopilotClient(new CopilotClientOptions
428428
{
429-
OnListModels = (ct) => Task.FromResult(new List<ModelInfo>
429+
OnListModels = (ct) => Task.FromResult<IList<ModelInfo>>(new List<ModelInfo>
430430
{
431431
new()
432432
{

docs/setup/local-cli.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ func main() {
9999

100100
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
101101
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
102-
fmt.Println(*response.Data.Content)
102+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
103+
fmt.Println(d.Content)
104+
}
103105
}
104106
```
105107
<!-- /docs-validate: hidden -->
@@ -115,7 +117,9 @@ defer client.Stop()
115117

116118
session, _ := client.CreateSession(ctx, &copilot.SessionConfig{Model: "gpt-4.1"})
117119
response, _ := session.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Hello!"})
118-
fmt.Println(*response.Data.Content)
120+
if d, ok := response.Data.(*copilot.AssistantMessageData); ok {
121+
fmt.Println(d.Content)
122+
}
119123
```
120124

121125
</details>

dotnet/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Ping the server to check connectivity.
131131

132132
Get current connection state.
133133

134-
##### `ListSessionsAsync(): Task<List<SessionMetadata>>`
134+
##### `ListSessionsAsync(): Task<IList<SessionMetadata>>`
135135

136136
List all available sessions.
137137

dotnet/src/Client.cs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public sealed partial class CopilotClient : IDisposable, IAsyncDisposable
7575
private int? _negotiatedProtocolVersion;
7676
private List<ModelInfo>? _modelsCache;
7777
private readonly SemaphoreSlim _modelsCacheLock = new(1, 1);
78-
private readonly Func<CancellationToken, Task<List<ModelInfo>>>? _onListModels;
78+
private readonly Func<CancellationToken, Task<IList<ModelInfo>>>? _onListModels;
7979
private readonly List<Action<SessionLifecycleEvent>> _lifecycleHandlers = [];
8080
private readonly Dictionary<string, List<Action<SessionLifecycleEvent>>> _typedLifecycleHandlers = [];
8181
private readonly object _lifecycleHandlersLock = new();
@@ -735,7 +735,7 @@ public async Task<GetAuthStatusResponse> GetAuthStatusAsync(CancellationToken ca
735735
/// The cache is cleared when the client disconnects.
736736
/// </remarks>
737737
/// <exception cref="InvalidOperationException">Thrown when the client is not connected or not authenticated.</exception>
738-
public async Task<List<ModelInfo>> ListModelsAsync(CancellationToken cancellationToken = default)
738+
public async Task<IList<ModelInfo>> ListModelsAsync(CancellationToken cancellationToken = default)
739739
{
740740
await _modelsCacheLock.WaitAsync(cancellationToken);
741741
try
@@ -746,7 +746,7 @@ public async Task<List<ModelInfo>> ListModelsAsync(CancellationToken cancellatio
746746
return [.. _modelsCache]; // Return a copy to prevent cache mutation
747747
}
748748

749-
List<ModelInfo> models;
749+
IList<ModelInfo> models;
750750
if (_onListModels is not null)
751751
{
752752
// Use custom handler instead of CLI RPC
@@ -847,7 +847,7 @@ public async Task DeleteSessionAsync(string sessionId, CancellationToken cancell
847847
/// }
848848
/// </code>
849849
/// </example>
850-
public async Task<List<SessionMetadata>> ListSessionsAsync(SessionListFilter? filter = null, CancellationToken cancellationToken = default)
850+
public async Task<IList<SessionMetadata>> ListSessionsAsync(SessionListFilter? filter = null, CancellationToken cancellationToken = default)
851851
{
852852
var connection = await EnsureConnectedAsync(cancellationToken);
853853

@@ -1467,7 +1467,7 @@ public void OnSessionLifecycle(string type, string sessionId, JsonElement? metad
14671467
client.DispatchLifecycleEvent(evt);
14681468
}
14691469

1470-
public async Task<UserInputRequestResponse> OnUserInputRequest(string sessionId, string question, List<string>? choices = null, bool? allowFreeform = null)
1470+
public async Task<UserInputRequestResponse> OnUserInputRequest(string sessionId, string question, IList<string>? choices = null, bool? allowFreeform = null)
14711471
{
14721472
var session = client.GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
14731473
var request = new UserInputRequest
@@ -1621,26 +1621,26 @@ internal record CreateSessionRequest(
16211621
string? SessionId,
16221622
string? ClientName,
16231623
string? ReasoningEffort,
1624-
List<ToolDefinition>? Tools,
1624+
IList<ToolDefinition>? Tools,
16251625
SystemMessageConfig? SystemMessage,
1626-
List<string>? AvailableTools,
1627-
List<string>? ExcludedTools,
1626+
IList<string>? AvailableTools,
1627+
IList<string>? ExcludedTools,
16281628
ProviderConfig? Provider,
16291629
bool? RequestPermission,
16301630
bool? RequestUserInput,
16311631
bool? Hooks,
16321632
string? WorkingDirectory,
16331633
bool? Streaming,
1634-
Dictionary<string, McpServerConfig>? McpServers,
1634+
IDictionary<string, McpServerConfig>? McpServers,
16351635
string? EnvValueMode,
1636-
List<CustomAgentConfig>? CustomAgents,
1636+
IList<CustomAgentConfig>? CustomAgents,
16371637
string? Agent,
16381638
string? ConfigDir,
16391639
bool? EnableConfigDiscovery,
1640-
List<string>? SkillDirectories,
1641-
List<string>? DisabledSkills,
1640+
IList<string>? SkillDirectories,
1641+
IList<string>? DisabledSkills,
16421642
InfiniteSessionConfig? InfiniteSessions,
1643-
List<CommandWireDefinition>? Commands = null,
1643+
IList<CommandWireDefinition>? Commands = null,
16441644
bool? RequestElicitation = null,
16451645
string? Traceparent = null,
16461646
string? Tracestate = null,
@@ -1673,10 +1673,10 @@ internal record ResumeSessionRequest(
16731673
string? ClientName,
16741674
string? Model,
16751675
string? ReasoningEffort,
1676-
List<ToolDefinition>? Tools,
1676+
IList<ToolDefinition>? Tools,
16771677
SystemMessageConfig? SystemMessage,
1678-
List<string>? AvailableTools,
1679-
List<string>? ExcludedTools,
1678+
IList<string>? AvailableTools,
1679+
IList<string>? ExcludedTools,
16801680
ProviderConfig? Provider,
16811681
bool? RequestPermission,
16821682
bool? RequestUserInput,
@@ -1686,14 +1686,14 @@ internal record ResumeSessionRequest(
16861686
bool? EnableConfigDiscovery,
16871687
bool? DisableResume,
16881688
bool? Streaming,
1689-
Dictionary<string, McpServerConfig>? McpServers,
1689+
IDictionary<string, McpServerConfig>? McpServers,
16901690
string? EnvValueMode,
1691-
List<CustomAgentConfig>? CustomAgents,
1691+
IList<CustomAgentConfig>? CustomAgents,
16921692
string? Agent,
1693-
List<string>? SkillDirectories,
1694-
List<string>? DisabledSkills,
1693+
IList<string>? SkillDirectories,
1694+
IList<string>? DisabledSkills,
16951695
InfiniteSessionConfig? InfiniteSessions,
1696-
List<CommandWireDefinition>? Commands = null,
1696+
IList<CommandWireDefinition>? Commands = null,
16971697
bool? RequestElicitation = null,
16981698
string? Traceparent = null,
16991699
string? Tracestate = null,

dotnet/src/Generated/Rpc.cs

Lines changed: 24 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)