@pyai/sdk 0.1.2 → 0.2.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 +156 -17
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +107 -2
- package/dist/index.d.ts +868 -7
- package/dist/index.js +587 -5
- package/package.json +2 -1
- package/src/cli.ts +115 -2
- package/src/index.ts +1220 -11
package/dist/index.d.ts
CHANGED
|
@@ -46,18 +46,70 @@ export interface TranscriptionJob {
|
|
|
46
46
|
result_url?: string;
|
|
47
47
|
error?: string;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Output container/codec for `audio.speech`. This is the **exact** set the
|
|
51
|
+
* server accepts on `POST /v1/audio/speech` — any other value is rejected with
|
|
52
|
+
* `400 unsupported_format`. The default (when `response_format` is omitted) is
|
|
53
|
+
* `mp3`. Omit `sample_rate` for the engine's native 24 kHz (`g711_*` is always
|
|
54
|
+
* 8 kHz).
|
|
55
|
+
*
|
|
56
|
+
* | format | rates (Hz) | Content-Type |
|
|
57
|
+
* |---|---|---|
|
|
58
|
+
* | `mp3` (default) | 8000/16000/24000/48000 | `audio/mpeg` |
|
|
59
|
+
* | `wav` | 8000/16000/24000/48000 | `audio/wav` |
|
|
60
|
+
* | `opus` | 8000/16000/24000/48000 | `audio/ogg` |
|
|
61
|
+
* | `aac` | 8000/16000/24000/48000 | `audio/aac` |
|
|
62
|
+
* | `flac` | 8000/16000/24000/48000 | `audio/flac` |
|
|
63
|
+
* | `pcm` | 8000/16000/24000/48000 | `audio/pcm` (raw int16 LE mono, no header) |
|
|
64
|
+
* | `g711_ulaw` | 8000 (forced) | `audio/basic` |
|
|
65
|
+
* | `g711_alaw` | 8000 (forced) | `audio/basic` |
|
|
66
|
+
*/
|
|
67
|
+
export type SpeechFormat = "wav" | "mp3" | "opus" | "aac" | "flac" | "pcm" | "g711_ulaw" | "g711_alaw";
|
|
68
|
+
/**
|
|
69
|
+
* The runtime list of accepted `audio.speech` formats (mirrors {@link SpeechFormat}),
|
|
70
|
+
* for building dropdowns / validating input before a request. Branch on the
|
|
71
|
+
* named values; the order matches the contract doc.
|
|
72
|
+
*/
|
|
73
|
+
export declare const SPEECH_FORMATS: readonly ["wav", "mp3", "opus", "aac", "flac", "pcm", "g711_ulaw", "g711_alaw"];
|
|
74
|
+
/** Sample rates (Hz) the server accepts for `audio.speech` (`g711_*` is always 8 kHz). */
|
|
75
|
+
export declare const SPEECH_SAMPLE_RATES: readonly [8000, 16000, 24000, 48000];
|
|
76
|
+
export type SpeechSampleRate = (typeof SPEECH_SAMPLE_RATES)[number];
|
|
49
77
|
export interface SpeechParams {
|
|
50
78
|
input: string;
|
|
51
79
|
voice?: string;
|
|
52
80
|
model?: string;
|
|
53
|
-
response_format?: "wav" | "mp3" | "opus" | "aac" | "flac" | "pcm";
|
|
54
81
|
/**
|
|
55
|
-
* Output
|
|
56
|
-
*
|
|
57
|
-
*
|
|
82
|
+
* Output container/codec, resampled+encoded server-side. One of
|
|
83
|
+
* {@link SpeechFormat} — anything else is a `400 unsupported_format`. Omit for
|
|
84
|
+
* the default of `mp3`.
|
|
85
|
+
*
|
|
86
|
+
* `g711_ulaw`/`g711_alaw` return raw 8 kHz mono G.711 — the bytes Twilio/SIP
|
|
87
|
+
* media streams expect, so you can hand the response straight to a telephony
|
|
88
|
+
* frame without a client-side resampler or μ-law encoder. `sample_rate` is
|
|
89
|
+
* forced to 8000 for those (omit it, or set exactly 8000). `pcm` is raw,
|
|
90
|
+
* headerless int16 LE mono at `sample_rate`. `mp3`/`opus` are buffered (not
|
|
91
|
+
* chunk-streamed) — use them with `speech`, not `speechStream`.
|
|
58
92
|
*/
|
|
59
|
-
|
|
93
|
+
response_format?: SpeechFormat;
|
|
94
|
+
/**
|
|
95
|
+
* Output sample rate in Hz. One of {@link SpeechSampleRate}
|
|
96
|
+
* (8000/16000/24000/48000) — anything else is a `400`. Omit for the engine's
|
|
97
|
+
* native 24 kHz; `g711_*` is always 8000 (forced). Set `8000`/`16000` for
|
|
98
|
+
* telephony pipelines, most often with `response_format: "pcm"`.
|
|
99
|
+
*/
|
|
100
|
+
sample_rate?: SpeechSampleRate;
|
|
60
101
|
speed?: number;
|
|
102
|
+
/**
|
|
103
|
+
* Deterministic sampling seed for reproducible eval runs. Forward-compatible:
|
|
104
|
+
* honored once the engine supports it (otherwise ignored server-side), so it's
|
|
105
|
+
* always safe to send.
|
|
106
|
+
*/
|
|
107
|
+
seed?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Sampling temperature (lower = more deterministic). Forward-compatible —
|
|
110
|
+
* honored once the engine supports it, otherwise ignored.
|
|
111
|
+
*/
|
|
112
|
+
temperature?: number;
|
|
61
113
|
}
|
|
62
114
|
export interface CreateJobParams {
|
|
63
115
|
audio_url: string;
|
|
@@ -69,13 +121,660 @@ export interface CreateJobParams {
|
|
|
69
121
|
webhook_url?: string;
|
|
70
122
|
}
|
|
71
123
|
export interface RealtimeOptions {
|
|
72
|
-
/** "omni" (agentic
|
|
124
|
+
/** "omni" (agentic voice) or "flow" (legacy voice duplex). Default "omni". */
|
|
73
125
|
product?: "omni" | "flow";
|
|
74
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Optional opaque tag echoed to your `kb_endpoint` and recorded on the call.
|
|
128
|
+
* Omni is zero-state: the session is authorized by the key's org, so there is
|
|
129
|
+
* nothing to create first and this tag is never required.
|
|
130
|
+
*/
|
|
131
|
+
sessionLabel?: string;
|
|
132
|
+
/**
|
|
133
|
+
* @deprecated Use {@link sessionLabel}. Kept for back-compat — emitted as the
|
|
134
|
+
* `agent_id` query alias, which the gateway still accepts. Ignored if
|
|
135
|
+
* `sessionLabel` is set.
|
|
136
|
+
*/
|
|
75
137
|
agentId?: string;
|
|
76
138
|
/** Extra query params (e.g. format, rate). */
|
|
77
139
|
query?: Record<string, string>;
|
|
78
140
|
}
|
|
141
|
+
/** Parameters for minting an ephemeral browser Omni session token (server-side). */
|
|
142
|
+
export interface OmniSessionParams {
|
|
143
|
+
/**
|
|
144
|
+
* Browser origins (scheme://host[:port]) the minted token may connect from.
|
|
145
|
+
* Required and non-empty — a browser token must be origin-locked. `*` is not
|
|
146
|
+
* allowed.
|
|
147
|
+
*/
|
|
148
|
+
allowedOrigins: string[];
|
|
149
|
+
/** Token lifetime in seconds. Default 60 server-side; max 600. Keep it short. */
|
|
150
|
+
ttlSeconds?: number;
|
|
151
|
+
/** Optional opaque tag echoed back to your `kb_endpoint` and recorded on the call. */
|
|
152
|
+
sessionLabel?: string;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The result of {@link PyAI.omni}.createSession — a short-lived credential safe
|
|
156
|
+
* to hand to the browser. Use {@link OmniSession.token} as the WebSocket
|
|
157
|
+
* subprotocol `pyai-key.<token>` against {@link OmniSession.url}.
|
|
158
|
+
*/
|
|
159
|
+
export interface OmniSession {
|
|
160
|
+
object?: "omni.session";
|
|
161
|
+
/** The ephemeral session token. Short-lived + origin-locked; browser-safe. */
|
|
162
|
+
token: string;
|
|
163
|
+
/** Token expiry, Unix epoch milliseconds. */
|
|
164
|
+
expires_at: number;
|
|
165
|
+
/** The Omni realtime WebSocket URL to connect to. */
|
|
166
|
+
url: string;
|
|
167
|
+
/** Echoed back when supplied on the request. */
|
|
168
|
+
session_label?: string;
|
|
169
|
+
}
|
|
170
|
+
/** Frame `type`s emitted by the Hear streaming-STT WebSocket. */
|
|
171
|
+
export declare const HearFrameType: {
|
|
172
|
+
/** Eager live hypothesis for the current utterance. */
|
|
173
|
+
readonly Partial: "partial";
|
|
174
|
+
/** Partial whose prefix has stabilized (won't be revised). */
|
|
175
|
+
readonly PartialStable: "partial_stable";
|
|
176
|
+
/** Stable transcript at end-of-utterance (endpoint or commit). */
|
|
177
|
+
readonly SpeechFinal: "speech_final";
|
|
178
|
+
/** Corrected, full-context transcript following `speech_final`. */
|
|
179
|
+
readonly Final: "final";
|
|
180
|
+
/** Final billed-usage summary, emitted just before a graceful close. */
|
|
181
|
+
readonly Usage: "usage";
|
|
182
|
+
/** Server-side fault frame. */
|
|
183
|
+
readonly Error: "error";
|
|
184
|
+
};
|
|
185
|
+
export type HearFrameType = (typeof HearFrameType)[keyof typeof HearFrameType];
|
|
186
|
+
/** WebSocket close codes used across the PyAI realtime/streaming surfaces. */
|
|
187
|
+
export declare const WSCloseCode: {
|
|
188
|
+
/** Normal closure. */
|
|
189
|
+
readonly Normal: 1000;
|
|
190
|
+
/** Auth/policy: bad key, missing scope, or revoked token. */
|
|
191
|
+
readonly PolicyViolation: 1008;
|
|
192
|
+
/** Engine/internal error. */
|
|
193
|
+
readonly InternalError: 1011;
|
|
194
|
+
/** Over the concurrency cap (PyAI-specific; mirrors HTTP 429). */
|
|
195
|
+
readonly OverCapacity: 4429;
|
|
196
|
+
};
|
|
197
|
+
export type WSCloseCode = (typeof WSCloseCode)[keyof typeof WSCloseCode];
|
|
198
|
+
/**
|
|
199
|
+
* Stable, machine-readable error `code`s (the documented contract). Branch on
|
|
200
|
+
* these. The set is treated as open — `PyAIError.code` stays `string` — so a
|
|
201
|
+
* new server code never breaks the build, but the known ones are named here.
|
|
202
|
+
*/
|
|
203
|
+
export declare const ErrorCode: {
|
|
204
|
+
readonly Unauthorized: "unauthorized";
|
|
205
|
+
readonly Forbidden: "forbidden";
|
|
206
|
+
readonly OriginNotAllowed: "origin_not_allowed";
|
|
207
|
+
readonly InvalidAgentId: "invalid_agent_id";
|
|
208
|
+
readonly CreditExhausted: "credit_exhausted";
|
|
209
|
+
readonly KeyBudgetExceeded: "key_budget_exceeded";
|
|
210
|
+
readonly InsufficientQuota: "insufficient_quota";
|
|
211
|
+
readonly RateLimitExceeded: "rate_limit_exceeded";
|
|
212
|
+
readonly ConcurrencyLimitExceeded: "concurrency_limit_exceeded";
|
|
213
|
+
readonly DailyCapExceeded: "daily_cap_exceeded";
|
|
214
|
+
readonly IdempotencyConflict: "idempotency_conflict";
|
|
215
|
+
readonly NotFound: "not_found";
|
|
216
|
+
readonly NumberInUse: "number_in_use";
|
|
217
|
+
};
|
|
218
|
+
export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
219
|
+
/** A top-3 knowledge-base passage attached to Cue (grounded) finals. */
|
|
220
|
+
export interface HearGroundingPassage {
|
|
221
|
+
content: string;
|
|
222
|
+
score: number;
|
|
223
|
+
}
|
|
224
|
+
/** Live hypothesis frame (`partial` / `partial_stable`). */
|
|
225
|
+
export interface HearPartialFrame {
|
|
226
|
+
type: "partial" | "partial_stable";
|
|
227
|
+
text: string;
|
|
228
|
+
/** Prefix that has stabilized (won't change). */
|
|
229
|
+
stable_text?: string;
|
|
230
|
+
/** The still-changing tail. */
|
|
231
|
+
active_text?: string;
|
|
232
|
+
utterance_id: string;
|
|
233
|
+
/** Audio-timeline position of the hypothesis, ms. */
|
|
234
|
+
t_ms: number;
|
|
235
|
+
}
|
|
236
|
+
/** Finalized-utterance frame (`speech_final` / `final`). */
|
|
237
|
+
export interface HearFinalFrame {
|
|
238
|
+
type: "speech_final" | "final";
|
|
239
|
+
text: string;
|
|
240
|
+
utterance_id: string;
|
|
241
|
+
t_ms: number;
|
|
242
|
+
/** Active-speech length of the utterance (the billed signal), ms. */
|
|
243
|
+
audio_ms: number;
|
|
244
|
+
/** Present only with Cue grounding enabled (top KB passages). */
|
|
245
|
+
grounding?: HearGroundingPassage[];
|
|
246
|
+
}
|
|
247
|
+
/** Final billed-usage summary (`usage`), emitted just before a graceful close
|
|
248
|
+
* so realtime spend can be reconciled in-band (a realtime WS carries no
|
|
249
|
+
* `x-pyai-units` response header). Best-effort: absent if there was no billable
|
|
250
|
+
* audio or the close was abnormal. */
|
|
251
|
+
export interface HearUsageFrame {
|
|
252
|
+
type: "usage";
|
|
253
|
+
/** `hear` for plain streaming, `cue` when grounding was enabled. */
|
|
254
|
+
product: "hear" | "cue";
|
|
255
|
+
/** The billed meter (`hear.requests` or `cue.minutes`). */
|
|
256
|
+
meter: string;
|
|
257
|
+
/** Summed active-speech audio billed for the session, in seconds. */
|
|
258
|
+
audio_seconds: number;
|
|
259
|
+
/** The same quantity in minutes. */
|
|
260
|
+
minutes: number;
|
|
261
|
+
}
|
|
262
|
+
/** Server fault frame (`error`). */
|
|
263
|
+
export interface HearErrorFrame {
|
|
264
|
+
type: "error";
|
|
265
|
+
code?: string;
|
|
266
|
+
message: string;
|
|
267
|
+
}
|
|
268
|
+
export type HearFrame = HearPartialFrame | HearFinalFrame | HearUsageFrame | HearErrorFrame;
|
|
269
|
+
/**
|
|
270
|
+
* Minimal structural WebSocket — matches both the browser/Node global
|
|
271
|
+
* `WebSocket` and the `ws` package, and lets tests inject a mock.
|
|
272
|
+
*/
|
|
273
|
+
export interface WebSocketLike {
|
|
274
|
+
send(data: string | ArrayBufferLike | ArrayBufferView | Blob): void;
|
|
275
|
+
close(code?: number, reason?: string): void;
|
|
276
|
+
readonly readyState: number;
|
|
277
|
+
onopen: ((ev: unknown) => void) | null;
|
|
278
|
+
onmessage: ((ev: {
|
|
279
|
+
data: unknown;
|
|
280
|
+
}) => void) | null;
|
|
281
|
+
onerror: ((ev: unknown) => void) | null;
|
|
282
|
+
onclose: ((ev: {
|
|
283
|
+
code: number;
|
|
284
|
+
reason: string;
|
|
285
|
+
}) => void) | null;
|
|
286
|
+
}
|
|
287
|
+
export type WebSocketCtor = new (url: string, protocols?: string | string[]) => WebSocketLike;
|
|
288
|
+
export interface HearStreamOptions {
|
|
289
|
+
/** Streaming STT model. Server default `pyai-hear`. */
|
|
290
|
+
model?: string;
|
|
291
|
+
/** ISO-639-1 hint, e.g. "en". */
|
|
292
|
+
language?: string;
|
|
293
|
+
/** Input PCM sample rate in Hz. Default 16000 server-side. */
|
|
294
|
+
sampleRate?: number;
|
|
295
|
+
/** Audio frame encoding. Default "pcm16". */
|
|
296
|
+
encoding?: "pcm16" | "opus";
|
|
297
|
+
/** Emit eager partial hypotheses. Default true server-side. */
|
|
298
|
+
interimResults?: boolean;
|
|
299
|
+
/**
|
|
300
|
+
* Format spoken numbers as digits in the transcript (e.g. "one two three" →
|
|
301
|
+
* "123"). Useful for voice agents that read back phone numbers, codes, and
|
|
302
|
+
* amounts. Default false (spoken form). Forwards `?numerals=true` on the URL.
|
|
303
|
+
*/
|
|
304
|
+
numerals?: boolean;
|
|
305
|
+
/**
|
|
306
|
+
* Turn-segmentation tuning: trailing-pause (ms, 50–2000) that ends an
|
|
307
|
+
* utterance. Forwards `?endpointing_ms=` — clamped + honored once the engine
|
|
308
|
+
* supports it; a no-op when omitted. Drive end-of-turn yourself with
|
|
309
|
+
* {@link HearStream.commit} for full control today.
|
|
310
|
+
*/
|
|
311
|
+
endpointingMs?: number;
|
|
312
|
+
/**
|
|
313
|
+
* Enable Cue knowledge-base grounding: sends `{type:"config",grounding:true}`
|
|
314
|
+
* on open, after which `speech_final`/`final` frames carry a `grounding`
|
|
315
|
+
* array. Bills a single `cue.minutes` line instead of the Hear rate.
|
|
316
|
+
*/
|
|
317
|
+
grounding?: boolean;
|
|
318
|
+
/** Cue: number of KB passages to retrieve per turn (1–20, default 3). */
|
|
319
|
+
groundingK?: number;
|
|
320
|
+
/** Cue: drop passages scoring below this (0–1, default 0 = keep all). */
|
|
321
|
+
groundingMinScore?: number;
|
|
322
|
+
/** Cue: max ms to wait for retrieval at the final before failing open to
|
|
323
|
+
* `grounding: []` (50–2000, default 450). */
|
|
324
|
+
groundingTimeoutMs?: number;
|
|
325
|
+
/** Extra query params merged onto the connect URL. */
|
|
326
|
+
query?: Record<string, string>;
|
|
327
|
+
/** Fired once the socket opens (after the optional grounding config). */
|
|
328
|
+
onOpen?: () => void;
|
|
329
|
+
/** Fired on `partial` / `partial_stable`. */
|
|
330
|
+
onPartial?: (frame: HearPartialFrame) => void;
|
|
331
|
+
/** Fired on `speech_final` / `final`. */
|
|
332
|
+
onFinal?: (frame: HearFinalFrame) => void;
|
|
333
|
+
/** Fired on the final `usage` summary (in-band realtime reconciliation). */
|
|
334
|
+
onUsage?: (frame: HearUsageFrame) => void;
|
|
335
|
+
/** Fired on an `error` frame or a transport-level error. */
|
|
336
|
+
onError?: (err: HearErrorFrame | Error) => void;
|
|
337
|
+
/** Fired when the socket closes (code per `WSCloseCode`). */
|
|
338
|
+
onClose?: (code: number, reason: string) => void;
|
|
339
|
+
/** Injectable WebSocket constructor (defaults to the global). */
|
|
340
|
+
webSocket?: WebSocketCtor;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* A live Hear streaming-STT session. Hides the frame protocol: stream audio
|
|
344
|
+
* with {@link HearStream.sendAudio}, get `onPartial`/`onFinal`/`onError`
|
|
345
|
+
* callbacks, force-finalize with {@link HearStream.commit}, and flush+close
|
|
346
|
+
* with {@link HearStream.close}. Construct via `pyai.audio.transcriptions.stream()`.
|
|
347
|
+
*/
|
|
348
|
+
export declare class HearStream {
|
|
349
|
+
private readonly ws;
|
|
350
|
+
private readonly opts;
|
|
351
|
+
private closed;
|
|
352
|
+
constructor(url: string, subprotocol: string, opts: HearStreamOptions);
|
|
353
|
+
private handleMessage;
|
|
354
|
+
/** Send a chunk of audio (PCM16 or opus per `encoding`). */
|
|
355
|
+
sendAudio(chunk: ArrayBufferLike | ArrayBufferView | Blob): void;
|
|
356
|
+
/** Force-finalize the current utterance (e.g. on VAD end-of-turn). */
|
|
357
|
+
commit(): void;
|
|
358
|
+
/** Close the socket; the server flushes a final for any buffered audio. */
|
|
359
|
+
close(code?: number, reason?: string): void;
|
|
360
|
+
/** The underlying socket (escape hatch for advanced use). */
|
|
361
|
+
get socket(): WebSocketLike;
|
|
362
|
+
/** Current WebSocket readyState. */
|
|
363
|
+
get readyState(): number;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Event names on Omni **server → client** frames. ⚠️ Note the asymmetry:
|
|
367
|
+
* inbound frames are keyed on `event`, but your **outbound** control frames
|
|
368
|
+
* (`configure`, `dtmf`, …) are keyed on `type`. {@link OmniConnection} handles
|
|
369
|
+
* both sides for you; this map is for matching frames in `onEvent`.
|
|
370
|
+
*/
|
|
371
|
+
export declare const OmniEvent: {
|
|
372
|
+
/** Handshake; advertises protocol version + audio formats. */
|
|
373
|
+
readonly Hello: "hello";
|
|
374
|
+
/** Ack for your `configure` frame (echoes the resolved `voice_id`). */
|
|
375
|
+
readonly Configured: "configured";
|
|
376
|
+
/** Session is live; includes the resolved agent + audio caps. */
|
|
377
|
+
readonly SessionStarted: "session_started";
|
|
378
|
+
/** Turn boundary (user/assistant speaking). */
|
|
379
|
+
readonly Turn: "turn";
|
|
380
|
+
/** Incremental/final transcript text. */
|
|
381
|
+
readonly Transcript: "transcript";
|
|
382
|
+
/** User interrupted; assistant audio is being cut. */
|
|
383
|
+
readonly BargeIn: "barge_in";
|
|
384
|
+
/** Alias for barge-in on some engine builds. */
|
|
385
|
+
readonly Flush: "flush";
|
|
386
|
+
/** Session is closing; see close code. */
|
|
387
|
+
readonly SessionEnd: "session_end";
|
|
388
|
+
/** Server fault frame. */
|
|
389
|
+
readonly Error: "error";
|
|
390
|
+
};
|
|
391
|
+
export type OmniEvent = (typeof OmniEvent)[keyof typeof OmniEvent];
|
|
392
|
+
/** A server → client Omni frame. Keyed on `event` (not `type`); open for forward-compat. */
|
|
393
|
+
export interface OmniServerFrame {
|
|
394
|
+
event: string;
|
|
395
|
+
[k: string]: unknown;
|
|
396
|
+
}
|
|
397
|
+
/** A binary agent-audio chunk delivered to {@link OmniConnectOptions.onAudio}. */
|
|
398
|
+
export type OmniAudioChunk = ArrayBuffer | ArrayBufferView | Blob;
|
|
399
|
+
/**
|
|
400
|
+
* The agent config sent as the `configure` control frame. These are the wire
|
|
401
|
+
* (snake_case) fields the engine reads; it's an **open bag**, so forward-compat
|
|
402
|
+
* fields (e.g. `greeting` / `language` once the engine acks them) pass straight
|
|
403
|
+
* through. The SDK supplies the `{"type":"configure"}` envelope for you — which
|
|
404
|
+
* is the whole point: a hand-rolled `{"event":"configure"}` is acked but
|
|
405
|
+
* silently dropped, leaving the agent with no brain and zero turns.
|
|
406
|
+
*/
|
|
407
|
+
export interface OmniConfigure {
|
|
408
|
+
/** Voice to speak with (stock / clone / designed id). */
|
|
409
|
+
voice_id?: string;
|
|
410
|
+
/** System prompt / role + instructions for the agent. */
|
|
411
|
+
persona?: string;
|
|
412
|
+
/** Customer-hosted URL the engine calls per turn for grounding. */
|
|
413
|
+
kb_endpoint?: string;
|
|
414
|
+
/** Bearer the engine presents to `kb_endpoint`. */
|
|
415
|
+
kb_token?: string;
|
|
416
|
+
/** Forward-compatible: any other key the engine honors. */
|
|
417
|
+
[k: string]: unknown;
|
|
418
|
+
}
|
|
419
|
+
export interface OmniConnectOptions {
|
|
420
|
+
/** Optional opaque per-session tag echoed to your `kb_endpoint`. Omni is zero-state. */
|
|
421
|
+
sessionLabel?: string;
|
|
422
|
+
/**
|
|
423
|
+
* Ephemeral browser token from `omni.createSession`. When set it is used as
|
|
424
|
+
* the WS subprotocol (`pyai-key.<token>`) instead of the client's secret key,
|
|
425
|
+
* so a page never holds a secret key.
|
|
426
|
+
*/
|
|
427
|
+
token?: string;
|
|
428
|
+
/** Connect-URL sample rate: 24000 browser, 16000 wideband telephony, 8000 G.711/Twilio. */
|
|
429
|
+
rate?: 24000 | 16000 | 8000;
|
|
430
|
+
/** Connect-URL audio format. Default `pcm16`. */
|
|
431
|
+
format?: "pcm16";
|
|
432
|
+
/**
|
|
433
|
+
* Agent config sent as `{"type":"configure",...}` the instant the socket
|
|
434
|
+
* opens. Omit to send it yourself later via {@link OmniConnection.configure}.
|
|
435
|
+
*/
|
|
436
|
+
configure?: OmniConfigure;
|
|
437
|
+
/** Extra query params merged onto the connect URL. */
|
|
438
|
+
query?: Record<string, string>;
|
|
439
|
+
/** Fired once the socket opens (after the optional auto-configure). */
|
|
440
|
+
onOpen?: () => void;
|
|
441
|
+
/** Fired for each binary agent-audio chunk — play it out as it arrives. */
|
|
442
|
+
onAudio?: (chunk: OmniAudioChunk) => void;
|
|
443
|
+
/** Fired on the `hello` handshake frame. */
|
|
444
|
+
onHello?: (frame: OmniServerFrame) => void;
|
|
445
|
+
/** Fired on the `configured` ack. */
|
|
446
|
+
onConfigured?: (frame: OmniServerFrame) => void;
|
|
447
|
+
/** Fired on `session_started`. */
|
|
448
|
+
onSessionStarted?: (frame: OmniServerFrame) => void;
|
|
449
|
+
/** Fired on `turn` boundaries. */
|
|
450
|
+
onTurn?: (frame: OmniServerFrame) => void;
|
|
451
|
+
/** Fired on `transcript` text frames. */
|
|
452
|
+
onTranscript?: (frame: OmniServerFrame) => void;
|
|
453
|
+
/** Fired on `barge_in` / `flush` (user interrupted). */
|
|
454
|
+
onBargeIn?: (frame: OmniServerFrame) => void;
|
|
455
|
+
/** Fired on `session_end`. */
|
|
456
|
+
onSessionEnd?: (frame: OmniServerFrame) => void;
|
|
457
|
+
/** Fired on EVERY JSON frame (including unknown/forward-compat ones). */
|
|
458
|
+
onEvent?: (frame: OmniServerFrame) => void;
|
|
459
|
+
/** Fired on an `error` frame or a transport-level error. */
|
|
460
|
+
onError?: (err: OmniServerFrame | Error) => void;
|
|
461
|
+
/** Fired when the socket closes (code per {@link WSCloseCode}). */
|
|
462
|
+
onClose?: (code: number, reason: string) => void;
|
|
463
|
+
/** Injectable WebSocket constructor (defaults to the global). */
|
|
464
|
+
webSocket?: WebSocketCtor;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* A live Omni agentic-voice session over `/v1/omni`. Hides the wire protocol's
|
|
468
|
+
* frame-key asymmetry: it sends control frames keyed on `type` (`configure`,
|
|
469
|
+
* `dtmf`) and parses server frames keyed on `event`, so you cannot trip the #1
|
|
470
|
+
* Omni integration bug (mirroring the server's `event` key on outbound, which
|
|
471
|
+
* is silently dropped). Construct via `pyai.omni.connect()`.
|
|
472
|
+
*
|
|
473
|
+
* @example
|
|
474
|
+
* const omni = pyai.omni.connect({
|
|
475
|
+
* rate: 16000,
|
|
476
|
+
* configure: { voice_id: "stock_emma_en_gb", persona: "You are a receptionist." },
|
|
477
|
+
* onAudio: (chunk) => speaker.write(chunk),
|
|
478
|
+
* onTranscript: (f) => console.log(f.text),
|
|
479
|
+
* });
|
|
480
|
+
* omni.sendAudio(pcm16Chunk); // stream caller audio continuously
|
|
481
|
+
*/
|
|
482
|
+
export declare class OmniConnection {
|
|
483
|
+
private readonly ws;
|
|
484
|
+
private readonly opts;
|
|
485
|
+
private closed;
|
|
486
|
+
constructor(url: string, subprotocol: string, opts: OmniConnectOptions);
|
|
487
|
+
private handleMessage;
|
|
488
|
+
/**
|
|
489
|
+
* Send (or update) the agent config. Always emitted as
|
|
490
|
+
* `{"type":"configure", ...}` — the correct key. (A hand-rolled
|
|
491
|
+
* `{"event":"configure"}` is acked but silently dropped by the engine.)
|
|
492
|
+
*/
|
|
493
|
+
configure(cfg: OmniConfigure): void;
|
|
494
|
+
/** Stream a chunk of caller audio (PCM16 LE mono at the negotiated rate). */
|
|
495
|
+
sendAudio(chunk: ArrayBufferLike | ArrayBufferView | Blob): void;
|
|
496
|
+
/** Send DTMF digits as a `{"type":"dtmf"}` control frame. */
|
|
497
|
+
sendDtmf(digits: string): void;
|
|
498
|
+
/**
|
|
499
|
+
* Send an arbitrary control frame for forward-compat control types the SDK
|
|
500
|
+
* does not model yet. Reminder: client → server frames are keyed on `type`,
|
|
501
|
+
* never `event`.
|
|
502
|
+
*/
|
|
503
|
+
send(frame: Record<string, unknown>): void;
|
|
504
|
+
/** Close the session. */
|
|
505
|
+
close(code?: number, reason?: string): void;
|
|
506
|
+
/** The underlying socket (escape hatch for advanced use). */
|
|
507
|
+
get socket(): WebSocketLike;
|
|
508
|
+
/** Current WebSocket readyState. */
|
|
509
|
+
get readyState(): number;
|
|
510
|
+
}
|
|
511
|
+
/** Shape of `GET /v1/me`. Fields are best-effort / forward-compatible. */
|
|
512
|
+
export interface MeResponse {
|
|
513
|
+
object?: string;
|
|
514
|
+
key_id?: string;
|
|
515
|
+
org_id?: string;
|
|
516
|
+
/** "live" | "test" (a.k.a. environment). */
|
|
517
|
+
environment?: string;
|
|
518
|
+
env?: string;
|
|
519
|
+
scopes?: string[];
|
|
520
|
+
limits?: Record<string, unknown>;
|
|
521
|
+
[k: string]: unknown;
|
|
522
|
+
}
|
|
523
|
+
export interface TelephonyCapabilities {
|
|
524
|
+
voice?: boolean;
|
|
525
|
+
sms?: boolean;
|
|
526
|
+
}
|
|
527
|
+
export interface TelephonyAvailableNumber {
|
|
528
|
+
object?: "telephony.available_number";
|
|
529
|
+
/** E.164. */
|
|
530
|
+
phone_number: string;
|
|
531
|
+
country?: string;
|
|
532
|
+
area_code?: string | null;
|
|
533
|
+
locality?: string | null;
|
|
534
|
+
region?: string | null;
|
|
535
|
+
capabilities?: TelephonyCapabilities;
|
|
536
|
+
monthly_cost_cents?: number;
|
|
537
|
+
}
|
|
538
|
+
export interface TelephonyNumber {
|
|
539
|
+
object?: "telephony.number";
|
|
540
|
+
id: string;
|
|
541
|
+
/** E.164. */
|
|
542
|
+
phone_number: string;
|
|
543
|
+
country?: string;
|
|
544
|
+
area_code?: string | null;
|
|
545
|
+
capabilities?: TelephonyCapabilities;
|
|
546
|
+
/** Agent that answers inbound calls to this number. */
|
|
547
|
+
agent_id?: string | null;
|
|
548
|
+
recording?: boolean;
|
|
549
|
+
monthly_cost_cents?: number;
|
|
550
|
+
status?: "active" | "released";
|
|
551
|
+
created_at?: number;
|
|
552
|
+
released_at?: number | null;
|
|
553
|
+
}
|
|
554
|
+
export type TraceVerdict = "PASS" | "WARN" | "FAIL";
|
|
555
|
+
export type TraceSeverity = "low" | "medium" | "high" | "critical";
|
|
556
|
+
export interface TraceInteraction {
|
|
557
|
+
object?: "trace.interaction";
|
|
558
|
+
/** call_id */
|
|
559
|
+
id: string;
|
|
560
|
+
agent_id?: string | null;
|
|
561
|
+
product?: string | null;
|
|
562
|
+
verdict: TraceVerdict;
|
|
563
|
+
findings?: number;
|
|
564
|
+
blocked_turns?: number;
|
|
565
|
+
modified_turns?: number;
|
|
566
|
+
packs_enforced?: string;
|
|
567
|
+
scored_at?: number;
|
|
568
|
+
}
|
|
569
|
+
export interface TraceFinding {
|
|
570
|
+
object?: "trace.finding";
|
|
571
|
+
id: string;
|
|
572
|
+
/** call_id */
|
|
573
|
+
interaction_id: string;
|
|
574
|
+
agent_id?: string | null;
|
|
575
|
+
check_id: string;
|
|
576
|
+
severity: TraceSeverity;
|
|
577
|
+
verdict?: string;
|
|
578
|
+
confidence?: number;
|
|
579
|
+
action?: "flag" | "preempt_next" | "escalate";
|
|
580
|
+
speaker?: "agent" | "caller" | "any" | null;
|
|
581
|
+
reason?: string;
|
|
582
|
+
preempt_instruction?: string | null;
|
|
583
|
+
at_t?: number | null;
|
|
584
|
+
tier?: number;
|
|
585
|
+
}
|
|
586
|
+
/** A tool invocation recorded on a timeline turn. */
|
|
587
|
+
export interface TraceToolCall {
|
|
588
|
+
name: string;
|
|
589
|
+
/** Arguments the agent passed (engine-shaped JSON). */
|
|
590
|
+
args?: unknown;
|
|
591
|
+
/** Tool result returned to the agent (engine-shaped JSON). */
|
|
592
|
+
result?: unknown;
|
|
593
|
+
/** Audio-timeline position of the call, ms. */
|
|
594
|
+
t_ms?: number;
|
|
595
|
+
}
|
|
596
|
+
/** Barge-in timing for a timeline turn. */
|
|
597
|
+
export interface TraceBargeMetrics {
|
|
598
|
+
/** Time from caller speech onset to barge-in detection, ms. */
|
|
599
|
+
detect_ms?: number;
|
|
600
|
+
/** Whether the agent cleanly recovered after the barge-in. */
|
|
601
|
+
recovered?: boolean;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Known timeline-turn roles. Left open (see {@link TraceTimelineTurn.role}) so a
|
|
605
|
+
* new server-side role never breaks the build — branch defensively.
|
|
606
|
+
*/
|
|
607
|
+
export type TraceTimelineRole = "agent" | "caller" | "system" | "tool";
|
|
608
|
+
/** One turn of a per-call operational timeline (eval scorecard-v1). */
|
|
609
|
+
export interface TraceTimelineTurn {
|
|
610
|
+
/** Monotonic turn index within the call. */
|
|
611
|
+
seq: number;
|
|
612
|
+
/** Audio-timeline position of the turn, ms. */
|
|
613
|
+
t_ms: number;
|
|
614
|
+
/** Who spoke/acted this turn. Open-ended for forward-compat. */
|
|
615
|
+
role: TraceTimelineRole | (string & {});
|
|
616
|
+
/** Transcript/text for the turn, when available. */
|
|
617
|
+
text?: string;
|
|
618
|
+
/** Time-to-first-audio for the turn (latency scoring), ms. */
|
|
619
|
+
ttfb_ms?: number;
|
|
620
|
+
/** Turn-detection (endpointing) latency, ms. */
|
|
621
|
+
endpointing_ms?: number;
|
|
622
|
+
/** Barge-in detect/recovery timing for the turn. */
|
|
623
|
+
barge?: TraceBargeMetrics;
|
|
624
|
+
/** Tool calls made during the turn (tool-use scoring). */
|
|
625
|
+
tool_calls?: TraceToolCall[];
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Aggregate per-call quality metrics (eval scorecard-v1). All optional and
|
|
629
|
+
* forward-compatible — present once the engine emits them.
|
|
630
|
+
*/
|
|
631
|
+
export interface QualityMetrics {
|
|
632
|
+
/** Word error rate vs. reference transcript, 0–1 (lower is better). */
|
|
633
|
+
wer?: number;
|
|
634
|
+
/** Representative time-to-first-audio across turns, ms. */
|
|
635
|
+
ttfb_ms?: number;
|
|
636
|
+
/** 95th-percentile end-to-end turn latency, ms. */
|
|
637
|
+
turn_p95_ms?: number;
|
|
638
|
+
/** Barge-in recovery rate, 0–1. */
|
|
639
|
+
barge_recovery?: number;
|
|
640
|
+
/** Task-success score, 0–1. */
|
|
641
|
+
task_success?: number;
|
|
642
|
+
/** Composite voice-agent quality index (engine-defined scale). */
|
|
643
|
+
vaqi?: number;
|
|
644
|
+
[k: string]: unknown;
|
|
645
|
+
}
|
|
646
|
+
export interface TraceInteractionDetail extends TraceInteraction {
|
|
647
|
+
/** Hash-chain link proving the record is unaltered. */
|
|
648
|
+
audit_hash?: string;
|
|
649
|
+
scorecard?: Record<string, unknown>;
|
|
650
|
+
tier2_findings?: TraceFinding[];
|
|
651
|
+
/**
|
|
652
|
+
* Scorecard schema version, e.g. `"trace-scorecard-v1"`. Present once the
|
|
653
|
+
* engine emits the eval block below.
|
|
654
|
+
*/
|
|
655
|
+
scorecard_version?: string;
|
|
656
|
+
/**
|
|
657
|
+
* Per-call operational timeline. Forward-compatible: empty/undefined until
|
|
658
|
+
* the engine emits per-turn timing (Ask 1 of the evals engine plan).
|
|
659
|
+
*/
|
|
660
|
+
timeline?: TraceTimelineTurn[];
|
|
661
|
+
/** Aggregate per-call quality metrics. Forward-compatible (see above). */
|
|
662
|
+
quality_metrics?: QualityMetrics;
|
|
663
|
+
}
|
|
664
|
+
export interface TraceViolation {
|
|
665
|
+
object?: "trace.violation";
|
|
666
|
+
id: string;
|
|
667
|
+
/** call_id */
|
|
668
|
+
interaction_id: string;
|
|
669
|
+
agent_id?: string | null;
|
|
670
|
+
rule_id: string;
|
|
671
|
+
pack_id?: string | null;
|
|
672
|
+
severity: TraceSeverity;
|
|
673
|
+
action_taken?: "pass" | "flag" | "modify" | "block";
|
|
674
|
+
citation?: string;
|
|
675
|
+
reason?: string;
|
|
676
|
+
at_t?: number | null;
|
|
677
|
+
}
|
|
678
|
+
export interface TraceConfigInput {
|
|
679
|
+
agent_id?: string;
|
|
680
|
+
enabled?: boolean;
|
|
681
|
+
channels?: Array<"voice" | "text">;
|
|
682
|
+
/** Map of pack_id → { enabled, version }. */
|
|
683
|
+
rule_packs?: Record<string, {
|
|
684
|
+
enabled?: boolean;
|
|
685
|
+
version?: string | null;
|
|
686
|
+
}>;
|
|
687
|
+
guardrails?: Record<string, unknown>;
|
|
688
|
+
[k: string]: unknown;
|
|
689
|
+
}
|
|
690
|
+
export interface TraceConfig {
|
|
691
|
+
object?: "trace.config";
|
|
692
|
+
agent_id?: string | null;
|
|
693
|
+
enabled?: boolean;
|
|
694
|
+
mode?: "warn" | "modify" | "block" | "human_handoff";
|
|
695
|
+
etag?: string;
|
|
696
|
+
updated_at?: number;
|
|
697
|
+
config?: TraceConfigInput;
|
|
698
|
+
}
|
|
699
|
+
export interface TraceRulePackSpec {
|
|
700
|
+
pack_id: string;
|
|
701
|
+
version: string;
|
|
702
|
+
jurisdiction?: string;
|
|
703
|
+
legal_status?: string;
|
|
704
|
+
rules: Array<Record<string, unknown>>;
|
|
705
|
+
}
|
|
706
|
+
export interface TraceRulePack {
|
|
707
|
+
object?: "trace.rule_pack";
|
|
708
|
+
id?: string;
|
|
709
|
+
pack_id: string;
|
|
710
|
+
version?: string;
|
|
711
|
+
builtin?: boolean;
|
|
712
|
+
jurisdiction?: string | null;
|
|
713
|
+
legal_status?: string | null;
|
|
714
|
+
etag?: string;
|
|
715
|
+
status?: "active" | "deprecated";
|
|
716
|
+
created_at?: number;
|
|
717
|
+
/** The authored DSL (only on the single-pack GET). */
|
|
718
|
+
spec?: Record<string, unknown>;
|
|
719
|
+
}
|
|
720
|
+
export interface TraceExposure {
|
|
721
|
+
object?: "trace.exposure";
|
|
722
|
+
window_days?: number;
|
|
723
|
+
interactions_scanned?: number;
|
|
724
|
+
with_a_gap?: number;
|
|
725
|
+
gap_rate?: number;
|
|
726
|
+
by_rule?: Array<{
|
|
727
|
+
rule_id: string;
|
|
728
|
+
pack_id?: string | null;
|
|
729
|
+
count: number;
|
|
730
|
+
rate: number;
|
|
731
|
+
}>;
|
|
732
|
+
by_verdict?: {
|
|
733
|
+
PASS?: number;
|
|
734
|
+
WARN?: number;
|
|
735
|
+
FAIL?: number;
|
|
736
|
+
};
|
|
737
|
+
top_exposure?: string | null;
|
|
738
|
+
}
|
|
739
|
+
export interface RecapConfigInput {
|
|
740
|
+
enabled?: boolean;
|
|
741
|
+
webhook_url?: string | null;
|
|
742
|
+
default_pack_id?: string;
|
|
743
|
+
}
|
|
744
|
+
export interface RecapConfig {
|
|
745
|
+
object?: "recap.config";
|
|
746
|
+
enabled?: boolean;
|
|
747
|
+
webhook_url?: string | null;
|
|
748
|
+
default_pack_id?: string;
|
|
749
|
+
updated_at?: number;
|
|
750
|
+
}
|
|
751
|
+
export interface RecapCallSummary {
|
|
752
|
+
object?: "recap.call";
|
|
753
|
+
call_id: string;
|
|
754
|
+
pack_id?: string;
|
|
755
|
+
status?: "pending" | "processing" | "complete" | "failed";
|
|
756
|
+
call_duration_s?: number | null;
|
|
757
|
+
created_at?: number;
|
|
758
|
+
completed_at?: number | null;
|
|
759
|
+
}
|
|
760
|
+
export interface RecapCall extends RecapCallSummary {
|
|
761
|
+
record?: unknown;
|
|
762
|
+
error?: string | null;
|
|
763
|
+
crm_write_status?: string | null;
|
|
764
|
+
}
|
|
765
|
+
export interface RecapCallTriggerInput {
|
|
766
|
+
utterances: Array<{
|
|
767
|
+
speaker_role?: "agent" | "customer";
|
|
768
|
+
text: string;
|
|
769
|
+
offset_s?: number;
|
|
770
|
+
duration_s?: number;
|
|
771
|
+
}>;
|
|
772
|
+
pack_id?: string;
|
|
773
|
+
call_duration_s?: number;
|
|
774
|
+
call_direction?: "inbound" | "outbound";
|
|
775
|
+
customer_name?: string;
|
|
776
|
+
crm_fields?: Record<string, unknown>;
|
|
777
|
+
}
|
|
79
778
|
export declare class PyAI {
|
|
80
779
|
private readonly apiKey;
|
|
81
780
|
private readonly baseURL;
|
|
@@ -86,6 +785,9 @@ export declare class PyAI {
|
|
|
86
785
|
private request;
|
|
87
786
|
private toError;
|
|
88
787
|
private getJson;
|
|
788
|
+
private postJson;
|
|
789
|
+
private putJson;
|
|
790
|
+
private deleteReq;
|
|
89
791
|
models: {
|
|
90
792
|
list: () => Promise<ListResponse<{
|
|
91
793
|
id: string;
|
|
@@ -116,10 +818,26 @@ export declare class PyAI {
|
|
|
116
818
|
file: Blob;
|
|
117
819
|
filename?: string;
|
|
118
820
|
model?: string;
|
|
821
|
+
language?: string;
|
|
822
|
+
response_format?: "json" | "text" | "verbose_json";
|
|
823
|
+
/**
|
|
824
|
+
* Deterministic seed for reproducible eval runs. Forward-compatible:
|
|
825
|
+
* honored once the engine supports it, otherwise ignored.
|
|
826
|
+
*/
|
|
827
|
+
seed?: number;
|
|
828
|
+
/** Sampling temperature. Forward-compatible (honored when supported). */
|
|
829
|
+
temperature?: number;
|
|
119
830
|
}) => Promise<{
|
|
120
831
|
text: string;
|
|
121
832
|
[k: string]: unknown;
|
|
122
833
|
}>;
|
|
834
|
+
/**
|
|
835
|
+
* Open a live streaming-STT WebSocket (Hear). Hides the frame protocol
|
|
836
|
+
* behind `onPartial`/`onFinal`/`onError`; stream audio with `sendAudio`,
|
|
837
|
+
* force-finalize with `commit()`, flush+close with `close()`. Set
|
|
838
|
+
* `grounding: true` for Cue (turn detection + KB context).
|
|
839
|
+
*/
|
|
840
|
+
stream: (opts?: HearStreamOptions) => HearStream;
|
|
123
841
|
};
|
|
124
842
|
};
|
|
125
843
|
transcriptionJobs: {
|
|
@@ -132,10 +850,153 @@ export declare class PyAI {
|
|
|
132
850
|
cursor?: string;
|
|
133
851
|
}) => Promise<ListResponse<TranscriptionJob>>;
|
|
134
852
|
};
|
|
853
|
+
/**
|
|
854
|
+
* Introspect the calling key: scopes, environment, and limits. Useful for a
|
|
855
|
+
* preflight/doctor check. (New route; older deployments may 404 — handle it.)
|
|
856
|
+
*/
|
|
857
|
+
me: () => Promise<MeResponse>;
|
|
858
|
+
clones: {
|
|
859
|
+
/** List the org's cloned voices. */
|
|
860
|
+
list: () => Promise<ListResponse<Voice>>;
|
|
861
|
+
/** Enroll a custom voice from reference audio (>= ~10s). Scope `voice:clone`. */
|
|
862
|
+
create: (params: {
|
|
863
|
+
name: string;
|
|
864
|
+
file: Blob;
|
|
865
|
+
filename?: string;
|
|
866
|
+
}) => Promise<Voice>;
|
|
867
|
+
/**
|
|
868
|
+
* Fetch a single cloned voice by id. The API exposes no GET-by-id for
|
|
869
|
+
* clones, so this filters `list()` client-side and throws a 404 `PyAIError`
|
|
870
|
+
* when the id isn't found.
|
|
871
|
+
*/
|
|
872
|
+
get: (id: string) => Promise<Voice>;
|
|
873
|
+
/** Delete a cloned voice (tenant-isolated). Scope `voice:clone`. */
|
|
874
|
+
delete: (id: string) => Promise<void>;
|
|
875
|
+
};
|
|
876
|
+
telephony: {
|
|
877
|
+
numbers: {
|
|
878
|
+
/** Search the carrier's available US local numbers. */
|
|
879
|
+
available: (params?: {
|
|
880
|
+
areaCode?: string;
|
|
881
|
+
contains?: string;
|
|
882
|
+
limit?: number;
|
|
883
|
+
}) => Promise<ListResponse<TelephonyAvailableNumber>>;
|
|
884
|
+
/** List the org's managed numbers (active only unless `includeReleased`). */
|
|
885
|
+
list: (params?: {
|
|
886
|
+
includeReleased?: boolean;
|
|
887
|
+
}) => Promise<ListResponse<TelephonyNumber>>;
|
|
888
|
+
/** Provision (buy) a specific available number, optionally bound to an agent. */
|
|
889
|
+
buy: (params: {
|
|
890
|
+
phone_number: string;
|
|
891
|
+
agent_id?: string | null;
|
|
892
|
+
}) => Promise<TelephonyNumber>;
|
|
893
|
+
/** Route a number to an agent (`agentId: null` to unassign). */
|
|
894
|
+
assign: (id: string, agentId: string | null) => Promise<TelephonyNumber>;
|
|
895
|
+
/** Release a number back to the carrier (idempotent). */
|
|
896
|
+
release: (id: string) => Promise<TelephonyNumber>;
|
|
897
|
+
};
|
|
898
|
+
};
|
|
899
|
+
trace: {
|
|
900
|
+
interactions: {
|
|
901
|
+
/** List scanned interactions (scorecards), newest first. Scope `trace:read`. */
|
|
902
|
+
list: (params?: {
|
|
903
|
+
verdict?: TraceVerdict;
|
|
904
|
+
agentId?: string;
|
|
905
|
+
limit?: number;
|
|
906
|
+
cursor?: string;
|
|
907
|
+
}) => Promise<ListResponse<TraceInteraction>>;
|
|
908
|
+
/** The full per-call evidence view (findings, redactions, audit hash). */
|
|
909
|
+
get: (id: string) => Promise<TraceInteractionDetail>;
|
|
910
|
+
};
|
|
911
|
+
violations: {
|
|
912
|
+
/** Drill-down of every fired Tier-0 rule across scorecards. Scope `trace:read`. */
|
|
913
|
+
list: (params?: {
|
|
914
|
+
ruleId?: string;
|
|
915
|
+
severity?: TraceSeverity;
|
|
916
|
+
interactionId?: string;
|
|
917
|
+
limit?: number;
|
|
918
|
+
cursor?: string;
|
|
919
|
+
}) => Promise<ListResponse<TraceViolation>>;
|
|
920
|
+
};
|
|
921
|
+
findings: {
|
|
922
|
+
/** List Tier-2 (async semantic) findings — advisory, non-blocking. Scope `trace:read`. */
|
|
923
|
+
list: (params?: {
|
|
924
|
+
checkId?: string;
|
|
925
|
+
action?: "flag" | "preempt_next" | "escalate";
|
|
926
|
+
severity?: TraceSeverity;
|
|
927
|
+
interactionId?: string;
|
|
928
|
+
limit?: number;
|
|
929
|
+
cursor?: string;
|
|
930
|
+
}) => Promise<ListResponse<TraceFinding>>;
|
|
931
|
+
};
|
|
932
|
+
config: {
|
|
933
|
+
/** Read per-agent Trace config (omit `agentId` for the org default). Scope `trace:configure`. */
|
|
934
|
+
get: (agentId?: string) => Promise<TraceConfig>;
|
|
935
|
+
/** Upsert per-agent Trace config. Scope `trace:configure`. */
|
|
936
|
+
set: (input: TraceConfigInput) => Promise<TraceConfig>;
|
|
937
|
+
};
|
|
938
|
+
rulePacks: {
|
|
939
|
+
/** List built-in + custom rule packs. Scope `trace:configure`. */
|
|
940
|
+
list: () => Promise<ListResponse<TraceRulePack>>;
|
|
941
|
+
/** Upload a custom rule pack (Trace DSL). Scope `trace:configure`. */
|
|
942
|
+
create: (spec: TraceRulePackSpec) => Promise<TraceRulePack>;
|
|
943
|
+
/** Resolve a rule pack by id (latest active, or pin `version`). */
|
|
944
|
+
get: (id: string, version?: string) => Promise<TraceRulePack>;
|
|
945
|
+
};
|
|
946
|
+
/** Compliance exposure summary over a trailing window. Scope `trace:read`. */
|
|
947
|
+
exposure: (windowDays?: number) => Promise<TraceExposure>;
|
|
948
|
+
/**
|
|
949
|
+
* Convenience: the per-call operational timeline (eval scorecard-v1). A thin
|
|
950
|
+
* wrapper over `interactions.get(id)` that returns the `timeline` array, or
|
|
951
|
+
* `[]` when the engine hasn't emitted one yet (forward-compatible). Scope
|
|
952
|
+
* `trace:read`.
|
|
953
|
+
*/
|
|
954
|
+
callTimeline: (id: string) => Promise<TraceTimelineTurn[]>;
|
|
955
|
+
};
|
|
956
|
+
recap: {
|
|
957
|
+
config: {
|
|
958
|
+
get: () => Promise<RecapConfig>;
|
|
959
|
+
set: (input: RecapConfigInput) => Promise<RecapConfig>;
|
|
960
|
+
};
|
|
961
|
+
calls: {
|
|
962
|
+
list: (params?: {
|
|
963
|
+
limit?: number;
|
|
964
|
+
cursor?: string;
|
|
965
|
+
status?: string;
|
|
966
|
+
}) => Promise<ListResponse<RecapCallSummary>>;
|
|
967
|
+
get: (callId: string) => Promise<RecapCall>;
|
|
968
|
+
trigger: (callId: string, input: RecapCallTriggerInput) => Promise<RecapCallSummary>;
|
|
969
|
+
};
|
|
970
|
+
};
|
|
971
|
+
omni: {
|
|
972
|
+
/**
|
|
973
|
+
* Mint an ephemeral, origin-locked Omni session token a browser can use to
|
|
974
|
+
* open ONE realtime session **directly** — the public/private split for
|
|
975
|
+
* realtime. **Call this from your server** with a secret key holding
|
|
976
|
+
* `omni:session`; never ship the secret key to a page. Hand the returned
|
|
977
|
+
* `token` to the browser, which connects with
|
|
978
|
+
* `new WebSocket(session.url, ["pyai-key." + session.token])`. The token
|
|
979
|
+
* expires after `ttlSeconds` (default 60s) and only works from
|
|
980
|
+
* `allowedOrigins`. Scope `omni:session`.
|
|
981
|
+
*/
|
|
982
|
+
createSession: (params: OmniSessionParams) => Promise<OmniSession>;
|
|
983
|
+
/**
|
|
984
|
+
* Open a live Omni agentic-voice session over `/v1/omni`. Returns an
|
|
985
|
+
* {@link OmniConnection} that handles the wire protocol's frame-key
|
|
986
|
+
* asymmetry for you — it sends `type`-keyed control frames (`configure`,
|
|
987
|
+
* `dtmf`) and parses `event`-keyed server frames — so you can't trip the #1
|
|
988
|
+
* Omni integration bug. Omni is zero-state: nothing to create first; the
|
|
989
|
+
* agent's behavior travels in the `configure` frame. Pass `token` (from
|
|
990
|
+
* `createSession`) to connect from a browser without the secret key.
|
|
991
|
+
*/
|
|
992
|
+
connect: (opts?: OmniConnectOptions) => OmniConnection;
|
|
993
|
+
};
|
|
135
994
|
/** Build the realtime WebSocket URL for the chosen product. */
|
|
136
995
|
realtimeURL(opts?: RealtimeOptions): string;
|
|
137
996
|
/** The subprotocol that carries the key on a WS upgrade (browser-safe auth). */
|
|
138
997
|
realtimeSubprotocol(): string;
|
|
998
|
+
/** Build the Hear streaming-STT WebSocket URL (`/v1/audio/transcriptions/stream`). */
|
|
999
|
+
hearStreamURL(opts?: HearStreamOptions): string;
|
|
139
1000
|
/**
|
|
140
1001
|
* Open a realtime WebSocket. Uses the global WebSocket (browser, Node 22+).
|
|
141
1002
|
* The key travels as a subprotocol so it works from the browser without
|