Use string enums for .NET session events#1226
Conversation
Generate string-backed value types for session event schema enums so unknown values emitted by newer runtimes deserialize without throwing and preserve their raw string values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR updates the .NET session-events code generation to improve forward compatibility when newer Copilot runtimes emit previously-unknown enum string values into persisted session history, preventing deserialization failures in APIs like GetMessagesAsync.
Changes:
- Update C# session-event codegen to generate string-backed readonly struct “enums” (with custom
JsonConverter) for session event schema enums. - Regenerate
dotnet/src/Generated/SessionEvents.csto use the new string-enum structs and hide converter types from IntelliSense. - Add a unit test covering preservation of an unknown
abort.reasonvalue during deserialization.
Show a summary per file
| File | Description |
|---|---|
| scripts/codegen/csharp.ts | Generates string-backed enum structs (with converters) for session-event enums. |
| dotnet/src/Generated/SessionEvents.cs | Regenerated session event types using the new string-enum structs. |
| dotnet/test/Unit/ForwardCompatibilityTests.cs | Adds coverage ensuring unknown enum values in known events are preserved. |
Copilot's findings
- Files reviewed: 2/3 changed files
- Comments generated: 2
|
@brettcannon, we can do it as a separate PR, but we probably want to apply a forward-compat-focused fix here for Python as well? |
Extend the generated string-backed value type enum model to RPC schema enums so unknown wire values from newer runtimes deserialize without throwing and preserve their raw values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
Update generated C# string enum value types to back Value with a nullable field so default instances expose an empty string instead of null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
Move generated string enum JSON read/write validation into a handwritten SDK helper and have generated converters delegate to it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the C# generator so known string enum static properties are emitted after the constructor, then regenerate the C# protocol outputs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the C# generator so generated string enum structs place only the backing field before the constructor, with Value and known static properties after it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency ReviewThis PR correctly fixes a forward-compatibility issue in the .NET SDK where regular C# enums would throw during deserialization of unknown session-event enum values. The approach (string-backed readonly structs) is idiomatic and well-designed. Forward-compatibility status across SDKs
Python has the same forward-compatibility gapThe Python codegen ( class AbortReason(Enum):
"Finite reason code describing why the current turn was aborted"
USER_INITIATED = "user_initiated"
REMOTE_COMMAND = "remote_command"
USER_ABORT = "user_abort"And deserializes them with: def parse_enum(c: type[EnumT], x: Any) -> EnumT:
assert isinstance(x, str)
return c(x) # ← raises ValueError for unknown valuesIf the runtime adds a new Note: Suggested fix for Python codegenIn lines.push(` `@classmethod``);
lines.push(` def _missing_(cls, value: object) -> "${enumName}":`);
lines.push(` obj = object.__new__(cls)`);
lines.push(` obj._value_ = value`);
lines.push(` return obj`);This would make all Python session-event enums forward-compatible, consistent with the fix applied to .NET in this PR. The regenerated This is not a blocker for merging this PR (which is purely a .NET change), but it would be worth a follow-up issue/PR to keep the Python SDK in parity.
|
Newer Copilot runtime versions can add string enum values to persisted session events before the .NET SDK schema has been regenerated. Regular .NET enums throw during deserialization in that case, which can break
GetMessagesAsyncwhen replaying session history.Summary
dotnet/src/Generated/SessionEvents.csand hide generated JSON converter types from IntelliSense withEditorBrowsable(Never).Testing
dotnet test dotnet\test\GitHub.Copilot.SDK.Test.csproj --filter "FullyQualifiedName~GitHub.Copilot.SDK.Test.Unit.ForwardCompatibilityTests|FullyQualifiedName~GitHub.Copilot.SDK.Test.Unit.SessionEventSerializationTests" --logger "console;verbosity=minimal"