@pyai/sdk 0.2.2 → 0.3.1
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 +35 -19
- package/dist/index.d.ts +108 -43
- package/dist/index.js +179 -70
- package/package.json +18 -3
- package/src/index.ts +292 -102
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@ dependencies; runs in the browser and Node 18+.
|
|
|
8
8
|
## PyAI products
|
|
9
9
|
|
|
10
10
|
- **[Hear](https://pyai.com/models/hear)**, Lightning-fast, telephony-native **speech-to-text**. Whisper-compatible transcription tuned for real phone-call audio, with live streaming partials so your app reacts mid-sentence, plus async batch transcription for big archives. `POST /v1/audio/transcriptions`
|
|
11
|
-
- **[Speak](https://pyai.com/models/speak)**, Ultra-realistic **text-to-speech** that starts speaking in tens of milliseconds. Stream lifelike, expressive voices, choose from
|
|
11
|
+
- **[Speak](https://pyai.com/models/speak)**, Ultra-realistic **text-to-speech** that starts speaking in tens of milliseconds. Stream lifelike, expressive voices, choose from 144 stock voices, or clone any voice instantly, for free. `POST /v1/audio/speech`
|
|
12
12
|
- **[Omni](https://pyai.com/models/omni)** _(flagship)_, One **API for a complete, end-to-end voice AI agent**. A single WebSocket where your agent listens, thinks, and speaks, grounded in your knowledge bases and tools, with human-like turn-taking and instant barge-in, no STT, LLM, or TTS to stitch together yourself. `wss://api.pyai.com/v1/omni`
|
|
13
13
|
- **[Trace](https://pyai.com/models/trace)** _(flagship)_, The **compliance API that keeps your AI agents safe**. Trace automatically checks every call for HIPAA, TCPA, and PII risks (plus your own brand-voice rules), flags the exact rule broken, redacts sensitive data, and seals each call with a tamper-evident audit trail, so a risky conversation never slips through. `GET /v1/trace/interactions`
|
|
14
|
-
- **
|
|
14
|
+
- **Cue**, reserved turn-detection and grounding fields on Hear streaming. Grounding is not active on the serving route yet.
|
|
15
15
|
- **[AMD](https://pyai.com/models/amd)**, **Answering-machine detection** that tells your dialer who or what answered, human, voicemail, IVR, iPhone/Google screening, dead number, fax, in a fraction of Twilio's dead-air dwell, with the reason. A one-line-TwiML Twilio Media Streams drop-in; billed per answered call (first 5,000/month free). `wss://api.pyai.com/v1/amd/stream`
|
|
16
16
|
- **[Telephony](https://pyai.com/models/telephony)**, Instant **managed phone numbers** for your voice agents. Provision a US number and route live calls straight into an Omni agent, no carrier contracts, no telephony glue. `POST /v1/telephony/numbers`
|
|
17
17
|
|
|
@@ -93,6 +93,16 @@ omni.sendDtmf("5");
|
|
|
93
93
|
omni.close();
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
Live `0x02` transcript bodies are plain UTF-8 caller-text deltas, not JSON.
|
|
97
|
+
`onTranscript` receives the normalized
|
|
98
|
+
`{ event:"transcript", role:"user", text, final:false, mode:"delta" }` shape.
|
|
99
|
+
Coalesce successive deltas for the current caller turn. Bounded direct JSON
|
|
100
|
+
bodies remain accepted for older bridges.
|
|
101
|
+
|
|
102
|
+
`rate` configures caller input. A `rate: 16000` session still receives 24 kHz
|
|
103
|
+
agent audio; `rate: 8000` receives 8 kHz. Read `hello.audio_out` before playback.
|
|
104
|
+
Omni has no commit frame—keep streaming silence during caller pauses.
|
|
105
|
+
|
|
96
106
|
From the browser, mint an ephemeral token server-side with
|
|
97
107
|
`pyai.omni.createSession({ allowedOrigins })` and pass it as `token` so the page
|
|
98
108
|
never holds a secret key:
|
|
@@ -101,31 +111,37 @@ never holds a secret key:
|
|
|
101
111
|
const omni = pyai.omni.connect({ token: session.token, configure: { voice_id, persona } });
|
|
102
112
|
```
|
|
103
113
|
|
|
104
|
-
> Omni
|
|
105
|
-
|
|
106
|
-
>
|
|
107
|
-
> `pyai.realtimeSubprotocol()` (or `pyai.connectRealtime()`)
|
|
108
|
-
>
|
|
109
|
-
>
|
|
114
|
+
> Omni connects only to `wss://api.pyai.com/v1/omni` and is **zero-state**, no
|
|
115
|
+
> agent to create. `sessionLabel` is an optional opaque tag (never required).
|
|
116
|
+
> Need the raw socket? Use `pyai.realtimeURL({ sessionLabel })` with
|
|
117
|
+
> `pyai.realtimeSubprotocol()` (or `pyai.connectRealtime()`).
|
|
118
|
+
> The raw URL helper accepts canonical `format`, `rate`, and `api_key` query
|
|
119
|
+
> parameters; retired connect aliases, model selectors, and token query names
|
|
120
|
+
> throw instead of being translated.
|
|
110
121
|
|
|
111
|
-
## Streaming speech-to-text (Hear
|
|
122
|
+
## Streaming speech-to-text (Hear)
|
|
112
123
|
|
|
113
124
|
`transcriptions.stream()` hides the WebSocket frame protocol behind callbacks.
|
|
114
|
-
It opens `wss://api.pyai.com/v1/audio/transcriptions/stream` (key carried as the
|
|
125
|
+
It opens `wss://api.pyai.com/v1/audio/transcriptions/stream?protocol=pyai-hear-v1` (key carried as the
|
|
115
126
|
WS subprotocol, so it works in the browser), routes the wire frames to
|
|
116
|
-
`onPartial`/`onFinal`/`onError`, and gives you `sendAudio`,
|
|
117
|
-
`close()`:
|
|
127
|
+
`onConfigAck`/`onPartial`/`onFinal`/`onError`, and gives you `sendAudio`,
|
|
128
|
+
`configureEndpointing()`, `commit()`, and `close()`:
|
|
118
129
|
|
|
119
130
|
```ts
|
|
120
131
|
const hear = pyai.audio.transcriptions.stream({
|
|
121
132
|
sampleRate: 16000,
|
|
133
|
+
endpointingMs: 800, // minimum trailing pause; may wait up to max(800, 1500) ms
|
|
134
|
+
onConfigAck: (ack) => {
|
|
135
|
+
if (ack.warnings.length) throw new Error(JSON.stringify(ack.warnings));
|
|
136
|
+
},
|
|
122
137
|
onPartial: (f) => console.log("…", f.text),
|
|
123
|
-
onFinal: (f) => console.log("✓", f.text,
|
|
138
|
+
onFinal: (f) => console.log("✓", f.text, f.endpoint_reason),
|
|
124
139
|
onError: (e) => console.error(e),
|
|
125
140
|
});
|
|
126
141
|
|
|
127
|
-
micChunks.on("data", (pcm16) => hear.sendAudio(pcm16)); //
|
|
128
|
-
|
|
142
|
+
micChunks.on("data", (pcm16) => hear.sendAudio(pcm16)); // keep sending silence through pauses
|
|
143
|
+
hear.configureEndpointing(950); // update without reconnecting
|
|
144
|
+
vad.on("end", () => hear.commit()); // optional forced final
|
|
129
145
|
// hear.close() also flushes a final for any buffered audio
|
|
130
146
|
```
|
|
131
147
|
|
|
@@ -163,8 +179,8 @@ const ulaw = await pyai.audio.speech({
|
|
|
163
179
|
|
|
164
180
|
| `response_format` | sample rates (Hz) | Content-Type |
|
|
165
181
|
|---|---|---|
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
182
|
+
| `wav` (default) | 8000 / 16000 / 24000 / 48000 | `audio/wav` |
|
|
183
|
+
| `mp3` | 8000 / 16000 / 24000 / 48000 | `audio/mpeg` |
|
|
168
184
|
| `opus` | 8000 / 16000 / 24000 / 48000 | `audio/ogg` |
|
|
169
185
|
| `aac` | 8000 / 16000 / 24000 / 48000 | `audio/aac` |
|
|
170
186
|
| `flac` | 8000 / 16000 / 24000 / 48000 | `audio/flac` |
|
|
@@ -175,7 +191,7 @@ const ulaw = await pyai.audio.speech({
|
|
|
175
191
|
`sample_rate` is optional, omit it for the engine's native 24 kHz (`g711_*` is
|
|
176
192
|
always 8 kHz). The set is typed (`SpeechFormat`) and exported as `SPEECH_FORMATS`
|
|
177
193
|
/ `SPEECH_SAMPLE_RATES` for dropdowns and validation. Any other value is a
|
|
178
|
-
`400 unsupported_format`; omit `response_format` for the default `
|
|
194
|
+
`400 unsupported_format`; omit `response_format` for the default `wav`.
|
|
179
195
|
|
|
180
196
|
> See [`examples/speak-telephony-formats`](../../examples/speak-telephony-formats)
|
|
181
197
|
> for the full before/after: ~120 lines of resampler + μ-law replaced by one
|
|
@@ -292,7 +308,7 @@ Speak→Hear round-trip, and prints remediation hints for any failure:
|
|
|
292
308
|
```bash
|
|
293
309
|
export PYAI_API_KEY=pyai_test_...
|
|
294
310
|
npx pyai doctor
|
|
295
|
-
# PASS key (/v1/me), env=test; 3 scope(s): hear:transcribe,
|
|
311
|
+
# PASS key (/v1/me), env=test; 3 scope(s): hear:transcribe, speak:synthesize, hear:stream
|
|
296
312
|
# PASS models.list, 12 models
|
|
297
313
|
# PASS voices.list, 38 voices
|
|
298
314
|
# PASS speak→hear round-trip, synth 45210 bytes → "the quick brown fox…"
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,9 @@ export declare class PyAIError extends Error {
|
|
|
24
24
|
constructor(status: number, message: string, code?: string, type?: string, requestId?: string);
|
|
25
25
|
}
|
|
26
26
|
export interface Voice {
|
|
27
|
+
/** Canonical catalog identifier returned by GET /v1/voices. */
|
|
28
|
+
voice_id: string;
|
|
29
|
+
/** SDK compatibility alias, always equal to voice_id. */
|
|
27
30
|
id: string;
|
|
28
31
|
name?: string;
|
|
29
32
|
gender?: string;
|
|
@@ -49,13 +52,13 @@ export interface TranscriptionJob {
|
|
|
49
52
|
* Output container/codec for `audio.speech`. This is the **exact** set the
|
|
50
53
|
* server accepts on `POST /v1/audio/speech`, any other value is rejected with
|
|
51
54
|
* `400 unsupported_format`. The default (when `response_format` is omitted) is
|
|
52
|
-
* `
|
|
55
|
+
* `wav`. Omit `sample_rate` for the engine's native 24 kHz (`g711_*` is always
|
|
53
56
|
* 8 kHz).
|
|
54
57
|
*
|
|
55
58
|
* | format | rates (Hz) | Content-Type |
|
|
56
59
|
* |---|---|---|
|
|
57
|
-
* | `
|
|
58
|
-
* | `
|
|
60
|
+
* | `wav` (default) | 8000/16000/24000/48000 | `audio/wav` |
|
|
61
|
+
* | `mp3` | 8000/16000/24000/48000 | `audio/mpeg` |
|
|
59
62
|
* | `opus` | 8000/16000/24000/48000 | `audio/ogg` |
|
|
60
63
|
* | `aac` | 8000/16000/24000/48000 | `audio/aac` |
|
|
61
64
|
* | `flac` | 8000/16000/24000/48000 | `audio/flac` |
|
|
@@ -73,14 +76,16 @@ export declare const SPEECH_FORMATS: readonly ["wav", "mp3", "opus", "aac", "fla
|
|
|
73
76
|
/** Sample rates (Hz) the server accepts for `audio.speech` (`g711_*` is always 8 kHz). */
|
|
74
77
|
export declare const SPEECH_SAMPLE_RATES: readonly [8000, 16000, 24000, 48000];
|
|
75
78
|
export type SpeechSampleRate = (typeof SPEECH_SAMPLE_RATES)[number];
|
|
79
|
+
/** Canonical Speak model plus the intentional OpenAI drop-in aliases. */
|
|
80
|
+
export type SpeakModel = "pyai-speak" | "tts-1" | "tts-1-hd";
|
|
76
81
|
export interface SpeechParams {
|
|
77
82
|
input: string;
|
|
78
83
|
voice?: string;
|
|
79
|
-
model?:
|
|
84
|
+
model?: SpeakModel;
|
|
80
85
|
/**
|
|
81
86
|
* Output container/codec, resampled+encoded server-side. One of
|
|
82
87
|
* {@link SpeechFormat}, anything else is a `400 unsupported_format`. Omit for
|
|
83
|
-
* the default of `
|
|
88
|
+
* the default of `wav`.
|
|
84
89
|
*
|
|
85
90
|
* `g711_ulaw`/`g711_alaw` return raw 8 kHz mono G.711, the bytes Twilio/SIP
|
|
86
91
|
* media streams expect, so you can hand the response straight to a telephony
|
|
@@ -97,15 +102,14 @@ export interface SpeechParams {
|
|
|
97
102
|
* telephony pipelines, most often with `response_format: "pcm"`.
|
|
98
103
|
*/
|
|
99
104
|
sample_rate?: SpeechSampleRate;
|
|
105
|
+
/** Reserved; currently returns `400 unsupported_parameter` when provided. */
|
|
100
106
|
speed?: number;
|
|
101
107
|
/**
|
|
102
|
-
*
|
|
103
|
-
* honored once the engine supports it (otherwise ignored server-side), so it's
|
|
104
|
-
* always safe to send.
|
|
108
|
+
* Reserved; currently returns `400 unsupported_parameter` when provided.
|
|
105
109
|
*/
|
|
106
110
|
seed?: number;
|
|
107
111
|
/**
|
|
108
|
-
*
|
|
112
|
+
* Reserved; currently returns `400 unsupported_parameter` when provided.
|
|
109
113
|
*/
|
|
110
114
|
temperature?: number;
|
|
111
115
|
}
|
|
@@ -119,8 +123,6 @@ export interface CreateJobParams {
|
|
|
119
123
|
webhook_url?: string;
|
|
120
124
|
}
|
|
121
125
|
export interface RealtimeOptions {
|
|
122
|
-
/** "omni" (agentic voice) or "flow" (legacy voice duplex). Default "omni". */
|
|
123
|
-
product?: "omni" | "flow";
|
|
124
126
|
/**
|
|
125
127
|
* Optional opaque tag echoed to your `kb_endpoint` and recorded on the call.
|
|
126
128
|
* Omni is zero-state: the session is authorized by the key's org, so there is
|
|
@@ -128,12 +130,10 @@ export interface RealtimeOptions {
|
|
|
128
130
|
*/
|
|
129
131
|
sessionLabel?: string;
|
|
130
132
|
/**
|
|
131
|
-
*
|
|
132
|
-
* `
|
|
133
|
-
*
|
|
133
|
+
* Extra canonical query params (`format`, `rate`, or the intentional
|
|
134
|
+
* server-side `api_key` auth option). Retired connect aliases and model/token
|
|
135
|
+
* selectors are rejected.
|
|
134
136
|
*/
|
|
135
|
-
agentId?: string;
|
|
136
|
-
/** Extra query params (e.g. format, rate). */
|
|
137
137
|
query?: Record<string, string>;
|
|
138
138
|
}
|
|
139
139
|
/** Parameters for minting an ephemeral browser Omni session token (server-side). */
|
|
@@ -167,6 +167,8 @@ export interface OmniSession {
|
|
|
167
167
|
}
|
|
168
168
|
/** Frame `type`s emitted by the Hear streaming-STT WebSocket. */
|
|
169
169
|
export declare const HearFrameType: {
|
|
170
|
+
/** Applied endpointing configuration and validation warnings. */
|
|
171
|
+
readonly ConfigAck: "config_ack";
|
|
170
172
|
/** Eager live hypothesis for the current utterance. */
|
|
171
173
|
readonly Partial: "partial";
|
|
172
174
|
/** Partial whose prefix has stabilized (won't be revised). */
|
|
@@ -202,7 +204,7 @@ export declare const ErrorCode: {
|
|
|
202
204
|
readonly Unauthorized: "unauthorized";
|
|
203
205
|
readonly Forbidden: "forbidden";
|
|
204
206
|
readonly OriginNotAllowed: "origin_not_allowed";
|
|
205
|
-
readonly
|
|
207
|
+
readonly InvalidSessionLabel: "invalid_session_label";
|
|
206
208
|
readonly CreditExhausted: "credit_exhausted";
|
|
207
209
|
readonly KeyBudgetExceeded: "key_budget_exceeded";
|
|
208
210
|
readonly InsufficientQuota: "insufficient_quota";
|
|
@@ -219,6 +221,22 @@ export interface HearGroundingPassage {
|
|
|
219
221
|
content: string;
|
|
220
222
|
score: number;
|
|
221
223
|
}
|
|
224
|
+
/** One endpointing validation result echoed in a `config_ack` frame. */
|
|
225
|
+
export interface HearConfigWarning {
|
|
226
|
+
field: string;
|
|
227
|
+
value: unknown;
|
|
228
|
+
effective?: number;
|
|
229
|
+
reason: "clamped_to_range" | "not_a_number" | "unknown_config_field" | (string & {});
|
|
230
|
+
}
|
|
231
|
+
/** Applied endpointing settings after connect-time or mid-session config. */
|
|
232
|
+
export interface HearConfigAckFrame {
|
|
233
|
+
type: "config_ack";
|
|
234
|
+
endpointing_ms: number;
|
|
235
|
+
effective_floor_ms: number;
|
|
236
|
+
effective_ceiling_ms: number;
|
|
237
|
+
score_interval_ms: number;
|
|
238
|
+
warnings: HearConfigWarning[];
|
|
239
|
+
}
|
|
222
240
|
/** Live hypothesis frame (`partial` / `partial_stable`). */
|
|
223
241
|
export interface HearPartialFrame {
|
|
224
242
|
type: "partial" | "partial_stable";
|
|
@@ -232,6 +250,7 @@ export interface HearPartialFrame {
|
|
|
232
250
|
t_ms: number;
|
|
233
251
|
}
|
|
234
252
|
/** Finalized-utterance frame (`speech_final` / `final`). */
|
|
253
|
+
export type HearEndpointReason = "peak_te_early" | "silence_backstop" | "commit" | (string & {});
|
|
235
254
|
export interface HearFinalFrame {
|
|
236
255
|
type: "speech_final" | "final";
|
|
237
256
|
text: string;
|
|
@@ -239,6 +258,8 @@ export interface HearFinalFrame {
|
|
|
239
258
|
t_ms: number;
|
|
240
259
|
/** Active-speech length of the utterance (the billed signal), ms. */
|
|
241
260
|
audio_ms: number;
|
|
261
|
+
/** Why the utterance ended. Log this when tuning automatic endpointing. */
|
|
262
|
+
endpoint_reason: HearEndpointReason;
|
|
242
263
|
/** Present only with Cue grounding enabled (top KB passages). */
|
|
243
264
|
grounding?: HearGroundingPassage[];
|
|
244
265
|
}
|
|
@@ -250,7 +271,7 @@ export interface HearUsageFrame {
|
|
|
250
271
|
type: "usage";
|
|
251
272
|
/** `hear` for plain streaming, `cue` when grounding was enabled. */
|
|
252
273
|
product: "hear" | "cue";
|
|
253
|
-
/** The billed meter (`hear.
|
|
274
|
+
/** The billed meter (`hear.minutes` or `cue.minutes`). */
|
|
254
275
|
meter: string;
|
|
255
276
|
/** Summed active-speech audio billed for the session, in seconds. */
|
|
256
277
|
audio_seconds: number;
|
|
@@ -263,7 +284,7 @@ export interface HearErrorFrame {
|
|
|
263
284
|
code?: string;
|
|
264
285
|
message: string;
|
|
265
286
|
}
|
|
266
|
-
export type HearFrame = HearPartialFrame | HearFinalFrame | HearUsageFrame | HearErrorFrame;
|
|
287
|
+
export type HearFrame = HearConfigAckFrame | HearPartialFrame | HearFinalFrame | HearUsageFrame | HearErrorFrame;
|
|
267
288
|
/**
|
|
268
289
|
* Minimal structural WebSocket, matches both the browser/Node global
|
|
269
290
|
* `WebSocket` and the `ws` package, and lets tests inject a mock.
|
|
@@ -286,8 +307,12 @@ export type WebSocketCtor = new (url: string, protocols?: string | string[]) =>
|
|
|
286
307
|
export interface HearStreamOptions {
|
|
287
308
|
/** Streaming STT model. Server default `pyai-hear`. */
|
|
288
309
|
model?: string;
|
|
289
|
-
/**
|
|
290
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Hear is English-only. Set `"en"` explicitly; omission also means English
|
|
312
|
+
* and does not enable language detection. Other values receive
|
|
313
|
+
* `400 unsupported_language`.
|
|
314
|
+
*/
|
|
315
|
+
language?: "en";
|
|
291
316
|
/** Input PCM sample rate in Hz. Default 16000 server-side. */
|
|
292
317
|
sampleRate?: number;
|
|
293
318
|
/** Audio frame encoding. Default "pcm16". */
|
|
@@ -301,16 +326,14 @@ export interface HearStreamOptions {
|
|
|
301
326
|
*/
|
|
302
327
|
numerals?: boolean;
|
|
303
328
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
* {@link HearStream.commit} for full control today.
|
|
329
|
+
* Minimum trailing-pause length before an utterance may end (50-5000 ms).
|
|
330
|
+
* Turn detection may wait longer, bounded at `max(endpointingMs, 1500)`.
|
|
331
|
+
* The server confirms the applied value through `onConfigAck`.
|
|
308
332
|
*/
|
|
309
333
|
endpointingMs?: number;
|
|
310
334
|
/**
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* array. Bills a single `cue.minutes` line instead of the Hear rate.
|
|
335
|
+
* Reserved Cue grounding configuration. Grounding is not active on the
|
|
336
|
+
* serving Hear stream; do not rely on grounding frames or Cue metering yet.
|
|
314
337
|
*/
|
|
315
338
|
grounding?: boolean;
|
|
316
339
|
/** Cue: number of KB passages to retrieve per turn (1-20, default 3). */
|
|
@@ -322,8 +345,11 @@ export interface HearStreamOptions {
|
|
|
322
345
|
groundingTimeoutMs?: number;
|
|
323
346
|
/** Extra query params merged onto the connect URL. */
|
|
324
347
|
query?: Record<string, string>;
|
|
325
|
-
/** Fired once the socket opens
|
|
348
|
+
/** Fired once the socket opens. */
|
|
326
349
|
onOpen?: () => void;
|
|
350
|
+
/** Fired after connect-time or mid-session endpointing config. Assert that
|
|
351
|
+
* `warnings` is empty before relying on the requested floor. */
|
|
352
|
+
onConfigAck?: (frame: HearConfigAckFrame) => void;
|
|
327
353
|
/** Fired on `partial` / `partial_stable`. */
|
|
328
354
|
onPartial?: (frame: HearPartialFrame) => void;
|
|
329
355
|
/** Fired on `speech_final` / `final`. */
|
|
@@ -340,8 +366,10 @@ export interface HearStreamOptions {
|
|
|
340
366
|
/**
|
|
341
367
|
* A live Hear streaming-STT session. Hides the frame protocol: stream audio
|
|
342
368
|
* with {@link HearStream.sendAudio}, get `onPartial`/`onFinal`/`onError`
|
|
343
|
-
* callbacks,
|
|
344
|
-
*
|
|
369
|
+
* callbacks, update the silence floor with
|
|
370
|
+
* {@link HearStream.configureEndpointing}, force-finalize with
|
|
371
|
+
* {@link HearStream.commit}, and flush+close with {@link HearStream.close}.
|
|
372
|
+
* Construct via `pyai.audio.transcriptions.stream()`.
|
|
345
373
|
*/
|
|
346
374
|
export declare class HearStream {
|
|
347
375
|
private readonly ws;
|
|
@@ -351,6 +379,8 @@ export declare class HearStream {
|
|
|
351
379
|
private handleMessage;
|
|
352
380
|
/** Send a chunk of audio (PCM16 or opus per `encoding`). */
|
|
353
381
|
sendAudio(chunk: ArrayBufferLike | ArrayBufferView | Blob): void;
|
|
382
|
+
/** Change the minimum trailing-pause floor without reconnecting. */
|
|
383
|
+
configureEndpointing(endpointingMs: number): void;
|
|
354
384
|
/** Force-finalize the current utterance (e.g. on VAD end-of-turn). */
|
|
355
385
|
commit(): void;
|
|
356
386
|
/** Close the socket; the server flushes a final for any buffered audio. */
|
|
@@ -420,6 +450,21 @@ export interface OmniServerFrame {
|
|
|
420
450
|
event: string;
|
|
421
451
|
[k: string]: unknown;
|
|
422
452
|
}
|
|
453
|
+
/** Canonical, sanitized transcript delivered by the native Omni demux.
|
|
454
|
+
* The live wire sends caller text deltas; the JSON fields are SDK-owned
|
|
455
|
+
* normalization so applications don't have to special-case the byte payload. */
|
|
456
|
+
export interface OmniTranscriptFrame extends OmniServerFrame {
|
|
457
|
+
event: "transcript";
|
|
458
|
+
role: "user" | "assistant";
|
|
459
|
+
text: string;
|
|
460
|
+
final: boolean;
|
|
461
|
+
/** Live text frames append; legacy JSON frames replace unless they use `delta`. */
|
|
462
|
+
mode: "delta" | "replace";
|
|
463
|
+
/** Optional ordering hint on legacy JSON frames. */
|
|
464
|
+
sequence?: number;
|
|
465
|
+
}
|
|
466
|
+
/** Normalize the live UTF-8 `0x02` text body and bounded legacy JSON bodies. */
|
|
467
|
+
export declare function normalizeOmniTranscriptBody(bytes: Uint8Array): OmniTranscriptFrame | null;
|
|
423
468
|
/** A binary agent-audio chunk delivered to {@link OmniConnectOptions.onAudio}. */
|
|
424
469
|
export type OmniAudioChunk = ArrayBuffer | ArrayBufferView | Blob;
|
|
425
470
|
export interface OmniToolDef {
|
|
@@ -430,7 +475,7 @@ export interface OmniToolDef {
|
|
|
430
475
|
endpoint?: string;
|
|
431
476
|
}
|
|
432
477
|
export interface OmniToolCallFrame {
|
|
433
|
-
|
|
478
|
+
event: "tool_call";
|
|
434
479
|
call_id: string;
|
|
435
480
|
name: string;
|
|
436
481
|
arguments?: Record<string, unknown>;
|
|
@@ -455,7 +500,7 @@ export interface OmniConfigure {
|
|
|
455
500
|
/**
|
|
456
501
|
* Session language, end to end (recognition, reasoning, voice). Also
|
|
457
502
|
* settable on the agent profile (`language` on `POST /v1/agents`), which
|
|
458
|
-
* applies automatically when
|
|
503
|
+
* applies automatically when `session_label` is the saved profile id;
|
|
459
504
|
* an inline value here wins for the session. Default `en`. Fail-safe: an
|
|
460
505
|
* unknown/not-yet-enabled language falls back to `en` (the `configured`
|
|
461
506
|
* ack carries `language_active` + `language_fallback: true`), the call
|
|
@@ -477,7 +522,11 @@ export interface OmniConnectOptions {
|
|
|
477
522
|
* so a page never holds a secret key.
|
|
478
523
|
*/
|
|
479
524
|
token?: string;
|
|
480
|
-
/**
|
|
525
|
+
/**
|
|
526
|
+
* Caller-input sample rate. `24000` and `16000` sessions receive agent audio
|
|
527
|
+
* at 24 kHz; `8000` sessions receive 8 kHz. Read `hello.audio_out` rather than
|
|
528
|
+
* assuming output matches this value.
|
|
529
|
+
*/
|
|
481
530
|
rate?: 24000 | 16000 | 8000;
|
|
482
531
|
/** Connect-URL audio format. Default `pcm16`. */
|
|
483
532
|
format?: "pcm16";
|
|
@@ -500,7 +549,7 @@ export interface OmniConnectOptions {
|
|
|
500
549
|
onSessionStarted?: (frame: OmniServerFrame) => void;
|
|
501
550
|
/** Fired on `turn` boundaries. */
|
|
502
551
|
onTurn?: (frame: OmniServerFrame) => void;
|
|
503
|
-
/** Fired
|
|
552
|
+
/** Fired for each normalized caller-transcript delta (`0x02` plain UTF-8 live). */
|
|
504
553
|
onTranscript?: (frame: OmniServerFrame) => void;
|
|
505
554
|
/** Fired on `barge_in` / `flush` (user interrupted). */
|
|
506
555
|
onBargeIn?: (frame: OmniServerFrame) => void;
|
|
@@ -539,6 +588,8 @@ export declare class OmniConnection {
|
|
|
539
588
|
private closed;
|
|
540
589
|
/** Serializes async Blob reads in {@link sendAudio} so frames stay ordered. */
|
|
541
590
|
private blobTail;
|
|
591
|
+
/** Serializes inbound Blob decoding so browser frames stay ordered. */
|
|
592
|
+
private inboundTail;
|
|
542
593
|
constructor(url: string, subprotocol: string, opts: OmniConnectOptions);
|
|
543
594
|
private handleMessage;
|
|
544
595
|
private dispatchFrame;
|
|
@@ -841,8 +892,13 @@ export interface RecapCallTriggerInput {
|
|
|
841
892
|
customer_name?: string;
|
|
842
893
|
crm_fields?: Record<string, unknown>;
|
|
843
894
|
}
|
|
844
|
-
/**
|
|
845
|
-
|
|
895
|
+
/**
|
|
896
|
+
* The answered-by vocabulary on stored call records and the
|
|
897
|
+
* `amd.call.completed` webhook: the routing classes plus the machine subtypes.
|
|
898
|
+
*/
|
|
899
|
+
export type AmdAnsweredBy = "human" | "machine" | "voicemail" | "screening" | "ivr" | "music" | "sit_invalid" | "unknown";
|
|
900
|
+
/** The routing classes pushed on the mid-call wire event (`event: "amd"`). */
|
|
901
|
+
export type AmdWireAnsweredBy = "human" | "machine" | "sit_invalid" | "unknown";
|
|
846
902
|
/** Twilio's `AnsweredBy` enum, echoed for drop-in migration parity. */
|
|
847
903
|
export type AmdTwilioAnsweredBy = "human" | "machine_start" | "machine_end_beep" | "machine_end_silence" | "machine_end_other" | "fax" | "unknown";
|
|
848
904
|
export interface AmdConfigInput {
|
|
@@ -880,11 +936,16 @@ export interface AmdCall extends AmdCallSummary {
|
|
|
880
936
|
meta?: Record<string, unknown> | null;
|
|
881
937
|
error?: string | null;
|
|
882
938
|
}
|
|
883
|
-
/**
|
|
939
|
+
/**
|
|
940
|
+
* A mid-call AMD decision event pushed on the stream (and to the per-call
|
|
941
|
+
* TwiML `webhook`). Carries the coarse routing class; the machine subtype
|
|
942
|
+
* (`voicemail`/`ivr`/`screening`/`music`) is on the stored call record
|
|
943
|
+
* (`AmdCall`) and the `amd.call.completed` webhook instead.
|
|
944
|
+
*/
|
|
884
945
|
export interface AmdDecisionEvent {
|
|
885
946
|
event?: "amd";
|
|
886
947
|
call_id?: string;
|
|
887
|
-
answered_by?:
|
|
948
|
+
answered_by?: AmdWireAnsweredBy;
|
|
888
949
|
answered_by_twilio?: string | null;
|
|
889
950
|
confidence?: number | null;
|
|
890
951
|
decision_ms?: number | null;
|
|
@@ -954,7 +1015,11 @@ export declare class PyAI {
|
|
|
954
1015
|
file: Blob;
|
|
955
1016
|
filename?: string;
|
|
956
1017
|
model?: string;
|
|
957
|
-
|
|
1018
|
+
/**
|
|
1019
|
+
* Hear is English-only. Omission means English, not auto-detect; other
|
|
1020
|
+
* values receive `400 unsupported_language`.
|
|
1021
|
+
*/
|
|
1022
|
+
language?: "en";
|
|
958
1023
|
response_format?: "json" | "text" | "verbose_json";
|
|
959
1024
|
/**
|
|
960
1025
|
* Deterministic seed for reproducible eval runs. Forward-compatible:
|
|
@@ -994,7 +1059,7 @@ export declare class PyAI {
|
|
|
994
1059
|
clones: {
|
|
995
1060
|
/** List the org's cloned voices. */
|
|
996
1061
|
list: () => Promise<ListResponse<Voice>>;
|
|
997
|
-
/** Enroll a custom voice from reference audio (>= ~10s). Scope `
|
|
1062
|
+
/** Enroll a custom voice from reference audio (>= ~10s). Scope `speak:clone`. */
|
|
998
1063
|
create: (params: {
|
|
999
1064
|
name: string;
|
|
1000
1065
|
file: Blob;
|
|
@@ -1006,7 +1071,7 @@ export declare class PyAI {
|
|
|
1006
1071
|
* when the id isn't found.
|
|
1007
1072
|
*/
|
|
1008
1073
|
get: (id: string) => Promise<Voice>;
|
|
1009
|
-
/** Delete a cloned voice (tenant-isolated). Scope `
|
|
1074
|
+
/** Delete a cloned voice (tenant-isolated). Scope `speak:clone`. */
|
|
1010
1075
|
delete: (id: string) => Promise<void>;
|
|
1011
1076
|
};
|
|
1012
1077
|
telephony: {
|
|
@@ -1151,7 +1216,7 @@ export declare class PyAI {
|
|
|
1151
1216
|
*/
|
|
1152
1217
|
connect: (opts?: OmniConnectOptions) => OmniConnection;
|
|
1153
1218
|
};
|
|
1154
|
-
/** Build the
|
|
1219
|
+
/** Build the canonical Omni WebSocket URL. */
|
|
1155
1220
|
realtimeURL(opts?: RealtimeOptions): string;
|
|
1156
1221
|
/** The subprotocol that carries the key on a WS upgrade (browser-safe auth). */
|
|
1157
1222
|
realtimeSubprotocol(): string;
|