refactor(server): centralize speech provider resolver typing

This commit is contained in:
Mohamed Boudra
2026-02-14 00:44:08 +07:00
parent cfd061a86d
commit c5d7fa52b4
6 changed files with 28 additions and 26 deletions
@@ -1,5 +1,6 @@
import type pino from "pino";
import type { SpeechToTextProvider, TranscriptionResult } from "../speech/speech-provider.js";
import { toResolver, type Resolvable } from "../speech/provider-resolver.js";
import { maybePersistDebugAudio } from "./stt-debug.js";
import { parsePcm16MonoWav, parsePcmRateFromFormat } from "../speech/audio.js";
import { Pcm16MonoResampler } from "./pcm16-resampler.js";
@@ -44,11 +45,11 @@ export class STTManager {
constructor(
sessionId: string,
logger: pino.Logger,
stt: SpeechToTextProvider | null | (() => SpeechToTextProvider | null)
stt: Resolvable<SpeechToTextProvider | null>
) {
this.sessionId = sessionId;
this.logger = logger.child({ module: "agent", component: "stt-manager", sessionId });
this.resolveStt = typeof stt === "function" ? stt : () => stt;
this.resolveStt = toResolver(stt);
}
/**
@@ -1,6 +1,7 @@
import type pino from "pino";
import { v4 as uuidv4 } from "uuid";
import type { TextToSpeechProvider } from "../speech/speech-provider.js";
import { toResolver, type Resolvable } from "../speech/provider-resolver.js";
import type { SessionOutboundMessage } from "../messages.js";
interface PendingPlayback {
@@ -100,10 +101,10 @@ export class TTSManager {
constructor(
sessionId: string,
logger: pino.Logger,
tts: TextToSpeechProvider | null | (() => TextToSpeechProvider | null)
tts: Resolvable<TextToSpeechProvider | null>
) {
this.logger = logger.child({ module: "agent", component: "tts-manager", sessionId });
this.resolveTts = typeof tts === "function" ? tts : () => tts;
this.resolveTts = toResolver(tts);
}
/**
@@ -11,6 +11,7 @@ import type {
SpeechToTextProvider,
StreamingTranscriptionSession,
} from "../speech/speech-provider.js";
import { toResolver, type Resolvable } from "../speech/provider-resolver.js";
import { parsePcmRateFromFormat, pcm16lePeakAbs } from "../speech/audio.js";
const PCM_CHANNELS = 1;
@@ -126,19 +127,14 @@ export class DictationStreamManager {
logger: pino.Logger;
emit: (msg: DictationStreamOutboundMessage) => void;
sessionId: string;
stt: SpeechToTextProvider | null | (() => SpeechToTextProvider | null);
stt: Resolvable<SpeechToTextProvider | null>;
finalTimeoutMs?: number;
autoCommitSeconds?: number;
}) {
this.logger = params.logger.child({ component: "dictation-stream-manager" });
this.emit = params.emit;
this.sessionId = params.sessionId;
if (typeof params.stt === "function") {
this.resolveStt = params.stt;
} else {
const sttProvider = params.stt;
this.resolveStt = () => sttProvider;
}
this.resolveStt = toResolver(params.stt);
this.finalTimeoutMs = params.finalTimeoutMs ?? DEFAULT_DICTATION_FINAL_TIMEOUT_MS;
this.autoCommitSeconds =
params.autoCommitSeconds ??
+4 -3
View File
@@ -130,6 +130,7 @@ import {
listLocalSpeechModels,
type LocalSpeechModelId,
} from "./speech/providers/local/models.js";
import type { Resolvable } from "./speech/provider-resolver.js";
import type { SpeechReadinessSnapshot } from "./speech/speech-runtime.js";
import type pino from "pino";
@@ -324,8 +325,8 @@ export type SessionOptions = {
agentManager: AgentManager;
agentStorage: AgentStorage;
createAgentMcpTransport: AgentMcpTransportFactory;
stt: SpeechToTextProvider | null | (() => SpeechToTextProvider | null);
tts: TextToSpeechProvider | null | (() => TextToSpeechProvider | null);
stt: Resolvable<SpeechToTextProvider | null>;
tts: Resolvable<TextToSpeechProvider | null>;
terminalManager: TerminalManager | null;
voice?: {
voiceAgentMcpStdio?: VoiceMcpStdioConfig | null;
@@ -340,7 +341,7 @@ export type SessionOptions = {
};
dictation?: {
finalTimeoutMs?: number;
stt?: SpeechToTextProvider | null | (() => SpeechToTextProvider | null);
stt?: Resolvable<SpeechToTextProvider | null>;
localModels?: {
modelsDir: string;
defaultModelIds: LocalSpeechModelId[];
@@ -0,0 +1,8 @@
export type Resolvable<T> = T | (() => T);
export function toResolver<T>(value: Resolvable<T>): () => T {
if (typeof value === "function") {
return value as () => T;
}
return () => value;
}
+7 -12
View File
@@ -26,6 +26,7 @@ import type { AgentProviderRuntimeSettingsMap } from "./agent/provider-launch-co
import { PushTokenStore } from "./push/token-store.js";
import { PushService } from "./push/push-service.js";
import type { SpeechToTextProvider, TextToSpeechProvider } from "./speech/speech-provider.js";
import type { Resolvable } from "./speech/provider-resolver.js";
import type { SpeechReadinessSnapshot } from "./speech/speech-runtime.js";
import type { LocalSpeechModelId } from "./speech/providers/local/models.js";
import type {
@@ -94,18 +95,12 @@ export class VoiceAssistantWebSocketServer {
private readonly pushTokenStore: PushTokenStore;
private readonly pushService: PushService;
private readonly createAgentMcpTransport: AgentMcpTransportFactory;
private readonly stt:
| SpeechToTextProvider
| null
| (() => SpeechToTextProvider | null);
private readonly tts:
| TextToSpeechProvider
| null
| (() => TextToSpeechProvider | null);
private readonly stt: Resolvable<SpeechToTextProvider | null>;
private readonly tts: Resolvable<TextToSpeechProvider | null>;
private readonly terminalManager: TerminalManager | null;
private readonly dictation: {
finalTimeoutMs?: number;
stt?: SpeechToTextProvider | null | (() => SpeechToTextProvider | null);
stt?: Resolvable<SpeechToTextProvider | null>;
localModels?: {
modelsDir: string;
defaultModelIds: LocalSpeechModelId[];
@@ -135,8 +130,8 @@ export class VoiceAssistantWebSocketServer {
createAgentMcpTransport: AgentMcpTransportFactory,
wsConfig: WebSocketServerConfig,
speech?: {
stt: SpeechToTextProvider | null | (() => SpeechToTextProvider | null);
tts: TextToSpeechProvider | null | (() => TextToSpeechProvider | null);
stt: Resolvable<SpeechToTextProvider | null>;
tts: Resolvable<TextToSpeechProvider | null>;
},
terminalManager?: TerminalManager | null,
voice?: {
@@ -146,7 +141,7 @@ export class VoiceAssistantWebSocketServer {
},
dictation?: {
finalTimeoutMs?: number;
stt?: SpeechToTextProvider | null | (() => SpeechToTextProvider | null);
stt?: Resolvable<SpeechToTextProvider | null>;
localModels?: {
modelsDir: string;
defaultModelIds: LocalSpeechModelId[];