@mastra/voice-speechify 0.13.0 → 0.14.0
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/CHANGELOG.md +86 -0
- package/README.md +24 -4
- package/dist/_types/@internal_voice/dist/_types/@internal_ai-sdk-v5/dist/index.d.ts +93 -3
- package/dist/_types/@internal_voice/dist/_types/@internal_core/dist/request-context/index.d.ts +10 -0
- package/dist/docs/SKILL.md +1 -2
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-voice-overview.md +5 -3
- package/dist/docs/references/reference-voice-speechify.md +12 -6
- package/dist/index.cjs +23 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -6
- package/dist/index.js.map +1 -1
- package/dist/voices.d.ts +8 -1
- package/dist/voices.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/docs/references/docs-agents-adding-voice.md +0 -381
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,91 @@
|
|
|
1
1
|
# @mastra/voice-speechify
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added support for Speechify's Simba 3.2 and Simba 3.0 text-to-speech models. Simba 3.2 is Speechify's latest streaming model with lower latency and richer expressivity, and is the recommended model for English speech. ([#19411](https://github.com/mastra-ai/mastra/pull/19411))
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { SpeechifyVoice } from '@mastra/voice-speechify';
|
|
11
|
+
|
|
12
|
+
// Set as the default model
|
|
13
|
+
const voice = new SpeechifyVoice({
|
|
14
|
+
speechModel: { name: 'simba-3.2' },
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Or override per request
|
|
18
|
+
const stream = await voice.speak('Hello world', { model: 'simba-3.2' });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Note: `simba-3.2` and `simba-3.0` are currently English only. The default model remains `simba-english`.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Fixed voice selection for the Simba 3 models. Speechify's `simba-3.2` and `simba-3.0` serve a curated voice set only (`beatrice_32`, `dominic_32`, `edmund_32`, `geffen_32`, `harper_32`, `hugh_32`, `imogen_32`, `wyatt_32`), so pairing them with a classic catalog voice like `george` failed with an API error. ([#19415](https://github.com/mastra-ai/mastra/pull/19415))
|
|
26
|
+
- Added the curated Simba 3 voices to the voice list, so they type-check as `speaker` and appear in `getSpeakers()`
|
|
27
|
+
- The default speaker now follows the configured model: `harper_32` for Simba 3 models, `george` otherwise
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { SpeechifyVoice } from '@mastra/voice-speechify';
|
|
31
|
+
|
|
32
|
+
// Works out of the box now — defaults to the harper_32 voice
|
|
33
|
+
const voice = new SpeechifyVoice({
|
|
34
|
+
speechModel: { name: 'simba-3.2' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Or pick a curated voice explicitly
|
|
38
|
+
new SpeechifyVoice({
|
|
39
|
+
speechModel: { name: 'simba-3.2' },
|
|
40
|
+
speaker: 'imogen_32',
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
When overriding the model per request, pass a matching speaker too: `voice.speak('Hi', { model: 'simba-3.2', speaker: 'harper_32' })`.
|
|
45
|
+
|
|
46
|
+
## 0.14.0-alpha.0
|
|
47
|
+
|
|
48
|
+
### Minor Changes
|
|
49
|
+
|
|
50
|
+
- Added support for Speechify's Simba 3.2 and Simba 3.0 text-to-speech models. Simba 3.2 is Speechify's latest streaming model with lower latency and richer expressivity, and is the recommended model for English speech. ([#19411](https://github.com/mastra-ai/mastra/pull/19411))
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { SpeechifyVoice } from '@mastra/voice-speechify';
|
|
54
|
+
|
|
55
|
+
// Set as the default model
|
|
56
|
+
const voice = new SpeechifyVoice({
|
|
57
|
+
speechModel: { name: 'simba-3.2' },
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Or override per request
|
|
61
|
+
const stream = await voice.speak('Hello world', { model: 'simba-3.2' });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Note: `simba-3.2` and `simba-3.0` are currently English only. The default model remains `simba-english`.
|
|
65
|
+
|
|
66
|
+
### Patch Changes
|
|
67
|
+
|
|
68
|
+
- Fixed voice selection for the Simba 3 models. Speechify's `simba-3.2` and `simba-3.0` serve a curated voice set only (`beatrice_32`, `dominic_32`, `edmund_32`, `geffen_32`, `harper_32`, `hugh_32`, `imogen_32`, `wyatt_32`), so pairing them with a classic catalog voice like `george` failed with an API error. ([#19415](https://github.com/mastra-ai/mastra/pull/19415))
|
|
69
|
+
- Added the curated Simba 3 voices to the voice list, so they type-check as `speaker` and appear in `getSpeakers()`
|
|
70
|
+
- The default speaker now follows the configured model: `harper_32` for Simba 3 models, `george` otherwise
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { SpeechifyVoice } from '@mastra/voice-speechify';
|
|
74
|
+
|
|
75
|
+
// Works out of the box now — defaults to the harper_32 voice
|
|
76
|
+
const voice = new SpeechifyVoice({
|
|
77
|
+
speechModel: { name: 'simba-3.2' },
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Or pick a curated voice explicitly
|
|
81
|
+
new SpeechifyVoice({
|
|
82
|
+
speechModel: { name: 'simba-3.2' },
|
|
83
|
+
speaker: 'imogen_32',
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
When overriding the model per request, pass a matching speaker too: `voice.speak('Hi', { model: 'simba-3.2', speaker: 'harper_32' })`.
|
|
88
|
+
|
|
3
89
|
## 0.13.0
|
|
4
90
|
|
|
5
91
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -23,10 +23,10 @@ import { SpeechifyVoice } from '@mastra/voice-speechify';
|
|
|
23
23
|
|
|
24
24
|
const voice = new SpeechifyVoice({
|
|
25
25
|
speechModel: {
|
|
26
|
-
name: 'simba-
|
|
26
|
+
name: 'simba-3.2', // Optional, defaults to 'simba-english'
|
|
27
27
|
apiKey: 'your-api-key', // Optional, can use SPEECHIFY_API_KEY env var
|
|
28
28
|
},
|
|
29
|
-
speaker: '
|
|
29
|
+
speaker: 'harper_32', // Optional, defaults to a voice that matches the model
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
// List available speakers
|
|
@@ -34,7 +34,7 @@ const speakers = await voice.getSpeakers();
|
|
|
34
34
|
|
|
35
35
|
// Generate speech
|
|
36
36
|
const stream = await voice.speak('Hello world', {
|
|
37
|
-
speaker: '
|
|
37
|
+
speaker: 'harper_32', // Optional, defaults to constructor speaker
|
|
38
38
|
// Additional Speechify options
|
|
39
39
|
audioFormat: 'mp3',
|
|
40
40
|
});
|
|
@@ -49,7 +49,7 @@ The `SpeechifyVoice` constructor accepts the following options:
|
|
|
49
49
|
|
|
50
50
|
```typescript
|
|
51
51
|
interface SpeechifyConfig {
|
|
52
|
-
name?:
|
|
52
|
+
name?: SpeechifyModel; // Optional Speechify model name (default: 'simba-english')
|
|
53
53
|
apiKey?: string; // Optional API key (can also use env var)
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -59,6 +59,19 @@ new SpeechifyVoice({
|
|
|
59
59
|
})
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
## Available Models
|
|
63
|
+
|
|
64
|
+
- `simba-3.2`: Speechify's latest streaming-native model with the lowest latency and richest expressivity. Recommended for English. Currently English only.
|
|
65
|
+
- `simba-3.0`: The earlier Simba 3 model, still available. Currently English only.
|
|
66
|
+
- `simba-english`: The default model, optimized for English.
|
|
67
|
+
- `simba-multilingual`: Optimized for non-English or mixed-language input.
|
|
68
|
+
|
|
69
|
+
The model can also be overridden per request. When overriding to a Simba 3 model, pass a matching speaker too:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const stream = await voice.speak('Hello world', { model: 'simba-3.2', speaker: 'harper_32' });
|
|
73
|
+
```
|
|
74
|
+
|
|
62
75
|
## Available Speakers
|
|
63
76
|
|
|
64
77
|
You can get a list of available speakers:
|
|
@@ -66,3 +79,10 @@ You can get a list of available speakers:
|
|
|
66
79
|
```typescript
|
|
67
80
|
const speakers = await voice.getSpeakers();
|
|
68
81
|
```
|
|
82
|
+
|
|
83
|
+
Voice availability depends on the model:
|
|
84
|
+
|
|
85
|
+
- `simba-3.2` and `simba-3.0` serve a curated voice set only: `beatrice_32`, `dominic_32`, `edmund_32`, `geffen_32`, `harper_32`, `hugh_32`, `imogen_32`, `wyatt_32`. `simba-3.2` also accepts cloned voices approved by Speechify.
|
|
86
|
+
- `simba-english` and `simba-multilingual` serve the full classic catalog (`george`, `henry`, `carly`, ...) and self-serve cloned voices.
|
|
87
|
+
|
|
88
|
+
The default speaker follows the configured model: `harper_32` for the Simba 3 models, otherwise `george`.
|
|
@@ -231,6 +231,7 @@ declare namespace _ai_sdk_provider_utils {
|
|
|
231
231
|
Validator,
|
|
232
232
|
asSchema,
|
|
233
233
|
asValidator,
|
|
234
|
+
cancelResponseBody,
|
|
234
235
|
combineHeaders,
|
|
235
236
|
convertAsyncIteratorToReadableStream,
|
|
236
237
|
convertBase64ToUint8Array,
|
|
@@ -249,13 +250,16 @@ declare namespace _ai_sdk_provider_utils {
|
|
|
249
250
|
dynamicTool,
|
|
250
251
|
executeTool,
|
|
251
252
|
extractResponseHeaders,
|
|
253
|
+
fetchWithValidatedRedirects,
|
|
252
254
|
generateId,
|
|
253
255
|
getErrorMessage,
|
|
254
256
|
getFromApi,
|
|
255
257
|
getRuntimeEnvironmentUserAgent,
|
|
256
258
|
injectJsonInstructionIntoMessages,
|
|
257
259
|
isAbortError,
|
|
260
|
+
isBrowserRuntime,
|
|
258
261
|
isParsableJson,
|
|
262
|
+
isSameOrigin,
|
|
259
263
|
isUrlSupported,
|
|
260
264
|
isValidator,
|
|
261
265
|
jsonSchema,
|
|
@@ -494,6 +498,20 @@ export declare type CallSettings = {
|
|
|
494
498
|
*/
|
|
495
499
|
export declare type CallWarning = LanguageModelV2CallWarning;
|
|
496
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Cancels a response body to release the underlying connection.
|
|
503
|
+
*
|
|
504
|
+
* When a fetch Response is rejected without consuming its body (e.g. a failed
|
|
505
|
+
* status code, an open-redirect rejection, or a Content-Length that exceeds the
|
|
506
|
+
* size limit), the underlying TCP socket is not returned to the connection pool
|
|
507
|
+
* and may stay open until the process runs out of file descriptors. Cancelling
|
|
508
|
+
* the body avoids this leak.
|
|
509
|
+
*
|
|
510
|
+
* Errors thrown while cancelling are ignored: the body may already be locked,
|
|
511
|
+
* disturbed, or absent, none of which should mask the original rejection.
|
|
512
|
+
*/
|
|
513
|
+
declare function cancelResponseBody(response: Response): Promise<void>;
|
|
514
|
+
|
|
497
515
|
export declare interface ChatInit<UI_MESSAGE extends UIMessage> {
|
|
498
516
|
/**
|
|
499
517
|
* A unique identifier for the chat. If not provided, a random one will be
|
|
@@ -956,7 +974,21 @@ export declare type CreateUIMessage<UI_MESSAGE extends UIMessage> = Omit<UI_MESS
|
|
|
956
974
|
role?: UI_MESSAGE['role'];
|
|
957
975
|
};
|
|
958
976
|
|
|
959
|
-
|
|
977
|
+
/**
|
|
978
|
+
* Creates a UI message stream that can be used to send messages to the client.
|
|
979
|
+
*
|
|
980
|
+
* @param options.execute - A function that is called with a writer to write UI message chunks to the stream.
|
|
981
|
+
* @param options.onError - A function that extracts an error message from an error. Defaults to `() => 'An error occurred.'` so server-side error details are not leaked to the client; supply your own to surface richer messages.
|
|
982
|
+
* @param options.originalMessages - The original messages. If provided, persistence mode is assumed
|
|
983
|
+
* and a message ID is provided for the response message.
|
|
984
|
+
* @param options.onStepFinish - A callback that is called when each step finishes. Useful for persisting intermediate messages.
|
|
985
|
+
* @param options.onFinish - A callback that is called when the stream finishes.
|
|
986
|
+
* @param options.generateId - A function that generates a unique ID. Defaults to the built-in ID generator.
|
|
987
|
+
*
|
|
988
|
+
* @returns A `ReadableStream` of UI message chunks.
|
|
989
|
+
*/
|
|
990
|
+
export declare function createUIMessageStream<UI_MESSAGE extends UIMessage>({ execute, onError, // prevent leaking server error details to the client by default
|
|
991
|
+
originalMessages, onFinish, generateId, }: {
|
|
960
992
|
execute: (options: {
|
|
961
993
|
writer: UIMessageStreamWriter<UI_MESSAGE>;
|
|
962
994
|
}) => Promise<void> | void;
|
|
@@ -2129,6 +2161,36 @@ declare function extractResponseHeaders(response: Response): {
|
|
|
2129
2161
|
*/
|
|
2130
2162
|
declare type FetchFunction = typeof globalThis.fetch;
|
|
2131
2163
|
|
|
2164
|
+
/**
|
|
2165
|
+
* Fetches a URL while enforcing the SSRF download guard on every hop.
|
|
2166
|
+
*
|
|
2167
|
+
* Redirects are followed manually (`redirect: 'manual'`) so each hop is
|
|
2168
|
+
* validated with {@link validateDownloadUrl} *before* it is requested. Relying
|
|
2169
|
+
* on the default `redirect: 'follow'` would issue the request to a redirect
|
|
2170
|
+
* target (e.g. an internal address) before we ever see its URL, defeating the
|
|
2171
|
+
* SSRF guard.
|
|
2172
|
+
*
|
|
2173
|
+
* A `redirect: 'manual'` request yields an unreadable opaque response in the
|
|
2174
|
+
* browser (and in other spec-compliant fetch implementations), so the redirect
|
|
2175
|
+
* target cannot be validated here. In a real browser this is safe to follow
|
|
2176
|
+
* natively because SSRF is not reachable (fetch is constrained by CORS and
|
|
2177
|
+
* cannot reach a server's internal network or cloud-metadata). On any other
|
|
2178
|
+
* runtime we cannot validate the hop, so we fail closed rather than follow it
|
|
2179
|
+
* blindly and bypass the SSRF guard.
|
|
2180
|
+
*
|
|
2181
|
+
* The returned response is the final (non-redirect) response. The caller is
|
|
2182
|
+
* responsible for checking `response.ok` and reading the body.
|
|
2183
|
+
*
|
|
2184
|
+
* @throws DownloadError if a hop is unsafe, the redirect limit is exceeded, or
|
|
2185
|
+
* a redirect cannot be validated on a non-browser runtime.
|
|
2186
|
+
*/
|
|
2187
|
+
declare function fetchWithValidatedRedirects({ url, headers, abortSignal, maxRedirects, }: {
|
|
2188
|
+
url: string;
|
|
2189
|
+
headers?: HeadersInit;
|
|
2190
|
+
abortSignal?: AbortSignal;
|
|
2191
|
+
maxRedirects?: number;
|
|
2192
|
+
}): Promise<Response>;
|
|
2193
|
+
|
|
2132
2194
|
/**
|
|
2133
2195
|
File content part of a prompt. It contains a file.
|
|
2134
2196
|
*/
|
|
@@ -2261,7 +2323,7 @@ declare interface GatewayGenerationInfoParams {
|
|
|
2261
2323
|
id: string;
|
|
2262
2324
|
}
|
|
2263
2325
|
|
|
2264
|
-
declare type GatewayImageModelId = 'bfl/flux-2-flex' | 'bfl/flux-2-klein-4b' | 'bfl/flux-2-klein-9b' | 'bfl/flux-2-max' | 'bfl/flux-2-pro' | 'bfl/flux-kontext-max' | 'bfl/flux-kontext-pro' | 'bfl/flux-pro-1.0-fill' | 'bfl/flux-pro-1.1' | 'bfl/flux-pro-1.1-ultra' | 'bytedance/seedream-4.0' | 'bytedance/seedream-4.5' | 'bytedance/seedream-5.0-lite' | 'google/imagen-4.0-fast-generate-001' | 'google/imagen-4.0-generate-001' | 'google/imagen-4.0-ultra-generate-001' | 'openai/gpt-image-1' | 'openai/gpt-image-1-mini' | 'openai/gpt-image-1.5' | 'openai/gpt-image-2' | 'prodia/flux-fast-schnell' | 'recraft/recraft-v2' | 'recraft/recraft-v3' | 'recraft/recraft-v4' | 'recraft/recraft-v4-pro' | '
|
|
2326
|
+
declare type GatewayImageModelId = 'bfl/flux-2-flex' | 'bfl/flux-2-klein-4b' | 'bfl/flux-2-klein-9b' | 'bfl/flux-2-max' | 'bfl/flux-2-pro' | 'bfl/flux-kontext-max' | 'bfl/flux-kontext-pro' | 'bfl/flux-pro-1.0-fill' | 'bfl/flux-pro-1.1' | 'bfl/flux-pro-1.1-ultra' | 'bytedance/seedream-4.0' | 'bytedance/seedream-4.5' | 'bytedance/seedream-5.0-lite' | 'google/imagen-4.0-fast-generate-001' | 'google/imagen-4.0-generate-001' | 'google/imagen-4.0-ultra-generate-001' | 'openai/gpt-image-1' | 'openai/gpt-image-1-mini' | 'openai/gpt-image-1.5' | 'openai/gpt-image-2' | 'prodia/flux-fast-schnell' | 'quiverai/arrow-1.1' | 'recraft/recraft-v2' | 'recraft/recraft-v3' | 'recraft/recraft-v4' | 'recraft/recraft-v4-pro' | 'recraft/recraft-v4.1' | 'recraft/recraft-v4.1-pro' | 'recraft/recraft-v4.1-utility' | 'recraft/recraft-v4.1-utility-pro' | 'xai/grok-imagine-image' | (string & {});
|
|
2265
2327
|
|
|
2266
2328
|
declare interface GatewayLanguageModelEntry {
|
|
2267
2329
|
/**
|
|
@@ -2312,7 +2374,7 @@ declare interface GatewayLanguageModelEntry {
|
|
|
2312
2374
|
|
|
2313
2375
|
declare type GatewayLanguageModelSpecification = Pick<LanguageModelV2, 'specificationVersion' | 'provider' | 'modelId'>;
|
|
2314
2376
|
|
|
2315
|
-
export declare type GatewayModelId = 'alibaba/qwen-3-14b' | 'alibaba/qwen-3-235b' | 'alibaba/qwen-3-30b' | 'alibaba/qwen-3-32b' | 'alibaba/qwen-3.6-max-preview' | 'alibaba/qwen3-235b-a22b-thinking' | 'alibaba/qwen3-coder' | 'alibaba/qwen3-coder-30b-a3b' | 'alibaba/qwen3-coder-next' | 'alibaba/qwen3-coder-plus' | 'alibaba/qwen3-max' | 'alibaba/qwen3-max-preview' | 'alibaba/qwen3-max-thinking' | 'alibaba/qwen3-next-80b-a3b-instruct' | 'alibaba/qwen3-next-80b-a3b-thinking' | 'alibaba/qwen3-vl-235b-a22b-instruct' | 'alibaba/qwen3-vl-instruct' | 'alibaba/qwen3-vl-thinking' | 'alibaba/qwen3.5-flash' | 'alibaba/qwen3.5-plus' | 'alibaba/qwen3.6-27b' | 'alibaba/qwen3.6-plus' | 'amazon/nova-2-lite' | 'amazon/nova-lite' | 'amazon/nova-micro' | 'amazon/nova-pro' | 'anthropic/claude-3-haiku' | 'anthropic/claude-3.5-haiku' | 'anthropic/claude-
|
|
2377
|
+
export declare type GatewayModelId = 'alibaba/qwen-3-14b' | 'alibaba/qwen-3-235b' | 'alibaba/qwen-3-30b' | 'alibaba/qwen-3-32b' | 'alibaba/qwen-3.6-max-preview' | 'alibaba/qwen3-235b-a22b-thinking' | 'alibaba/qwen3-coder' | 'alibaba/qwen3-coder-30b-a3b' | 'alibaba/qwen3-coder-next' | 'alibaba/qwen3-coder-plus' | 'alibaba/qwen3-max' | 'alibaba/qwen3-max-preview' | 'alibaba/qwen3-max-thinking' | 'alibaba/qwen3-next-80b-a3b-instruct' | 'alibaba/qwen3-next-80b-a3b-thinking' | 'alibaba/qwen3-vl-235b-a22b-instruct' | 'alibaba/qwen3-vl-instruct' | 'alibaba/qwen3-vl-thinking' | 'alibaba/qwen3.5-flash' | 'alibaba/qwen3.5-plus' | 'alibaba/qwen3.6-27b' | 'alibaba/qwen3.6-plus' | 'alibaba/qwen3.7-max' | 'alibaba/qwen3.7-plus' | 'amazon/nova-2-lite' | 'amazon/nova-lite' | 'amazon/nova-micro' | 'amazon/nova-pro' | 'anthropic/claude-3-haiku' | 'anthropic/claude-3.5-haiku' | 'anthropic/claude-fable-5' | 'anthropic/claude-haiku-4.5' | 'anthropic/claude-opus-4' | 'anthropic/claude-opus-4.1' | 'anthropic/claude-opus-4.5' | 'anthropic/claude-opus-4.6' | 'anthropic/claude-opus-4.7' | 'anthropic/claude-opus-4.8' | 'anthropic/claude-sonnet-4' | 'anthropic/claude-sonnet-4.5' | 'anthropic/claude-sonnet-4.6' | 'anthropic/claude-sonnet-5' | 'arcee-ai/trinity-large-preview' | 'arcee-ai/trinity-large-thinking' | 'arcee-ai/trinity-mini' | 'bytedance/seed-1.6' | 'bytedance/seed-1.8' | 'cohere/command-a' | 'deepseek/deepseek-r1' | 'deepseek/deepseek-v3' | 'deepseek/deepseek-v3.1' | 'deepseek/deepseek-v3.1-terminus' | 'deepseek/deepseek-v3.2' | 'deepseek/deepseek-v3.2-thinking' | 'deepseek/deepseek-v4-flash' | 'deepseek/deepseek-v4-pro' | 'google/gemini-2.5-flash' | 'google/gemini-2.5-flash-image' | 'google/gemini-2.5-flash-lite' | 'google/gemini-2.5-pro' | 'google/gemini-3-flash' | 'google/gemini-3-pro-image' | 'google/gemini-3-pro-preview' | 'google/gemini-3.1-flash-image' | 'google/gemini-3.1-flash-image-preview' | 'google/gemini-3.1-flash-lite' | 'google/gemini-3.1-flash-lite-image' | 'google/gemini-3.1-flash-lite-preview' | 'google/gemini-3.1-pro-preview' | 'google/gemini-3.5-flash' | 'google/gemma-4-26b-a4b-it' | 'google/gemma-4-31b-it' | 'inception/mercury-2' | 'inception/mercury-coder-small' | 'interfaze/interfaze-beta' | 'kwaipilot/kat-coder-pro-v1' | 'kwaipilot/kat-coder-pro-v2' | 'meituan/longcat-flash-chat' | 'meituan/longcat-flash-thinking-2601' | 'meta/llama-3.1-70b' | 'meta/llama-3.1-8b' | 'meta/llama-3.2-11b' | 'meta/llama-3.2-1b' | 'meta/llama-3.2-3b' | 'meta/llama-3.2-90b' | 'meta/llama-3.3-70b' | 'meta/llama-4-maverick' | 'meta/llama-4-scout' | 'minimax/minimax-m2' | 'minimax/minimax-m2.1' | 'minimax/minimax-m2.1-lightning' | 'minimax/minimax-m2.5' | 'minimax/minimax-m2.5-highspeed' | 'minimax/minimax-m2.7' | 'minimax/minimax-m2.7-highspeed' | 'minimax/minimax-m3' | 'mistral/codestral' | 'mistral/devstral-2' | 'mistral/devstral-small' | 'mistral/devstral-small-2' | 'mistral/magistral-medium' | 'mistral/magistral-small' | 'mistral/ministral-14b' | 'mistral/ministral-3b' | 'mistral/ministral-8b' | 'mistral/mistral-large-3' | 'mistral/mistral-medium' | 'mistral/mistral-medium-3.5' | 'mistral/mistral-nemo' | 'mistral/mistral-small' | 'mistral/pixtral-12b' | 'mistral/pixtral-large' | 'moonshotai/kimi-k2' | 'moonshotai/kimi-k2-thinking' | 'moonshotai/kimi-k2.5' | 'moonshotai/kimi-k2.6' | 'moonshotai/kimi-k2.7-code' | 'moonshotai/kimi-k2.7-code-highspeed' | 'morph/morph-v3-fast' | 'morph/morph-v3-large' | 'nvidia/nemotron-3-nano-30b-a3b' | 'nvidia/nemotron-3-super-120b-a12b' | 'nvidia/nemotron-3-ultra-550b-a55b' | 'nvidia/nemotron-nano-12b-v2-vl' | 'nvidia/nemotron-nano-9b-v2' | 'openai/gpt-3.5-turbo' | 'openai/gpt-3.5-turbo-instruct' | 'openai/gpt-4-turbo' | 'openai/gpt-4.1' | 'openai/gpt-4.1-mini' | 'openai/gpt-4.1-nano' | 'openai/gpt-4o' | 'openai/gpt-4o-mini' | 'openai/gpt-4o-mini-search-preview' | 'openai/gpt-5' | 'openai/gpt-5-chat' | 'openai/gpt-5-codex' | 'openai/gpt-5-mini' | 'openai/gpt-5-nano' | 'openai/gpt-5-pro' | 'openai/gpt-5.1-codex' | 'openai/gpt-5.1-codex-max' | 'openai/gpt-5.1-codex-mini' | 'openai/gpt-5.1-instant' | 'openai/gpt-5.1-thinking' | 'openai/gpt-5.2' | 'openai/gpt-5.2-chat' | 'openai/gpt-5.2-codex' | 'openai/gpt-5.2-pro' | 'openai/gpt-5.3-chat' | 'openai/gpt-5.3-codex' | 'openai/gpt-5.4' | 'openai/gpt-5.4-mini' | 'openai/gpt-5.4-nano' | 'openai/gpt-5.4-pro' | 'openai/gpt-5.5' | 'openai/gpt-5.5-pro' | 'openai/gpt-oss-120b' | 'openai/gpt-oss-20b' | 'openai/gpt-oss-safeguard-20b' | 'openai/o1' | 'openai/o3' | 'openai/o3-deep-research' | 'openai/o3-mini' | 'openai/o3-pro' | 'openai/o4-mini' | 'perplexity/sonar' | 'perplexity/sonar-pro' | 'perplexity/sonar-reasoning-pro' | 'sakana/fugu-ultra' | 'stepfun/step-3.5-flash' | 'stepfun/step-3.7-flash' | 'xai/grok-4.1-fast-non-reasoning' | 'xai/grok-4.1-fast-reasoning' | 'xai/grok-4.20-multi-agent' | 'xai/grok-4.20-multi-agent-beta' | 'xai/grok-4.20-non-reasoning' | 'xai/grok-4.20-non-reasoning-beta' | 'xai/grok-4.20-reasoning' | 'xai/grok-4.20-reasoning-beta' | 'xai/grok-4.3' | 'xai/grok-build-0.1' | 'xiaomi/mimo-v2-flash' | 'xiaomi/mimo-v2-pro' | 'xiaomi/mimo-v2.5' | 'xiaomi/mimo-v2.5-pro' | 'zai/glm-4.5' | 'zai/glm-4.5-air' | 'zai/glm-4.5v' | 'zai/glm-4.6' | 'zai/glm-4.6v' | 'zai/glm-4.6v-flash' | 'zai/glm-4.7' | 'zai/glm-4.7-flash' | 'zai/glm-4.7-flashx' | 'zai/glm-5' | 'zai/glm-5-turbo' | 'zai/glm-5.1' | 'zai/glm-5.2' | 'zai/glm-5.2-fast' | 'zai/glm-5v-turbo' | (string & {});
|
|
2316
2378
|
|
|
2317
2379
|
declare interface GatewayProvider extends ProviderV2 {
|
|
2318
2380
|
(modelId: GatewayModelId): LanguageModelV2;
|
|
@@ -3424,6 +3486,16 @@ export declare class InvalidToolInputError extends AISDKError {
|
|
|
3424
3486
|
|
|
3425
3487
|
declare function isAbortError(error: unknown): error is Error;
|
|
3426
3488
|
|
|
3489
|
+
/**
|
|
3490
|
+
* Returns `true` when running in a browser.
|
|
3491
|
+
*
|
|
3492
|
+
* Detection keys on the presence of a global `window`, matching the browser
|
|
3493
|
+
* check used elsewhere in this package (see `getRuntimeEnvironmentUserAgent`)
|
|
3494
|
+
* so the SDK has a single, consistent definition of "browser". Server runtimes
|
|
3495
|
+
* (Node.js, Deno, Bun, edge/workers) do not define `window`.
|
|
3496
|
+
*/
|
|
3497
|
+
declare function isBrowserRuntime(globalThisAny?: any): boolean;
|
|
3498
|
+
|
|
3427
3499
|
/**
|
|
3428
3500
|
* Check if a message part is a data part.
|
|
3429
3501
|
*/
|
|
@@ -3456,6 +3528,20 @@ declare function isParsableJson(input: string): boolean;
|
|
|
3456
3528
|
*/
|
|
3457
3529
|
export declare function isReasoningUIPart(part: UIMessagePart<UIDataTypes, UITools>): part is ReasoningUIPart;
|
|
3458
3530
|
|
|
3531
|
+
/**
|
|
3532
|
+
* Returns true when `url` has the same origin (scheme + host + port) as
|
|
3533
|
+
* `baseUrl`.
|
|
3534
|
+
*
|
|
3535
|
+
* Used to decide whether provider credentials may be attached to a request to a
|
|
3536
|
+
* URL taken from a provider response (e.g. a polling or media-download URL).
|
|
3537
|
+
* Credentials must only be sent to the provider's own origin; a response that
|
|
3538
|
+
* names a foreign host (a CDN, or an attacker-controlled host if the response
|
|
3539
|
+
* is tampered with) must not receive the API key.
|
|
3540
|
+
*
|
|
3541
|
+
* Returns false if either value is not a valid absolute URL (fail-closed).
|
|
3542
|
+
*/
|
|
3543
|
+
declare function isSameOrigin(url: string, baseUrl: string): boolean;
|
|
3544
|
+
|
|
3459
3545
|
/**
|
|
3460
3546
|
* Type guard to check if a message part is a text part.
|
|
3461
3547
|
*/
|
|
@@ -8714,6 +8800,10 @@ export declare const userModelMessageSchema: z.ZodType<UserModelMessage>;
|
|
|
8714
8800
|
* Validates that a URL is safe to download from, blocking private/internal addresses
|
|
8715
8801
|
* to prevent SSRF attacks.
|
|
8716
8802
|
*
|
|
8803
|
+
* Note: this performs string/literal-IP checks only. It does not resolve DNS, so a
|
|
8804
|
+
* hostname that resolves to a private address is not blocked here (see callers, which
|
|
8805
|
+
* should additionally constrain egress at the network layer when handling untrusted URLs).
|
|
8806
|
+
*
|
|
8717
8807
|
* @param url - The URL string to validate.
|
|
8718
8808
|
* @throws DownloadError if the URL is unsafe.
|
|
8719
8809
|
*/
|
package/dist/_types/@internal_voice/dist/_types/@internal_core/dist/request-context/index.d.ts
CHANGED
|
@@ -129,6 +129,16 @@ declare class RequestContext<Values extends Record<string, any> | unknown = unkn
|
|
|
129
129
|
* a clean JSON-safe dict for cross-context cycles.
|
|
130
130
|
*/
|
|
131
131
|
private isSerializable;
|
|
132
|
+
/**
|
|
133
|
+
* Custom span serialization to prevent leaking internal state (like auth
|
|
134
|
+
* tokens stored in the private `registry` Map) into observability spans.
|
|
135
|
+
*
|
|
136
|
+
* `deepClean` in `@mastra/observability` calls this method before falling
|
|
137
|
+
* back to `Object.keys()` — which would walk the runtime-enumerable
|
|
138
|
+
* `registry` field and serialize its raw Map entries (including any
|
|
139
|
+
* bearer tokens) into exported spans.
|
|
140
|
+
*/
|
|
141
|
+
serializeForSpan(): Record<string, unknown>;
|
|
132
142
|
/**
|
|
133
143
|
* Get all values as a typed object for destructuring.
|
|
134
144
|
* Returns Record<string, any> when untyped, or the Values type when typed.
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: mastra-voice-speechify
|
|
|
3
3
|
description: Documentation for @mastra/voice-speechify. Use when working with @mastra/voice-speechify APIs, configuration, or implementation.
|
|
4
4
|
metadata:
|
|
5
5
|
package: "@mastra/voice-speechify"
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.14.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
|
@@ -16,7 +16,6 @@ Read the individual reference documents for detailed explanations and code examp
|
|
|
16
16
|
|
|
17
17
|
### Docs
|
|
18
18
|
|
|
19
|
-
- [Voice](references/docs-agents-adding-voice.md) - Learn how to add voice capabilities to your Mastra agents for text-to-speech and speech-to-text interactions.
|
|
20
19
|
- [Voice in Mastra](references/docs-voice-overview.md) - Overview of voice capabilities in Mastra, including text-to-speech, speech-to-text, and real-time speech-to-speech interactions.
|
|
21
20
|
|
|
22
21
|
### Reference
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
1
3
|
# Voice in Mastra
|
|
2
4
|
|
|
3
5
|
Mastra's Voice system provides a unified interface for voice interactions, enabling text-to-speech (TTS), speech-to-text (STT), and real-time speech-to-speech (STS) capabilities in your applications.
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## Add voice to agents
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Pass a voice provider to an agent with the `voice` property. The same property supports text-to-speech (TTS), speech-to-text (STT), and real-time speech-to-speech (STS), depending on the provider you configure.
|
|
8
10
|
|
|
9
11
|
```typescript
|
|
10
12
|
import { Agent } from '@mastra/core/agent'
|
|
@@ -1137,7 +1139,7 @@ const voiceAgent = new Agent({
|
|
|
1137
1139
|
})
|
|
1138
1140
|
```
|
|
1139
1141
|
|
|
1140
|
-
### Using
|
|
1142
|
+
### Using multiple voice providers
|
|
1141
1143
|
|
|
1142
1144
|
This example demonstrates how to create and use two different voice providers in Mastra: OpenAI for speech-to-text (STT) and PlayAI for text-to-speech (TTS).
|
|
1143
1145
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
1
3
|
# Speechify
|
|
2
4
|
|
|
3
5
|
The Speechify voice implementation in Mastra provides text-to-speech capabilities using Speechify's API.
|
|
@@ -13,15 +15,15 @@ const voice = new SpeechifyVoice()
|
|
|
13
15
|
// Initialize with custom configuration
|
|
14
16
|
const voice = new SpeechifyVoice({
|
|
15
17
|
speechModel: {
|
|
16
|
-
name: 'simba-
|
|
18
|
+
name: 'simba-3.2',
|
|
17
19
|
apiKey: 'your-api-key',
|
|
18
20
|
},
|
|
19
|
-
speaker: '
|
|
21
|
+
speaker: 'harper_32', // Default voice (simba-3.2 serves the curated Simba 3 voices only)
|
|
20
22
|
})
|
|
21
23
|
|
|
22
24
|
// Convert text to speech
|
|
23
25
|
const audioStream = await voice.speak('Hello, world!', {
|
|
24
|
-
speaker: '
|
|
26
|
+
speaker: 'imogen_32', // Override default voice
|
|
25
27
|
})
|
|
26
28
|
```
|
|
27
29
|
|
|
@@ -29,11 +31,11 @@ const audioStream = await voice.speak('Hello, world!', {
|
|
|
29
31
|
|
|
30
32
|
**speechModel** (`SpeechifyConfig`): Configuration for text-to-speech functionality (Default: `{ name: 'simba-english' }`)
|
|
31
33
|
|
|
32
|
-
**speechModel.name** (`
|
|
34
|
+
**speechModel.name** (`SpeechifyModel`): The Speechify model to use ('simba-3.2', 'simba-3.0', 'simba-english', or 'simba-multilingual')
|
|
33
35
|
|
|
34
36
|
**speechModel.apiKey** (`string`): Speechify API key. Falls back to SPEECHIFY\_API\_KEY environment variable
|
|
35
37
|
|
|
36
|
-
**speaker** (`SpeechifyVoiceId`): Default voice ID to use for speech synthesis (Default: `'george'`)
|
|
38
|
+
**speaker** (`SpeechifyVoiceId`): Default voice ID to use for speech synthesis. The Simba 3 models serve a curated voice set only (harper\_32, imogen\_32, ...); the classic catalog voices (george, henry, ...) work with simba-english and simba-multilingual (Default: `'harper_32' for Simba 3 models, otherwise 'george'`)
|
|
37
39
|
|
|
38
40
|
## Methods
|
|
39
41
|
|
|
@@ -47,7 +49,7 @@ Converts text to speech using the configured speech model and voice.
|
|
|
47
49
|
|
|
48
50
|
**options.speaker** (`string`): Override the default speaker for this request
|
|
49
51
|
|
|
50
|
-
**options.model** (`
|
|
52
|
+
**options.model** (`SpeechifyModel`): Override the default model for this request
|
|
51
53
|
|
|
52
54
|
Returns: `Promise<NodeJS.ReadableStream>`
|
|
53
55
|
|
|
@@ -71,5 +73,9 @@ This method isn't supported by Speechify and will throw an error. Speechify does
|
|
|
71
73
|
|
|
72
74
|
- Speechify requires an API key for authentication
|
|
73
75
|
- The default model is 'simba-english'
|
|
76
|
+
- 'simba-3.2' is Speechify's latest streaming model with the lowest latency and richest expressivity, and the recommended model for English
|
|
77
|
+
- 'simba-3.2' and 'simba-3.0' are currently English only; use 'simba-multilingual' for non-English or mixed-language input
|
|
78
|
+
- 'simba-3.2' and 'simba-3.0' serve a curated voice set only: 'beatrice\_32', 'dominic\_32', 'edmund\_32', 'geffen\_32', 'harper\_32', 'hugh\_32', 'imogen\_32', 'wyatt\_32'. Classic catalog voices such as 'george' return an error on these models
|
|
79
|
+
- The default speaker follows the configured model: 'harper\_32' for the Simba 3 models, otherwise 'george'
|
|
74
80
|
- Speech-to-text functionality isn't supported
|
|
75
81
|
- Additional audio stream options can be passed through the speak() method's options parameter
|
package/dist/index.cjs
CHANGED
|
@@ -265,6 +265,16 @@ var MastraVoice = class extends MastraBase {
|
|
|
265
265
|
};
|
|
266
266
|
|
|
267
267
|
// src/voices.ts
|
|
268
|
+
var SIMBA_3_VOICES = [
|
|
269
|
+
"beatrice_32",
|
|
270
|
+
"dominic_32",
|
|
271
|
+
"edmund_32",
|
|
272
|
+
"geffen_32",
|
|
273
|
+
"harper_32",
|
|
274
|
+
"hugh_32",
|
|
275
|
+
"imogen_32",
|
|
276
|
+
"wyatt_32"
|
|
277
|
+
];
|
|
268
278
|
var SPEECHIFY_VOICES = [
|
|
269
279
|
"henry",
|
|
270
280
|
"bwyneth",
|
|
@@ -976,15 +986,19 @@ var SPEECHIFY_VOICES = [
|
|
|
976
986
|
];
|
|
977
987
|
|
|
978
988
|
// src/index.ts
|
|
989
|
+
var isSimba3Model = (model) => model === "simba-3.0" || model === "simba-3.2";
|
|
979
990
|
var SpeechifyVoice = class extends MastraVoice {
|
|
980
991
|
client;
|
|
981
992
|
constructor({ speechModel, speaker } = {}) {
|
|
993
|
+
const modelName = speechModel?.name ?? "simba-english";
|
|
982
994
|
super({
|
|
983
995
|
speechModel: {
|
|
984
|
-
name:
|
|
996
|
+
name: modelName,
|
|
985
997
|
apiKey: speechModel?.apiKey ?? process.env.SPEECHIFY_API_KEY
|
|
986
998
|
},
|
|
987
|
-
|
|
999
|
+
// The Simba 3 models serve only the curated SIMBA_3_VOICES, so the
|
|
1000
|
+
// default speaker has to follow the configured model.
|
|
1001
|
+
speaker: speaker ?? (isSimba3Model(modelName) ? "harper_32" : "george")
|
|
988
1002
|
});
|
|
989
1003
|
const apiKey = speechModel?.apiKey ?? process.env.SPEECHIFY_API_KEY;
|
|
990
1004
|
if (!apiKey) {
|
|
@@ -993,7 +1007,7 @@ var SpeechifyVoice = class extends MastraVoice {
|
|
|
993
1007
|
this.client = new apiSdk.Speechify({ apiKey });
|
|
994
1008
|
}
|
|
995
1009
|
async getSpeakers() {
|
|
996
|
-
return SPEECHIFY_VOICES.map((voice) => ({
|
|
1010
|
+
return [...SIMBA_3_VOICES, ...SPEECHIFY_VOICES].map((voice) => ({
|
|
997
1011
|
voiceId: voice,
|
|
998
1012
|
name: voice
|
|
999
1013
|
}));
|
|
@@ -1011,11 +1025,14 @@ var SpeechifyVoice = class extends MastraVoice {
|
|
|
1011
1025
|
}
|
|
1012
1026
|
async speak(input, options) {
|
|
1013
1027
|
const text = typeof input === "string" ? input : await this.streamToString(input);
|
|
1028
|
+
const { speaker, model, ...streamOptions } = options ?? {};
|
|
1014
1029
|
const request = {
|
|
1030
|
+
...streamOptions,
|
|
1015
1031
|
input: text,
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1032
|
+
// The SDK sends `model` to the API verbatim, so casting the wider
|
|
1033
|
+
// SpeechifyModel union into its narrower VoiceModelName is safe.
|
|
1034
|
+
model: model || this.speechModel?.name,
|
|
1035
|
+
voiceId: speaker || this.speaker
|
|
1019
1036
|
};
|
|
1020
1037
|
const webStream = await this.client.audioStream(request);
|
|
1021
1038
|
const reader = webStream.getReader();
|