@juspay/neurolink 12.47.13 → 12.48.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 +3 -3
- package/dist/auth/middleware/AuthMiddleware.d.ts +1 -1
- package/dist/browser/neurolink.min.js +578 -565
- package/dist/cli/factories/commandFactory.d.ts +7 -0
- package/dist/cli/factories/commandFactory.js +26 -0
- package/dist/cli/loop/optionsSchema.js +9 -0
- package/dist/context/budgetChecker.js +54 -2
- package/dist/context/contextDecision.js +2 -0
- package/dist/context/toolPairRepair.d.ts +12 -0
- package/dist/context/toolPairRepair.js +29 -3
- package/dist/core/baseProvider.d.ts +92 -3
- package/dist/core/baseProvider.js +254 -10
- package/dist/core/conversationMemoryManager.js +17 -2
- package/dist/core/loopEngine.js +1 -1
- package/dist/core/modules/MessageBuilder.js +11 -3
- package/dist/core/modules/TelemetryHandler.d.ts +2 -2
- package/dist/core/modules/ToolsManager.d.ts +35 -0
- package/dist/core/modules/ToolsManager.js +159 -55
- package/dist/core/nativeGenerateLoop.d.ts +58 -1
- package/dist/core/nativeGenerateLoop.js +277 -3
- package/dist/core/redisConversationMemoryManager.js +10 -3
- package/dist/core/resolveRequestKind.d.ts +24 -4
- package/dist/core/resolveRequestKind.js +31 -4
- package/dist/core/toolExecutionRecorder.d.ts +6 -0
- package/dist/core/toolExecutionRecorder.js +24 -2
- package/dist/core/toolRoutingDecision.js +1 -0
- package/dist/factories/mediaHandlerCatalog.js +5 -0
- package/dist/factories/providerDescriptors.js +15 -0
- package/dist/files/fileTools.d.ts +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +9 -2
- package/dist/memory/condensationPrompt.d.ts +8 -0
- package/dist/memory/condensationPrompt.js +29 -0
- package/dist/memory/hippocampusInitializer.d.ts +14 -2
- package/dist/memory/hippocampusInitializer.js +64 -3
- package/dist/neurolink.d.ts +252 -3
- package/dist/neurolink.js +898 -43
- package/dist/providers/amazonBedrock/client.js +6 -0
- package/dist/providers/amazonSagemaker.js +14 -1
- package/dist/providers/anthropic/client.js +148 -19
- package/dist/providers/anthropic/loopAdapter.js +2 -2
- package/dist/providers/googleAiStudio/client.js +29 -14
- package/dist/providers/openaiChatCompletionsBase.js +103 -23
- package/dist/providers/systemOneDecision.d.ts +6 -0
- package/dist/providers/systemOneDecision.js +14 -63
- package/dist/providers/typesafe.d.ts +6 -0
- package/dist/providers/typesafe.js +6 -0
- package/dist/rag/retrieval/searchDecision.js +1 -0
- package/dist/routing/classifierRouter.js +6 -5
- package/dist/routing/classifierStrategies.js +8 -1
- package/dist/types/classifierRouter.d.ts +16 -3
- package/dist/types/common.d.ts +2 -0
- package/dist/types/config.d.ts +9 -0
- package/dist/types/context.d.ts +8 -1
- package/dist/types/conversation.d.ts +87 -0
- package/dist/types/decision.d.ts +210 -1
- package/dist/types/decision.js +9 -1
- package/dist/types/dispatch.d.ts +11 -4
- package/dist/types/generate.d.ts +118 -54
- package/dist/types/loopEngine.d.ts +7 -2
- package/dist/types/memory.d.ts +177 -9
- package/dist/types/openaiCompatible.d.ts +11 -3
- package/dist/types/stream.d.ts +13 -16
- package/dist/types/stt.d.ts +58 -1
- package/dist/types/tools.d.ts +14 -0
- package/dist/types/tools.js +8 -0
- package/dist/types/tts.d.ts +108 -0
- package/dist/types/voice.d.ts +41 -4
- package/dist/utils/decisionAnswers.d.ts +31 -1
- package/dist/utils/decisionAnswers.js +114 -0
- package/dist/utils/decisionLimits.d.ts +39 -0
- package/dist/utils/decisionLimits.js +116 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +9 -0
- package/dist/utils/messageBuilder.d.ts +45 -1
- package/dist/utils/messageBuilder.js +393 -16
- package/dist/utils/multimodalOptionsBuilder.d.ts +1 -0
- package/dist/utils/multimodalOptionsBuilder.js +1 -0
- package/dist/utils/speechText.d.ts +41 -0
- package/dist/utils/speechText.js +364 -0
- package/dist/utils/toolResultStatus.d.ts +26 -0
- package/dist/utils/toolResultStatus.js +73 -0
- package/dist/utils/ttsProcessor.d.ts +29 -0
- package/dist/utils/ttsProcessor.js +84 -2
- package/dist/voice/index.d.ts +1 -0
- package/dist/voice/index.js +3 -0
- package/dist/voice/providers/ElevenLabsSTT.d.ts +42 -0
- package/dist/voice/providers/ElevenLabsSTT.js +351 -0
- package/dist/voice/providers/ElevenLabsTTS.d.ts +81 -1
- package/dist/voice/providers/ElevenLabsTTS.js +415 -74
- package/docs-site/static/search-index.json +48 -33
- package/package.json +5 -2
- package/dist/utils/toolEndEmitter.d.ts +0 -25
- package/dist/utils/toolEndEmitter.js +0 -64
package/dist/types/memory.d.ts
CHANGED
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* re-export) keep their original public names — only their definitions
|
|
20
20
|
* move from `import("@juspay/hippocampus").Foo` to local structural form.
|
|
21
21
|
*/
|
|
22
|
+
import type { TokenUsage } from "./analytics.js";
|
|
23
|
+
import type { AdditionalMemoryUser } from "./generate.js";
|
|
24
|
+
import type { NeurolinkCredentials } from "./providers.js";
|
|
22
25
|
export type MemorySqliteStorageConfig = {
|
|
23
26
|
type: "sqlite";
|
|
24
27
|
/** Path to SQLite file. Default: ./data/hippocampus.sqlite */
|
|
@@ -56,17 +59,159 @@ export type HippocampusAddOptions = {
|
|
|
56
59
|
prompt?: string;
|
|
57
60
|
maxWords?: number;
|
|
58
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* The exact request shape Hippocampus's condenser sends to `generate()`
|
|
64
|
+
* (`@juspay/hippocampus` `src/client.ts`, the `neurolink.generate({...})`
|
|
65
|
+
* call inside `add()`). A full `NeuroLink` instance satisfies this
|
|
66
|
+
* structurally; so does any host object that can answer a plain text prompt.
|
|
67
|
+
*/
|
|
68
|
+
export type HippocampusCondenserGenerateOptions = {
|
|
69
|
+
input: {
|
|
70
|
+
text: string;
|
|
71
|
+
};
|
|
72
|
+
provider?: string;
|
|
73
|
+
model?: string;
|
|
74
|
+
temperature?: number;
|
|
75
|
+
disableTools?: boolean;
|
|
76
|
+
};
|
|
77
|
+
/** The only field Hippocampus reads back from the condensation call. */
|
|
78
|
+
export type HippocampusCondenserResult = {
|
|
79
|
+
content?: string;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Minimal `generate()`-bearing object Hippocampus can use for condensation
|
|
83
|
+
* instead of constructing its own bare `new NeuroLink()`.
|
|
84
|
+
*/
|
|
85
|
+
export type HippocampusNeurolinkLike = {
|
|
86
|
+
generate: (options: HippocampusCondenserGenerateOptions) => Promise<HippocampusCondenserResult>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Condenser settings forwarded to Hippocampus.
|
|
90
|
+
*
|
|
91
|
+
* `provider` / `model` / `temperature` select the condensation model.
|
|
92
|
+
* `credentials` and `instance` are read by `@juspay/hippocampus` ≥0.2.0;
|
|
93
|
+
* the peer floor is 0.2.1, which also substitutes the condensation
|
|
94
|
+
* placeholders literally (user content containing `$&` no longer corrupts
|
|
95
|
+
* the prompt). NeuroLink always fills `instance` itself — a dedicated
|
|
96
|
+
* child instance that carries this instance's `credentials` — unless the
|
|
97
|
+
* host supplies one, so condensation stops depending on provider keys being
|
|
98
|
+
* present in `process.env`.
|
|
99
|
+
*/
|
|
100
|
+
export type HippocampusNeurolinkConfig = {
|
|
101
|
+
provider?: string;
|
|
102
|
+
model?: string;
|
|
103
|
+
temperature?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Credentials for the condenser's own NeuroLink instance. Defaults to the
|
|
106
|
+
* parent `new NeuroLink({ credentials })` value.
|
|
107
|
+
*/
|
|
108
|
+
credentials?: NeurolinkCredentials;
|
|
109
|
+
/**
|
|
110
|
+
* Host-managed condenser. When set, NeuroLink does not build a child
|
|
111
|
+
* instance and passes this object through untouched.
|
|
112
|
+
*/
|
|
113
|
+
instance?: HippocampusNeurolinkLike;
|
|
114
|
+
};
|
|
59
115
|
/** Constructor config accepted by the Hippocampus class. */
|
|
60
116
|
export type HippocampusConfig = {
|
|
61
117
|
storage?: HippocampusStorageConfig;
|
|
62
118
|
prompt?: string;
|
|
63
|
-
neurolink?:
|
|
64
|
-
provider?: string;
|
|
65
|
-
model?: string;
|
|
66
|
-
temperature?: number;
|
|
67
|
-
};
|
|
119
|
+
neurolink?: HippocampusNeurolinkConfig;
|
|
68
120
|
maxWords?: number;
|
|
69
121
|
};
|
|
122
|
+
/**
|
|
123
|
+
* One completed turn as seen by the memory write hooks. `usage`,
|
|
124
|
+
* `finishReason` and `toolsUsed` are best-effort: the generate path has the
|
|
125
|
+
* full result, the stream path only knows the provider, the accumulated
|
|
126
|
+
* text and this request's own stream result's tool names.
|
|
127
|
+
*/
|
|
128
|
+
export type MemoryTurn = {
|
|
129
|
+
/** The caller's original prompt, before memory context was prepended. */
|
|
130
|
+
prompt: string;
|
|
131
|
+
/** The assistant's final text, trimmed. */
|
|
132
|
+
response: string;
|
|
133
|
+
/** Primary memory owner — `context.userId`. */
|
|
134
|
+
userId: string;
|
|
135
|
+
/** `context.sessionId`, when the call carried one. */
|
|
136
|
+
sessionId?: string;
|
|
137
|
+
provider?: string;
|
|
138
|
+
model?: string;
|
|
139
|
+
/** Names of tools that ran during the turn. */
|
|
140
|
+
toolsUsed?: string[];
|
|
141
|
+
/** Token usage — generate path only. */
|
|
142
|
+
usage?: TokenUsage;
|
|
143
|
+
/** Provider finish reason — generate path only. */
|
|
144
|
+
finishReason?: string;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Gate that decides whether a turn is written to memory at all. Runs inside
|
|
148
|
+
* the deferred background write, never on the response path. Returning
|
|
149
|
+
* `false` skips every `add()` for the turn (primary owner and
|
|
150
|
+
* `additionalUsers`). A thrown error is logged and treated as `false`.
|
|
151
|
+
*/
|
|
152
|
+
export type MemoryShouldWriteHook = (turn: MemoryTurn) => boolean | Promise<boolean>;
|
|
153
|
+
/**
|
|
154
|
+
* Transform (or veto) the exact text handed to `Hippocampus.add()`. Receives
|
|
155
|
+
* the default `"User: …\nAssistant: …"` rendering; return a replacement
|
|
156
|
+
* string, or `null` to skip the write. A thrown error is logged and the
|
|
157
|
+
* write is skipped — a missed memory is recoverable, a polluted condensed
|
|
158
|
+
* summary is not.
|
|
159
|
+
*/
|
|
160
|
+
export type MemoryBeforeStoreHook = (content: string, turn: MemoryTurn) => string | null | Promise<string | null>;
|
|
161
|
+
/**
|
|
162
|
+
* Write-side hooks accepted both per call (`generate({ memory })` /
|
|
163
|
+
* `stream({ memory })`) and on the instance
|
|
164
|
+
* (`conversationMemory.memory`). When both are set for the same hook, the
|
|
165
|
+
* per-call one wins for that call.
|
|
166
|
+
*/
|
|
167
|
+
export type MemoryWriteHooks = {
|
|
168
|
+
shouldWrite?: MemoryShouldWriteHook;
|
|
169
|
+
onBeforeStore?: MemoryBeforeStoreHook;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Per-call `memory` block shared by `GenerateOptions` and `StreamOptions`.
|
|
173
|
+
*
|
|
174
|
+
* Overrides the instance-level memory behaviour for one call. All flags
|
|
175
|
+
* default to `true` when the instance memory SDK is enabled; when it is
|
|
176
|
+
* disabled this block has no effect.
|
|
177
|
+
*/
|
|
178
|
+
export type MemoryCallOptions = MemoryWriteHooks & {
|
|
179
|
+
/** Master toggle for this call. When false, both read and write are skipped. Defaults to true. */
|
|
180
|
+
enabled?: boolean;
|
|
181
|
+
/** Whether to read condensed memory and prepend to prompt. Defaults to true. */
|
|
182
|
+
read?: boolean;
|
|
183
|
+
/** Whether to write (add/condense) the conversation into memory after completion. Defaults to true. */
|
|
184
|
+
write?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Additional users whose memory should be retrieved/stored alongside the primary user.
|
|
187
|
+
* Each entry can override the condensation prompt and maxWords for that user.
|
|
188
|
+
* Primary user is still determined by context.userId.
|
|
189
|
+
*/
|
|
190
|
+
additionalUsers?: AdditionalMemoryUser[];
|
|
191
|
+
/**
|
|
192
|
+
* Condensation prompt for the primary owner on this call. Precedence:
|
|
193
|
+
* per-call > instance `conversationMemory.memory.prompt` > Hippocampus
|
|
194
|
+
* default. Must contain `{{OLD_MEMORY}}` and `{{NEW_CONTENT}}`; a template
|
|
195
|
+
* missing either is logged and the instance prompt is used instead. An
|
|
196
|
+
* empty or whitespace-only string counts as unset.
|
|
197
|
+
*/
|
|
198
|
+
prompt?: string;
|
|
199
|
+
/** Max words for the primary owner's condensed memory on this call. */
|
|
200
|
+
maxWords?: number;
|
|
201
|
+
};
|
|
202
|
+
/** Placeholder names a condensation prompt template can carry. */
|
|
203
|
+
export type CondensationPlaceholder = "OLD_MEMORY" | "NEW_CONTENT" | "MAX_WORDS";
|
|
204
|
+
/**
|
|
205
|
+
* Result of `validateCondensationPrompt()`. `missing` lists every absent
|
|
206
|
+
* placeholder; `fatal` is the subset whose absence breaks memory
|
|
207
|
+
* (`OLD_MEMORY`: each turn overwrites the summary; `NEW_CONTENT`: memory
|
|
208
|
+
* never grows). A missing `MAX_WORDS` only loses the word cap.
|
|
209
|
+
*/
|
|
210
|
+
export type CondensationPromptValidation = {
|
|
211
|
+
valid: boolean;
|
|
212
|
+
missing: CondensationPlaceholder[];
|
|
213
|
+
fatal: CondensationPlaceholder[];
|
|
214
|
+
};
|
|
70
215
|
/**
|
|
71
216
|
* Subset of the @juspay/hippocampus client surface that NeuroLink core
|
|
72
217
|
* actually calls. Defining this locally lets the initializer / SDK code
|
|
@@ -78,13 +223,36 @@ export type HippocampusLike = {
|
|
|
78
223
|
delete: (ownerId: string) => Promise<void>;
|
|
79
224
|
close: () => Promise<void>;
|
|
80
225
|
};
|
|
226
|
+
/** Builds a Hippocampus-compatible client from the config NeuroLink assembled. */
|
|
227
|
+
export type HippocampusClientFactory = (config: HippocampusConfig) => HippocampusLike;
|
|
81
228
|
/**
|
|
82
|
-
* Consumer-facing memory config.
|
|
83
|
-
*
|
|
84
|
-
*
|
|
229
|
+
* Consumer-facing memory config. The `enabled` flag toggles activation; the
|
|
230
|
+
* `HippocampusConfig` part is passed to the Hippocampus constructor when the
|
|
231
|
+
* optional package is installed. The remaining fields are NeuroLink-side and
|
|
232
|
+
* never reach Hippocampus.
|
|
85
233
|
*/
|
|
86
|
-
export type HippocampusMemory = HippocampusConfig & {
|
|
234
|
+
export type HippocampusMemory = HippocampusConfig & MemoryWriteHooks & {
|
|
87
235
|
enabled?: boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Host-managed Hippocampus client (or any object with the same
|
|
238
|
+
* `add/get/delete/close` surface). When set, NeuroLink skips loading and
|
|
239
|
+
* constructing `@juspay/hippocampus` and uses this instance directly.
|
|
240
|
+
* `add()` and `get()` are what core calls and must both be functions;
|
|
241
|
+
* a client missing either disables memory with an `error` log.
|
|
242
|
+
*
|
|
243
|
+
* As a factory it receives the `HippocampusConfig` NeuroLink assembled —
|
|
244
|
+
* including the credentialed condenser under `neurolink.instance` — so a
|
|
245
|
+
* host can construct its own client (a subclass, a different version, a
|
|
246
|
+
* test double) from exactly what `new Hippocampus(config)` would get.
|
|
247
|
+
*/
|
|
248
|
+
client?: HippocampusLike | HippocampusClientFactory;
|
|
249
|
+
/**
|
|
250
|
+
* When true, a condensation prompt template (instance `prompt` or
|
|
251
|
+
* `HC_CONDENSATION_PROMPT`) missing `{{OLD_MEMORY}}` or `{{NEW_CONTENT}}`
|
|
252
|
+
* makes the constructor throw instead of the default disable-and-log
|
|
253
|
+
* (at `error`). An empty or whitespace-only template counts as unset.
|
|
254
|
+
*/
|
|
255
|
+
strictPrompt?: boolean;
|
|
88
256
|
};
|
|
89
257
|
/**
|
|
90
258
|
* Shape of the dynamically-required `@juspay/hippocampus` module surface
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { DeferredUsage
|
|
1
|
+
import type { DeferredUsage } from "./common.js";
|
|
2
2
|
import type { JSONSchema7 } from "./middleware.js";
|
|
3
3
|
import type { LanguageModelV3, LanguageModelV3CallOptions } from "./middleware.js";
|
|
4
4
|
import type { StreamOptions } from "./stream.js";
|
|
5
5
|
import type { Tool } from "./tools.js";
|
|
6
|
+
import type { StepResult } from "./providers.js";
|
|
6
7
|
export type OpenAICompatChatRole = "system" | "user" | "assistant" | "tool";
|
|
7
8
|
export type OpenAICompatTextContent = {
|
|
8
9
|
type: "text";
|
|
@@ -223,6 +224,8 @@ export type ToolExecutionSummaryInternal = {
|
|
|
223
224
|
error?: string;
|
|
224
225
|
startTime: Date;
|
|
225
226
|
endTime: Date;
|
|
227
|
+
/** Zero-based loop step that ran this tool, when the loop tracks one. */
|
|
228
|
+
stepIndex?: number;
|
|
226
229
|
};
|
|
227
230
|
export type StreamLoopArgs = {
|
|
228
231
|
maxSteps: number;
|
|
@@ -233,11 +236,16 @@ export type StreamLoopArgs = {
|
|
|
233
236
|
options: StreamOptions;
|
|
234
237
|
conversation: OpenAICompatChatMessage[];
|
|
235
238
|
openAITools: OpenAICompatChatTool[] | undefined;
|
|
236
|
-
|
|
239
|
+
/**
|
|
240
|
+
* The wire `tool_choice` for one step. A function rather than a value
|
|
241
|
+
* because a forced choice applies only to the first `toolChoiceSteps`
|
|
242
|
+
* steps, and a caller's `prepareStep` hook may override it per step;
|
|
243
|
+
* `steps` is the record of the steps completed so far, handed to that hook.
|
|
244
|
+
*/
|
|
245
|
+
stepToolChoice: (step: number, steps: StepResult<Record<string, Tool>>[]) => Promise<OpenAICompatToolChoiceWire | undefined>;
|
|
237
246
|
toolsRecord: Record<string, Tool>;
|
|
238
247
|
/** Wire → registered tool-name map when sanitization was needed (see buildWireToolNameMaps). */
|
|
239
248
|
toolNameFromWire?: Map<string, string>;
|
|
240
|
-
emitter: TypedEventEmitter<NeuroLinkEvents> | undefined;
|
|
241
249
|
toolsUsed: string[];
|
|
242
250
|
toolExecutionSummaries: ToolExecutionSummaryInternal[];
|
|
243
251
|
pushChunk: (chunk: OpenAICompatStreamChunk) => void;
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -9,9 +9,10 @@ import type { TokenUsage } from "./analytics.js";
|
|
|
9
9
|
import type { JsonValue, UnknownRecord } from "./common.js";
|
|
10
10
|
import type { TerminalAgentModeOption, TerminalAgentModeVersion } from "./agentMode.js";
|
|
11
11
|
import type { Content, ImageWithAltText } from "./content.js";
|
|
12
|
-
import type { ChatMessage } from "./conversation.js";
|
|
12
|
+
import type { ChatMessage, ToolReplayMode } from "./conversation.js";
|
|
13
13
|
import type { StreamNoOutputSentinel } from "./noOutputSentinel.js";
|
|
14
|
-
import type {
|
|
14
|
+
import type { GenerateStopReason, TTSMetadata, ToolExecutionCaptureOptions } from "./generate.js";
|
|
15
|
+
import type { MemoryCallOptions } from "./memory.js";
|
|
15
16
|
import type { AIModelProviderConfig, NeurolinkCredentials } from "./providers.js";
|
|
16
17
|
import type { TTSChunk, TTSOptions, TTSResult } from "./tts.js";
|
|
17
18
|
import type { STTOptions, STTResult } from "./stt.js";
|
|
@@ -580,10 +581,18 @@ export type StreamOptions = {
|
|
|
580
581
|
/**
|
|
581
582
|
* Tool choice configuration for streaming generation.
|
|
582
583
|
* Mirrors generate() so translated/fallback requests can preserve forced tool use.
|
|
584
|
+
* A forced choice (`"required"` or a named tool) is applied only to the
|
|
585
|
+
* first `toolChoiceSteps` steps (default 1); see GenerateOptions.toolChoice.
|
|
583
586
|
*/
|
|
584
587
|
toolChoice?: ToolChoice<Record<string, Tool>>;
|
|
588
|
+
/** Leading steps a forced `toolChoice` stays in force (default 1). See GenerateOptions.toolChoiceSteps. */
|
|
589
|
+
toolChoiceSteps?: number;
|
|
590
|
+
/** How stored tool steps are replayed into the prompt. See GenerateOptions.replayToolSteps. */
|
|
591
|
+
replayToolSteps?: ToolReplayMode;
|
|
585
592
|
/**
|
|
586
593
|
* Optional callback that runs before each stream step in a multi-step generation.
|
|
594
|
+
* Only a returned `toolChoice` is honoured (for that step); `activeTools` is
|
|
595
|
+
* accepted but ignored. See GenerateOptions.prepareStep.
|
|
587
596
|
*/
|
|
588
597
|
prepareStep?: (options: {
|
|
589
598
|
steps: StepResult<Record<string, Tool>>[];
|
|
@@ -739,21 +748,9 @@ export type StreamOptions = {
|
|
|
739
748
|
* Override the global memory SDK behavior for this specific call.
|
|
740
749
|
* All flags default to `true` when the global memory SDK is enabled.
|
|
741
750
|
* If the global memory SDK is disabled, these flags have no effect.
|
|
751
|
+
* Shared with `GenerateOptions` — see `MemoryCallOptions`.
|
|
742
752
|
*/
|
|
743
|
-
memory?:
|
|
744
|
-
/** Master toggle for this call. When false, both read and write are skipped. Defaults to true. */
|
|
745
|
-
enabled?: boolean;
|
|
746
|
-
/** Whether to read condensed memory and prepend to prompt. Defaults to true. */
|
|
747
|
-
read?: boolean;
|
|
748
|
-
/** Whether to write (add/condense) the conversation into memory after completion. Defaults to true. */
|
|
749
|
-
write?: boolean;
|
|
750
|
-
/**
|
|
751
|
-
* Additional users whose memory should be retrieved/stored alongside the primary user.
|
|
752
|
-
* Each entry can override the condensation prompt and maxWords for that user.
|
|
753
|
-
* Primary user is still determined by context.userId.
|
|
754
|
-
*/
|
|
755
|
-
additionalUsers?: AdditionalMemoryUser[];
|
|
756
|
-
};
|
|
753
|
+
memory?: MemoryCallOptions;
|
|
757
754
|
/** PII detection — scans and optionally redacts PII from input before the LLM call. */
|
|
758
755
|
piiDetection?: {
|
|
759
756
|
enabled?: boolean;
|
package/dist/types/stt.d.ts
CHANGED
|
@@ -51,10 +51,25 @@ export type STTOptions = {
|
|
|
51
51
|
/**
|
|
52
52
|
* STT result from transcription
|
|
53
53
|
*/
|
|
54
|
+
/**
|
|
55
|
+
* Where a provider's `STTResult.confidence` came from, when it has to say —
|
|
56
|
+
* Scribe reports a per-word `logprob` on some responses and only a
|
|
57
|
+
* language-detection probability on others, and a caller reading the number
|
|
58
|
+
* should know which it is getting. `"none"` means the provider reported no
|
|
59
|
+
* transcript-level signal at all and the field is 0.
|
|
60
|
+
*/
|
|
61
|
+
export type STTConfidenceSource = "word_logprobs" | "language_probability" | "none";
|
|
54
62
|
export type STTResult = {
|
|
55
63
|
/** Full transcribed text */
|
|
56
64
|
text: string;
|
|
57
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Transcript confidence (0-1) — Deepgram's alternative confidence,
|
|
67
|
+
* Whisper's `exp(avg_logprob)`, Scribe's mean per-word `exp(logprob)`.
|
|
68
|
+
* Always present: a strict-TS consumer reads it without a guard. A provider
|
|
69
|
+
* with no transcript-level signal reports 0 and, where it can, says so in
|
|
70
|
+
* `metadata.confidenceSource` rather than passing off a different number
|
|
71
|
+
* (a language-detection probability, say) as this one silently.
|
|
72
|
+
*/
|
|
58
73
|
confidence: number;
|
|
59
74
|
/** Detected language code */
|
|
60
75
|
language?: string;
|
|
@@ -74,6 +89,8 @@ export type STTResult = {
|
|
|
74
89
|
provider?: string;
|
|
75
90
|
/** Model used */
|
|
76
91
|
model?: string;
|
|
92
|
+
/** What `confidence` was derived from, for providers that must choose. */
|
|
93
|
+
confidenceSource?: STTConfidenceSource;
|
|
77
94
|
/** Additional provider-specific metadata */
|
|
78
95
|
[key: string]: unknown;
|
|
79
96
|
};
|
|
@@ -435,6 +452,46 @@ export type ElevenLabsVoice = {
|
|
|
435
452
|
export type ElevenLabsVoicesResponse = {
|
|
436
453
|
voices: ElevenLabsVoice[];
|
|
437
454
|
};
|
|
455
|
+
/**
|
|
456
|
+
* Scribe model ids the batch `speech-to-text` endpoint accepts. `scribe_v2`
|
|
457
|
+
* is the current model and the default; `scribe_v2_medical` is its clinical
|
|
458
|
+
* fine-tune; `scribe_v1` (and the experimental variant) are deprecated. The
|
|
459
|
+
* `(string & {})` member keeps the union open so a newly released id can be
|
|
460
|
+
* used without a cast.
|
|
461
|
+
*/
|
|
462
|
+
export type ElevenLabsSTTModel = "scribe_v2" | "scribe_v2_medical" | "scribe_v1" | "scribe_v1_experimental" | (string & {});
|
|
463
|
+
export type ElevenLabsSTTOptions = STTOptions & {
|
|
464
|
+
/** Scribe model id. Default `scribe_v2`. */
|
|
465
|
+
model?: ElevenLabsSTTModel;
|
|
466
|
+
/**
|
|
467
|
+
* Annotate non-speech audio events ("(laughter)", "(music)") in the
|
|
468
|
+
* transcript. ElevenLabs defaults this to true; NeuroLink sends `false` so
|
|
469
|
+
* the transcript reads as plain speech unless asked otherwise.
|
|
470
|
+
* @default false
|
|
471
|
+
*/
|
|
472
|
+
tagAudioEvents?: boolean;
|
|
473
|
+
/** Per-request timeout in milliseconds. Default 60_000. */
|
|
474
|
+
timeoutMs?: number;
|
|
475
|
+
/**
|
|
476
|
+
* API base URL including the `/v1` prefix. Default
|
|
477
|
+
* `ELEVENLABS_BASE_URL` or `https://api.elevenlabs.io/v1`.
|
|
478
|
+
*/
|
|
479
|
+
baseUrl?: string;
|
|
480
|
+
};
|
|
481
|
+
export type ElevenLabsSTTWord = {
|
|
482
|
+
text: string;
|
|
483
|
+
start?: number;
|
|
484
|
+
end?: number;
|
|
485
|
+
type?: "word" | "spacing" | "audio_event" | string;
|
|
486
|
+
speaker_id?: string;
|
|
487
|
+
logprob?: number;
|
|
488
|
+
};
|
|
489
|
+
export type ElevenLabsSTTResponse = {
|
|
490
|
+
language_code?: string;
|
|
491
|
+
language_probability?: number;
|
|
492
|
+
text: string;
|
|
493
|
+
words?: ElevenLabsSTTWord[];
|
|
494
|
+
};
|
|
438
495
|
export type AzureVoiceInfo = {
|
|
439
496
|
Name: string;
|
|
440
497
|
DisplayName: string;
|
package/dist/types/tools.d.ts
CHANGED
|
@@ -358,6 +358,8 @@ export type ToolEventPayload = {
|
|
|
358
358
|
timestamp?: number;
|
|
359
359
|
duration?: number;
|
|
360
360
|
executionId?: string;
|
|
361
|
+
/** The model's tool-call id when the loop supplied one, for pairing start/end. */
|
|
362
|
+
toolCallId?: string;
|
|
361
363
|
};
|
|
362
364
|
/**
|
|
363
365
|
* Tool execution summary for completed executions
|
|
@@ -570,3 +572,15 @@ export type BashToolResult = {
|
|
|
570
572
|
stderr: string;
|
|
571
573
|
error?: string;
|
|
572
574
|
};
|
|
575
|
+
/**
|
|
576
|
+
* Own property stamped on a tool object whose `execute` already emits one
|
|
577
|
+
* `tool:start` / `tool:end` pair per execution. It lives on the OBJECT, not
|
|
578
|
+
* the function: later layers (the execution recorder, discovery) replace
|
|
579
|
+
* `execute` via `{ ...tool, execute }`, which drops a function-identity check
|
|
580
|
+
* but carries a symbol-keyed own property along.
|
|
581
|
+
*/
|
|
582
|
+
export declare const TOOL_EVENTS_WRAPPED: unique symbol;
|
|
583
|
+
/** A `Tool` that may carry the {@link TOOL_EVENTS_WRAPPED} marker. */
|
|
584
|
+
export type EventWrappedTool = Tool & {
|
|
585
|
+
[TOOL_EVENTS_WRAPPED]?: true;
|
|
586
|
+
};
|
package/dist/types/tools.js
CHANGED
|
@@ -22,3 +22,11 @@ export function isToolDefinition(value) {
|
|
|
22
22
|
typeof value.description === "string" &&
|
|
23
23
|
typeof value.execute === "function");
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Own property stamped on a tool object whose `execute` already emits one
|
|
27
|
+
* `tool:start` / `tool:end` pair per execution. It lives on the OBJECT, not
|
|
28
|
+
* the function: later layers (the execution recorder, discovery) replace
|
|
29
|
+
* `execute` via `{ ...tool, execute }`, which drops a function-identity check
|
|
30
|
+
* but carries a symbol-keyed own property along.
|
|
31
|
+
*/
|
|
32
|
+
export const TOOL_EVENTS_WRAPPED = Symbol.for("neurolink.toolEventsWrapped");
|
package/dist/types/tts.d.ts
CHANGED
|
@@ -25,12 +25,80 @@ export type TTSQuality = "standard" | "hd";
|
|
|
25
25
|
* still surfacing the built-in choices in editor autocomplete.
|
|
26
26
|
*/
|
|
27
27
|
export type TTSProviderName = "google-ai" | "vertex" | "openai-tts" | "elevenlabs" | "elevenlabs-tts" | "azure-tts" | "fish-audio" | "sixtydb" | "cartesia" | (string & {});
|
|
28
|
+
/**
|
|
29
|
+
* What `generate({ tts })` synthesizes.
|
|
30
|
+
*
|
|
31
|
+
* - `"direct"` — the input text / prompt itself, with no LLM call. This is
|
|
32
|
+
* the default, and what every documented "speak this text" caller relies
|
|
33
|
+
* on.
|
|
34
|
+
* - `"response"` — the model's generated reply, after generation completes.
|
|
35
|
+
*
|
|
36
|
+
* `stream()` always synthesizes the streamed response and ignores this.
|
|
37
|
+
*/
|
|
38
|
+
export type TTSSynthesisMode = "direct" | "response";
|
|
39
|
+
/**
|
|
40
|
+
* Options for {@link prepareTextForSpeech} — the optional cleanup pass that
|
|
41
|
+
* turns model output (markdown, URLs, emoji) into text a TTS voice can read
|
|
42
|
+
* aloud. Every default below is what `tts: { sanitize: true }` applies.
|
|
43
|
+
*/
|
|
44
|
+
export type SpeechSanitizeOptions = {
|
|
45
|
+
/**
|
|
46
|
+
* Strip markdown syntax: headings, emphasis, inline code, list bullets,
|
|
47
|
+
* blockquotes, tables (kept as comma-separated rows), links and images
|
|
48
|
+
* (kept as their text). Fenced code blocks follow `codeBlocks`.
|
|
49
|
+
* @default true
|
|
50
|
+
*/
|
|
51
|
+
markdown?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* How fenced code blocks are spoken. `"drop"` removes them entirely,
|
|
54
|
+
* `"phrase"` replaces each block with `codeBlockPhrase`, `"keep"` strips
|
|
55
|
+
* only the fence lines and reads the contents. Incremental `stream()`
|
|
56
|
+
* synthesis always uses `"keep"`: a segment may hold an unterminated fence,
|
|
57
|
+
* so the block's extent is unknowable per segment.
|
|
58
|
+
* @default "phrase"
|
|
59
|
+
*/
|
|
60
|
+
codeBlocks?: "drop" | "phrase" | "keep";
|
|
61
|
+
/**
|
|
62
|
+
* Spoken stand-in for a fenced code block when `codeBlocks` is `"phrase"`.
|
|
63
|
+
* @default "Code block omitted."
|
|
64
|
+
*/
|
|
65
|
+
codeBlockPhrase?: string;
|
|
66
|
+
/**
|
|
67
|
+
* How URLs are spoken. `"hostname"` reduces `https://docs.example.com/a/b`
|
|
68
|
+
* to `docs.example.com`; `"remove"` drops the URL altogether.
|
|
69
|
+
* @default "hostname"
|
|
70
|
+
*/
|
|
71
|
+
urls?: "hostname" | "remove";
|
|
72
|
+
/**
|
|
73
|
+
* Remove emoji and pictographs (`\p{Extended_Pictographic}`,
|
|
74
|
+
* `\p{Emoji_Presentation}`, plus modifiers and joiners).
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
emoji?: boolean;
|
|
78
|
+
};
|
|
79
|
+
/** {@link SpeechSanitizeOptions} with every default applied. */
|
|
80
|
+
export type ResolvedSpeechSanitizeOptions = Required<SpeechSanitizeOptions>;
|
|
28
81
|
/**
|
|
29
82
|
* TTS configuration options
|
|
30
83
|
*/
|
|
31
84
|
export type TTSOptions = {
|
|
32
85
|
/** Enable TTS output */
|
|
33
86
|
enabled?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* What to synthesize: the input text (`"direct"`, the default) or the
|
|
89
|
+
* model's reply (`"response"`). An explicit `mode` wins over the legacy
|
|
90
|
+
* `useAiResponse` flag. Ignored by `stream()`, which always synthesizes the
|
|
91
|
+
* streamed response.
|
|
92
|
+
*
|
|
93
|
+
* @example Speak the model's reply
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const result = await neurolink.generate({
|
|
96
|
+
* input: { text: "Tell me a joke" },
|
|
97
|
+
* tts: { enabled: true, mode: "response" },
|
|
98
|
+
* });
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
mode?: TTSSynthesisMode;
|
|
34
102
|
/**
|
|
35
103
|
* Use the AI-generated response for TTS instead of the input text
|
|
36
104
|
*
|
|
@@ -41,6 +109,8 @@ export type TTSOptions = {
|
|
|
41
109
|
* When true: TTS will synthesize the AI-generated response after generation completes
|
|
42
110
|
*
|
|
43
111
|
* @default false
|
|
112
|
+
* @deprecated Use `mode: "response"` / `mode: "direct"` instead. Still
|
|
113
|
+
* honoured when `mode` is not set.
|
|
44
114
|
*
|
|
45
115
|
* @example Using input text directly (default)
|
|
46
116
|
* ```typescript
|
|
@@ -63,12 +133,37 @@ export type TTSOptions = {
|
|
|
63
133
|
* ```
|
|
64
134
|
*/
|
|
65
135
|
useAiResponse?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Clean the text before it reaches the voice: strip markdown, reduce URLs
|
|
138
|
+
* to their hostname, drop emoji. `true` applies the defaults of
|
|
139
|
+
* {@link SpeechSanitizeOptions}; an object tunes them. Off by default so
|
|
140
|
+
* existing callers get byte-identical synthesis input. In `stream()` the
|
|
141
|
+
* pass runs per segment with fenced code kept (fence lines stripped).
|
|
142
|
+
* @default false
|
|
143
|
+
*/
|
|
144
|
+
sanitize?: boolean | SpeechSanitizeOptions;
|
|
145
|
+
/**
|
|
146
|
+
* Cancels synthesis. A handler that supports it (ElevenLabs) aborts the
|
|
147
|
+
* request in flight and makes no further retry attempt once this fires.
|
|
148
|
+
* `generate()` derives one from its own synthesis timeout and the caller's
|
|
149
|
+
* `abortSignal`, so a handler's retry loop cannot outlive the call that
|
|
150
|
+
* started it and issue a billable request nobody is waiting for.
|
|
151
|
+
*/
|
|
152
|
+
signal?: AbortSignal;
|
|
66
153
|
/** Voice identifier (e.g., "en-US-Neural2-C") */
|
|
67
154
|
voice?: string;
|
|
68
155
|
/** Audio format (default: mp3) */
|
|
69
156
|
format?: TTSAudioFormat;
|
|
70
157
|
/** Speaking rate 0.25-4.0 (default: 1.0) */
|
|
71
158
|
speed?: number;
|
|
159
|
+
/**
|
|
160
|
+
* BCP-47 language tag (e.g. "en-US", "hi") for providers that accept one.
|
|
161
|
+
* Provider-specific: ElevenLabs reduces it to the ISO 639-1 primary subtag
|
|
162
|
+
* (`en-US` → `en`) and forwards it as `language_code` on every model except
|
|
163
|
+
* `eleven_multilingual_v2`, which rejects the field; Cartesia maps it to
|
|
164
|
+
* `language`.
|
|
165
|
+
*/
|
|
166
|
+
language?: string;
|
|
72
167
|
/** Voice pitch adjustment -20.0 to 20.0 semitones (default: 0.0) */
|
|
73
168
|
pitch?: number;
|
|
74
169
|
/** Volume gain in dB -96.0 to 16.0 (default: 0.0) */
|
|
@@ -88,6 +183,19 @@ export type TTSOptions = {
|
|
|
88
183
|
*/
|
|
89
184
|
streamingBufferSize?: number;
|
|
90
185
|
};
|
|
186
|
+
/**
|
|
187
|
+
* Handler-level wall-clock knobs a provider option type may carry (today:
|
|
188
|
+
* `ElevenLabsTTSOptions`). `generate()`'s outer synthesis timeout is raised to
|
|
189
|
+
* at least `timeoutMs × (1 + retries)` plus backoff slack — with the handler
|
|
190
|
+
* defaults (30 s, one retry) standing in for a knob the caller left unset —
|
|
191
|
+
* so a handler's own retry loop is never cut short from outside.
|
|
192
|
+
*/
|
|
193
|
+
export type TTSHandlerTimeBudget = {
|
|
194
|
+
/** Per-attempt request timeout in milliseconds (default 30 000; capped at 2³¹−1). */
|
|
195
|
+
timeoutMs?: number;
|
|
196
|
+
/** Retries after the first attempt (total attempts = 1 + retries). */
|
|
197
|
+
retries?: number;
|
|
198
|
+
};
|
|
91
199
|
/**
|
|
92
200
|
* TTS audio result returned from generation
|
|
93
201
|
*/
|
package/dist/types/voice.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
export * from "./tts.js";
|
|
14
14
|
export * from "./stt.js";
|
|
15
15
|
export * from "./realtime.js";
|
|
16
|
-
import type { TTSAudioFormat, TTSOptions, TTSResult, TTSVoice } from "./tts.js";
|
|
16
|
+
import type { TTSAudioFormat, TTSHandlerTimeBudget, TTSOptions, TTSResult, TTSVoice } from "./tts.js";
|
|
17
17
|
import type { TTSHandler } from "./common.js";
|
|
18
18
|
import type { STTResult, STTHandler } from "./stt.js";
|
|
19
19
|
import type { RealtimeHandler } from "./realtime.js";
|
|
@@ -28,7 +28,7 @@ export type VoiceProviderType = "tts" | "stt" | "realtime";
|
|
|
28
28
|
/**
|
|
29
29
|
* Voice provider name union type
|
|
30
30
|
*/
|
|
31
|
-
export type VoiceProviderName = "google-tts" | "elevenlabs" | "openai-tts" | "sixtydb" | "azure-tts" | "sarvam" | "murf" | "playai" | "speechify" | "cartesia" | "deepgram" | "gladia" | "whisper" | "assemblyai" | "google-stt" | "azure-stt" | "openai-realtime" | "gemini-live";
|
|
31
|
+
export type VoiceProviderName = "google-tts" | "elevenlabs" | "openai-tts" | "sixtydb" | "azure-tts" | "sarvam" | "murf" | "playai" | "speechify" | "cartesia" | "deepgram" | "gladia" | "whisper" | "assemblyai" | "google-stt" | "azure-stt" | "elevenlabs-stt" | "openai-realtime" | "gemini-live";
|
|
32
32
|
/**
|
|
33
33
|
* Base voice provider configuration
|
|
34
34
|
*/
|
|
@@ -264,13 +264,50 @@ export type AzureTTSOptions = TTSOptions & {
|
|
|
264
264
|
*/
|
|
265
265
|
allowRawSSML?: boolean;
|
|
266
266
|
};
|
|
267
|
-
export type ElevenLabsModel = "eleven_multilingual_v2" | "eleven_turbo_v2_5" | "eleven_turbo_v2" | "eleven_monolingual_v1";
|
|
268
|
-
|
|
267
|
+
export type ElevenLabsModel = "eleven_multilingual_v2" | "eleven_turbo_v2_5" | "eleven_turbo_v2" | "eleven_flash_v2_5" | "eleven_flash_v2" | "eleven_v3" | "eleven_monolingual_v1";
|
|
268
|
+
/** Opus bitrates (kbps) ElevenLabs accepts on `opus_48000_*`. */
|
|
269
|
+
export type ElevenLabsOpusBitrate = 32 | 64 | 96 | 128 | 192;
|
|
270
|
+
/** MP3 bitrates (kbps) ElevenLabs accepts on `mp3_44100_*`. */
|
|
271
|
+
export type ElevenLabsMp3Bitrate = 32 | 64 | 96 | 128 | 192;
|
|
272
|
+
/**
|
|
273
|
+
* Every `output_format` value the ElevenLabs text-to-speech endpoint accepts.
|
|
274
|
+
* There is no `ogg_*` family — Ogg/Opus is `opus_48000_<kbps>`.
|
|
275
|
+
*/
|
|
276
|
+
export type ElevenLabsOutputFormat = "mp3_22050_32" | "mp3_44100_32" | "mp3_44100_64" | "mp3_44100_96" | "mp3_44100_128" | "mp3_44100_192" | "opus_48000_32" | "opus_48000_64" | "opus_48000_96" | "opus_48000_128" | "opus_48000_192" | "pcm_8000" | "pcm_16000" | "pcm_22050" | "pcm_24000" | "pcm_44100" | "pcm_48000" | "ulaw_8000" | "alaw_8000";
|
|
277
|
+
/** The `voice_settings` object on an ElevenLabs synthesis request. */
|
|
278
|
+
export type ElevenLabsVoiceSettings = {
|
|
279
|
+
stability?: number;
|
|
280
|
+
similarity_boost?: number;
|
|
281
|
+
style?: number;
|
|
282
|
+
use_speaker_boost?: boolean;
|
|
283
|
+
/** 0.7–1.2; `TTSOptions.speed` is clamped into this range. */
|
|
284
|
+
speed?: number;
|
|
285
|
+
};
|
|
286
|
+
export type ElevenLabsTTSOptions = TTSOptions & TTSHandlerTimeBudget & {
|
|
269
287
|
model?: ElevenLabsModel;
|
|
270
288
|
stability?: number;
|
|
271
289
|
similarityBoost?: number;
|
|
272
290
|
style?: number;
|
|
273
291
|
useSpeakerBoost?: boolean;
|
|
292
|
+
/** Bitrate for `format: "ogg" | "opus"` (→ `opus_48000_<kbps>`). Default 64; an unlisted value falls back to it with a warning. */
|
|
293
|
+
opusBitrate?: ElevenLabsOpusBitrate;
|
|
294
|
+
/** Bitrate for `format: "mp3"` (→ `mp3_44100_<kbps>`). Default 128; an unlisted value falls back to it with a warning. */
|
|
295
|
+
mp3Bitrate?: ElevenLabsMp3Bitrate;
|
|
296
|
+
/**
|
|
297
|
+
* Language sent as `language_code`, an ISO 639-1 code; a BCP-47 tag is
|
|
298
|
+
* reduced to its primary subtag (`en-US` → `en`). Sent on every model
|
|
299
|
+
* except `eleven_multilingual_v2`, which does not accept the field (the
|
|
300
|
+
* API ignores the code on any other model that cannot enforce it).
|
|
301
|
+
* Falls back to the generic `TTSOptions.language`.
|
|
302
|
+
*/
|
|
303
|
+
languageCode?: string;
|
|
304
|
+
/** Raw `voice_settings` overrides; explicit fields win over the camelCase ones. */
|
|
305
|
+
voiceSettings?: ElevenLabsVoiceSettings;
|
|
306
|
+
/**
|
|
307
|
+
* API base URL including the `/v1` prefix. Default
|
|
308
|
+
* `ELEVENLABS_BASE_URL` or `https://api.elevenlabs.io/v1`.
|
|
309
|
+
*/
|
|
310
|
+
baseUrl?: string;
|
|
274
311
|
};
|
|
275
312
|
export type GoogleVoiceType = "Standard" | "WaveNet" | "Neural2" | "Studio" | "Polyglot";
|
|
276
313
|
export type GoogleTTSOptions = TTSOptions & {
|