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
The Go codegen for session events (generated_session_events.go) uses quicktype, which represents the discriminated union of all session event Data payloads as a single flat struct with every property from every event type merged together:
typeDatastruct {
Content*string// from assistant.messageTitle*string// from session.title_changedToolName*string// from tool.execution_start// ... hundreds of fields from all event types
}
This means that if a new session event type is added that has a property with the same name but a different type as an existing event, the shared field must change type to accommodate both. For example, content was *string but a new event used content as a structured object — quicktype changed it to *DataContent (a union of string and map), breaking all existing consumers that read Content as *string.
This is fundamentally unmanageable: any new session event type can silently break the Go SDK's public API by changing the type of a field that existing consumers rely on.
Impact
Every go/generated_session_events.go regeneration is a potential breaking change
SDK consumers cannot safely use response.Data.Content (or any shared field) without risking that a future codegen run changes its type
A representation of session event data that is additive-only — adding a new event type should never change the types of existing event payloads. Some options:
Per-event-type structs: Generate a separate struct for each event type's data (e.g., AssistantMessageData, ToolExecutionStartData), with a typed accessor on SessionEvent that returns the concrete type based on the Type discriminator. This is what the C# codegen does.
Embed + type-switch: Keep a minimal base struct with common fields, and generate per-event structs that consumers access via a type switch or typed getter method.
Interface-based: Define a SessionEventData interface with per-type implementations, using a custom UnmarshalJSON that dispatches based on the type field.
All of these ensure that adding event type B never changes the struct shape of event type A.
Current workaround
In #1029 I explicitly reverted the Go-specific session events codegen change, and added a build check suppression (09f7cee). When we fix the code generator, we must also re-enable the build check.
Problem
The Go codegen for session events (
generated_session_events.go) uses quicktype, which represents the discriminated union of all session eventDatapayloads as a single flat struct with every property from every event type merged together:This means that if a new session event type is added that has a property with the same name but a different type as an existing event, the shared field must change type to accommodate both. For example,
contentwas*stringbut a new event usedcontentas a structured object — quicktype changed it to*DataContent(a union of string and map), breaking all existing consumers that readContentas*string.This is fundamentally unmanageable: any new session event type can silently break the Go SDK's public API by changing the type of a field that existing consumers rely on.
Impact
go/generated_session_events.goregeneration is a potential breaking changeresponse.Data.Content(or any shared field) without risking that a future codegen run changes its typeContenttype change unrelated to the PR's purposeDesired outcome
A representation of session event data that is additive-only — adding a new event type should never change the types of existing event payloads. Some options:
Per-event-type structs: Generate a separate struct for each event type's data (e.g.,
AssistantMessageData,ToolExecutionStartData), with a typed accessor onSessionEventthat returns the concrete type based on theTypediscriminator. This is what the C# codegen does.Embed + type-switch: Keep a minimal base struct with common fields, and generate per-event structs that consumers access via a type switch or typed getter method.
Interface-based: Define a
SessionEventDatainterface with per-type implementations, using a customUnmarshalJSONthat dispatches based on thetypefield.All of these ensure that adding event type B never changes the struct shape of event type A.
Current workaround
In #1029 I explicitly reverted the Go-specific session events codegen change, and added a build check suppression (09f7cee). When we fix the code generator, we must also re-enable the build check.