Skip to content

Avoid initializing every session event type on first deserialization #2777

Closed

Description

@davkean

SessionEvent.FromJson deserializes through the polymorphic base JsonTypeInfo. On the first event, System.Text.Json configures metadata for every derived session event type before returning the one concrete event that was received.

A cold-process console reproduction that deserializes one user.message event shows these medians across 15 processes:

Target Current Discriminator dispatch prototype
.NET Framework 4.7.2 5,466 ms 315 ms
.NET 8 512 ms / 5.09 MB 139 ms / 0.42 MB

The prototype reads the existing type discriminator and deserializes with only the matching source-generated concrete JsonTypeInfo. Unknown and missing discriminators continue to produce the base SessionEvent, preserving forward compatibility.

The expected behavior is for first-event deserialization to configure only the metadata required by the received event type, without changing known, unknown, union, or forward-compatible event semantics.

Activity

  1. stephentoub commented on Sep 28, 2026

    @stephentoub
    Collaborator

    If there's a perf issue here with System.Text.Json's polymorphic deserialization, shouldn't we fix that in STJ?
    cc: @eiriktsarpalis

  2. eiriktsarpalis commented on Sep 28, 2026

    @eiriktsarpalis

    STJ will generally attempt to configure the entire type graph up front before it attempts any serialization or deserialization operation. We could decide type that a particular shape warrants lazy expansion, but that comes at the expense of serving the user with configuration errors halfway through a serialization operation. Feel free to transfer the issue o dotnet/runtime and we can take a look at possible improvements or if there's an unanticipated performance bug lurking.

  3. patniko commented on Oct 26, 2026

    @patniko
    Contributor

    Thanks for the analysis and the prototype. The discriminator-dispatch approach from #2778 is now in the .NET SDK: SessionEvent.FromJson and live event binding read the type discriminator and deserialize with only the matching source-generated type metadata instead of configuring every derived event type up front, while unknown or missing discriminators still fall back to the base SessionEvent. This is available in Copilot SDK v1.0.17 and later and substantially reduces first-event latency, especially on .NET Framework. If you still see the cold-start cost on the latest version, feel free to reopen.

    Triaged as part of a Copilot SDK backlog review, with help from GitHub Copilot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions