@avakado.ai/schemas 1.1.31 → 1.1.33
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 +16 -0
- package/package.json +1 -1
- package/src/models/Agent.js +19 -1
- package/types.d.ts +1 -0
- package/src/media.test.js +0 -85
package/README.md
CHANGED
|
@@ -123,3 +123,19 @@ await Subscription.createIndexes();
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
That is why an index or enum change is a major version bump.
|
|
126
|
+
|
|
127
|
+
### Realtime speech providers
|
|
128
|
+
|
|
129
|
+
Realtime agents may store `speechConfig` separately from the model's
|
|
130
|
+
`responseConfig`. Omit it for existing/native voice behavior, or explicitly use
|
|
131
|
+
`{ provider: "native" }`. An external voice is configured as follows:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
speechConfig: {
|
|
135
|
+
provider: "elevenlabs",
|
|
136
|
+
voiceId: "your-voice-id",
|
|
137
|
+
voiceName: "My voice", // Optional display metadata
|
|
138
|
+
modelId: "eleven_flash_v2_5",
|
|
139
|
+
settings: { stability: 0.5, similarityBoost: 0.75 }
|
|
140
|
+
}
|
|
141
|
+
```
|
package/package.json
CHANGED
package/src/models/Agent.js
CHANGED
|
@@ -83,6 +83,22 @@ const ModelConfigSchema = new Schema({
|
|
|
83
83
|
const ResponseConfigSchema = new Schema({
|
|
84
84
|
provider: { type: String, enum: [...Object.keys(ProviderConfig), 'elevenlabs', 'custom'], required: true },
|
|
85
85
|
}, { _id: false, discriminatorKey: 'provider' });
|
|
86
|
+
const SpeechConfigSchema = new Schema({
|
|
87
|
+
provider: { type: String, enum: ['native', 'elevenlabs'], required: true },
|
|
88
|
+
}, { _id: false, discriminatorKey: 'provider', strict: 'throw' });
|
|
89
|
+
SpeechConfigSchema.discriminator('native', new Schema({}, { _id: false, strict: 'throw' }));
|
|
90
|
+
SpeechConfigSchema.discriminator('elevenlabs', new Schema({
|
|
91
|
+
voiceId: { type: String, required: true, trim: true },
|
|
92
|
+
voiceName: { type: String, trim: true },
|
|
93
|
+
modelId: { type: String, required: true, trim: true },
|
|
94
|
+
settings: {
|
|
95
|
+
type: new Schema({
|
|
96
|
+
stability: { type: Number, min: 0, max: 1 },
|
|
97
|
+
similarityBoost: { type: Number, min: 0, max: 1 },
|
|
98
|
+
}, { _id: false, strict: 'throw' }),
|
|
99
|
+
default: undefined,
|
|
100
|
+
},
|
|
101
|
+
}, { _id: false, strict: 'throw' }));
|
|
86
102
|
const RealtimeConfigSchema = new Schema({
|
|
87
103
|
modality: {
|
|
88
104
|
type: String, required: true,
|
|
@@ -95,7 +111,9 @@ const RealtimeConfigSchema = new Schema({
|
|
|
95
111
|
message: props => `Invalid modality "${props.value}" for this provider`,
|
|
96
112
|
}
|
|
97
113
|
},
|
|
98
|
-
responseConfig: ResponseConfigSchema
|
|
114
|
+
responseConfig: ResponseConfigSchema,
|
|
115
|
+
// Missing on existing agents means native speech; no migration required.
|
|
116
|
+
speechConfig: { type: SpeechConfigSchema, default: undefined },
|
|
99
117
|
}, { _id: false });
|
|
100
118
|
const responseConfigPath = RealtimeConfigSchema.path('responseConfig');
|
|
101
119
|
responseConfigPath.discriminator('openai', new Schema({
|
package/types.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export interface AgentModel {
|
|
|
46
46
|
personalInfo?: { name?: string; description?: string; avatar?: string; systemPrompt?: { role?: string; objective?: string; instructionsAndWorkflow?: string; constraintsAndRules?: string; }; };
|
|
47
47
|
modality?: string;
|
|
48
48
|
responseConfig?: { provider: "openai" | "gemini" | "anthropic" | "elevenlabs" | "custom"; };
|
|
49
|
+
speechConfig?: { provider: "native"; } | { voiceId: string; voiceName?: string; modelId: string; settings?: { stability?: number; similarityBoost?: number; }; provider: "elevenlabs"; };
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export interface Amount {
|
package/src/media.test.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { MediaPlanError, negotiateCall, selectChannelMedia } from "./media.js";
|
|
4
|
-
|
|
5
|
-
test("exotel 8 kHz pcm is resampled to openai 24 kHz", () => {
|
|
6
|
-
const plan = negotiateCall({ channelName: "Exotel", provider: "openai" });
|
|
7
|
-
assert.deepEqual(plan.channel, { encoding: "pcm16", rate: 8000 });
|
|
8
|
-
assert.deepEqual(plan.provider.input, { encoding: "pcm16", rate: 24000 });
|
|
9
|
-
assert.deepEqual(plan.provider.output, { encoding: "pcm16", rate: 24000 });
|
|
10
|
-
assert.equal(plan.uplink, "pcm16:8000->pcm16:24000");
|
|
11
|
-
assert.equal(plan.downlink, "pcm16:24000->pcm16:8000");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("exotel 16 kHz pcm is resampled to openai 24 kHz", () => {
|
|
15
|
-
const plan = negotiateCall({
|
|
16
|
-
channelName: "exotel",
|
|
17
|
-
channelConfig: { media: { encoding: "pcm16", rate: 16000 } },
|
|
18
|
-
provider: "openai",
|
|
19
|
-
});
|
|
20
|
-
assert.equal(plan.channel.rate, 16000);
|
|
21
|
-
assert.equal(plan.provider.input.rate, 24000);
|
|
22
|
-
assert.equal(plan.uplink, "pcm16:16000->pcm16:24000");
|
|
23
|
-
assert.equal(plan.downlink, "pcm16:24000->pcm16:16000");
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test("exotel 8 kHz and gemini bridge 16 kHz in and 24 kHz out", () => {
|
|
27
|
-
const plan = negotiateCall({ channelName: "exotel", provider: "gemini" });
|
|
28
|
-
assert.deepEqual(plan.provider.input, { encoding: "pcm16", rate: 16000 });
|
|
29
|
-
assert.deepEqual(plan.provider.output, { encoding: "pcm16", rate: 24000 });
|
|
30
|
-
assert.equal(plan.uplink, "pcm16:8000->pcm16:16000");
|
|
31
|
-
assert.equal(plan.downlink, "pcm16:24000->pcm16:8000");
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("exotel 16 kHz into gemini only downsamples the model output", () => {
|
|
35
|
-
const plan = negotiateCall({
|
|
36
|
-
channelName: "exotel",
|
|
37
|
-
channelConfig: { media: { encoding: "pcm16", rate: 16000 } },
|
|
38
|
-
provider: "google",
|
|
39
|
-
});
|
|
40
|
-
assert.equal(plan.uplink, "identity");
|
|
41
|
-
assert.equal(plan.downlink, "pcm16:24000->pcm16:16000");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("exotel 24 kHz into gemini only downsamples the caller audio", () => {
|
|
45
|
-
const plan = negotiateCall({
|
|
46
|
-
channelName: "exotel",
|
|
47
|
-
channelConfig: { media: { encoding: "pcm16", rate: 24000 } },
|
|
48
|
-
provider: "gemini",
|
|
49
|
-
});
|
|
50
|
-
assert.equal(plan.uplink, "pcm16:24000->pcm16:16000");
|
|
51
|
-
assert.equal(plan.downlink, "identity");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("whatsapp and twilio default to g711 ulaw and match openai", () => {
|
|
55
|
-
for (const channelName of ["Whatsapp", "twilio", "tataTele"]) {
|
|
56
|
-
const plan = negotiateCall({ channelName, provider: "openai" });
|
|
57
|
-
assert.deepEqual(plan.channel, { encoding: "g711_ulaw", rate: 8000 });
|
|
58
|
-
assert.equal(plan.uplink, "identity");
|
|
59
|
-
assert.equal(plan.downlink, "identity");
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("whatsapp ulaw into gemini uses the registered converters", () => {
|
|
64
|
-
const plan = negotiateCall({ channelName: "whatsapp", provider: "gemini" });
|
|
65
|
-
assert.equal(plan.uplink, "g711_ulaw:8000->pcm16:16000");
|
|
66
|
-
assert.equal(plan.downlink, "pcm16:24000->g711_ulaw:8000");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("a wire outside the channel menu is rejected", () => {
|
|
70
|
-
assert.throws(
|
|
71
|
-
() => selectChannelMedia("exotel", { encoding: "pcm16", rate: 48000 }),
|
|
72
|
-
MediaPlanError
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("alaw into gemini fails until a converter exists", () => {
|
|
77
|
-
assert.throws(
|
|
78
|
-
() => negotiateCall({
|
|
79
|
-
channelName: "whatsapp",
|
|
80
|
-
channelConfig: { media: { encoding: "g711_alaw", rate: 8000 } },
|
|
81
|
-
provider: "gemini",
|
|
82
|
-
}),
|
|
83
|
-
/No converter/
|
|
84
|
-
);
|
|
85
|
-
});
|