@@ -106,7 +106,10 @@ public ClientProvider(InputClient inputClient)
106106 _publicCtorDescription = $ "Initializes a new instance of { Name } .";
107107 ClientOptions = _inputClient . Parent is null ? ClientOptionsProvider . CreateClientOptionsProvider ( _inputClient , this ) : null ;
108108 ClientOptionsParameter = ClientOptions != null ? ScmKnownParameters . ClientOptions ( ClientOptions . Type ) : null ;
109- ClientSettings = ClientOptions != null ? new ClientSettingsProvider ( _inputClient , this ) : null ;
109+ bool isIndividuallyInitialized = ( _inputClient . InitializedBy & InputClientInitializedBy . Individually ) != 0 ;
110+ ClientSettings = isIndividuallyInitialized
111+ ? new ClientSettingsProvider ( _inputClient , this )
112+ : null ;
110113 IsMultiServiceClient = _inputClient . IsMultiServiceClient ;
111114
112115 var apiKey = _inputAuth ? . ApiKey ;
@@ -133,8 +136,7 @@ public ClientProvider(InputClient inputClient)
133136 this ,
134137 initializationValue : Literal ( apiKey . Prefix ) ) :
135138 null ;
136- // skip auth fields for sub-clients
137- _apiKeyAuthFields = ClientOptions is null ? null : new ( apiKeyAuthField , authorizationHeaderField , authorizationApiKeyPrefixField ) ;
139+ _apiKeyAuthFields = isIndividuallyInitialized ? new ( apiKeyAuthField , authorizationHeaderField , authorizationApiKeyPrefixField ) : null ;
138140 }
139141
140142 var tokenAuth = _inputAuth ? . OAuth2 ;
@@ -158,8 +160,7 @@ public ClientProvider(InputClient inputClient)
158160
159161 var tokenCredentialScopesField = BuildTokenCredentialScopesField ( tokenAuth , tokenCredentialType ) ;
160162
161- // skip auth fields for sub-clients
162- _oauth2Fields = ClientOptions is null ? null : new ( tokenCredentialField , tokenCredentialScopesField ) ;
163+ _oauth2Fields = isIndividuallyInitialized ? new ( tokenCredentialField , tokenCredentialScopesField ) : null ;
163164 }
164165 EndpointField = new (
165166 FieldModifiers . Private | FieldModifiers . ReadOnly ,
@@ -300,14 +301,8 @@ private IReadOnlyList<ParameterProvider> GetSubClientInternalConstructorParamete
300301 PipelineProperty . AsParameter
301302 } ;
302303
303- if ( _apiKeyAuthFields != null )
304- {
305- subClientParameters . Add ( _apiKeyAuthFields . AuthField . AsParameter ) ;
306- }
307- if ( _oauth2Fields != null )
308- {
309- subClientParameters . Add ( _oauth2Fields . AuthField . AsParameter ) ;
310- }
304+ // Auth credentials are NOT included here — the parent passes its authenticated
305+ // pipeline, so the sub-client doesn't need separate credential parameters.
311306 subClientParameters . Add ( _endpointParameter ) ;
312307 subClientParameters . AddRange ( ClientParameters ) ;
313308
@@ -385,6 +380,12 @@ private IReadOnlyList<ParameterProvider> GetClientParameters()
385380 public ClientOptionsProvider ? ClientOptions { get ; }
386381 public ClientSettingsProvider ? ClientSettings { get ; }
387382
383+ /// <summary>
384+ /// Gets the effective <see cref="ClientOptionsProvider"/> — the client's own options for root clients,
385+ /// or the root client's options for individually-initialized sub-clients.
386+ /// </summary>
387+ internal ClientOptionsProvider ? EffectiveClientOptions => ClientOptions ?? GetRootClient ( ) ? . ClientOptions ;
388+
388389 public PropertyProvider PipelineProperty { get ; }
389390 public FieldProvider EndpointField { get ; }
390391
@@ -647,7 +648,9 @@ void AppendPublicConstructors(
647648 foreach ( var p in requiredParameters )
648649 {
649650 if ( authParamName == null || p . Name != authParamName )
651+ {
650652 initializerArgs . Add ( p ) ;
653+ }
651654 }
652655 initializerArgs . Add ( ClientOptionsParameter ! ) ;
653656
@@ -686,6 +689,14 @@ private IEnumerable<ConstructorProvider> BuildSettingsConstructors()
686689 yield break ;
687690 }
688691
692+ // Only publicly constructible clients should get the Settings constructor.
693+ // Internal clients (e.g., those made internal via custom code) cannot be
694+ // constructed by consumers, so a public Settings constructor is not useful.
695+ if ( ! DeclarationModifiers . HasFlag ( TypeSignatureModifiers . Public ) )
696+ {
697+ yield break ;
698+ }
699+
689700 var settingsParam = new ParameterProvider ( SettingsParamName , $ "The settings for { Name } .", ClientSettings . Type ) ;
690701 var experimentalAttr = new AttributeStatement ( typeof ( ExperimentalAttribute ) , [ Literal ( ClientSettingsProvider . ClientSettingsDiagnosticId ) ] ) ;
691702
@@ -733,64 +744,108 @@ private IEnumerable<ConstructorProvider> BuildSettingsConstructors()
733744 private void AppendSubClientPublicConstructors ( List < ConstructorProvider > constructors )
734745 {
735746 // For sub-clients that can be initialized individually, we need to create public constructors
736- // similar to the root client constructors but adapted for sub- client needs
747+ // with the same auth pattern as the root client.
737748 var primaryConstructors = new List < ConstructorProvider > ( ) ;
738749 var secondaryConstructors = new List < ConstructorProvider > ( ) ;
739750
740- // if there is key auth
751+ var rootClient = GetRootClient ( ) ;
752+ var clientOptionsParameter = rootClient ? . ClientOptionsParameter ;
753+ var clientOptionsProvider = rootClient ? . ClientOptions ;
754+
755+ if ( clientOptionsParameter == null || clientOptionsProvider == null )
756+ {
757+ return ;
758+ }
759+
760+ // Add the internal AuthenticationPolicy constructor first — public constructors chain to it.
761+ var authPolicyParam = new ParameterProvider (
762+ "authenticationPolicy" ,
763+ $ "The authentication policy to use for pipeline creation.",
764+ new CSharpType ( typeof ( AuthenticationPolicy ) , isNullable : true ) ) ;
765+
766+ var requiredNonAuthParams = GetRequiredParameters ( null ) ;
767+ ParameterProvider [ ] internalConstructorParameters = [ authPolicyParam , _endpointParameter , .. requiredNonAuthParams , clientOptionsParameter ] ;
768+
769+ var internalConstructor = new ConstructorProvider (
770+ new ConstructorSignature ( Type , _publicCtorDescription , MethodSignatureModifiers . Internal , internalConstructorParameters ) ,
771+ BuildPrimaryConstructorBody ( internalConstructorParameters , null , authPolicyParam , clientOptionsProvider , clientOptionsParameter , addExplicitValidation : true ) ,
772+ this ) ;
773+ primaryConstructors . Add ( internalConstructor ) ;
774+
775+ // Add public constructors with auth — same pattern as root client
741776 if ( _apiKeyAuthFields != null )
742777 {
743778 AppendSubClientPublicConstructorsForAuth ( _apiKeyAuthFields , primaryConstructors , secondaryConstructors ) ;
744779 }
745- // if there is oauth2 auth
746780 if ( _oauth2Fields != null )
747781 {
748782 AppendSubClientPublicConstructorsForAuth ( _oauth2Fields , primaryConstructors , secondaryConstructors ) ;
749783 }
750784
751- // if there is no auth
785+ bool onlyContainsUnsupportedAuth = _inputAuth != null && _apiKeyAuthFields == null && _oauth2Fields == null ;
752786 if ( _apiKeyAuthFields == null && _oauth2Fields == null )
753787 {
754- AppendSubClientPublicConstructorsForAuth ( null , primaryConstructors , secondaryConstructors ) ;
788+ AppendSubClientPublicConstructorsForAuth ( null , primaryConstructors , secondaryConstructors , onlyContainsUnsupportedAuth ) ;
755789 }
756790
757791 constructors . AddRange ( secondaryConstructors ) ;
758792 constructors . AddRange ( primaryConstructors ) ;
759793
794+ // Add Settings constructor for individually-initialized sub-clients
795+ foreach ( var settingsConstructor in BuildSettingsConstructors ( ) )
796+ {
797+ constructors . Add ( settingsConstructor ) ;
798+ }
799+
760800 void AppendSubClientPublicConstructorsForAuth (
761801 AuthFields ? authFields ,
762802 List < ConstructorProvider > primaryConstructors ,
763- List < ConstructorProvider > secondaryConstructors )
764- {
765- // For a sub-client with individual initialization, we need:
766- // - endpoint parameter
767- // - auth parameter (if auth exists)
768- // - client options parameter (we need to get this from the root client)
769- var rootClient = GetRootClient ( ) ;
770- var clientOptionsParameter = rootClient ? . ClientOptionsParameter ;
771- var clientOptionsProvider = rootClient ? . ClientOptions ;
772- if ( clientOptionsParameter == null || clientOptionsProvider == null )
803+ List < ConstructorProvider > secondaryConstructors ,
804+ bool onlyContainsUnsupportedAuth = false )
805+ {
806+ // Public constructor with credential parameter — delegates to the internal constructor via this(...).
807+ var requiredParameters = GetRequiredParameters ( authFields ? . AuthField ) ;
808+ ParameterProvider [ ] primaryConstructorParameters = [ _endpointParameter , .. requiredParameters , clientOptionsParameter ] ;
809+ var constructorModifier = onlyContainsUnsupportedAuth ? MethodSignatureModifiers . Internal : MethodSignatureModifiers . Public ;
810+
811+ // Build the auth policy expression for the this() initializer
812+ ValueExpression authPolicyArg = BuildAuthPolicyArgument ( authFields , requiredParameters ) ;
813+ var initializerArgs = new List < ValueExpression > { authPolicyArg , _endpointParameter } ;
814+ string ? authParamName = authFields != null
815+ ? ( authFields . AuthField . Name != TokenProviderFieldName ? CredentialParamName : authFields . AuthField . AsParameter . Name )
816+ : null ;
817+ foreach ( var p in requiredParameters )
773818 {
774- // Cannot create public constructor without client options
775- return ;
819+ if ( authParamName == null || p . Name != authParamName )
820+ {
821+ initializerArgs . Add ( p ) ;
822+ }
776823 }
824+ initializerArgs . Add ( clientOptionsParameter ! ) ;
777825
778- var requiredParameters = GetRequiredParameters ( authFields ? . AuthField ) ;
779- ParameterProvider [ ] primaryConstructorParameters = [ _endpointParameter , .. requiredParameters , clientOptionsParameter ] ;
780826 var primaryConstructor = new ConstructorProvider (
781- new ConstructorSignature ( Type , _publicCtorDescription , MethodSignatureModifiers . Public , primaryConstructorParameters ) ,
782- BuildPrimaryConstructorBody ( primaryConstructorParameters , authFields , null , clientOptionsProvider , clientOptionsParameter ) ,
827+ new ConstructorSignature ( Type , _publicCtorDescription , constructorModifier , primaryConstructorParameters ,
828+ initializer : new ConstructorInitializer ( false , initializerArgs ) ) ,
829+ MethodBodyStatement . Empty ,
783830 this ) ;
784-
785831 primaryConstructors . Add ( primaryConstructor ) ;
786832
787833 // If the endpoint parameter contains an initialization value, it is not required.
788834 ParameterProvider [ ] secondaryConstructorParameters = _endpointParameter . InitializationValue is null
789835 ? [ _endpointParameter , .. requiredParameters ]
790836 : [ .. requiredParameters ] ;
791- var secondaryConstructor = BuildSecondaryConstructor ( secondaryConstructorParameters , primaryConstructorParameters , MethodSignatureModifiers . Public ) ;
837+ var secondaryConstructor = BuildSecondaryConstructor ( secondaryConstructorParameters , primaryConstructorParameters , constructorModifier ) ;
792838
793839 secondaryConstructors . Add ( secondaryConstructor ) ;
840+
841+ // When endpoint has a default value and there are required parameters,
842+ // add an additional constructor that accepts required parameters + options.
843+ if ( _endpointParameter . InitializationValue is not null && requiredParameters . Count > 0 )
844+ {
845+ ParameterProvider [ ] simplifiedConstructorWithOptionsParameters = [ .. requiredParameters , clientOptionsParameter ] ;
846+ var simplifiedConstructorWithOptions = BuildSecondaryConstructor ( simplifiedConstructorWithOptionsParameters , primaryConstructorParameters , constructorModifier ) ;
847+ secondaryConstructors . Add ( simplifiedConstructorWithOptions ) ;
848+ }
794849 }
795850 }
796851
@@ -917,11 +972,18 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<Paramete
917972 }
918973
919974 ValueExpression perRetryPolicies ;
920- if ( authPolicyParam != null && authFields != null )
975+ if ( authPolicyParam != null )
921976 {
922- // Internal implementation constructor: use the authenticationPolicy parameter directly
923- perRetryPoliciesList . Add ( authPolicyParam ) ;
924- perRetryPolicies = New . Array ( ScmCodeModelGenerator . Instance . TypeFactory . ClientPipelineApi . PipelinePolicyType , isInline : true , [ .. perRetryPoliciesList ] ) ;
977+ // Internal implementation constructor: generate a runtime null check for the auth policy.
978+ // No-auth clients pass null, so we must guard against adding null to the policies array.
979+ var pipelinePolicyType = ScmCodeModelGenerator . Instance . TypeFactory . ClientPipelineApi . PipelinePolicyType ;
980+ var perRetryWithoutAuth = New . Array ( pipelinePolicyType , isInline : true , [ .. perRetryPoliciesList ] ) ;
981+ var perRetryWithAuth = New . Array ( pipelinePolicyType , isInline : true , [ .. perRetryPoliciesList , authPolicyParam ] ) ;
982+
983+ body . Add ( new IfElseStatement (
984+ authPolicyParam . NotEqual ( Null ) ,
985+ PipelineProperty . Assign ( This . ToApi < ClientPipelineApi > ( ) . Create ( clientOptionsParameter , perRetryWithAuth ) ) . Terminate ( ) ,
986+ PipelineProperty . Assign ( This . ToApi < ClientPipelineApi > ( ) . Create ( clientOptionsParameter , perRetryWithoutAuth ) ) . Terminate ( ) ) ) ;
925987 }
926988 else
927989 {
@@ -940,9 +1002,9 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<Paramete
9401002 perRetryPolicies = New . Array ( ScmCodeModelGenerator . Instance . TypeFactory . ClientPipelineApi . PipelinePolicyType , isInline : true , [ .. perRetryPoliciesList ] ) ;
9411003 break ;
9421004 }
943- }
9441005
945- body . Add ( PipelineProperty . Assign ( This . ToApi < ClientPipelineApi > ( ) . Create ( clientOptionsParameter , perRetryPolicies ) ) . Terminate ( ) ) ;
1006+ body . Add ( PipelineProperty . Assign ( This . ToApi < ClientPipelineApi > ( ) . Create ( clientOptionsParameter , perRetryPolicies ) ) . Terminate ( ) ) ;
1007+ }
9461008
9471009 foreach ( var f in Fields )
9481010 {
0 commit comments