Description
The C# emitter collapses an optional nullable property's omitted and explicitly null states. Setting the generated property to null omits it from the request instead of writing JSON null.
This breaks services where omission selects a default but explicit null disables a feature. For example, Foundry voice-agent turn detection defaults to enabled and requires "turn_detection": null to disable it.
Input and reproduction
The pinned TypeSpec declarations correctly model both optionality and nullability:
noise_reduction?: VoiceAgentNoiseReduction | null;
turn_detection?: VoiceAgentTurnDetectionConfig | null;
transcription?: VoiceAgentInputTranscription | null;
Using the generated model in Azure/azure-sdk-for-net#62884:
using System;
using System.ClientModel.Primitives;
using Azure.AI.Projects.Agents;
#pragma warning disable AAIP001
var input = new VoiceAgentAudioInputConfig
{
TurnDetection = null
};
Console.WriteLine(ModelReaderWriter.Write(
input,
new ModelReaderWriterOptions("W"),
AzureAIProjectsAgentsContext.Default).ToString());
Actual: {}
Expected: {"turn_detection":null}
Leaving TurnDetection unset should still produce {}. The generated model needs to preserve the distinction rather than serializing all unset nullable properties as null.
The same omission occurs for NoiseReduction and Transcription. Serialization through the containing voice-agent definition produces "audio":{"input":{}}, so this also affects actual agent request bodies. The omission was reproduced against the compiled SDK and its real dependencies without service calls.
Upstream implementation
In the pinned generator, MrwSerializationTypeDefinition.CreateConditionalSerializationStatement uses Optional.IsDefined(property) and generates an explicit-null branch only for isRequired && isNullable. Optional nullable properties fall through to an if (IsDefined(...)) guard, and these generated reference-type properties have no explicit-presence tracking.
The SDK's active custom visitors only add experimental attributes or adjust virtual/override modifiers; they do not change these property types or serialization conditions.
Environment
Expected coverage
Please cover omitted, explicitly null, and non-null values for optional nullable model properties, including nested wire serialization and preservation of explicit null when reading and then writing a model.
Description
The C# emitter collapses an optional nullable property's omitted and explicitly null states. Setting the generated property to
nullomits it from the request instead of writing JSON null.This breaks services where omission selects a default but explicit null disables a feature. For example, Foundry voice-agent turn detection defaults to enabled and requires
"turn_detection": nullto disable it.Input and reproduction
The pinned TypeSpec declarations correctly model both optionality and nullability:
Using the generated model in Azure/azure-sdk-for-net#62884:
Actual:
{}Expected:
{"turn_detection":null}Leaving
TurnDetectionunset should still produce{}. The generated model needs to preserve the distinction rather than serializing all unset nullable properties as null.The same omission occurs for
NoiseReductionandTranscription. Serialization through the containing voice-agent definition produces"audio":{"input":{}}, so this also affects actual agent request bodies. The omission was reproduced against the compiled SDK and its real dependencies without service calls.Upstream implementation
In the pinned generator,
MrwSerializationTypeDefinition.CreateConditionalSerializationStatementusesOptional.IsDefined(property)and generates an explicit-null branch only forisRequired && isNullable. Optional nullable properties fall through to anif (IsDefined(...))guard, and these generated reference-type properties have no explicit-presence tracking.The SDK's active custom visitors only add experimental attributes or adjust
virtual/overridemodifiers; they do not change these property types or serialization conditions.Environment
@typespec/http-client-csharp1.0.0-alpha.20260910.2Microsoft.TypeSpec.Generator.ClientModel1.0.0-alpha.20260910.29b8c51de8c15b6dc748ea9cf576d87f91ef058c4efa46fdc6e3fca32a195fc575b873fd696a7b572Expected coverage
Please cover omitted, explicitly null, and non-null values for optional nullable model properties, including nested wire serialization and preservation of explicit null when reading and then writing a model.