@framers/agentos 0.1.75 → 0.1.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -34
- package/dist/core/agency/AgentCommunicationBus.d.ts +1 -0
- package/dist/core/agency/AgentCommunicationBus.d.ts.map +1 -1
- package/dist/core/agency/AgentCommunicationBus.js +62 -8
- package/dist/core/agency/AgentCommunicationBus.js.map +1 -1
- package/dist/core/agency/IAgentCommunicationBus.d.ts +1 -1
- package/dist/core/agency/IAgentCommunicationBus.d.ts.map +1 -1
- package/dist/orchestration/runtime/LoopController.d.ts +10 -10
- package/dist/orchestration/runtime/LoopController.d.ts.map +1 -1
- package/dist/orchestration/runtime/LoopController.js +1 -1
- package/dist/orchestration/runtime/LoopController.js.map +1 -1
- package/dist/orchestration/runtime/index.d.ts +1 -1
- package/dist/orchestration/runtime/index.d.ts.map +1 -1
- package/dist/orchestration/runtime/index.js.map +1 -1
- package/dist/speech/FallbackProxy.d.ts +104 -0
- package/dist/speech/FallbackProxy.d.ts.map +1 -0
- package/dist/speech/FallbackProxy.js +151 -0
- package/dist/speech/FallbackProxy.js.map +1 -0
- package/dist/speech/SpeechProviderResolver.d.ts +103 -0
- package/dist/speech/SpeechProviderResolver.d.ts.map +1 -0
- package/dist/speech/SpeechProviderResolver.js +256 -0
- package/dist/speech/SpeechProviderResolver.js.map +1 -0
- package/dist/speech/SpeechRuntime.d.ts +23 -1
- package/dist/speech/SpeechRuntime.d.ts.map +1 -1
- package/dist/speech/SpeechRuntime.js +82 -8
- package/dist/speech/SpeechRuntime.js.map +1 -1
- package/dist/speech/index.d.ts +6 -0
- package/dist/speech/index.d.ts.map +1 -1
- package/dist/speech/index.js +6 -0
- package/dist/speech/index.js.map +1 -1
- package/dist/speech/providerCatalog.d.ts.map +1 -1
- package/dist/speech/providerCatalog.js +15 -1
- package/dist/speech/providerCatalog.js.map +1 -1
- package/dist/speech/providers/AssemblyAISTTProvider.d.ts +49 -0
- package/dist/speech/providers/AssemblyAISTTProvider.d.ts.map +1 -0
- package/dist/speech/providers/AssemblyAISTTProvider.js +151 -0
- package/dist/speech/providers/AssemblyAISTTProvider.js.map +1 -0
- package/dist/speech/providers/AzureSpeechSTTProvider.d.ts +48 -0
- package/dist/speech/providers/AzureSpeechSTTProvider.d.ts.map +1 -0
- package/dist/speech/providers/AzureSpeechSTTProvider.js +90 -0
- package/dist/speech/providers/AzureSpeechSTTProvider.js.map +1 -0
- package/dist/speech/providers/AzureSpeechTTSProvider.d.ts +60 -0
- package/dist/speech/providers/AzureSpeechTTSProvider.d.ts.map +1 -0
- package/dist/speech/providers/AzureSpeechTTSProvider.js +127 -0
- package/dist/speech/providers/AzureSpeechTTSProvider.js.map +1 -0
- package/dist/speech/providers/DeepgramBatchSTTProvider.d.ts +55 -0
- package/dist/speech/providers/DeepgramBatchSTTProvider.d.ts.map +1 -0
- package/dist/speech/providers/DeepgramBatchSTTProvider.js +102 -0
- package/dist/speech/providers/DeepgramBatchSTTProvider.js.map +1 -0
- package/dist/speech/types.d.ts +35 -0
- package/dist/speech/types.d.ts.map +1 -1
- package/dist/voice/CallManager.d.ts +1 -1
- package/dist/voice/CallManager.d.ts.map +1 -1
- package/dist/voice/CallManager.js +9 -0
- package/dist/voice/CallManager.js.map +1 -1
- package/dist/voice/MediaStreamParser.d.ts +83 -0
- package/dist/voice/MediaStreamParser.d.ts.map +1 -0
- package/dist/voice/MediaStreamParser.js +2 -0
- package/dist/voice/MediaStreamParser.js.map +1 -0
- package/dist/voice/TelephonyStreamTransport.d.ts +112 -0
- package/dist/voice/TelephonyStreamTransport.d.ts.map +1 -0
- package/dist/voice/TelephonyStreamTransport.js +208 -0
- package/dist/voice/TelephonyStreamTransport.js.map +1 -0
- package/dist/voice/index.d.ts +10 -0
- package/dist/voice/index.d.ts.map +1 -1
- package/dist/voice/index.js +11 -0
- package/dist/voice/index.js.map +1 -1
- package/dist/voice/parsers/PlivoMediaStreamParser.d.ts +43 -0
- package/dist/voice/parsers/PlivoMediaStreamParser.d.ts.map +1 -0
- package/dist/voice/parsers/PlivoMediaStreamParser.js +92 -0
- package/dist/voice/parsers/PlivoMediaStreamParser.js.map +1 -0
- package/dist/voice/parsers/TelnyxMediaStreamParser.d.ts +51 -0
- package/dist/voice/parsers/TelnyxMediaStreamParser.d.ts.map +1 -0
- package/dist/voice/parsers/TelnyxMediaStreamParser.js +103 -0
- package/dist/voice/parsers/TelnyxMediaStreamParser.js.map +1 -0
- package/dist/voice/parsers/TwilioMediaStreamParser.d.ts +50 -0
- package/dist/voice/parsers/TwilioMediaStreamParser.d.ts.map +1 -0
- package/dist/voice/parsers/TwilioMediaStreamParser.js +144 -0
- package/dist/voice/parsers/TwilioMediaStreamParser.js.map +1 -0
- package/dist/voice/providers/plivo.d.ts +77 -0
- package/dist/voice/providers/plivo.d.ts.map +1 -0
- package/dist/voice/providers/plivo.js +180 -0
- package/dist/voice/providers/plivo.js.map +1 -0
- package/dist/voice/providers/telnyx.d.ts +93 -0
- package/dist/voice/providers/telnyx.d.ts.map +1 -0
- package/dist/voice/providers/telnyx.js +193 -0
- package/dist/voice/providers/telnyx.js.map +1 -0
- package/dist/voice/providers/twilio.d.ts +79 -0
- package/dist/voice/providers/twilio.d.ts.map +1 -0
- package/dist/voice/providers/twilio.js +191 -0
- package/dist/voice/providers/twilio.js.map +1 -0
- package/dist/voice/twiml.d.ts +69 -0
- package/dist/voice/twiml.d.ts.map +1 -0
- package/dist/voice/twiml.js +92 -0
- package/dist/voice/twiml.js.map +1 -0
- package/dist/voice/types.d.ts +9 -1
- package/dist/voice/types.d.ts.map +1 -1
- package/dist/voice-pipeline/AcousticEndpointDetector.d.ts +90 -0
- package/dist/voice-pipeline/AcousticEndpointDetector.d.ts.map +1 -0
- package/dist/voice-pipeline/AcousticEndpointDetector.js +123 -0
- package/dist/voice-pipeline/AcousticEndpointDetector.js.map +1 -0
- package/dist/voice-pipeline/HardCutBargeinHandler.d.ts +67 -0
- package/dist/voice-pipeline/HardCutBargeinHandler.d.ts.map +1 -0
- package/dist/voice-pipeline/HardCutBargeinHandler.js +55 -0
- package/dist/voice-pipeline/HardCutBargeinHandler.js.map +1 -0
- package/dist/voice-pipeline/HeuristicEndpointDetector.d.ts +128 -0
- package/dist/voice-pipeline/HeuristicEndpointDetector.d.ts.map +1 -0
- package/dist/voice-pipeline/HeuristicEndpointDetector.js +240 -0
- package/dist/voice-pipeline/HeuristicEndpointDetector.js.map +1 -0
- package/dist/voice-pipeline/SoftFadeBargeinHandler.d.ts +96 -0
- package/dist/voice-pipeline/SoftFadeBargeinHandler.d.ts.map +1 -0
- package/dist/voice-pipeline/SoftFadeBargeinHandler.js +69 -0
- package/dist/voice-pipeline/SoftFadeBargeinHandler.js.map +1 -0
- package/dist/voice-pipeline/VoicePipelineOrchestrator.d.ts +122 -0
- package/dist/voice-pipeline/VoicePipelineOrchestrator.d.ts.map +1 -0
- package/dist/voice-pipeline/VoicePipelineOrchestrator.js +317 -0
- package/dist/voice-pipeline/VoicePipelineOrchestrator.js.map +1 -0
- package/dist/voice-pipeline/WebSocketStreamTransport.d.ts +148 -0
- package/dist/voice-pipeline/WebSocketStreamTransport.d.ts.map +1 -0
- package/dist/voice-pipeline/WebSocketStreamTransport.js +207 -0
- package/dist/voice-pipeline/WebSocketStreamTransport.js.map +1 -0
- package/dist/voice-pipeline/index.d.ts +13 -0
- package/dist/voice-pipeline/index.d.ts.map +1 -0
- package/dist/voice-pipeline/index.js +13 -0
- package/dist/voice-pipeline/index.js.map +1 -0
- package/dist/voice-pipeline/types.d.ts +905 -0
- package/dist/voice-pipeline/types.d.ts.map +1 -0
- package/dist/voice-pipeline/types.js +23 -0
- package/dist/voice-pipeline/types.js.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import type { SpeechToTextProvider, TextToSpeechProvider, SpeechAudioInput, SpeechTranscriptionOptions, SpeechTranscriptionResult, SpeechSynthesisOptions, SpeechSynthesisResult, SpeechVoice } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Payload emitted on the `provider_fallback` event when a provider in the chain
|
|
5
|
+
* fails and the proxy advances to the next candidate.
|
|
6
|
+
*/
|
|
7
|
+
export interface ProviderFallbackEvent {
|
|
8
|
+
/** ID of the provider that failed. */
|
|
9
|
+
from: string;
|
|
10
|
+
/** ID of the provider that will be tried next. */
|
|
11
|
+
to: string;
|
|
12
|
+
/** Whether this is an STT or TTS chain. */
|
|
13
|
+
kind: 'stt' | 'tts';
|
|
14
|
+
/** The error thrown by the failing provider. */
|
|
15
|
+
error: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A {@link SpeechToTextProvider} that wraps an ordered chain of STT providers.
|
|
19
|
+
* Providers are tried left-to-right; the first successful result is returned.
|
|
20
|
+
* On each failure (except the last) a `provider_fallback` event is emitted on
|
|
21
|
+
* the supplied {@link EventEmitter} so callers can observe the fallback path.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const proxy = new FallbackSTTProxy([whisperProvider, deepgramProvider], emitter);
|
|
26
|
+
* const result = await proxy.transcribe(audio);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class FallbackSTTProxy implements SpeechToTextProvider {
|
|
30
|
+
private readonly chain;
|
|
31
|
+
private readonly emitter;
|
|
32
|
+
/** Derived from the first provider in the chain (or `'fallback-stt'` for empty chains). */
|
|
33
|
+
readonly id: string;
|
|
34
|
+
/** Human-readable name showing the full chain: `"Fallback STT (p1 → p2)"`. */
|
|
35
|
+
readonly displayName: string;
|
|
36
|
+
/** `true` only when the first provider in the chain supports streaming. */
|
|
37
|
+
readonly supportsStreaming: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* @param chain Ordered list of STT providers to try. Must contain at least one entry
|
|
40
|
+
* for `transcribe()` to succeed, though an empty chain is allowed
|
|
41
|
+
* (it will always throw).
|
|
42
|
+
* @param emitter EventEmitter on which `provider_fallback` events are published.
|
|
43
|
+
*/
|
|
44
|
+
constructor(chain: SpeechToTextProvider[], emitter: EventEmitter);
|
|
45
|
+
/**
|
|
46
|
+
* Attempt transcription using each provider in order.
|
|
47
|
+
*
|
|
48
|
+
* Emits a `provider_fallback` event (typed as {@link ProviderFallbackEvent})
|
|
49
|
+
* whenever a non-final provider throws. Re-throws the last provider's error
|
|
50
|
+
* when the entire chain is exhausted, and throws `Error('No providers in
|
|
51
|
+
* fallback chain')` when `chain` is empty.
|
|
52
|
+
*/
|
|
53
|
+
transcribe(audio: SpeechAudioInput, options?: SpeechTranscriptionOptions): Promise<SpeechTranscriptionResult>;
|
|
54
|
+
/** Delegates to the first provider in the chain, or returns `'fallback'` for an empty chain. */
|
|
55
|
+
getProviderName(): string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A {@link TextToSpeechProvider} that wraps an ordered chain of TTS providers.
|
|
59
|
+
* Providers are tried left-to-right; the first successful result is returned.
|
|
60
|
+
* On each failure (except the last) a `provider_fallback` event is emitted on
|
|
61
|
+
* the supplied {@link EventEmitter}.
|
|
62
|
+
*
|
|
63
|
+
* Voice listing is delegated to the first provider that exposes
|
|
64
|
+
* `listAvailableVoices()`. If none do, an empty array is returned.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const proxy = new FallbackTTSProxy([elevenlabsProvider, openaiTtsProvider], emitter);
|
|
69
|
+
* const audio = await proxy.synthesize('Hello world');
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare class FallbackTTSProxy implements TextToSpeechProvider {
|
|
73
|
+
private readonly chain;
|
|
74
|
+
private readonly emitter;
|
|
75
|
+
/** Derived from the first provider in the chain (or `'fallback-tts'` for empty chains). */
|
|
76
|
+
readonly id: string;
|
|
77
|
+
/** Human-readable name showing the full chain: `"Fallback TTS (p1 → p2)"`. */
|
|
78
|
+
readonly displayName: string;
|
|
79
|
+
/** `true` only when the first provider in the chain supports streaming. */
|
|
80
|
+
readonly supportsStreaming: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* @param chain Ordered list of TTS providers to try.
|
|
83
|
+
* @param emitter EventEmitter on which `provider_fallback` events are published.
|
|
84
|
+
*/
|
|
85
|
+
constructor(chain: TextToSpeechProvider[], emitter: EventEmitter);
|
|
86
|
+
/**
|
|
87
|
+
* Attempt synthesis using each provider in order.
|
|
88
|
+
*
|
|
89
|
+
* Emits a `provider_fallback` event (typed as {@link ProviderFallbackEvent})
|
|
90
|
+
* whenever a non-final provider throws. Re-throws the last provider's error
|
|
91
|
+
* when the entire chain is exhausted, and throws `Error('No providers in
|
|
92
|
+
* fallback chain')` when `chain` is empty.
|
|
93
|
+
*/
|
|
94
|
+
synthesize(text: string, options?: SpeechSynthesisOptions): Promise<SpeechSynthesisResult>;
|
|
95
|
+
/** Delegates to the first provider in the chain, or returns `'fallback'` for an empty chain. */
|
|
96
|
+
getProviderName(): string;
|
|
97
|
+
/**
|
|
98
|
+
* Returns voice list from the first provider in the chain that exposes
|
|
99
|
+
* `listAvailableVoices()`. Falls back to an empty array when no provider
|
|
100
|
+
* supports this method.
|
|
101
|
+
*/
|
|
102
|
+
listAvailableVoices(): Promise<SpeechVoice[]>;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=FallbackProxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FallbackProxy.d.ts","sourceRoot":"","sources":["../../src/speech/FallbackProxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,0BAA0B,EAC1B,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,2CAA2C;IAC3C,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,gDAAgD;IAChD,KAAK,EAAE,OAAO,CAAC;CAChB;AAMD;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAiB,YAAW,oBAAoB;IAiBzD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAjB1B,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,2EAA2E;IAC3E,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;gBAEgB,KAAK,EAAE,oBAAoB,EAAE,EAC7B,OAAO,EAAE,YAAY;IAOxC;;;;;;;OAOG;IACG,UAAU,CACd,KAAK,EAAE,gBAAgB,EACvB,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,yBAAyB,CAAC;IA2BrC,gGAAgG;IAChG,eAAe,IAAI,MAAM;CAG1B;AAMD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,gBAAiB,YAAW,oBAAoB;IAezD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAf1B,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,2EAA2E;IAC3E,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAEpC;;;OAGG;gBAEgB,KAAK,EAAE,oBAAoB,EAAE,EAC7B,OAAO,EAAE,YAAY;IAOxC;;;;;;;OAOG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC;IA2BjC,gGAAgG;IAChG,eAAe,IAAI,MAAM;IAIzB;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;CAQpD"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// FallbackSTTProxy
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
/**
|
|
5
|
+
* A {@link SpeechToTextProvider} that wraps an ordered chain of STT providers.
|
|
6
|
+
* Providers are tried left-to-right; the first successful result is returned.
|
|
7
|
+
* On each failure (except the last) a `provider_fallback` event is emitted on
|
|
8
|
+
* the supplied {@link EventEmitter} so callers can observe the fallback path.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const proxy = new FallbackSTTProxy([whisperProvider, deepgramProvider], emitter);
|
|
13
|
+
* const result = await proxy.transcribe(audio);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export class FallbackSTTProxy {
|
|
17
|
+
/**
|
|
18
|
+
* @param chain Ordered list of STT providers to try. Must contain at least one entry
|
|
19
|
+
* for `transcribe()` to succeed, though an empty chain is allowed
|
|
20
|
+
* (it will always throw).
|
|
21
|
+
* @param emitter EventEmitter on which `provider_fallback` events are published.
|
|
22
|
+
*/
|
|
23
|
+
constructor(chain, emitter) {
|
|
24
|
+
this.chain = chain;
|
|
25
|
+
this.emitter = emitter;
|
|
26
|
+
this.id = chain[0]?.id ?? 'fallback-stt';
|
|
27
|
+
this.displayName = `Fallback STT (${chain.map((p) => p.id).join(' → ')})`;
|
|
28
|
+
this.supportsStreaming = chain[0]?.supportsStreaming ?? false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Attempt transcription using each provider in order.
|
|
32
|
+
*
|
|
33
|
+
* Emits a `provider_fallback` event (typed as {@link ProviderFallbackEvent})
|
|
34
|
+
* whenever a non-final provider throws. Re-throws the last provider's error
|
|
35
|
+
* when the entire chain is exhausted, and throws `Error('No providers in
|
|
36
|
+
* fallback chain')` when `chain` is empty.
|
|
37
|
+
*/
|
|
38
|
+
async transcribe(audio, options) {
|
|
39
|
+
if (this.chain.length === 0) {
|
|
40
|
+
throw new Error('No providers in fallback chain');
|
|
41
|
+
}
|
|
42
|
+
for (let i = 0; i < this.chain.length; i++) {
|
|
43
|
+
try {
|
|
44
|
+
return await this.chain[i].transcribe(audio, options);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (i < this.chain.length - 1) {
|
|
48
|
+
const event = {
|
|
49
|
+
from: this.chain[i].id,
|
|
50
|
+
to: this.chain[i + 1].id,
|
|
51
|
+
kind: 'stt',
|
|
52
|
+
error,
|
|
53
|
+
};
|
|
54
|
+
this.emitter.emit('provider_fallback', event);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Unreachable — TypeScript requires an explicit throw after the loop.
|
|
62
|
+
throw new Error('No providers in fallback chain');
|
|
63
|
+
}
|
|
64
|
+
/** Delegates to the first provider in the chain, or returns `'fallback'` for an empty chain. */
|
|
65
|
+
getProviderName() {
|
|
66
|
+
return this.chain[0]?.getProviderName() ?? 'fallback';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// FallbackTTSProxy
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* A {@link TextToSpeechProvider} that wraps an ordered chain of TTS providers.
|
|
74
|
+
* Providers are tried left-to-right; the first successful result is returned.
|
|
75
|
+
* On each failure (except the last) a `provider_fallback` event is emitted on
|
|
76
|
+
* the supplied {@link EventEmitter}.
|
|
77
|
+
*
|
|
78
|
+
* Voice listing is delegated to the first provider that exposes
|
|
79
|
+
* `listAvailableVoices()`. If none do, an empty array is returned.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const proxy = new FallbackTTSProxy([elevenlabsProvider, openaiTtsProvider], emitter);
|
|
84
|
+
* const audio = await proxy.synthesize('Hello world');
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export class FallbackTTSProxy {
|
|
88
|
+
/**
|
|
89
|
+
* @param chain Ordered list of TTS providers to try.
|
|
90
|
+
* @param emitter EventEmitter on which `provider_fallback` events are published.
|
|
91
|
+
*/
|
|
92
|
+
constructor(chain, emitter) {
|
|
93
|
+
this.chain = chain;
|
|
94
|
+
this.emitter = emitter;
|
|
95
|
+
this.id = chain[0]?.id ?? 'fallback-tts';
|
|
96
|
+
this.displayName = `Fallback TTS (${chain.map((p) => p.id).join(' → ')})`;
|
|
97
|
+
this.supportsStreaming = chain[0]?.supportsStreaming ?? false;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Attempt synthesis using each provider in order.
|
|
101
|
+
*
|
|
102
|
+
* Emits a `provider_fallback` event (typed as {@link ProviderFallbackEvent})
|
|
103
|
+
* whenever a non-final provider throws. Re-throws the last provider's error
|
|
104
|
+
* when the entire chain is exhausted, and throws `Error('No providers in
|
|
105
|
+
* fallback chain')` when `chain` is empty.
|
|
106
|
+
*/
|
|
107
|
+
async synthesize(text, options) {
|
|
108
|
+
if (this.chain.length === 0) {
|
|
109
|
+
throw new Error('No providers in fallback chain');
|
|
110
|
+
}
|
|
111
|
+
for (let i = 0; i < this.chain.length; i++) {
|
|
112
|
+
try {
|
|
113
|
+
return await this.chain[i].synthesize(text, options);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (i < this.chain.length - 1) {
|
|
117
|
+
const event = {
|
|
118
|
+
from: this.chain[i].id,
|
|
119
|
+
to: this.chain[i + 1].id,
|
|
120
|
+
kind: 'tts',
|
|
121
|
+
error,
|
|
122
|
+
};
|
|
123
|
+
this.emitter.emit('provider_fallback', event);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Unreachable — TypeScript requires an explicit throw after the loop.
|
|
131
|
+
throw new Error('No providers in fallback chain');
|
|
132
|
+
}
|
|
133
|
+
/** Delegates to the first provider in the chain, or returns `'fallback'` for an empty chain. */
|
|
134
|
+
getProviderName() {
|
|
135
|
+
return this.chain[0]?.getProviderName() ?? 'fallback';
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Returns voice list from the first provider in the chain that exposes
|
|
139
|
+
* `listAvailableVoices()`. Falls back to an empty array when no provider
|
|
140
|
+
* supports this method.
|
|
141
|
+
*/
|
|
142
|
+
async listAvailableVoices() {
|
|
143
|
+
for (const provider of this.chain) {
|
|
144
|
+
if (typeof provider.listAvailableVoices === 'function') {
|
|
145
|
+
return provider.listAvailableVoices();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=FallbackProxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FallbackProxy.js","sourceRoot":"","sources":["../../src/speech/FallbackProxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import type { SpeechProviderKind, SpeechToTextProvider, TextToSpeechProvider, SpeechVadProvider, WakeWordProvider, SpeechResolverConfig, ProviderRequirements, ProviderRegistration } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Central resolver for speech providers (STT, TTS, VAD, wake-word).
|
|
5
|
+
*
|
|
6
|
+
* Providers are registered with a kind, priority, and catalog metadata.
|
|
7
|
+
* Resolution filters by `isConfigured`, applies {@link ProviderRequirements},
|
|
8
|
+
* and optionally wraps multiple candidates in a {@link FallbackSTTProxy} or
|
|
9
|
+
* {@link FallbackTTSProxy} when fallback mode is enabled in the config.
|
|
10
|
+
*
|
|
11
|
+
* Emits:
|
|
12
|
+
* - `provider_registered` — when a new provider is registered via {@link register}.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SpeechProviderResolver extends EventEmitter {
|
|
15
|
+
private readonly config?;
|
|
16
|
+
private readonly env;
|
|
17
|
+
/** All registered providers keyed by id. */
|
|
18
|
+
private registrations;
|
|
19
|
+
/**
|
|
20
|
+
* @param config Optional resolver configuration (preferred providers, fallback mode).
|
|
21
|
+
* @param env Environment variable map used to check provider availability.
|
|
22
|
+
*/
|
|
23
|
+
constructor(config?: SpeechResolverConfig | undefined, env?: Record<string, string | undefined>);
|
|
24
|
+
/**
|
|
25
|
+
* Register a provider. Overwrites any existing registration with the same id.
|
|
26
|
+
* Emits a `provider_registered` event with `{ id, kind, source }`.
|
|
27
|
+
*/
|
|
28
|
+
register(reg: ProviderRegistration): void;
|
|
29
|
+
/**
|
|
30
|
+
* List all registrations for a given kind, sorted ascending by priority
|
|
31
|
+
* (lower number = higher priority).
|
|
32
|
+
*/
|
|
33
|
+
listProviders(kind: SpeechProviderKind): ProviderRegistration[];
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the best STT provider matching optional {@link ProviderRequirements}.
|
|
36
|
+
*
|
|
37
|
+
* When `config.stt.fallback` is true and multiple candidates exist, wraps them
|
|
38
|
+
* in a {@link FallbackSTTProxy}. Otherwise returns the single best match.
|
|
39
|
+
*
|
|
40
|
+
* @throws When no configured STT provider matches requirements.
|
|
41
|
+
*/
|
|
42
|
+
resolveSTT(requirements?: ProviderRequirements): SpeechToTextProvider;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the best TTS provider matching optional {@link ProviderRequirements}.
|
|
45
|
+
*
|
|
46
|
+
* When `config.tts.fallback` is true and multiple candidates exist, wraps them
|
|
47
|
+
* in a {@link FallbackTTSProxy}. Otherwise returns the single best match.
|
|
48
|
+
*
|
|
49
|
+
* @throws When no configured TTS provider matches requirements.
|
|
50
|
+
*/
|
|
51
|
+
resolveTTS(requirements?: ProviderRequirements): TextToSpeechProvider;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve the highest-priority configured VAD provider.
|
|
54
|
+
*
|
|
55
|
+
* @throws When no VAD provider is registered and configured.
|
|
56
|
+
*/
|
|
57
|
+
resolveVAD(): SpeechVadProvider;
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the highest-priority configured wake-word provider, or `null`
|
|
60
|
+
* when none is registered.
|
|
61
|
+
*/
|
|
62
|
+
resolveWakeWord(): WakeWordProvider | null;
|
|
63
|
+
/**
|
|
64
|
+
* Register core providers from the static catalog and optionally discover
|
|
65
|
+
* extension providers from an ExtensionManager-like object. Also applies
|
|
66
|
+
* user-configured preferred priorities afterwards.
|
|
67
|
+
*
|
|
68
|
+
* @param extensionManager Optional object exposing `getDescriptorsByKind(kind)`.
|
|
69
|
+
*/
|
|
70
|
+
refresh(extensionManager?: any): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Core resolution algorithm shared by {@link resolveSTT} and {@link resolveTTS}.
|
|
73
|
+
*
|
|
74
|
+
* When `requirements.preferredIds` is provided, returns matches in that order.
|
|
75
|
+
* Otherwise returns all configured providers matching requirements, sorted by
|
|
76
|
+
* priority (ascending).
|
|
77
|
+
*/
|
|
78
|
+
private resolveByKind;
|
|
79
|
+
/**
|
|
80
|
+
* Check whether a registration satisfies the given requirements
|
|
81
|
+
* (streaming, local, features).
|
|
82
|
+
*/
|
|
83
|
+
private matchesRequirements;
|
|
84
|
+
/**
|
|
85
|
+
* Register providers from the static core list. Each provider is marked
|
|
86
|
+
* `isConfigured` based on whether the required environment variables are set.
|
|
87
|
+
* Providers with `available === false` in the catalog are skipped.
|
|
88
|
+
*/
|
|
89
|
+
private registerCoreProviders;
|
|
90
|
+
/**
|
|
91
|
+
* Discover speech providers exposed by an ExtensionManager via
|
|
92
|
+
* `getDescriptorsByKind()`. Extension providers default to priority 200
|
|
93
|
+
* (lower than core's 100) unless the user overrides via preferred config.
|
|
94
|
+
*/
|
|
95
|
+
private discoverExtensionProviders;
|
|
96
|
+
/**
|
|
97
|
+
* Boost priority for providers listed in `config.stt.preferred` /
|
|
98
|
+
* `config.tts.preferred`. Earlier entries get lower (= higher priority)
|
|
99
|
+
* numbers starting at 50.
|
|
100
|
+
*/
|
|
101
|
+
private applyPreferredPriorities;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=SpeechProviderResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpeechProviderResolver.d.ts","sourceRoot":"","sources":["../../src/speech/SpeechProviderResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAEhB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAIpB;;;;;;;;;;GAUG;AACH,qBAAa,sBAAuB,SAAQ,YAAY;IASpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IATtB,4CAA4C;IAC5C,OAAO,CAAC,aAAa,CAA2C;IAEhE;;;OAGG;gBAEgB,MAAM,CAAC,EAAE,oBAAoB,YAAA,EAC7B,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe;IAKxE;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,oBAAoB,GAAG,IAAI;IAKzC;;;OAGG;IACH,aAAa,CAAC,IAAI,EAAE,kBAAkB,GAAG,oBAAoB,EAAE;IAM/D;;;;;;;OAOG;IACH,UAAU,CAAC,YAAY,CAAC,EAAE,oBAAoB,GAAG,oBAAoB;IAerE;;;;;;;OAOG;IACH,UAAU,CAAC,YAAY,CAAC,EAAE,oBAAoB,GAAG,oBAAoB;IAerE;;;;OAIG;IACH,UAAU,IAAI,iBAAiB;IAQ/B;;;OAGG;IACH,eAAe,IAAI,gBAAgB,GAAG,IAAI;IAS1C;;;;;;OAMG;IACG,OAAO,CAAC,gBAAgB,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAcpD;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAoBrB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAgC7B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAuClC;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;CAcjC"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { FallbackSTTProxy, FallbackTTSProxy } from './FallbackProxy.js';
|
|
3
|
+
import { findSpeechProviderCatalogEntry } from './providerCatalog.js';
|
|
4
|
+
/**
|
|
5
|
+
* Central resolver for speech providers (STT, TTS, VAD, wake-word).
|
|
6
|
+
*
|
|
7
|
+
* Providers are registered with a kind, priority, and catalog metadata.
|
|
8
|
+
* Resolution filters by `isConfigured`, applies {@link ProviderRequirements},
|
|
9
|
+
* and optionally wraps multiple candidates in a {@link FallbackSTTProxy} or
|
|
10
|
+
* {@link FallbackTTSProxy} when fallback mode is enabled in the config.
|
|
11
|
+
*
|
|
12
|
+
* Emits:
|
|
13
|
+
* - `provider_registered` — when a new provider is registered via {@link register}.
|
|
14
|
+
*/
|
|
15
|
+
export class SpeechProviderResolver extends EventEmitter {
|
|
16
|
+
/**
|
|
17
|
+
* @param config Optional resolver configuration (preferred providers, fallback mode).
|
|
18
|
+
* @param env Environment variable map used to check provider availability.
|
|
19
|
+
*/
|
|
20
|
+
constructor(config, env = process.env) {
|
|
21
|
+
super();
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.env = env;
|
|
24
|
+
/** All registered providers keyed by id. */
|
|
25
|
+
this.registrations = new Map();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Register a provider. Overwrites any existing registration with the same id.
|
|
29
|
+
* Emits a `provider_registered` event with `{ id, kind, source }`.
|
|
30
|
+
*/
|
|
31
|
+
register(reg) {
|
|
32
|
+
this.registrations.set(reg.id, reg);
|
|
33
|
+
this.emit('provider_registered', { id: reg.id, kind: reg.kind, source: reg.source });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* List all registrations for a given kind, sorted ascending by priority
|
|
37
|
+
* (lower number = higher priority).
|
|
38
|
+
*/
|
|
39
|
+
listProviders(kind) {
|
|
40
|
+
return [...this.registrations.values()]
|
|
41
|
+
.filter((r) => r.kind === kind)
|
|
42
|
+
.sort((a, b) => a.priority - b.priority);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the best STT provider matching optional {@link ProviderRequirements}.
|
|
46
|
+
*
|
|
47
|
+
* When `config.stt.fallback` is true and multiple candidates exist, wraps them
|
|
48
|
+
* in a {@link FallbackSTTProxy}. Otherwise returns the single best match.
|
|
49
|
+
*
|
|
50
|
+
* @throws When no configured STT provider matches requirements.
|
|
51
|
+
*/
|
|
52
|
+
resolveSTT(requirements) {
|
|
53
|
+
const candidates = this.resolveByKind('stt', requirements);
|
|
54
|
+
if (candidates.length === 0) {
|
|
55
|
+
throw new Error('No configured STT provider matches requirements');
|
|
56
|
+
}
|
|
57
|
+
if (this.config?.stt?.fallback && candidates.length > 1) {
|
|
58
|
+
return new FallbackSTTProxy(candidates.map((r) => r.provider), this);
|
|
59
|
+
}
|
|
60
|
+
return candidates[0].provider;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the best TTS provider matching optional {@link ProviderRequirements}.
|
|
64
|
+
*
|
|
65
|
+
* When `config.tts.fallback` is true and multiple candidates exist, wraps them
|
|
66
|
+
* in a {@link FallbackTTSProxy}. Otherwise returns the single best match.
|
|
67
|
+
*
|
|
68
|
+
* @throws When no configured TTS provider matches requirements.
|
|
69
|
+
*/
|
|
70
|
+
resolveTTS(requirements) {
|
|
71
|
+
const candidates = this.resolveByKind('tts', requirements);
|
|
72
|
+
if (candidates.length === 0) {
|
|
73
|
+
throw new Error('No configured TTS provider matches requirements');
|
|
74
|
+
}
|
|
75
|
+
if (this.config?.tts?.fallback && candidates.length > 1) {
|
|
76
|
+
return new FallbackTTSProxy(candidates.map((r) => r.provider), this);
|
|
77
|
+
}
|
|
78
|
+
return candidates[0].provider;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Resolve the highest-priority configured VAD provider.
|
|
82
|
+
*
|
|
83
|
+
* @throws When no VAD provider is registered and configured.
|
|
84
|
+
*/
|
|
85
|
+
resolveVAD() {
|
|
86
|
+
const vads = this.listProviders('vad').filter((r) => r.isConfigured);
|
|
87
|
+
if (vads.length === 0) {
|
|
88
|
+
throw new Error('No VAD provider registered');
|
|
89
|
+
}
|
|
90
|
+
return vads[0].provider;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the highest-priority configured wake-word provider, or `null`
|
|
94
|
+
* when none is registered.
|
|
95
|
+
*/
|
|
96
|
+
resolveWakeWord() {
|
|
97
|
+
const wakeWords = this.listProviders('wake-word').filter((r) => r.isConfigured);
|
|
98
|
+
return wakeWords.length > 0 ? wakeWords[0].provider : null;
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Bulk registration helpers
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
/**
|
|
104
|
+
* Register core providers from the static catalog and optionally discover
|
|
105
|
+
* extension providers from an ExtensionManager-like object. Also applies
|
|
106
|
+
* user-configured preferred priorities afterwards.
|
|
107
|
+
*
|
|
108
|
+
* @param extensionManager Optional object exposing `getDescriptorsByKind(kind)`.
|
|
109
|
+
*/
|
|
110
|
+
async refresh(extensionManager) {
|
|
111
|
+
this.registerCoreProviders();
|
|
112
|
+
if (extensionManager) {
|
|
113
|
+
this.discoverExtensionProviders(extensionManager);
|
|
114
|
+
}
|
|
115
|
+
this.applyPreferredPriorities();
|
|
116
|
+
}
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
// Private helpers
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
/**
|
|
121
|
+
* Core resolution algorithm shared by {@link resolveSTT} and {@link resolveTTS}.
|
|
122
|
+
*
|
|
123
|
+
* When `requirements.preferredIds` is provided, returns matches in that order.
|
|
124
|
+
* Otherwise returns all configured providers matching requirements, sorted by
|
|
125
|
+
* priority (ascending).
|
|
126
|
+
*/
|
|
127
|
+
resolveByKind(kind, requirements) {
|
|
128
|
+
if (requirements?.preferredIds?.length) {
|
|
129
|
+
const results = [];
|
|
130
|
+
for (const id of requirements.preferredIds) {
|
|
131
|
+
const reg = this.registrations.get(id);
|
|
132
|
+
if (reg && reg.kind === kind && reg.isConfigured && this.matchesRequirements(reg, requirements)) {
|
|
133
|
+
results.push(reg);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return results;
|
|
137
|
+
}
|
|
138
|
+
return this.listProviders(kind)
|
|
139
|
+
.filter((r) => r.isConfigured)
|
|
140
|
+
.filter((r) => this.matchesRequirements(r, requirements));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Check whether a registration satisfies the given requirements
|
|
144
|
+
* (streaming, local, features).
|
|
145
|
+
*/
|
|
146
|
+
matchesRequirements(reg, req) {
|
|
147
|
+
if (!req)
|
|
148
|
+
return true;
|
|
149
|
+
if (req.streaming !== undefined && reg.catalogEntry.streaming !== req.streaming)
|
|
150
|
+
return false;
|
|
151
|
+
if (req.local !== undefined && reg.catalogEntry.local !== req.local)
|
|
152
|
+
return false;
|
|
153
|
+
if (req.features?.length) {
|
|
154
|
+
const providerFeatures = reg.catalogEntry.features ?? [];
|
|
155
|
+
if (!req.features.every((f) => providerFeatures.includes(f)))
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Register providers from the static core list. Each provider is marked
|
|
162
|
+
* `isConfigured` based on whether the required environment variables are set.
|
|
163
|
+
* Providers with `available === false` in the catalog are skipped.
|
|
164
|
+
*/
|
|
165
|
+
registerCoreProviders() {
|
|
166
|
+
const coreProviders = [
|
|
167
|
+
{ id: 'openai-whisper', kind: 'stt', envVars: ['OPENAI_API_KEY'] },
|
|
168
|
+
{ id: 'deepgram-batch', kind: 'stt', envVars: ['DEEPGRAM_API_KEY'] },
|
|
169
|
+
{ id: 'assemblyai', kind: 'stt', envVars: ['ASSEMBLYAI_API_KEY'] },
|
|
170
|
+
{ id: 'azure-speech-stt', kind: 'stt', envVars: ['AZURE_SPEECH_KEY', 'AZURE_SPEECH_REGION'] },
|
|
171
|
+
{ id: 'openai-tts', kind: 'tts', envVars: ['OPENAI_API_KEY'] },
|
|
172
|
+
{ id: 'elevenlabs', kind: 'tts', envVars: ['ELEVENLABS_API_KEY'] },
|
|
173
|
+
{ id: 'azure-speech-tts', kind: 'tts', envVars: ['AZURE_SPEECH_KEY', 'AZURE_SPEECH_REGION'] },
|
|
174
|
+
{ id: 'agentos-adaptive-vad', kind: 'vad', envVars: [] },
|
|
175
|
+
];
|
|
176
|
+
for (const def of coreProviders) {
|
|
177
|
+
const catalogEntry = findSpeechProviderCatalogEntry(def.id);
|
|
178
|
+
if (!catalogEntry)
|
|
179
|
+
continue;
|
|
180
|
+
if (catalogEntry.available === false)
|
|
181
|
+
continue;
|
|
182
|
+
const isConfigured = def.envVars.length === 0 || def.envVars.every((v) => Boolean(this.env[v]));
|
|
183
|
+
this.register({
|
|
184
|
+
id: def.id,
|
|
185
|
+
kind: def.kind,
|
|
186
|
+
provider: null, // Lazy — actual provider instance created on first use.
|
|
187
|
+
catalogEntry,
|
|
188
|
+
isConfigured,
|
|
189
|
+
priority: 100,
|
|
190
|
+
source: 'core',
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Discover speech providers exposed by an ExtensionManager via
|
|
196
|
+
* `getDescriptorsByKind()`. Extension providers default to priority 200
|
|
197
|
+
* (lower than core's 100) unless the user overrides via preferred config.
|
|
198
|
+
*/
|
|
199
|
+
discoverExtensionProviders(extensionManager) {
|
|
200
|
+
/** Maps extension descriptor kinds to {@link SpeechProviderKind}. */
|
|
201
|
+
const kindMap = {
|
|
202
|
+
'stt-provider': 'stt',
|
|
203
|
+
'tts-provider': 'tts',
|
|
204
|
+
'vad-provider': 'vad',
|
|
205
|
+
'wake-word-provider': 'wake-word',
|
|
206
|
+
};
|
|
207
|
+
for (const descriptorKind of Object.keys(kindMap)) {
|
|
208
|
+
const descriptors = extensionManager.getDescriptorsByKind?.(descriptorKind) ?? [];
|
|
209
|
+
for (const desc of descriptors) {
|
|
210
|
+
const catalogEntry = findSpeechProviderCatalogEntry(desc.id);
|
|
211
|
+
const isConfigured = catalogEntry
|
|
212
|
+
? catalogEntry.envVars.length === 0 ||
|
|
213
|
+
catalogEntry.envVars.every((v) => Boolean(this.env[v]))
|
|
214
|
+
: true;
|
|
215
|
+
this.register({
|
|
216
|
+
id: desc.id,
|
|
217
|
+
kind: kindMap[descriptorKind] ?? 'stt',
|
|
218
|
+
provider: desc.payload,
|
|
219
|
+
catalogEntry: catalogEntry ?? {
|
|
220
|
+
id: desc.id,
|
|
221
|
+
kind: kindMap[descriptorKind] ?? 'stt',
|
|
222
|
+
label: desc.id,
|
|
223
|
+
envVars: [],
|
|
224
|
+
local: false,
|
|
225
|
+
description: '',
|
|
226
|
+
},
|
|
227
|
+
isConfigured,
|
|
228
|
+
priority: 200,
|
|
229
|
+
source: 'extension',
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Boost priority for providers listed in `config.stt.preferred` /
|
|
236
|
+
* `config.tts.preferred`. Earlier entries get lower (= higher priority)
|
|
237
|
+
* numbers starting at 50.
|
|
238
|
+
*/
|
|
239
|
+
applyPreferredPriorities() {
|
|
240
|
+
if (this.config?.stt?.preferred) {
|
|
241
|
+
for (let i = 0; i < this.config.stt.preferred.length; i++) {
|
|
242
|
+
const reg = this.registrations.get(this.config.stt.preferred[i]);
|
|
243
|
+
if (reg)
|
|
244
|
+
reg.priority = 50 + i;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (this.config?.tts?.preferred) {
|
|
248
|
+
for (let i = 0; i < this.config.tts.preferred.length; i++) {
|
|
249
|
+
const reg = this.registrations.get(this.config.tts.preferred[i]);
|
|
250
|
+
if (reg)
|
|
251
|
+
reg.priority = 50 + i;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=SpeechProviderResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpeechProviderResolver.js","sourceRoot":"","sources":["../../src/speech/SpeechProviderResolver.ts"],"names":[],"mappings":"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"}
|