@rimelabs/sdk 0.1.0-alpha.2 → 0.1.0-alpha.21

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +155 -0
  2. package/LICENSE-PRISM +201 -0
  3. package/NOTICE-PRISM +9 -0
  4. package/README.md +279 -114
  5. package/dist/auth.d.ts +9 -3
  6. package/dist/auth.js +12 -4
  7. package/dist/cancellation.d.ts +6 -0
  8. package/dist/cancellation.js +54 -0
  9. package/dist/client.d.ts +24 -23
  10. package/dist/client.js +41 -92
  11. package/dist/grpc.d.ts +27 -0
  12. package/dist/grpc.js +175 -0
  13. package/dist/index.d.ts +10 -2
  14. package/dist/index.js +6 -2
  15. package/dist/pcm.d.ts +21 -0
  16. package/dist/pcm.js +52 -0
  17. package/dist/realtime/async.d.ts +23 -0
  18. package/dist/realtime/async.js +87 -0
  19. package/dist/realtime/audio.d.ts +2 -0
  20. package/dist/realtime/audio.js +11 -0
  21. package/dist/realtime/client.d.ts +12 -0
  22. package/dist/realtime/client.js +139 -0
  23. package/dist/realtime/conversation.d.ts +47 -0
  24. package/dist/realtime/conversation.js +321 -0
  25. package/dist/realtime/faults.d.ts +2 -0
  26. package/dist/realtime/faults.js +25 -0
  27. package/dist/realtime/protocol.d.ts +99 -0
  28. package/dist/realtime/protocol.js +432 -0
  29. package/dist/realtime/session.d.ts +79 -0
  30. package/dist/realtime/session.js +808 -0
  31. package/dist/realtime/settings.d.ts +11 -0
  32. package/dist/realtime/settings.js +142 -0
  33. package/dist/realtime/transport.d.ts +16 -0
  34. package/dist/realtime/transport.js +86 -0
  35. package/dist/realtime/types.d.ts +292 -0
  36. package/dist/realtime/types.js +12 -0
  37. package/dist/stt/audio.d.ts +15 -0
  38. package/dist/stt/audio.js +46 -0
  39. package/dist/stt/client.d.ts +17 -0
  40. package/dist/stt/client.js +121 -0
  41. package/dist/stt/policy.d.ts +11 -0
  42. package/dist/stt/policy.js +11 -0
  43. package/dist/stt/protocol.d.ts +14 -0
  44. package/dist/stt/protocol.js +76 -0
  45. package/dist/stt/queue.d.ts +16 -0
  46. package/dist/stt/queue.js +45 -0
  47. package/dist/stt/stream.d.ts +48 -0
  48. package/dist/stt/stream.js +224 -0
  49. package/dist/stt/transport.d.ts +15 -0
  50. package/dist/stt/transport.js +94 -0
  51. package/dist/stt/types.d.ts +51 -0
  52. package/dist/stt/types.js +1 -0
  53. package/dist/{audio.d.ts → tts/audio.d.ts} +9 -0
  54. package/dist/{audio.js → tts/audio.js} +44 -4
  55. package/dist/tts/buffer.d.ts +3 -0
  56. package/dist/tts/buffer.js +53 -0
  57. package/dist/tts/client.d.ts +53 -0
  58. package/dist/tts/client.js +151 -0
  59. package/dist/tts/lexicon.d.ts +7 -0
  60. package/dist/tts/lexicon.js +23 -0
  61. package/dist/{policy.d.ts → tts/policy.d.ts} +2 -3
  62. package/dist/tts/policy.js +41 -0
  63. package/dist/{stream.d.ts → tts/stream.d.ts} +15 -2
  64. package/dist/{stream.js → tts/stream.js} +54 -30
  65. package/dist/tts/timestamps.d.ts +24 -0
  66. package/dist/tts/timestamps.js +46 -0
  67. package/dist/{transport.d.ts → tts/transport.d.ts} +10 -13
  68. package/dist/tts/transport.js +133 -0
  69. package/dist/validation.d.ts +5 -0
  70. package/dist/validation.js +28 -0
  71. package/docs/realtime.md +537 -0
  72. package/docs/stt.md +186 -0
  73. package/docs/tts.md +284 -0
  74. package/package.json +14 -12
  75. package/dist/policy.js +0 -82
  76. package/dist/sentences.d.ts +0 -21
  77. package/dist/sentences.js +0 -142
  78. package/dist/transport.js +0 -223
  79. package/vendor/LICENSE.blingfire +0 -21
  80. package/vendor/README.md +0 -11
  81. package/vendor/blingfire.cjs +0 -4
  82. package/vendor/blingfire.upstream.cjs +0 -1
  83. package/vendor/blingfire.wasm +0 -0
  84. /package/dist/{queue.d.ts → tts/queue.d.ts} +0 -0
  85. /package/dist/{queue.js → tts/queue.js} +0 -0
@@ -0,0 +1,11 @@
1
+ import type { ToolDefinition } from "./types.js";
2
+ import type { SessionSettings } from "./protocol.js";
3
+ export declare function toolSettings(tools: readonly ToolDefinition[]): SessionSettings["tools"];
4
+ /** Bounded policy changes used to resolve each reply's settings revision. */
5
+ export declare class InterruptionPolicies {
6
+ private changes;
7
+ private current;
8
+ private lastRevision;
9
+ record(revision: number | null, interrupt: boolean): void;
10
+ resolve(revision: number | null | undefined): boolean;
11
+ }
@@ -0,0 +1,142 @@
1
+ import { RimeInputError, RimeResourceLimitError } from "../errors.js";
2
+ function toolString(value) {
3
+ // Unicode mode matches lone surrogates without rejecting valid UTF-16 pairs.
4
+ if (/[\uD800-\uDFFF]/u.test(value))
5
+ throw new RimeInputError("Tool strings must be valid UTF-8");
6
+ return value;
7
+ }
8
+ /** Reject values that JSON.stringify would silently drop or change. */
9
+ function copyJson(value) {
10
+ if (typeof value === "string")
11
+ return toolString(value);
12
+ if (value === null || typeof value === "boolean")
13
+ return value;
14
+ if (typeof value === "number" && Number.isFinite(value))
15
+ return value;
16
+ if (Array.isArray(value))
17
+ return Array.from(value, copyJson);
18
+ if (value &&
19
+ typeof value === "object" &&
20
+ [Object.prototype, null].includes(Object.getPrototypeOf(value)))
21
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [
22
+ toolString(key),
23
+ copyJson(item),
24
+ ]));
25
+ throw new RimeInputError("Tool schemas must contain finite JSON values");
26
+ }
27
+ function fillerSettings(value) {
28
+ if (!value || typeof value !== "object" || Array.isArray(value))
29
+ throw new RimeInputError("prismFiller must be a filler object");
30
+ const kind = value.type;
31
+ if (!["none", "text", "auto"].includes(kind))
32
+ throw new RimeInputError("Prism filler type must be none, text, or auto");
33
+ const field = kind === "text" ? "text" : kind === "auto" ? "instructions" : null;
34
+ if (Object.entries(value).some(([key, item]) => item !== undefined && key !== "type" && key !== field))
35
+ throw new RimeInputError("Prism filler has fields not allowed for its type");
36
+ const text = field === null ? undefined : value[field];
37
+ if (kind === "text" || text !== undefined) {
38
+ // Rust str::trim uses Unicode White_Space, which differs from JS trim.
39
+ if (typeof text !== "string" ||
40
+ !/\P{White_Space}/u.test(text) ||
41
+ [...text].length > 500)
42
+ throw new RimeInputError("Prism filler text must be nonblank and at most 500 characters");
43
+ // Unicode mode matches lone surrogates but preserves valid UTF-16 pairs.
44
+ if (/[\uD800-\uDFFF]/u.test(text))
45
+ throw new RimeInputError("Prism filler text must be valid UTF-8");
46
+ }
47
+ if (kind === "text")
48
+ return { type: "text", text: text };
49
+ if (kind === "auto")
50
+ return text === undefined
51
+ ? { type: "auto" }
52
+ : { type: "auto", instructions: text };
53
+ return { type: "none" };
54
+ }
55
+ export function toolSettings(tools) {
56
+ if (!Array.isArray(tools))
57
+ throw new RimeInputError("tools must be an array");
58
+ const names = new Set();
59
+ return tools.map((tool) => {
60
+ if (!tool ||
61
+ typeof tool !== "object" ||
62
+ typeof tool.name !== "string" ||
63
+ !/\P{White_Space}/u.test(tool.name) ||
64
+ [...tool.name].length > 4000 ||
65
+ names.has(tool.name))
66
+ throw new RimeInputError("Tool names must be nonblank, unique, and at most 4000 characters");
67
+ toolString(tool.name);
68
+ names.add(tool.name);
69
+ if (!tool.parameters ||
70
+ Array.isArray(tool.parameters) ||
71
+ typeof tool.parameters !== "object" ||
72
+ (tool.description !== undefined && typeof tool.description !== "string"))
73
+ throw new RimeInputError("Tool parameters must be a JSON object and description must be a string");
74
+ let parameters;
75
+ try {
76
+ parameters = copyJson(tool.parameters);
77
+ }
78
+ catch (error) {
79
+ if (error instanceof RimeInputError)
80
+ throw error;
81
+ throw new RimeInputError("Tool schemas must contain finite JSON values");
82
+ }
83
+ if (parameters === null ||
84
+ typeof parameters !== "object" ||
85
+ Array.isArray(parameters))
86
+ throw new RimeInputError("Tool parameters must be an object");
87
+ return {
88
+ type: "function",
89
+ ...(tool.prismFiller === undefined
90
+ ? {}
91
+ : { prism_filler: fillerSettings(tool.prismFiller) }),
92
+ function: {
93
+ name: tool.name,
94
+ description: toolString(tool.description ?? ""),
95
+ parameters,
96
+ },
97
+ };
98
+ });
99
+ }
100
+ /** Bounded policy changes used to resolve each reply's settings revision. */
101
+ export class InterruptionPolicies {
102
+ changes = [];
103
+ current = true;
104
+ lastRevision = null;
105
+ record(revision, interrupt) {
106
+ const previous = this.changes.at(-1);
107
+ if (!previous) {
108
+ this.changes.push({ revision: revision ?? 0, interrupt });
109
+ }
110
+ else if (revision === null) {
111
+ if (interrupt !== this.current && !previous.unknown) {
112
+ // Earlier published revisions stay known; later ones are ambiguous
113
+ // until an acknowledgment supplies the new policy's revision.
114
+ this.changes.push({
115
+ revision: this.lastRevision === null ? 0 : this.lastRevision + 1,
116
+ interrupt,
117
+ unknown: true,
118
+ });
119
+ }
120
+ }
121
+ else if (previous.unknown || interrupt !== this.current) {
122
+ this.changes.push({ revision, interrupt });
123
+ }
124
+ if (revision !== null)
125
+ this.lastRevision = revision;
126
+ if (this.changes.length > 128)
127
+ this.changes.shift();
128
+ this.current = interrupt;
129
+ }
130
+ resolve(revision) {
131
+ if (revision == null || this.changes.length === 0)
132
+ return this.current;
133
+ for (let i = this.changes.length - 1; i >= 0; i--) {
134
+ if (this.changes[i].revision <= revision) {
135
+ if (this.changes[i].unknown)
136
+ throw new RimeResourceLimitError("Reply settings revision crosses an unreported interruption policy change");
137
+ return this.changes[i].interrupt;
138
+ }
139
+ }
140
+ throw new RimeResourceLimitError("Reply settings revision is no longer retained");
141
+ }
142
+ }
@@ -0,0 +1,16 @@
1
+ import { RimeError } from "../errors.js";
2
+ /** Private transport. The public declarations do not require ws types. */
3
+ export declare class RealtimeConnection {
4
+ private readonly socket;
5
+ private readonly opened;
6
+ private readonly ended;
7
+ private closing;
8
+ private connected;
9
+ readonly ready: Promise<void>;
10
+ onMessage: (raw: string) => void;
11
+ onFailure: (error: RimeError) => void;
12
+ constructor(endpoint: string, authorization: string, requestId?: string);
13
+ private failure;
14
+ send(encoded: string): Promise<void>;
15
+ close(): Promise<void>;
16
+ }
@@ -0,0 +1,86 @@
1
+ import WebSocket from "ws";
2
+ import { RimeAuthenticationError, RimeStreamError, RimeUnavailableError, } from "../errors.js";
3
+ import { Deferred } from "./async.js";
4
+ /** Private transport. The public declarations do not require ws types. */
5
+ export class RealtimeConnection {
6
+ socket;
7
+ opened = new Deferred();
8
+ ended = new Deferred();
9
+ closing = null;
10
+ connected = false;
11
+ ready = this.opened.promise;
12
+ onMessage = () => { };
13
+ onFailure = () => { };
14
+ constructor(endpoint, authorization, requestId) {
15
+ this.socket = new WebSocket(endpoint, {
16
+ headers: {
17
+ Authorization: authorization,
18
+ ...(requestId === undefined ? {} : { "x-request-id": requestId }),
19
+ },
20
+ followRedirects: false,
21
+ perMessageDeflate: false,
22
+ maxPayload: 1024 * 1024,
23
+ });
24
+ this.socket.on("open", () => {
25
+ this.connected = true;
26
+ this.opened.resolve();
27
+ });
28
+ this.socket.on("unexpected-response", (request, response) => {
29
+ const error = [401, 403].includes(response.statusCode ?? 0)
30
+ ? new RimeAuthenticationError("Realtime endpoint rejected credentials")
31
+ : new RimeUnavailableError("Realtime endpoint rejected the connection");
32
+ this.failure(error);
33
+ response.destroy();
34
+ request.destroy();
35
+ this.socket.terminate();
36
+ });
37
+ this.socket.on("error", () => this.failure(!this.connected
38
+ ? new RimeUnavailableError("Realtime handshake failed")
39
+ : new RimeStreamError("Invalid event or lost realtime connection")));
40
+ this.socket.on("message", (data, binary) => {
41
+ if (binary) {
42
+ this.failure(new RimeStreamError("Expected a JSON text event"));
43
+ return;
44
+ }
45
+ this.onMessage(data.toString());
46
+ });
47
+ this.socket.on("close", () => {
48
+ this.ended.resolve();
49
+ this.failure(new RimeStreamError("Realtime connection closed; reconnect is not automatic"));
50
+ });
51
+ }
52
+ failure(error) {
53
+ this.opened.reject(error);
54
+ this.onFailure(error);
55
+ }
56
+ send(encoded) {
57
+ return new Promise((resolve, reject) => {
58
+ this.socket.send(encoded, (error) => {
59
+ if (error)
60
+ reject(new RimeStreamError("Realtime write failed; outcome unknown"));
61
+ else
62
+ resolve();
63
+ });
64
+ });
65
+ }
66
+ close() {
67
+ if (!this.closing) {
68
+ this.closing = (async () => {
69
+ if (this.socket.readyState === WebSocket.CLOSED)
70
+ return;
71
+ const timer = setTimeout(() => this.socket.terminate(), 2000);
72
+ try {
73
+ if (this.socket.readyState === WebSocket.CONNECTING)
74
+ this.socket.terminate();
75
+ else
76
+ this.socket.close();
77
+ await this.ended.promise;
78
+ }
79
+ finally {
80
+ clearTimeout(timer);
81
+ }
82
+ })();
83
+ }
84
+ return this.closing;
85
+ }
86
+ }
@@ -0,0 +1,292 @@
1
+ import type { PCMFormat } from "../pcm.js";
2
+ export type { PCMFormat } from "../pcm.js";
3
+ import { RimeError, RimeTimeoutError } from "../errors.js";
4
+ export type JsonValue = null | boolean | number | string | JsonValue[] | JsonObject;
5
+ /** Your labels for replies, keys to strings, such as `{ step: "3" }`. Prism
6
+ * takes at most 16, keys up to 64 characters and values up to 512, and
7
+ * refuses keys starting with `prism_`. */
8
+ export type Labels = Readonly<Record<string, string>>;
9
+ export interface JsonObject {
10
+ [key: string]: JsonValue;
11
+ }
12
+ /** All durations are positive, finite seconds. */
13
+ export interface RealtimeTimeouts {
14
+ readonly connectS?: number;
15
+ readonly readyS?: number;
16
+ readonly requestS?: number;
17
+ }
18
+ export interface RealtimeOperationOptions {
19
+ readonly signal?: AbortSignal;
20
+ }
21
+ /** Speech while a tool runs. Text and instructions must be nonblank and at
22
+ * most 500 Unicode scalar values. Invalid UTF-8 is rejected.
23
+ * Omit the setting to use the server default. */
24
+ export type PrismFiller = {
25
+ readonly type: "none";
26
+ readonly text?: never;
27
+ readonly instructions?: never;
28
+ } | {
29
+ readonly type: "text";
30
+ readonly text: string;
31
+ readonly instructions?: never;
32
+ } | {
33
+ readonly type: "auto";
34
+ readonly instructions?: string;
35
+ readonly text?: never;
36
+ };
37
+ export interface ToolDefinition {
38
+ readonly name: string;
39
+ readonly parameters: JsonObject;
40
+ readonly description?: string;
41
+ readonly prismFiller?: PrismFiller;
42
+ }
43
+ export type TurnEagerness = "low" | "medium" | "high" | "auto";
44
+ /** Omitted fields use the server's turn timing defaults. */
45
+ export interface TurnDetection {
46
+ /** How readily Prism decides that the user has finished speaking. */
47
+ readonly eagerness?: TurnEagerness;
48
+ /** Maximum silence before ending a turn: an integer from 1000 to 10000 ms. */
49
+ readonly endOfTurnTimeoutMs?: number;
50
+ }
51
+ /** Effective server settings. Null means the server did not publish the field. */
52
+ export interface TurnDetectionInfo {
53
+ readonly eagerness: TurnEagerness | "unknown" | null;
54
+ readonly endOfTurnTimeoutMs: number | null;
55
+ }
56
+ export interface RealtimeConnectOptions extends RealtimeOperationOptions {
57
+ /** Defaults to wss://prism.api.rime.ai/v1/realtime. */
58
+ readonly endpoint?: string;
59
+ readonly model?: "prism";
60
+ readonly voice?: string | null;
61
+ readonly instructions?: string | null;
62
+ readonly tools?: readonly ToolDefinition[];
63
+ readonly interruptOnSpeech?: boolean;
64
+ readonly turnDetection?: TurnDetection;
65
+ readonly timeouts?: RealtimeTimeouts;
66
+ /** Sent as the upgrade's `x-request-id`. It must be nonblank printable ASCII, or
67
+ * `connect` throws `RimeInputError`. Prism uses it if it is at most 128
68
+ * characters, else makes its own; `info.requestId` reports the one it used.
69
+ * Omitted or `null` sends none. */
70
+ readonly requestId?: string | null;
71
+ /** Labels every reply's `response.started` carries in `metadata`, such as
72
+ * `{ step: "3" }`; change them with `session.setResponseMetadata`. Prism
73
+ * refuses keys starting with `prism_`. Omitted or `null` sets none. */
74
+ readonly responseMetadata?: Labels | null;
75
+ }
76
+ /** Omitted fields keep their values. Empty instructions or tools clear them. */
77
+ export interface RealtimeUpdateOptions extends RealtimeOperationOptions {
78
+ readonly instructions?: string;
79
+ readonly tools?: readonly ToolDefinition[];
80
+ readonly voice?: string;
81
+ readonly interruptOnSpeech?: boolean;
82
+ }
83
+ export interface ReplyOptions extends RealtimeOperationOptions {
84
+ readonly instruction?: string | null;
85
+ readonly toolCall?: ToolCallRef | null;
86
+ }
87
+ export interface AudioChunk {
88
+ readonly data: Uint8Array;
89
+ readonly format?: PCMFormat;
90
+ }
91
+ export interface ResponseRef {
92
+ readonly sessionId: string;
93
+ readonly responseId: string;
94
+ }
95
+ export interface ItemRef {
96
+ readonly sessionId: string;
97
+ readonly itemId: string;
98
+ }
99
+ export interface ToolCallRef extends ResponseRef {
100
+ readonly callId: string;
101
+ }
102
+ export interface OutputRef {
103
+ readonly response: ResponseRef;
104
+ readonly itemId: string;
105
+ readonly outputIndex: number;
106
+ readonly contentIndex: number;
107
+ }
108
+ export interface SessionInfo {
109
+ /** Settings revision published by the server; null when unavailable.
110
+ * Optional on caller-created values for compatibility. */
111
+ readonly settingsRevision?: number | null;
112
+ readonly sessionId: string;
113
+ /** The `x-request-id` Prism's logs name this session by. Null when the
114
+ * server does not publish it. */
115
+ readonly requestId: string | null;
116
+ /** The labels replies carry, as Prism last confirmed them. Null when the
117
+ * server does not publish them. */
118
+ readonly responseMetadata: Labels | null;
119
+ readonly model: "prism";
120
+ readonly voice: string;
121
+ readonly interruptOnSpeech: boolean;
122
+ readonly toolResultTimeoutS: number | null;
123
+ readonly toolContinuationTimeoutS: number | null;
124
+ readonly turnDetection: TurnDetectionInfo;
125
+ }
126
+ export interface RealtimeFault {
127
+ readonly code: string;
128
+ /** Optional for compatibility with caller-created faults. The SDK derives
129
+ * its output classification from the code and ignores supplied values. */
130
+ readonly retryable?: boolean;
131
+ readonly message: string;
132
+ readonly scope: "event" | "utterance" | "response" | "tool_roundtrip" | "session" | "unknown";
133
+ readonly requestId: string | null;
134
+ readonly responseId: string | null;
135
+ readonly itemId: string | null;
136
+ readonly callIds: readonly string[];
137
+ readonly correlationId: string | null;
138
+ readonly parameter: string | null;
139
+ }
140
+ /** An immutable fault produced by the SDK. */
141
+ export interface NormalizedRealtimeFault extends RealtimeFault {
142
+ /** Whether the same request, unchanged, may succeed on another attempt.
143
+ * True only for capacity_exceeded, unavailable, and response_timeout.
144
+ * Unknown codes return false. The application owns retry timing, limits,
145
+ * and recovery after partial output; this value does not replay a request. */
146
+ readonly retryable: boolean;
147
+ }
148
+ export declare class RealtimeAdmissionTimeout extends RimeTimeoutError {
149
+ }
150
+ export declare class RimeRealtimeError extends RimeError {
151
+ readonly fault: NormalizedRealtimeFault;
152
+ constructor(fault: RealtimeFault);
153
+ }
154
+ export interface InputReady {
155
+ readonly kind: "input.ready";
156
+ }
157
+ /** The user may have started speaking over a playing reply. Prism sends it
158
+ * before `speech.started` when it may interrupt the reply; it can be a false
159
+ * alarm, so lower playback on it rather than stopping. */
160
+ export interface SpeechHint {
161
+ readonly kind: "speech.hint";
162
+ readonly audioStartMs: number;
163
+ }
164
+ export interface SpeechStarted {
165
+ readonly kind: "speech.started";
166
+ readonly itemId: string;
167
+ readonly audioStartMs: number;
168
+ }
169
+ /** What ended the user's turn:
170
+ * - `semantic`: Prism judged from the user's speech that they had finished;
171
+ * `eagerness` sets how readily it does.
172
+ * - `timeout`: the user was silent for `endOfTurnTimeoutMs`, and the timeout
173
+ * ended the turn before Prism judged that they had finished.
174
+ * - `silence`: Prism's backup turn detection ended the turn at a short pause;
175
+ * it does not apply `eagerness` or `endOfTurnTimeoutMs`.
176
+ * - `max_duration`: the user spoke for the longest turn Prism takes; what
177
+ * they say next starts a new turn.
178
+ * - `detector_changed`: Prism switched between its main and backup turn
179
+ * detection while the user spoke; nothing the user did ended the turn. */
180
+ export type SpeechEndReason = "semantic" | "timeout" | "silence" | "max_duration" | "detector_changed";
181
+ export interface SpeechStopped {
182
+ readonly kind: "speech.stopped";
183
+ readonly itemId: string;
184
+ readonly audioEndMs: number;
185
+ /** Null means the server did not publish the field. */
186
+ readonly endReason: SpeechEndReason | "unknown" | null;
187
+ }
188
+ export interface InputCommitted {
189
+ readonly kind: "input.committed";
190
+ readonly itemId: string;
191
+ }
192
+ export interface TranscriptDelta {
193
+ readonly kind: "transcript.delta";
194
+ readonly itemId: string;
195
+ readonly delta: string;
196
+ }
197
+ export interface TranscriptFinal {
198
+ readonly kind: "transcript.final";
199
+ readonly itemId: string;
200
+ readonly text: string;
201
+ }
202
+ export interface TranscriptFailed<Fault extends RealtimeFault = RealtimeFault> {
203
+ readonly kind: "transcript.failed";
204
+ readonly itemId: string;
205
+ readonly error: Fault;
206
+ }
207
+ export interface ResponseStarted {
208
+ /** Settings revision published by the server; null when unavailable.
209
+ * Optional on caller-created values for compatibility. */
210
+ readonly settingsRevision?: number | null;
211
+ readonly kind: "response.started";
212
+ readonly response: ResponseRef;
213
+ readonly cause: "speech" | "text" | "proactive" | "tools" | "unknown";
214
+ readonly parent: ResponseRef | null;
215
+ readonly inputItemId: string | null;
216
+ /** The session's labels when the reply began. Prism's `prism_` keys are
217
+ * left out. */
218
+ readonly metadata: Labels;
219
+ /** The user items the reply answers: a spoken reply's committed turns, or
220
+ * a typed turn's item. Empty when the server names none. */
221
+ readonly inputItemIds: readonly string[];
222
+ }
223
+ export interface MessageStarted {
224
+ readonly kind: "message.started";
225
+ readonly output: OutputRef;
226
+ }
227
+ export interface TextDelta {
228
+ readonly kind: "text.delta";
229
+ readonly output: OutputRef;
230
+ readonly delta: string;
231
+ }
232
+ export interface TextDone {
233
+ readonly kind: "text.done";
234
+ readonly output: OutputRef;
235
+ readonly text: string;
236
+ }
237
+ export interface AudioDelta {
238
+ readonly kind: "audio.delta";
239
+ readonly output: OutputRef;
240
+ readonly audio: {
241
+ readonly data: Uint8Array;
242
+ readonly format: Required<PCMFormat>;
243
+ };
244
+ }
245
+ export interface AudioDone {
246
+ readonly kind: "audio.done";
247
+ readonly output: OutputRef;
248
+ }
249
+ export interface ToolCall {
250
+ readonly kind: "tool.call";
251
+ readonly call: ToolCallRef;
252
+ readonly itemId: string;
253
+ readonly name: string;
254
+ readonly arguments: JsonObject;
255
+ }
256
+ export interface ResponseAbandoned {
257
+ readonly kind: "response.abandoned";
258
+ readonly response: ResponseRef;
259
+ }
260
+ export interface ResponseEnded {
261
+ /** Settings revision published by the server; null when unavailable.
262
+ * Optional on caller-created values for compatibility. */
263
+ readonly settingsRevision?: number | null;
264
+ readonly kind: "response.ended";
265
+ readonly response: ResponseRef;
266
+ readonly status: "completed" | "cancelled" | "failed" | "unknown";
267
+ readonly reason: string | null;
268
+ }
269
+ export interface FaultEvent<Fault extends RealtimeFault = RealtimeFault> {
270
+ readonly kind: "error";
271
+ readonly error: Fault;
272
+ }
273
+ export type InputEvent<Fault extends RealtimeFault = RealtimeFault> = InputReady | SpeechHint | SpeechStarted | SpeechStopped | InputCommitted | TranscriptDelta | TranscriptFinal | TranscriptFailed<Fault>;
274
+ export type ResponseEvent = ResponseStarted | ResponseAbandoned | MessageStarted | TextDelta | TextDone | AudioDelta | AudioDone | ToolCall | ResponseEnded;
275
+ export interface SessionEvent<Fault extends RealtimeFault = RealtimeFault> {
276
+ readonly sessionId: string;
277
+ readonly eventId: string;
278
+ readonly requestId: string | null;
279
+ readonly payload: InputEvent<Fault> | ResponseEvent | FaultEvent<Fault>;
280
+ }
281
+ export interface PlaybackInterrupted {
282
+ readonly kind: "interrupted";
283
+ readonly output: OutputRef;
284
+ readonly audioEndMs: number;
285
+ }
286
+ export interface PlaybackFinished {
287
+ readonly kind: "finished";
288
+ readonly response: ResponseRef;
289
+ readonly playedMs?: number | null;
290
+ readonly audibleTailMs?: number | null;
291
+ }
292
+ export type PlaybackReport = PlaybackInterrupted | PlaybackFinished;
@@ -0,0 +1,12 @@
1
+ import { RimeError, RimeTimeoutError } from "../errors.js";
2
+ import { normalizeFault } from "./faults.js";
3
+ export class RealtimeAdmissionTimeout extends RimeTimeoutError {
4
+ }
5
+ export class RimeRealtimeError extends RimeError {
6
+ fault;
7
+ constructor(fault) {
8
+ const normalized = normalizeFault(fault);
9
+ super(`${normalized.code}: ${normalized.message}`, normalized.requestId);
10
+ this.fault = normalized;
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ import { type PCMFormat } from "../pcm.js";
2
+ /** One utterance of headerless signed PCM16 little-endian mono 16 kHz output.
3
+ * Fully consume each feed iterator before feeding the next chunk. Conversion
4
+ * advances one bounded source portion at a time so callers can apply backpressure.
5
+ */
6
+ export declare class InputAudio {
7
+ private readonly converter;
8
+ private readonly frameBytes;
9
+ private pending;
10
+ private finished;
11
+ constructor(format?: PCMFormat);
12
+ feed(data: Uint8Array): Generator<Buffer>;
13
+ /** Check EOF before committing; never silently pad or truncate a final frame. */
14
+ finish(): void;
15
+ }
@@ -0,0 +1,46 @@
1
+ import { RimeAudioFormatError, RimeInputError } from "../errors.js";
2
+ import { InputConverter, resolvePCMFormat } from "../pcm.js";
3
+ // Bound conversion work and temporary allocations for large source chunks.
4
+ const sourceBytes = 16384;
5
+ // Maximum decoded STT audio payload, excluding the protobuf envelope.
6
+ const messageBytes = 65536;
7
+ /** One utterance of headerless signed PCM16 little-endian mono 16 kHz output.
8
+ * Fully consume each feed iterator before feeding the next chunk. Conversion
9
+ * advances one bounded source portion at a time so callers can apply backpressure.
10
+ */
11
+ export class InputAudio {
12
+ converter;
13
+ frameBytes;
14
+ pending = Buffer.alloc(0);
15
+ finished = false;
16
+ constructor(format) {
17
+ const resolved = resolvePCMFormat(format);
18
+ this.converter = new InputConverter(resolved);
19
+ this.frameBytes = 2 * resolved.channels;
20
+ }
21
+ *feed(data) {
22
+ if (this.finished)
23
+ throw new RimeInputError("The audio input is finished");
24
+ if (!(data instanceof Uint8Array))
25
+ throw new RimeAudioFormatError("The audio source must yield PCM16 Uint8Array chunks");
26
+ for (let offset = 0; offset < data.length; offset += sourceBytes) {
27
+ const part = Buffer.concat([
28
+ this.pending,
29
+ data.subarray(offset, offset + sourceBytes),
30
+ ]);
31
+ const complete = part.length - (part.length % this.frameBytes);
32
+ this.pending = Buffer.from(part.subarray(complete));
33
+ if (complete) {
34
+ const converted = this.converter.process(part.subarray(0, complete));
35
+ for (let start = 0; start < converted.length; start += messageBytes)
36
+ yield converted.subarray(start, start + messageBytes);
37
+ }
38
+ }
39
+ }
40
+ /** Check EOF before committing; never silently pad or truncate a final frame. */
41
+ finish() {
42
+ this.finished = true;
43
+ if (this.pending.length)
44
+ throw new RimeAudioFormatError("The audio source ended with an incomplete PCM16 frame");
45
+ }
46
+ }
@@ -0,0 +1,17 @@
1
+ import { Credentials } from "../auth.js";
2
+ import { TranscriptStream } from "./stream.js";
3
+ import type { AudioSource, TranscriptionOptions, TranscribeOptions, Transcription } from "./types.js";
4
+ export declare class STT {
5
+ private readonly credentials;
6
+ private readonly checkOpen;
7
+ private connection;
8
+ private streams;
9
+ private readonly cancellation;
10
+ private readonly requests;
11
+ constructor(credentials: Credentials, checkOpen: () => void);
12
+ /** Transcribe complete WAV bytes (at most 16 MiB), without replay or retries. */
13
+ transcribe(audio: Uint8Array, options: TranscribeOptions): Promise<Transcription>;
14
+ private prepare;
15
+ stream(source: AudioSource, options: TranscriptionOptions): TranscriptStream;
16
+ close(): Promise<void>;
17
+ }