# ISpeechProviderResolver

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.ispeechproviderresolver/
> Summary: ISpeechProviderResolver: Returns a speech provider by name, after the calling tenant's provider checks.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

Returns a speech provider by name, after the calling tenant's provider checks.

```csharp
public interface ISpeechProviderResolver
```

## Remarks

Every Tracon path that sends a tenant's text or audio to a speech provider
resolves the provider here: the `speak`, `transcribe` and
`list_voices` tools, `POST /api/voice/speak`, `GET /api/voice/voices`
and the conversation socket. A workflow function node that speaks or voices a
dialogue resolves it here too. The one direct call is the platform health check
(`GET /api/voice/health`): it lists the default synthesizer's voices with the
configured credential and sends no tenant data.

A name selects a provider registered with `AddSpeechSynthesizer` or
`AddSpeechTranscriber`. [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) selects the unnamed default,
the one `UseVoice` or the consumer's own [ISpeechSynthesizer](/api/tracon.ispeechsynthesizer/)
registration binds. Names are compared in lower case.

**Order of the checks.** The tenant's egress policy is checked
first, against the instance's [ISpeechSynthesizer.ProviderName](/api/tracon.ispeechsynthesizer/#Tracon_ISpeechSynthesizer_ProviderName) (not
the registration name, so an alias cannot pass a policy). Then the tenant's own
credential for that provider is looked up. When the tenant has one, the provider
must support tenant credentials and the binding must not carry an endpoint
override; otherwise the call is refused rather than sent on the setup credential.
The returned provider puts the tenant's credential on every request it makes.

The policy and the binding are read each time a provider is resolved, not
cached. A tool call, an HTTP request and a function node resolve for every call,
so a policy saved now stops their next call. The conversation socket resolves
once, when the connection opens: an open connection keeps the providers it was
given until it closes, and a policy saved meanwhile applies from the next
connection. A returned instance keeps the decision it was resolved under; do not
keep it. When a store fails, the call fails and the provider is not called.

**Delivery:** no delivery guarantee applies. Resolving sends nothing to
the provider; the call made with the returned instance is the caller's, with that
provider's own guarantee.

**DI lifetime — singleton.** Registered by `AddTracon`.
Call this interface; do not implement or replace it. The tenant's egress policy and
credential checks above run inside it, and a replacement would send a tenant's text
or audio to a provider without them. To add a provider, register an
[ISpeechSynthesizer](/api/tracon.ispeechsynthesizer/) or [ISpeechTranscriber](/api/tracon.ispeechtranscriber/) as described
above.

**Tenant behavior — AMBIENT tenant.** No member takes a tenant
parameter; the checks use the current run's tenant, or the current
`ITenantContext` outside a run. The returned provider can carry that
tenant's credential: resolve it for each call and do not keep it for another
tenant.

A workflow function node that speaks with the engine named in the node's settings:

```csharp
builder.AddTracon()
       .AddSpeechSynthesizer("studio", provider => new StudioSpeechSynthesizer())
       .UseWorkflows()
       .AddWorkflowFunction<List<ChatMessage>, List<ChatMessage>, NarrationSettings>(
           "narrate",
           provider =>
           {
               var speech = provider.GetRequiredService<ISpeechProviderResolver>();

               return async (messages, settings, context, cancellationToken) =>
               {
                   var synthesizer = await speech.GetSynthesizerAsync(settings.Provider, cancellationToken);
                   var audio = await synthesizer.SynthesizeAsync(
                       new SpeechRequest { Text = messages[^1].Text },
                       cancellationToken);

                   return [new ChatMessage(ChatRole.Assistant, $"{audio.Data.Length} bytes")];
               };
           });
```

## Properties

### <a id="Tracon_ISpeechProviderResolver_Providers"></a> Providers

Gets the registered speech providers, the unnamed defaults included.

```csharp
IReadOnlyList<SpeechProviderDescriptor> Providers { get; }
```

#### Property Value

 [IReadOnlyList](https://learn.microsoft.com/dotnet/api/system.collections.generic.ireadonlylist\-1)<[SpeechProviderDescriptor](/api/tracon.speechproviderdescriptor/)\>

#### Remarks

Synthesizers come first, then transcribers; in each kind the unnamed default
comes first, then the named providers in ordinal order of their names. Reading
the list applies no tenant check and calls no provider.

## Methods

### <a id="Tracon_ISpeechProviderResolver_GetDialogueSynthesizerAsync_System_String_System_Threading_CancellationToken_"></a> GetDialogueSynthesizerAsync\(string?, CancellationToken\)

Returns the dialogue capability of a speech synthesizer for the current tenant.

```csharp
ValueTask<ISpeechDialogueSynthesizer> GetDialogueSynthesizerAsync(string? name = null, CancellationToken cancellationToken = default)
```

#### Parameters

`name` [string](https://learn.microsoft.com/dotnet/api/system.string)?

The registration name of the synthesizer, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) for the unnamed
default. Dialogue has no registration of its own: the synthesizer registered under
this name must implement [ISpeechDialogueSynthesizer](/api/tracon.ispeechdialoguesynthesizer/).

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[ISpeechDialogueSynthesizer](/api/tracon.ispeechdialoguesynthesizer/)\>

The dialogue synthesizer, carrying the tenant's credential when it has one.

#### Remarks

The capability is read from the synthesizer instance itself, never from a wrapper,
so a tenant with its own credential and a tenant without one see the same answer.
The tenant's checks then apply to [ISpeechDialogueSynthesizer.ProviderName](/api/tracon.ispeechdialoguesynthesizer/#Tracon_ISpeechDialogueSynthesizer_ProviderName)
in the order [ISpeechProviderResolver.GetSynthesizerAsync](/api/tracon.ispeechproviderresolver/#Tracon_ISpeechProviderResolver_GetSynthesizerAsync_System_String_System_Threading_CancellationToken_) uses.

A host's own synthesizer that voices no dialogue is reported, not replaced: the call
fails naming that provider, and the built-in client is not called in its place.

#### Exceptions

 [TraconException](/api/tracon.traconexception/)

No synthesizer is registered under `name`, or no default is
registered; the synthesizer cannot voice a dialogue; or the tenant's checks refuse
the provider. The message names the provider, never a key value.

 [OperationCanceledException](https://learn.microsoft.com/dotnet/api/system.operationcanceledexception)

`cancellationToken` was cancelled.

### <a id="Tracon_ISpeechProviderResolver_GetSynthesizerAsync_System_String_System_Threading_CancellationToken_"></a> GetSynthesizerAsync\(string?, CancellationToken\)

Returns a speech synthesizer for the current tenant.

```csharp
ValueTask<ISpeechSynthesizer> GetSynthesizerAsync(string? name = null, CancellationToken cancellationToken = default)
```

#### Parameters

`name` [string](https://learn.microsoft.com/dotnet/api/system.string)?

The registration name, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) for the unnamed default.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[ISpeechSynthesizer](/api/tracon.ispeechsynthesizer/)\>

The synthesizer, carrying the tenant's credential when it has one.

#### Exceptions

 [TraconException](/api/tracon.traconexception/)

No synthesizer is registered under `name`, or no default is
registered; or the tenant's checks refuse the provider. The message names the
tenant and the provider, never a key value.

 [OperationCanceledException](https://learn.microsoft.com/dotnet/api/system.operationcanceledexception)

`cancellationToken` was cancelled.

### <a id="Tracon_ISpeechProviderResolver_GetTranscriberAsync_System_String_System_Threading_CancellationToken_"></a> GetTranscriberAsync\(string?, CancellationToken\)

Returns a speech transcriber for the current tenant.

```csharp
ValueTask<ISpeechTranscriber> GetTranscriberAsync(string? name = null, CancellationToken cancellationToken = default)
```

#### Parameters

`name` [string](https://learn.microsoft.com/dotnet/api/system.string)?

The registration name, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) for the unnamed default.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[ISpeechTranscriber](/api/tracon.ispeechtranscriber/)\>

The transcriber, carrying the tenant's credential when it has one.

#### Exceptions

 [TraconException](/api/tracon.traconexception/)

No transcriber is registered under `name`, or no default is
registered; or the tenant's checks refuse the provider.

 [OperationCanceledException](https://learn.microsoft.com/dotnet/api/system.operationcanceledexception)

`cancellationToken` was cancelled.
