@rimelabs/sdk 0.1.0-alpha.19 → 0.1.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/realtime/client.js +31 -0
- package/dist/realtime/protocol.d.ts +1 -0
- package/dist/realtime/protocol.js +13 -1
- package/dist/realtime/types.d.ts +31 -0
- package/docs/realtime.md +33 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0-alpha.20](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.19...typescript-v0.1.0-alpha.20) (2026-10-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add Prism tool filler controls for Python and TypeScript ([#93](https://github.com/rimelabs/rime-sdk/issues/93)) ([c6d1344](https://github.com/rimelabs/rime-sdk/commit/c6d13445b565cf62b4dd0e7e630c4b86182d6a82))
|
|
9
|
+
* **realtime:** report what ended the user's turn ([#92](https://github.com/rimelabs/rime-sdk/issues/92)) ([88eb9f2](https://github.com/rimelabs/rime-sdk/commit/88eb9f20d9c9943a67b809452493cc27744b794e))
|
|
10
|
+
|
|
3
11
|
## [0.1.0-alpha.19](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.18...typescript-v0.1.0-alpha.19) (2026-10-21)
|
|
4
12
|
|
|
5
13
|
|
package/dist/realtime/client.js
CHANGED
|
@@ -48,6 +48,34 @@ function copyJson(value) {
|
|
|
48
48
|
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, copyJson(item)]));
|
|
49
49
|
throw new RimeInputError("Tool schemas must contain finite JSON values");
|
|
50
50
|
}
|
|
51
|
+
function fillerSettings(value) {
|
|
52
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
53
|
+
throw new RimeInputError("prismFiller must be a filler object");
|
|
54
|
+
const kind = value.type;
|
|
55
|
+
if (!["none", "text", "auto"].includes(kind))
|
|
56
|
+
throw new RimeInputError("Prism filler type must be none, text, or auto");
|
|
57
|
+
const field = kind === "text" ? "text" : kind === "auto" ? "instructions" : null;
|
|
58
|
+
if (Object.entries(value).some(([key, item]) => item !== undefined && key !== "type" && key !== field))
|
|
59
|
+
throw new RimeInputError("Prism filler has fields not allowed for its type");
|
|
60
|
+
const text = field === null ? undefined : value[field];
|
|
61
|
+
if (kind === "text" || text !== undefined) {
|
|
62
|
+
// Rust str::trim uses Unicode White_Space, which differs from JS trim.
|
|
63
|
+
if (typeof text !== "string" ||
|
|
64
|
+
!/\P{White_Space}/u.test(text) ||
|
|
65
|
+
[...text].length > 500)
|
|
66
|
+
throw new RimeInputError("Prism filler text must be nonblank and at most 500 characters");
|
|
67
|
+
// Unicode mode matches lone surrogates but preserves valid UTF-16 pairs.
|
|
68
|
+
if (/[\uD800-\uDFFF]/u.test(text))
|
|
69
|
+
throw new RimeInputError("Prism filler text must be valid UTF-8");
|
|
70
|
+
}
|
|
71
|
+
if (kind === "text")
|
|
72
|
+
return { type: "text", text: text };
|
|
73
|
+
if (kind === "auto")
|
|
74
|
+
return text === undefined
|
|
75
|
+
? { type: "auto" }
|
|
76
|
+
: { type: "auto", instructions: text };
|
|
77
|
+
return { type: "none" };
|
|
78
|
+
}
|
|
51
79
|
export class Realtime {
|
|
52
80
|
credentials;
|
|
53
81
|
checkOpen;
|
|
@@ -96,6 +124,9 @@ export class Realtime {
|
|
|
96
124
|
throw new RimeInputError("Tool parameters must be an object");
|
|
97
125
|
return {
|
|
98
126
|
type: "function",
|
|
127
|
+
...(tool.prismFiller === undefined
|
|
128
|
+
? {}
|
|
129
|
+
: { prism_filler: fillerSettings(tool.prismFiller) }),
|
|
99
130
|
function: {
|
|
100
131
|
name: tool.name,
|
|
101
132
|
description: tool.description ?? "",
|
|
@@ -230,13 +230,25 @@ function decodeValue(value, sessionId) {
|
|
|
230
230
|
audioStartMs: integer(event.audio_start_ms, "audio_start_ms"),
|
|
231
231
|
};
|
|
232
232
|
break;
|
|
233
|
-
case "input_audio_buffer.speech_stopped":
|
|
233
|
+
case "input_audio_buffer.speech_stopped": {
|
|
234
|
+
const reason = event.prism_end_reason === undefined
|
|
235
|
+
? null
|
|
236
|
+
: string(event.prism_end_reason, "prism_end_reason");
|
|
234
237
|
payload = {
|
|
235
238
|
kind: "speech.stopped",
|
|
236
239
|
itemId: id(event.item_id, "item_id"),
|
|
237
240
|
audioEndMs: integer(event.audio_end_ms, "audio_end_ms"),
|
|
241
|
+
endReason: reason === null ||
|
|
242
|
+
reason === "semantic" ||
|
|
243
|
+
reason === "timeout" ||
|
|
244
|
+
reason === "silence" ||
|
|
245
|
+
reason === "max_duration" ||
|
|
246
|
+
reason === "detector_changed"
|
|
247
|
+
? reason
|
|
248
|
+
: "unknown",
|
|
238
249
|
};
|
|
239
250
|
break;
|
|
251
|
+
}
|
|
240
252
|
case "input_audio_buffer.committed":
|
|
241
253
|
payload = {
|
|
242
254
|
kind: "input.committed",
|
package/dist/realtime/types.d.ts
CHANGED
|
@@ -14,10 +14,27 @@ export interface RealtimeTimeouts {
|
|
|
14
14
|
export interface RealtimeOperationOptions {
|
|
15
15
|
readonly signal?: AbortSignal;
|
|
16
16
|
}
|
|
17
|
+
/** Speech while a tool runs. Text and instructions must be nonblank and at
|
|
18
|
+
* most 500 Unicode scalar values. Invalid UTF-8 is rejected.
|
|
19
|
+
* Omit the setting to use the server default. */
|
|
20
|
+
export type PrismFiller = {
|
|
21
|
+
readonly type: "none";
|
|
22
|
+
readonly text?: never;
|
|
23
|
+
readonly instructions?: never;
|
|
24
|
+
} | {
|
|
25
|
+
readonly type: "text";
|
|
26
|
+
readonly text: string;
|
|
27
|
+
readonly instructions?: never;
|
|
28
|
+
} | {
|
|
29
|
+
readonly type: "auto";
|
|
30
|
+
readonly instructions?: string;
|
|
31
|
+
readonly text?: never;
|
|
32
|
+
};
|
|
17
33
|
export interface ToolDefinition {
|
|
18
34
|
readonly name: string;
|
|
19
35
|
readonly parameters: JsonObject;
|
|
20
36
|
readonly description?: string;
|
|
37
|
+
readonly prismFiller?: PrismFiller;
|
|
21
38
|
}
|
|
22
39
|
export type TurnEagerness = "low" | "medium" | "high" | "auto";
|
|
23
40
|
/** Omitted fields use the server's turn timing defaults. */
|
|
@@ -109,10 +126,24 @@ export interface SpeechStarted {
|
|
|
109
126
|
readonly itemId: string;
|
|
110
127
|
readonly audioStartMs: number;
|
|
111
128
|
}
|
|
129
|
+
/** What ended the user's turn:
|
|
130
|
+
* - `semantic`: Prism judged from the user's speech that they had finished;
|
|
131
|
+
* `eagerness` sets how readily it does.
|
|
132
|
+
* - `timeout`: the user was silent for `endOfTurnTimeoutMs`, and the timeout
|
|
133
|
+
* ended the turn before Prism judged that they had finished.
|
|
134
|
+
* - `silence`: Prism's backup turn detection ended the turn at a short pause;
|
|
135
|
+
* it does not apply `eagerness` or `endOfTurnTimeoutMs`.
|
|
136
|
+
* - `max_duration`: the user spoke for the longest turn Prism takes; what
|
|
137
|
+
* they say next starts a new turn.
|
|
138
|
+
* - `detector_changed`: Prism switched between its main and backup turn
|
|
139
|
+
* detection while the user spoke; nothing the user did ended the turn. */
|
|
140
|
+
export type SpeechEndReason = "semantic" | "timeout" | "silence" | "max_duration" | "detector_changed";
|
|
112
141
|
export interface SpeechStopped {
|
|
113
142
|
readonly kind: "speech.stopped";
|
|
114
143
|
readonly itemId: string;
|
|
115
144
|
readonly audioEndMs: number;
|
|
145
|
+
/** Null means the server did not publish the field. */
|
|
146
|
+
readonly endReason: SpeechEndReason | "unknown" | null;
|
|
116
147
|
}
|
|
117
148
|
export interface InputCommitted {
|
|
118
149
|
readonly kind: "input.committed";
|
package/docs/realtime.md
CHANGED
|
@@ -275,6 +275,37 @@ Declare tools with plain `ToolDefinition` objects. Names must be nonblank and
|
|
|
275
275
|
unique; schemas must contain finite JSON values. The SDK copies schemas before
|
|
276
276
|
connection setup, so later caller changes cannot alter initialization.
|
|
277
277
|
|
|
278
|
+
Set `prismFiller` to control what Prism says while the tool runs:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import type { ToolDefinition } from "@rimelabs/sdk";
|
|
282
|
+
|
|
283
|
+
const pressDigits: ToolDefinition = {
|
|
284
|
+
name: "press_digits",
|
|
285
|
+
parameters: { type: "object", properties: { digits: { type: "string" } } },
|
|
286
|
+
prismFiller: { type: "none" },
|
|
287
|
+
};
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
| Setting | Behavior |
|
|
291
|
+
| --- | --- |
|
|
292
|
+
| Omitted | Use the server default, currently `auto`. |
|
|
293
|
+
| `{ type: "none" }` | Suppress filler for this tool. |
|
|
294
|
+
| `{ type: "text", text: "One moment." }` | Speak the supplied text. |
|
|
295
|
+
| `{ type: "auto" }` | Let Prism write a line from the tool description. |
|
|
296
|
+
| `{ type: "auto", instructions: "Say you are checking the order." }` | Guide the generated line. |
|
|
297
|
+
|
|
298
|
+
Text and instructions must be valid UTF-8, contain at most 500 Unicode scalar
|
|
299
|
+
values, and contain a character outside the Unicode `White_Space` set. This
|
|
300
|
+
matches the engine's validation. The SDK preserves the supplied text and copies
|
|
301
|
+
filler settings before connection setup. Invalid settings raise `RimeInputError` before opening a
|
|
302
|
+
connection, including for JavaScript callers. The exported `PrismFiller` union
|
|
303
|
+
also checks TypeScript callers.
|
|
304
|
+
|
|
305
|
+
Filler applies when the reply has said nothing before calling a tool. If a reply
|
|
306
|
+
calls several tools, the first call's tool controls the filler. `none` suppresses
|
|
307
|
+
filler only; it does not silence other speech. Settings are fixed for the session.
|
|
308
|
+
|
|
278
309
|
Execute a tool once for each `tool.call` event. Validate its parsed `arguments`,
|
|
279
310
|
then submit a string result with `submitToolResult(payload.call, output)`.
|
|
280
311
|
Use `JSON.stringify(...)` for a structured result. Call
|
|
@@ -301,7 +332,8 @@ are exported from `@rimelabs/sdk`.
|
|
|
301
332
|
| --- | --- |
|
|
302
333
|
| `input.ready` | No data fields. Turn methods handle the readiness wait. |
|
|
303
334
|
| `speech.hint` | `audioStartMs`; the user may have started speaking over a playing reply. It can be a false alarm: lower playback, do not stop it. |
|
|
304
|
-
| `speech.started
|
|
335
|
+
| `speech.started` | `itemId`, `audioStartMs` |
|
|
336
|
+
| `speech.stopped` | `itemId`, `audioEndMs`, `endReason`: what ended the turn (`semantic`, `timeout`, `silence`, `max_duration` or `detector_changed`), `unknown` for a newer value, or null from a server that does not send it |
|
|
305
337
|
| `input.committed` | `itemId` |
|
|
306
338
|
| `transcript.delta`, `transcript.final` | `itemId` and `delta` or `text` |
|
|
307
339
|
| `transcript.failed` | `itemId`, `error` |
|