@pyai/sdk 0.2.1 → 0.2.3
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 +84 -25
- package/dist/cli.d.ts +4 -3
- package/dist/cli.js +78 -28
- package/dist/index.d.ts +212 -37
- package/dist/index.js +314 -30
- package/package.json +2 -2
- package/src/cli.ts +77 -29
- package/src/index.ts +481 -57
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @pyai/sdk
|
|
2
|
+
* @pyai/sdk, official TypeScript/JavaScript client for the PyAI API.
|
|
3
3
|
*
|
|
4
4
|
* Thin, dependency-free wrapper over the public OpenAI-compatible surface at
|
|
5
5
|
* https://api.pyai.com (contract: https://api.pyai.com/openapi.json). Runs in
|
|
6
|
-
* the browser and Node 22+ (uses global fetch + WebSocket). Keys are opaque
|
|
7
|
-
* never parsed.
|
|
6
|
+
* the browser and Node 22+ (uses global fetch + WebSocket). Keys are opaque, * never parsed.
|
|
8
7
|
*/
|
|
9
8
|
export interface PyAIOptions {
|
|
10
9
|
/** A pyai_live_ or pyai_test_ key. */
|
|
@@ -48,7 +47,7 @@ export interface TranscriptionJob {
|
|
|
48
47
|
}
|
|
49
48
|
/**
|
|
50
49
|
* Output container/codec for `audio.speech`. This is the **exact** set the
|
|
51
|
-
* server accepts on `POST /v1/audio/speech
|
|
50
|
+
* server accepts on `POST /v1/audio/speech`, any other value is rejected with
|
|
52
51
|
* `400 unsupported_format`. The default (when `response_format` is omitted) is
|
|
53
52
|
* `mp3`. Omit `sample_rate` for the engine's native 24 kHz (`g711_*` is always
|
|
54
53
|
* 8 kHz).
|
|
@@ -80,20 +79,20 @@ export interface SpeechParams {
|
|
|
80
79
|
model?: string;
|
|
81
80
|
/**
|
|
82
81
|
* Output container/codec, resampled+encoded server-side. One of
|
|
83
|
-
* {@link SpeechFormat}
|
|
82
|
+
* {@link SpeechFormat}, anything else is a `400 unsupported_format`. Omit for
|
|
84
83
|
* the default of `mp3`.
|
|
85
84
|
*
|
|
86
|
-
* `g711_ulaw`/`g711_alaw` return raw 8 kHz mono G.711
|
|
85
|
+
* `g711_ulaw`/`g711_alaw` return raw 8 kHz mono G.711, the bytes Twilio/SIP
|
|
87
86
|
* media streams expect, so you can hand the response straight to a telephony
|
|
88
87
|
* frame without a client-side resampler or μ-law encoder. `sample_rate` is
|
|
89
88
|
* forced to 8000 for those (omit it, or set exactly 8000). `pcm` is raw,
|
|
90
89
|
* headerless int16 LE mono at `sample_rate`. `mp3`/`opus` are buffered (not
|
|
91
|
-
* chunk-streamed)
|
|
90
|
+
* chunk-streamed), use them with `speech`, not `speechStream`.
|
|
92
91
|
*/
|
|
93
92
|
response_format?: SpeechFormat;
|
|
94
93
|
/**
|
|
95
94
|
* Output sample rate in Hz. One of {@link SpeechSampleRate}
|
|
96
|
-
* (8000/16000/24000/48000)
|
|
95
|
+
* (8000/16000/24000/48000), anything else is a `400`. Omit for the engine's
|
|
97
96
|
* native 24 kHz; `g711_*` is always 8000 (forced). Set `8000`/`16000` for
|
|
98
97
|
* telephony pipelines, most often with `response_format: "pcm"`.
|
|
99
98
|
*/
|
|
@@ -106,8 +105,7 @@ export interface SpeechParams {
|
|
|
106
105
|
*/
|
|
107
106
|
seed?: number;
|
|
108
107
|
/**
|
|
109
|
-
* Sampling temperature (lower = more deterministic). Forward-compatible
|
|
110
|
-
* honored once the engine supports it, otherwise ignored.
|
|
108
|
+
* Sampling temperature (lower = more deterministic). Forward-compatible, * honored once the engine supports it, otherwise ignored.
|
|
111
109
|
*/
|
|
112
110
|
temperature?: number;
|
|
113
111
|
}
|
|
@@ -130,7 +128,7 @@ export interface RealtimeOptions {
|
|
|
130
128
|
*/
|
|
131
129
|
sessionLabel?: string;
|
|
132
130
|
/**
|
|
133
|
-
* @deprecated Use {@link sessionLabel}. Kept for back-compat
|
|
131
|
+
* @deprecated Use {@link sessionLabel}. Kept for back-compat, emitted as the
|
|
134
132
|
* `agent_id` query alias, which the gateway still accepts. Ignored if
|
|
135
133
|
* `sessionLabel` is set.
|
|
136
134
|
*/
|
|
@@ -142,7 +140,7 @@ export interface RealtimeOptions {
|
|
|
142
140
|
export interface OmniSessionParams {
|
|
143
141
|
/**
|
|
144
142
|
* Browser origins (scheme://host[:port]) the minted token may connect from.
|
|
145
|
-
* Required and non-empty
|
|
143
|
+
* Required and non-empty, a browser token must be origin-locked. `*` is not
|
|
146
144
|
* allowed.
|
|
147
145
|
*/
|
|
148
146
|
allowedOrigins: string[];
|
|
@@ -152,7 +150,7 @@ export interface OmniSessionParams {
|
|
|
152
150
|
sessionLabel?: string;
|
|
153
151
|
}
|
|
154
152
|
/**
|
|
155
|
-
* The result of {@link PyAI.omni}.createSession
|
|
153
|
+
* The result of {@link PyAI.omni}.createSession, a short-lived credential safe
|
|
156
154
|
* to hand to the browser. Use {@link OmniSession.token} as the WebSocket
|
|
157
155
|
* subprotocol `pyai-key.<token>` against {@link OmniSession.url}.
|
|
158
156
|
*/
|
|
@@ -197,7 +195,7 @@ export declare const WSCloseCode: {
|
|
|
197
195
|
export type WSCloseCode = (typeof WSCloseCode)[keyof typeof WSCloseCode];
|
|
198
196
|
/**
|
|
199
197
|
* Stable, machine-readable error `code`s (the documented contract). Branch on
|
|
200
|
-
* these. The set is treated as open
|
|
198
|
+
* these. The set is treated as open, `PyAIError.code` stays `string`, so a
|
|
201
199
|
* new server code never breaks the build, but the known ones are named here.
|
|
202
200
|
*/
|
|
203
201
|
export declare const ErrorCode: {
|
|
@@ -267,7 +265,7 @@ export interface HearErrorFrame {
|
|
|
267
265
|
}
|
|
268
266
|
export type HearFrame = HearPartialFrame | HearFinalFrame | HearUsageFrame | HearErrorFrame;
|
|
269
267
|
/**
|
|
270
|
-
* Minimal structural WebSocket
|
|
268
|
+
* Minimal structural WebSocket, matches both the browser/Node global
|
|
271
269
|
* `WebSocket` and the `ws` package, and lets tests inject a mock.
|
|
272
270
|
*/
|
|
273
271
|
export interface WebSocketLike {
|
|
@@ -303,8 +301,8 @@ export interface HearStreamOptions {
|
|
|
303
301
|
*/
|
|
304
302
|
numerals?: boolean;
|
|
305
303
|
/**
|
|
306
|
-
* Turn-segmentation tuning: trailing-pause (ms, 50
|
|
307
|
-
* utterance. Forwards `?endpointing_ms
|
|
304
|
+
* Turn-segmentation tuning: trailing-pause (ms, 50-2000) that ends an
|
|
305
|
+
* utterance. Forwards `?endpointing_ms=`, clamped + honored once the engine
|
|
308
306
|
* supports it; a no-op when omitted. Drive end-of-turn yourself with
|
|
309
307
|
* {@link HearStream.commit} for full control today.
|
|
310
308
|
*/
|
|
@@ -315,12 +313,12 @@ export interface HearStreamOptions {
|
|
|
315
313
|
* array. Bills a single `cue.minutes` line instead of the Hear rate.
|
|
316
314
|
*/
|
|
317
315
|
grounding?: boolean;
|
|
318
|
-
/** Cue: number of KB passages to retrieve per turn (1
|
|
316
|
+
/** Cue: number of KB passages to retrieve per turn (1-20, default 3). */
|
|
319
317
|
groundingK?: number;
|
|
320
|
-
/** Cue: drop passages scoring below this (0
|
|
318
|
+
/** Cue: drop passages scoring below this (0-1, default 0 = keep all). */
|
|
321
319
|
groundingMinScore?: number;
|
|
322
320
|
/** Cue: max ms to wait for retrieval at the final before failing open to
|
|
323
|
-
* `grounding: []` (50
|
|
321
|
+
* `grounding: []` (50-2000, default 450). */
|
|
324
322
|
groundingTimeoutMs?: number;
|
|
325
323
|
/** Extra query params merged onto the connect URL. */
|
|
326
324
|
query?: Record<string, string>;
|
|
@@ -362,6 +360,32 @@ export declare class HearStream {
|
|
|
362
360
|
/** Current WebSocket readyState. */
|
|
363
361
|
get readyState(): number;
|
|
364
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* A live AMD (answering-machine-detection) stream. The wire is Twilio's Media
|
|
365
|
+
* Streams protocol, so if you're already on Twilio the usual path is one line of
|
|
366
|
+
* TwiML pointing `<Stream url="wss://api.pyai.com/v1/amd/stream">` at PyAI, no
|
|
367
|
+
* SDK needed. This helper is for server-side clients that fork the media
|
|
368
|
+
* themselves: send Twilio `start`/`media`/`stop` frames with {@link AmdStream.send}
|
|
369
|
+
* (or raw μ-law audio with {@link AmdStream.sendAudio}) and receive the `amd`
|
|
370
|
+
* decision via `onDecision`. Construct via `pyai.amd.stream()`.
|
|
371
|
+
*/
|
|
372
|
+
export declare class AmdStream {
|
|
373
|
+
private readonly ws;
|
|
374
|
+
private readonly opts;
|
|
375
|
+
private closed;
|
|
376
|
+
constructor(url: string, subprotocol: string, opts: AmdStreamOptions);
|
|
377
|
+
private handleMessage;
|
|
378
|
+
/** Send a Twilio Media Streams control/media frame (JSON) or a raw string. */
|
|
379
|
+
send(frame: string | Record<string, unknown>): void;
|
|
380
|
+
/** Send a raw audio chunk (G.711 μ-law 8 kHz for the Twilio-native path). */
|
|
381
|
+
sendAudio(chunk: ArrayBufferLike | ArrayBufferView | Blob): void;
|
|
382
|
+
/** Close the socket. */
|
|
383
|
+
close(code?: number, reason?: string): void;
|
|
384
|
+
/** The underlying socket (escape hatch for advanced use). */
|
|
385
|
+
get socket(): WebSocketLike;
|
|
386
|
+
/** Current WebSocket readyState. */
|
|
387
|
+
get readyState(): number;
|
|
388
|
+
}
|
|
365
389
|
/**
|
|
366
390
|
* Event names on Omni **server → client** frames. ⚠️ Note the asymmetry:
|
|
367
391
|
* inbound frames are keyed on `event`, but your **outbound** control frames
|
|
@@ -383,6 +407,8 @@ export declare const OmniEvent: {
|
|
|
383
407
|
readonly BargeIn: "barge_in";
|
|
384
408
|
/** Alias for barge-in on some engine builds. */
|
|
385
409
|
readonly Flush: "flush";
|
|
410
|
+
/** Engine requests a client-loop tool invocation. */
|
|
411
|
+
readonly ToolCall: "tool_call";
|
|
386
412
|
/** Session is closing; see close code. */
|
|
387
413
|
readonly SessionEnd: "session_end";
|
|
388
414
|
/** Server fault frame. */
|
|
@@ -394,15 +420,39 @@ export interface OmniServerFrame {
|
|
|
394
420
|
event: string;
|
|
395
421
|
[k: string]: unknown;
|
|
396
422
|
}
|
|
423
|
+
/** Canonical, sanitized transcript delivered by the native Omni demux. */
|
|
424
|
+
export interface OmniTranscriptFrame extends OmniServerFrame {
|
|
425
|
+
event: "transcript";
|
|
426
|
+
role: "user" | "assistant";
|
|
427
|
+
text: string;
|
|
428
|
+
final: boolean;
|
|
429
|
+
mode: "delta" | "replace";
|
|
430
|
+
sequence?: number;
|
|
431
|
+
}
|
|
432
|
+
/** Normalize the live UTF-8 0x02 body and the documented direct-object legacy shape. */
|
|
433
|
+
export declare function normalizeOmniTranscriptBody(bytes: Uint8Array): OmniTranscriptFrame | null;
|
|
397
434
|
/** A binary agent-audio chunk delivered to {@link OmniConnectOptions.onAudio}. */
|
|
398
435
|
export type OmniAudioChunk = ArrayBuffer | ArrayBufferView | Blob;
|
|
436
|
+
export interface OmniToolDef {
|
|
437
|
+
name: string;
|
|
438
|
+
description?: string;
|
|
439
|
+
parameters?: Record<string, unknown>;
|
|
440
|
+
/** When set, engine-POST mode. Omit for client-loop (default). */
|
|
441
|
+
endpoint?: string;
|
|
442
|
+
}
|
|
443
|
+
export interface OmniToolCallFrame {
|
|
444
|
+
type: "tool_call";
|
|
445
|
+
call_id: string;
|
|
446
|
+
name: string;
|
|
447
|
+
arguments?: Record<string, unknown>;
|
|
448
|
+
}
|
|
399
449
|
/**
|
|
400
450
|
* The agent config sent as the `configure` control frame. These are the wire
|
|
401
451
|
* (snake_case) fields the engine reads; it's an **open bag**, so forward-compat
|
|
402
|
-
* fields (e.g. `greeting
|
|
403
|
-
* through. The SDK supplies the `{"type":"configure"}` envelope for
|
|
404
|
-
* is the whole point: a hand-rolled `{"event":"configure"}` is
|
|
405
|
-
* silently dropped, leaving the agent with no brain and zero turns.
|
|
452
|
+
* fields (e.g. `greeting`, or `model_tier` once the engine acks it) pass
|
|
453
|
+
* straight through. The SDK supplies the `{"type":"configure"}` envelope for
|
|
454
|
+
* you, which is the whole point: a hand-rolled `{"event":"configure"}` is
|
|
455
|
+
* acked but silently dropped, leaving the agent with no brain and zero turns.
|
|
406
456
|
*/
|
|
407
457
|
export interface OmniConfigure {
|
|
408
458
|
/** Voice to speak with (stock / clone / designed id). */
|
|
@@ -413,6 +463,19 @@ export interface OmniConfigure {
|
|
|
413
463
|
kb_endpoint?: string;
|
|
414
464
|
/** Bearer the engine presents to `kb_endpoint`. */
|
|
415
465
|
kb_token?: string;
|
|
466
|
+
/**
|
|
467
|
+
* Session language, end to end (recognition, reasoning, voice). Also
|
|
468
|
+
* settable on the agent profile (`language` on `POST /v1/agents`), which
|
|
469
|
+
* applies automatically when connecting with `session_label={agent_id}`;
|
|
470
|
+
* an inline value here wins for the session. Default `en`. Fail-safe: an
|
|
471
|
+
* unknown/not-yet-enabled language falls back to `en` (the `configured`
|
|
472
|
+
* ack carries `language_active` + `language_fallback: true`), the call
|
|
473
|
+
* proceeds and bills as what was served. Per-language availability is
|
|
474
|
+
* staged, see the Language support reference.
|
|
475
|
+
*/
|
|
476
|
+
language?: "en" | "fr" | "es" | "de" | "hi";
|
|
477
|
+
/** Function calling definitions (client-loop when `endpoint` is omitted). */
|
|
478
|
+
tools?: OmniToolDef[];
|
|
416
479
|
/** Forward-compatible: any other key the engine honors. */
|
|
417
480
|
[k: string]: unknown;
|
|
418
481
|
}
|
|
@@ -438,7 +501,7 @@ export interface OmniConnectOptions {
|
|
|
438
501
|
query?: Record<string, string>;
|
|
439
502
|
/** Fired once the socket opens (after the optional auto-configure). */
|
|
440
503
|
onOpen?: () => void;
|
|
441
|
-
/** Fired for each binary agent-audio chunk
|
|
504
|
+
/** Fired for each binary agent-audio chunk, play it out as it arrives. */
|
|
442
505
|
onAudio?: (chunk: OmniAudioChunk) => void;
|
|
443
506
|
/** Fired on the `hello` handshake frame. */
|
|
444
507
|
onHello?: (frame: OmniServerFrame) => void;
|
|
@@ -452,6 +515,8 @@ export interface OmniConnectOptions {
|
|
|
452
515
|
onTranscript?: (frame: OmniServerFrame) => void;
|
|
453
516
|
/** Fired on `barge_in` / `flush` (user interrupted). */
|
|
454
517
|
onBargeIn?: (frame: OmniServerFrame) => void;
|
|
518
|
+
/** Fired when the engine requests a client-loop tool invocation. */
|
|
519
|
+
onToolCall?: (frame: OmniToolCallFrame) => void;
|
|
455
520
|
/** Fired on `session_end`. */
|
|
456
521
|
onSessionEnd?: (frame: OmniServerFrame) => void;
|
|
457
522
|
/** Fired on EVERY JSON frame (including unknown/forward-compat ones). */
|
|
@@ -483,18 +548,32 @@ export declare class OmniConnection {
|
|
|
483
548
|
private readonly ws;
|
|
484
549
|
private readonly opts;
|
|
485
550
|
private closed;
|
|
551
|
+
/** Serializes async Blob reads in {@link sendAudio} so frames stay ordered. */
|
|
552
|
+
private blobTail;
|
|
553
|
+
/** Serializes inbound Blob decoding so browser frames stay ordered. */
|
|
554
|
+
private inboundTail;
|
|
486
555
|
constructor(url: string, subprotocol: string, opts: OmniConnectOptions);
|
|
487
556
|
private handleMessage;
|
|
557
|
+
private dispatchFrame;
|
|
488
558
|
/**
|
|
489
559
|
* Send (or update) the agent config. Always emitted as
|
|
490
|
-
* `{"type":"configure", ...}
|
|
560
|
+
* `{"type":"configure", ...}`, the correct key. (A hand-rolled
|
|
491
561
|
* `{"event":"configure"}` is acked but silently dropped by the engine.)
|
|
492
562
|
*/
|
|
493
563
|
configure(cfg: OmniConfigure): void;
|
|
494
|
-
/**
|
|
564
|
+
/**
|
|
565
|
+
* Stream a chunk of caller audio (PCM16 LE mono at the negotiated rate) as a
|
|
566
|
+
* `0x01`-prefixed frame. The engine demuxes on the first byte and has no
|
|
567
|
+
* default branch, so an untagged chunk is dropped with no error.
|
|
568
|
+
*/
|
|
495
569
|
sendAudio(chunk: ArrayBufferLike | ArrayBufferView | Blob): void;
|
|
496
570
|
/** Send DTMF digits as a `{"type":"dtmf"}` control frame. */
|
|
497
571
|
sendDtmf(digits: string): void;
|
|
572
|
+
/** Reply to a client-loop {@link OmniEvent.ToolCall}. */
|
|
573
|
+
toolResult(callId: string, payload: {
|
|
574
|
+
result?: unknown;
|
|
575
|
+
error?: string;
|
|
576
|
+
}): void;
|
|
498
577
|
/**
|
|
499
578
|
* Send an arbitrary control frame for forward-compat control types the SDK
|
|
500
579
|
* does not model yet. Reminder: client → server frames are keyed on `type`,
|
|
@@ -602,7 +681,7 @@ export interface TraceBargeMetrics {
|
|
|
602
681
|
}
|
|
603
682
|
/**
|
|
604
683
|
* Known timeline-turn roles. Left open (see {@link TraceTimelineTurn.role}) so a
|
|
605
|
-
* new server-side role never breaks the build
|
|
684
|
+
* new server-side role never breaks the build, branch defensively.
|
|
606
685
|
*/
|
|
607
686
|
export type TraceTimelineRole = "agent" | "caller" | "system" | "tool";
|
|
608
687
|
/** One turn of a per-call operational timeline (eval scorecard-v1). */
|
|
@@ -626,18 +705,18 @@ export interface TraceTimelineTurn {
|
|
|
626
705
|
}
|
|
627
706
|
/**
|
|
628
707
|
* Aggregate per-call quality metrics (eval scorecard-v1). All optional and
|
|
629
|
-
* forward-compatible
|
|
708
|
+
* forward-compatible, present once the engine emits them.
|
|
630
709
|
*/
|
|
631
710
|
export interface QualityMetrics {
|
|
632
|
-
/** Word error rate vs. reference transcript, 0
|
|
711
|
+
/** Word error rate vs. reference transcript, 0-1 (lower is better). */
|
|
633
712
|
wer?: number;
|
|
634
713
|
/** Representative time-to-first-audio across turns, ms. */
|
|
635
714
|
ttfb_ms?: number;
|
|
636
715
|
/** 95th-percentile end-to-end turn latency, ms. */
|
|
637
716
|
turn_p95_ms?: number;
|
|
638
|
-
/** Barge-in recovery rate, 0
|
|
717
|
+
/** Barge-in recovery rate, 0-1. */
|
|
639
718
|
barge_recovery?: number;
|
|
640
|
-
/** Task-success score, 0
|
|
719
|
+
/** Task-success score, 0-1. */
|
|
641
720
|
task_success?: number;
|
|
642
721
|
/** Composite voice-agent quality index (engine-defined scale). */
|
|
643
722
|
vaqi?: number;
|
|
@@ -775,6 +854,76 @@ export interface RecapCallTriggerInput {
|
|
|
775
854
|
customer_name?: string;
|
|
776
855
|
crm_fields?: Record<string, unknown>;
|
|
777
856
|
}
|
|
857
|
+
/** PyAI's richer answered-by vocabulary (superset of Twilio's enum). */
|
|
858
|
+
export type AmdAnsweredBy = "human" | "voicemail" | "live_voicemail" | "screening" | "ivr" | "human_gatekeeper" | "sit_invalid" | "fax" | "silence" | "unknown";
|
|
859
|
+
/** Twilio's `AnsweredBy` enum, echoed for drop-in migration parity. */
|
|
860
|
+
export type AmdTwilioAnsweredBy = "human" | "machine_start" | "machine_end_beep" | "machine_end_silence" | "machine_end_other" | "fax" | "unknown";
|
|
861
|
+
export interface AmdConfigInput {
|
|
862
|
+
/** Operating point on the ROC curve, [0,1]. Near 0 = human-safe (never hang up
|
|
863
|
+
* on a person); near 1 = fire `machine` fast. A per-call TwiML `<Parameter>`
|
|
864
|
+
* overrides this. */
|
|
865
|
+
aggressiveness?: number;
|
|
866
|
+
/** Signed POST target for `amd.call.completed` events (https). */
|
|
867
|
+
webhookUrl?: string | null;
|
|
868
|
+
}
|
|
869
|
+
export interface AmdConfig {
|
|
870
|
+
object?: "amd.config";
|
|
871
|
+
aggressiveness?: number;
|
|
872
|
+
webhook_url?: string | null;
|
|
873
|
+
updated_at?: number;
|
|
874
|
+
}
|
|
875
|
+
export interface AmdCallSummary {
|
|
876
|
+
object?: "amd.call";
|
|
877
|
+
call_id: string;
|
|
878
|
+
session_label?: string | null;
|
|
879
|
+
status?: "completed" | "failed";
|
|
880
|
+
answered_by?: AmdAnsweredBy;
|
|
881
|
+
/** Twilio-enum projection of `answered_by` for drop-in routing parity. */
|
|
882
|
+
answered_by_twilio?: string | null;
|
|
883
|
+
confidence?: number | null;
|
|
884
|
+
/** Latency from answer to decision, in ms. */
|
|
885
|
+
decision_ms?: number | null;
|
|
886
|
+
created_at?: number;
|
|
887
|
+
}
|
|
888
|
+
export interface AmdCall extends AmdCallSummary {
|
|
889
|
+
/** Human-readable evidence, e.g. "machine phrase: 'leave a message' @1.2s". */
|
|
890
|
+
reason?: string | null;
|
|
891
|
+
aggressiveness?: number | null;
|
|
892
|
+
started_at?: number | null;
|
|
893
|
+
meta?: Record<string, unknown> | null;
|
|
894
|
+
error?: string | null;
|
|
895
|
+
}
|
|
896
|
+
/** A mid-call AMD decision event pushed on the stream (and to the webhook). */
|
|
897
|
+
export interface AmdDecisionEvent {
|
|
898
|
+
event?: "amd";
|
|
899
|
+
call_id?: string;
|
|
900
|
+
answered_by?: AmdAnsweredBy;
|
|
901
|
+
answered_by_twilio?: string | null;
|
|
902
|
+
confidence?: number | null;
|
|
903
|
+
decision_ms?: number | null;
|
|
904
|
+
reason?: string | null;
|
|
905
|
+
[k: string]: unknown;
|
|
906
|
+
}
|
|
907
|
+
export interface AmdStreamOptions {
|
|
908
|
+
/** Per-call operating point override (0-1), sent on the connect URL. */
|
|
909
|
+
aggressiveness?: number;
|
|
910
|
+
/** Opaque per-call tag, echoed back on the decision. */
|
|
911
|
+
sessionLabel?: string;
|
|
912
|
+
/** Extra query params merged onto the connect URL. */
|
|
913
|
+
query?: Record<string, string>;
|
|
914
|
+
/** Fired once the socket opens. */
|
|
915
|
+
onOpen?: () => void;
|
|
916
|
+
/** Fired when PyAI emits the `amd` decision event mid-call. */
|
|
917
|
+
onDecision?: (event: AmdDecisionEvent) => void;
|
|
918
|
+
/** Fired on any other JSON frame (forward-compatible). */
|
|
919
|
+
onMessage?: (frame: Record<string, unknown>) => void;
|
|
920
|
+
/** Fired on a transport-level error. */
|
|
921
|
+
onError?: (err: Error) => void;
|
|
922
|
+
/** Fired when the socket closes. */
|
|
923
|
+
onClose?: (code: number, reason: string) => void;
|
|
924
|
+
/** Injectable WebSocket constructor (defaults to the global). */
|
|
925
|
+
webSocket?: WebSocketCtor;
|
|
926
|
+
}
|
|
778
927
|
export declare class PyAI {
|
|
779
928
|
private readonly apiKey;
|
|
780
929
|
private readonly baseURL;
|
|
@@ -852,7 +1001,7 @@ export declare class PyAI {
|
|
|
852
1001
|
};
|
|
853
1002
|
/**
|
|
854
1003
|
* Introspect the calling key: scopes, environment, and limits. Useful for a
|
|
855
|
-
* preflight/doctor check. (New route; older deployments may 404
|
|
1004
|
+
* preflight/doctor check. (New route; older deployments may 404, handle it.)
|
|
856
1005
|
*/
|
|
857
1006
|
me: () => Promise<MeResponse>;
|
|
858
1007
|
clones: {
|
|
@@ -919,7 +1068,7 @@ export declare class PyAI {
|
|
|
919
1068
|
}) => Promise<ListResponse<TraceViolation>>;
|
|
920
1069
|
};
|
|
921
1070
|
findings: {
|
|
922
|
-
/** List Tier-2 (async semantic) findings
|
|
1071
|
+
/** List Tier-2 (async semantic) findings, advisory, non-blocking. Scope `trace:read`. */
|
|
923
1072
|
list: (params?: {
|
|
924
1073
|
checkId?: string;
|
|
925
1074
|
action?: "flag" | "preempt_next" | "escalate";
|
|
@@ -968,10 +1117,34 @@ export declare class PyAI {
|
|
|
968
1117
|
trigger: (callId: string, input: RecapCallTriggerInput) => Promise<RecapCallSummary>;
|
|
969
1118
|
};
|
|
970
1119
|
};
|
|
1120
|
+
amd: {
|
|
1121
|
+
config: {
|
|
1122
|
+
/** The org's AMD operating point + webhook. Scope `amd:configure`. */
|
|
1123
|
+
get: () => Promise<AmdConfig>;
|
|
1124
|
+
/** Set the account-default `aggressiveness` (0-1) and webhook. Scope `amd:configure`. */
|
|
1125
|
+
set: (input: AmdConfigInput) => Promise<AmdConfig>;
|
|
1126
|
+
};
|
|
1127
|
+
calls: {
|
|
1128
|
+
/** Recent AMD decisions, newest first. Scope `amd:read`. */
|
|
1129
|
+
list: (params?: {
|
|
1130
|
+
limit?: number;
|
|
1131
|
+
cursor?: string;
|
|
1132
|
+
sessionLabel?: string;
|
|
1133
|
+
}) => Promise<ListResponse<AmdCallSummary>>;
|
|
1134
|
+
/** The full decision (answered_by, reason, …) for one call. Scope `amd:read`. */
|
|
1135
|
+
get: (callId: string) => Promise<AmdCall>;
|
|
1136
|
+
};
|
|
1137
|
+
/**
|
|
1138
|
+
* Open a live AMD stream over `/v1/amd/stream` (Twilio Media Streams
|
|
1139
|
+
* protocol). Server-side helper for forking media yourself; the common
|
|
1140
|
+
* Twilio path is one line of TwiML, no SDK. Scope `amd:detect`.
|
|
1141
|
+
*/
|
|
1142
|
+
stream: (opts?: AmdStreamOptions) => AmdStream;
|
|
1143
|
+
};
|
|
971
1144
|
omni: {
|
|
972
1145
|
/**
|
|
973
1146
|
* Mint an ephemeral, origin-locked Omni session token a browser can use to
|
|
974
|
-
* open ONE realtime session **directly
|
|
1147
|
+
* open ONE realtime session **directly**, the public/private split for
|
|
975
1148
|
* realtime. **Call this from your server** with a secret key holding
|
|
976
1149
|
* `omni:session`; never ship the secret key to a page. Hand the returned
|
|
977
1150
|
* `token` to the browser, which connects with
|
|
@@ -983,8 +1156,8 @@ export declare class PyAI {
|
|
|
983
1156
|
/**
|
|
984
1157
|
* Open a live Omni agentic-voice session over `/v1/omni`. Returns an
|
|
985
1158
|
* {@link OmniConnection} that handles the wire protocol's frame-key
|
|
986
|
-
* asymmetry for you
|
|
987
|
-
* `dtmf`) and parses `event`-keyed server frames
|
|
1159
|
+
* asymmetry for you, it sends `type`-keyed control frames (`configure`,
|
|
1160
|
+
* `dtmf`) and parses `event`-keyed server frames, so you can't trip the #1
|
|
988
1161
|
* Omni integration bug. Omni is zero-state: nothing to create first; the
|
|
989
1162
|
* agent's behavior travels in the `configure` frame. Pass `token` (from
|
|
990
1163
|
* `createSession`) to connect from a browser without the secret key.
|
|
@@ -997,6 +1170,8 @@ export declare class PyAI {
|
|
|
997
1170
|
realtimeSubprotocol(): string;
|
|
998
1171
|
/** Build the Hear streaming-STT WebSocket URL (`/v1/audio/transcriptions/stream`). */
|
|
999
1172
|
hearStreamURL(opts?: HearStreamOptions): string;
|
|
1173
|
+
/** Build the AMD detection WebSocket URL (`/v1/amd/stream`). */
|
|
1174
|
+
amdStreamURL(opts?: AmdStreamOptions): string;
|
|
1000
1175
|
/**
|
|
1001
1176
|
* Open a realtime WebSocket. Uses the global WebSocket (browser, Node 22+).
|
|
1002
1177
|
* The key travels as a subprotocol so it works from the browser without
|