Skip to content

Commit 8e59b55

Browse files
authored
feat: adds support for speak fallback (#414)
* feat: adds support for speak fallback provider * feat: simplifies speak provider approach
1 parent c94bd34 commit 8e59b55

2 files changed

Lines changed: 90 additions & 25 deletions

File tree

src/lib/types/AgentLiveSchema.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
type Provider = { type: string } & Record<string, unknown>;
22

3+
type SpeakProvider = {
4+
provider: Provider;
5+
endpoint?: {
6+
url: string;
7+
headers?: Record<string, string>;
8+
};
9+
};
10+
311
/**
4-
* @see https://developers.deepgram.com/reference/voicebot-api-phase-preview#settingsconfiguration
12+
* @see https://developers.deepgram.com/docs/configure-voice-agent
513
*/
614
interface AgentLiveSchema extends Record<string, unknown> {
715
/**
@@ -42,15 +50,9 @@ interface AgentLiveSchema extends Record<string, unknown> {
4250
listen?: {
4351
provider: Provider;
4452
};
45-
speak?: {
46-
provider: Provider;
47-
endpoint?: {
48-
url: string;
49-
headers?: Record<string, string>;
50-
};
51-
};
53+
speak?: SpeakProvider | SpeakProvider[];
5254
/**
53-
* @see https://developers.deepgram.com/reference/voicebot-api-phase-preview#supported-llm-providers-and-models
55+
* @see https://developers.deepgram.com/docs/voice-agent-tts-models
5456
*/
5557
think?: {
5658
provider: Provider;
@@ -81,4 +83,4 @@ interface AgentLiveSchema extends Record<string, unknown> {
8183
};
8284
}
8385

84-
export type { AgentLiveSchema };
86+
export type { AgentLiveSchema, SpeakProvider };

tests/unit/live-client-message-handling.test.ts

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -537,32 +537,95 @@ describe("Unit Tests - Live Client Message Handling", () => {
537537
expect(mockConnection.send).toHaveBeenCalledWith(JSON.stringify({ type: "KeepAlive" }));
538538
});
539539

540-
it("should send injectUserMessage correctly", () => {
541-
const content = "Hello! Can you hear me?";
542-
client.injectUserMessage(content);
540+
describe("speak provider configuration", () => {
541+
it("should accept single provider", () => {
542+
const config = {
543+
audio: { input: { encoding: "linear16", sample_rate: 16000 } },
544+
agent: {
545+
speak: {
546+
provider: { type: "deepgram", model: "aura-2-zeus-en" },
547+
},
548+
},
549+
};
543550

544-
expect(mockConnection.send).toHaveBeenCalledWith(
545-
JSON.stringify({ type: "InjectUserMessage", content })
546-
);
551+
client.configure(config);
552+
expect(mockConnection.send).toHaveBeenCalledWith(
553+
JSON.stringify({ type: "Settings", ...config })
554+
);
555+
});
556+
557+
it("should accept array of providers", () => {
558+
const config = {
559+
audio: { input: { encoding: "linear16", sample_rate: 16000 } },
560+
agent: {
561+
speak: [
562+
{ provider: { type: "deepgram", model: "aura-2-zeus-en" } },
563+
{
564+
provider: { type: "openai", model: "tts-1", voice: "shimmer" },
565+
endpoint: { url: "https://api.openai.com/v1/audio/speech", headers: { auth: "key" } }
566+
},
567+
],
568+
},
569+
};
570+
571+
client.configure(config);
572+
expect(mockConnection.send).toHaveBeenCalledWith(
573+
JSON.stringify({ type: "Settings", ...config })
574+
);
575+
});
547576
});
548577

549-
it("should send injectUserMessage with different content types", () => {
550-
const testCases = [
551-
"What's the weather like today?",
552-
"Simple greeting",
553-
"Multi-line\nmessage content",
554-
"", // Edge case: empty string
555-
];
578+
describe("updateSpeak method", () => {
579+
it("should update with single provider", () => {
580+
const provider = { provider: { type: "deepgram", model: "aura-2-zeus-en" } };
581+
582+
client.updateSpeak(provider);
583+
expect(mockConnection.send).toHaveBeenCalledWith(
584+
JSON.stringify({ type: "UpdateSpeak", speak: provider })
585+
);
586+
});
556587

557-
testCases.forEach((content) => {
558-
jest.clearAllMocks(); // Reset mock between test cases
588+
it("should update with array of providers", () => {
589+
const providers = [
590+
{ provider: { type: "deepgram", model: "aura-2-zeus-en" } },
591+
{ provider: { type: "openai", model: "tts-1", voice: "shimmer" } },
592+
];
559593

594+
client.updateSpeak(providers);
595+
expect(mockConnection.send).toHaveBeenCalledWith(
596+
JSON.stringify({ type: "UpdateSpeak", speak: providers })
597+
);
598+
});
599+
});
600+
601+
describe("injectUserMessage method", () => {
602+
it("should send injectUserMessage correctly", () => {
603+
const content = "Hello! Can you hear me?";
560604
client.injectUserMessage(content);
561605

562606
expect(mockConnection.send).toHaveBeenCalledWith(
563607
JSON.stringify({ type: "InjectUserMessage", content })
564608
);
565609
});
610+
611+
it("should send injectUserMessage with different content types", () => {
612+
const testCases = [
613+
"What's the weather like today?",
614+
"Simple greeting",
615+
"Multi-line\nmessage content",
616+
"", // Edge case: empty string
617+
];
618+
619+
testCases.forEach((content) => {
620+
jest.clearAllMocks(); // Reset mock between test cases
621+
622+
client.injectUserMessage(content);
623+
624+
expect(mockConnection.send).toHaveBeenCalledWith(
625+
JSON.stringify({ type: "InjectUserMessage", content })
626+
);
627+
});
628+
});
566629
});
567630
});
568631
});

0 commit comments

Comments
 (0)