fix: require talk resolved payload

This commit is contained in:
Peter Steinberger
2026-03-08 16:25:32 +00:00
parent 404b1527e6
commit 2ed644f5d3
3 changed files with 48 additions and 18 deletions

View File

@@ -99,4 +99,21 @@ describe("validateTalkConfigResult", () => {
}),
).toBe(true);
});
it("rejects normalized talk payloads without talk.resolved", () => {
expect(
validateTalkConfigResult({
config: {
talk: {
provider: "elevenlabs",
providers: {
elevenlabs: {
voiceId: "voice-normalized",
},
},
},
},
}),
).toBe(false);
});
});

View File

@@ -35,27 +35,40 @@ const ResolvedTalkConfigSchema = Type.Object(
{ additionalProperties: false },
);
const LegacyTalkConfigSchema = Type.Object(
{
voiceId: Type.Optional(Type.String()),
voiceAliases: Type.Optional(Type.Record(Type.String(), Type.String())),
modelId: Type.Optional(Type.String()),
outputFormat: Type.Optional(Type.String()),
apiKey: Type.Optional(SecretInputSchema),
interruptOnSpeech: Type.Optional(Type.Boolean()),
silenceTimeoutMs: Type.Optional(Type.Integer({ minimum: 1 })),
},
{ additionalProperties: false },
);
const NormalizedTalkConfigSchema = Type.Object(
{
provider: Type.Optional(Type.String()),
providers: Type.Optional(Type.Record(Type.String(), TalkProviderConfigSchema)),
resolved: ResolvedTalkConfigSchema,
voiceId: Type.Optional(Type.String()),
voiceAliases: Type.Optional(Type.Record(Type.String(), Type.String())),
modelId: Type.Optional(Type.String()),
outputFormat: Type.Optional(Type.String()),
apiKey: Type.Optional(SecretInputSchema),
interruptOnSpeech: Type.Optional(Type.Boolean()),
silenceTimeoutMs: Type.Optional(Type.Integer({ minimum: 1 })),
},
{ additionalProperties: false },
);
export const TalkConfigResultSchema = Type.Object(
{
config: Type.Object(
{
talk: Type.Optional(
Type.Object(
{
provider: Type.Optional(Type.String()),
providers: Type.Optional(Type.Record(Type.String(), TalkProviderConfigSchema)),
resolved: Type.Optional(ResolvedTalkConfigSchema),
voiceId: Type.Optional(Type.String()),
voiceAliases: Type.Optional(Type.Record(Type.String(), Type.String())),
modelId: Type.Optional(Type.String()),
outputFormat: Type.Optional(Type.String()),
apiKey: Type.Optional(SecretInputSchema),
interruptOnSpeech: Type.Optional(Type.Boolean()),
silenceTimeoutMs: Type.Optional(Type.Integer({ minimum: 1 })),
},
{ additionalProperties: false },
),
),
talk: Type.Optional(Type.Union([LegacyTalkConfigSchema, NormalizedTalkConfigSchema])),
session: Type.Optional(
Type.Object(
{

View File

@@ -30,7 +30,7 @@ describe("talk.config contract fixtures", () => {
if (fixture.payloadValid) {
expect(validateTalkConfigResult(payload)).toBe(true);
} else {
expect((payload.config.talk as { resolved?: unknown }).resolved).toBeUndefined();
expect(validateTalkConfigResult(payload)).toBe(false);
}
if (!fixture.expectedSelection) {