@rimelabs/sdk 0.1.0-alpha.24 → 0.1.0-alpha.26
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 +14 -0
- package/dist/errors.d.ts +13 -1
- package/dist/errors.js +6 -0
- package/dist/realtime/protocol.d.ts +7 -1
- package/dist/realtime/protocol.js +32 -0
- package/dist/realtime/session.d.ts +2 -2
- package/dist/realtime/session.js +18 -6
- package/dist/realtime/transport.js +84 -5
- package/dist/realtime/types.d.ts +20 -1
- package/dist/realtime/types.js +8 -0
- package/docs/realtime.md +34 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0-alpha.26](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.25...typescript-v0.1.0-alpha.26) (2026-10-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* expose realtime connection diagnostics across SDKs ([#116](https://github.com/rimelabs/rime-sdk/issues/116)) ([da50cf4](https://github.com/rimelabs/rime-sdk/commit/da50cf41b0ca4631c0c71e48ef31cd207ab5e713))
|
|
9
|
+
|
|
10
|
+
## [0.1.0-alpha.25](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.24...typescript-v0.1.0-alpha.25) (2026-10-28)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* expose Prism reply labels and response data ([#114](https://github.com/rimelabs/rime-sdk/issues/114)) ([4a303a1](https://github.com/rimelabs/rime-sdk/commit/4a303a1b545019dea389f30d0c696e8f7e6cc6b1))
|
|
16
|
+
|
|
3
17
|
## [0.1.0-alpha.24](https://github.com/rimelabs/rime-sdk/compare/typescript-v0.1.0-alpha.23...typescript-v0.1.0-alpha.24) (2026-10-27)
|
|
4
18
|
|
|
5
19
|
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
/** Optional connection diagnostics. These fields do not initiate retries. */
|
|
2
|
+
export interface RimeErrorOptions extends ErrorOptions {
|
|
3
|
+
/** Refused HTTP upgrade status, such as 503; null when unavailable. */
|
|
4
|
+
statusCode?: number | null;
|
|
5
|
+
/** Received WebSocket close code, such as 1013; null when unavailable. */
|
|
6
|
+
closeCode?: number | null;
|
|
7
|
+
/** Server-requested delay in seconds. Zero is valid; null means unavailable. */
|
|
8
|
+
retryAfterSeconds?: number | null;
|
|
9
|
+
}
|
|
1
10
|
export declare class RimeError extends Error {
|
|
2
11
|
readonly requestId: string | null;
|
|
3
|
-
|
|
12
|
+
readonly statusCode: number | null;
|
|
13
|
+
readonly closeCode: number | null;
|
|
14
|
+
readonly retryAfterSeconds: number | null;
|
|
15
|
+
constructor(message: string, requestId?: string | null, options?: RimeErrorOptions);
|
|
4
16
|
}
|
|
5
17
|
export declare class RimeAuthenticationError extends RimeError {
|
|
6
18
|
}
|
package/dist/errors.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
export class RimeError extends Error {
|
|
2
2
|
requestId;
|
|
3
|
+
statusCode;
|
|
4
|
+
closeCode;
|
|
5
|
+
retryAfterSeconds;
|
|
3
6
|
constructor(message, requestId = null, options) {
|
|
4
7
|
super(message, options);
|
|
5
8
|
this.name = new.target.name;
|
|
6
9
|
this.requestId = requestId;
|
|
10
|
+
this.statusCode = options?.statusCode ?? null;
|
|
11
|
+
this.closeCode = options?.closeCode ?? null;
|
|
12
|
+
this.retryAfterSeconds = options?.retryAfterSeconds ?? null;
|
|
7
13
|
}
|
|
8
14
|
}
|
|
9
15
|
export class RimeAuthenticationError extends RimeError {
|
|
@@ -26,6 +26,8 @@ export interface SessionSettings {
|
|
|
26
26
|
}
|
|
27
27
|
/** A copy of the client's labels for every reply: keys to strings. */
|
|
28
28
|
export declare function responseMetadata(value: unknown): t.Labels;
|
|
29
|
+
/** Copy caller labels before combining them with the SDK's protocol fields. */
|
|
30
|
+
export declare function requestMetadata(value: t.Labels | null | undefined, reserved: Record<string, string>): Record<string, string>;
|
|
29
31
|
export interface SessionPatch {
|
|
30
32
|
truncation?: SessionSettings["truncation"];
|
|
31
33
|
voice?: string;
|
|
@@ -76,11 +78,15 @@ export interface ItemDeleted {
|
|
|
76
78
|
export interface AudioCleared {
|
|
77
79
|
kind: "audio.cleared";
|
|
78
80
|
}
|
|
81
|
+
export interface SessionIdleTimeout {
|
|
82
|
+
kind: "session.idle_timeout";
|
|
83
|
+
idleTimeoutS: number;
|
|
84
|
+
}
|
|
79
85
|
export interface ResponseEnded extends t.ResponseEnded {
|
|
80
86
|
drainToken: string | null;
|
|
81
87
|
}
|
|
82
88
|
export type Acknowledgment = SessionUpdated | HistoryListed | ItemDeleted | ItemCreated | ToolResultCreated | AudioCleared | t.ItemTruncated | t.ResponseStarted | ResponseEnded;
|
|
83
|
-
export type ServerPayload = SessionCreated | Acknowledgment | t.InputEvent<t.NormalizedRealtimeFault> | t.MessageStarted | t.TextDelta | t.TextDone | t.AudioDelta | t.AudioDone | t.ToolCall | t.FaultEvent<t.NormalizedRealtimeFault
|
|
89
|
+
export type ServerPayload = SessionCreated | Acknowledgment | t.InputEvent<t.NormalizedRealtimeFault> | t.MessageStarted | t.TextDelta | t.TextDone | t.AudioDelta | t.AudioDone | t.ToolCall | t.FaultEvent<t.NormalizedRealtimeFault> | SessionIdleTimeout;
|
|
84
90
|
export interface ServerEvent {
|
|
85
91
|
eventId: string;
|
|
86
92
|
requestId: string | null;
|
|
@@ -12,6 +12,13 @@ export function responseMetadata(value) {
|
|
|
12
12
|
throw new RimeInputError("responseMetadata must map keys to strings");
|
|
13
13
|
return Object.freeze({ ...value });
|
|
14
14
|
}
|
|
15
|
+
/** Copy caller labels before combining them with the SDK's protocol fields. */
|
|
16
|
+
export function requestMetadata(value, reserved) {
|
|
17
|
+
const labels = value == null ? {} : responseMetadata(value);
|
|
18
|
+
if (Object.keys(labels).some((key) => key.startsWith("prism_")))
|
|
19
|
+
throw new RimeInputError("request metadata keys cannot start with prism_");
|
|
20
|
+
return { ...labels, ...reserved };
|
|
21
|
+
}
|
|
15
22
|
/** A request carries its result type and checks it before exposing the result. */
|
|
16
23
|
export class Request {
|
|
17
24
|
kind;
|
|
@@ -67,6 +74,9 @@ function id(value, field) {
|
|
|
67
74
|
function optionalString(value, field) {
|
|
68
75
|
return value == null ? null : string(value, field);
|
|
69
76
|
}
|
|
77
|
+
function optionalId(value, field) {
|
|
78
|
+
return value == null ? null : id(value, field);
|
|
79
|
+
}
|
|
70
80
|
function integer(value, field) {
|
|
71
81
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
72
82
|
return invalid(field);
|
|
@@ -91,6 +101,17 @@ function responseTruncation(response) {
|
|
|
91
101
|
: string(value.first_kept_item_id, "prism_truncation.first_kept_item_id"),
|
|
92
102
|
});
|
|
93
103
|
}
|
|
104
|
+
function responseUsage(response) {
|
|
105
|
+
if (response.usage == null)
|
|
106
|
+
return null;
|
|
107
|
+
const usage = object(response.usage, "response.usage");
|
|
108
|
+
return Object.freeze({
|
|
109
|
+
inputTokens: integer(usage.input_tokens, "response.usage.input_tokens"),
|
|
110
|
+
outputTokens: integer(usage.output_tokens, "response.usage.output_tokens"),
|
|
111
|
+
totalTokens: integer(usage.total_tokens, "response.usage.total_tokens"),
|
|
112
|
+
contextWindow: integer(usage.context_window, "response.usage.context_window"),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
94
115
|
function duration(value, field) {
|
|
95
116
|
if (value == null)
|
|
96
117
|
return null;
|
|
@@ -287,6 +308,15 @@ function decodeValue(value, sessionId) {
|
|
|
287
308
|
case "conversation.item.deleted":
|
|
288
309
|
payload = { kind: "item.deleted", itemId: id(event.item_id, "item_id") };
|
|
289
310
|
break;
|
|
311
|
+
case "session.idle_timeout": {
|
|
312
|
+
if (event.reason !== "idle_timeout")
|
|
313
|
+
return invalid("reason");
|
|
314
|
+
const timeout = duration(event.idle_timeout_s, "idle_timeout_s");
|
|
315
|
+
if (timeout === null || timeout < 1)
|
|
316
|
+
return invalid("idle_timeout_s");
|
|
317
|
+
payload = { kind: "session.idle_timeout", idleTimeoutS: timeout };
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
290
320
|
case "input_audio_buffer.cleared":
|
|
291
321
|
payload = { kind: "audio.cleared" };
|
|
292
322
|
break;
|
|
@@ -398,6 +428,7 @@ function decodeValue(value, sessionId) {
|
|
|
398
428
|
: "unknown",
|
|
399
429
|
parent: parent === null ? null : ref(parent),
|
|
400
430
|
inputItemId,
|
|
431
|
+
instructionItemId: optionalId(metadata.prism_instruction_item_id, "prism_instruction_item_id"),
|
|
401
432
|
metadata: clientMetadata(metadata),
|
|
402
433
|
inputItemIds: Object.freeze(inputItemIds.map((value) => id(value, "prism_input_item_ids"))),
|
|
403
434
|
};
|
|
@@ -415,6 +446,7 @@ function decodeValue(value, sessionId) {
|
|
|
415
446
|
kind: "response.ended",
|
|
416
447
|
settingsRevision: revision(response),
|
|
417
448
|
truncation: responseTruncation(response),
|
|
449
|
+
usage: responseUsage(response),
|
|
418
450
|
response: ref(response.id),
|
|
419
451
|
status: status === "completed" ||
|
|
420
452
|
status === "cancelled" ||
|
|
@@ -56,7 +56,7 @@ export declare class RealtimeSession {
|
|
|
56
56
|
* complete list. Replies already started keep their original settings.
|
|
57
57
|
* Cancellation after submission does not undo an accepted update. */
|
|
58
58
|
update(options?: t.RealtimeUpdateOptions): Promise<t.SessionInfo>;
|
|
59
|
-
sendText(value: string, options?: t.
|
|
59
|
+
sendText(value: string, options?: t.ReplyRequestOptions): Promise<t.ResponseRef>;
|
|
60
60
|
requestReply(options?: t.ReplyOptions): Promise<t.ResponseRef>;
|
|
61
61
|
/** Read the items the next reply would see, in server order. */
|
|
62
62
|
getHistory(options?: t.RealtimeOperationOptions): Promise<readonly t.HistoryItem[]>;
|
|
@@ -66,7 +66,7 @@ export declare class RealtimeSession {
|
|
|
66
66
|
createItem(item: t.HistoryItem, options?: t.HistoryCreateOptions): Promise<t.ItemRef>;
|
|
67
67
|
addMessage(role: "user" | "assistant", value: string, options?: t.RealtimeOperationOptions): Promise<t.ItemRef>;
|
|
68
68
|
submitToolResult(call: t.ToolCallRef, output: string, options?: t.RealtimeOperationOptions): Promise<void>;
|
|
69
|
-
continueReply(parent: t.ResponseRef, options?: t.
|
|
69
|
+
continueReply(parent: t.ResponseRef, options?: t.ReplyRequestOptions): Promise<t.ResponseRef>;
|
|
70
70
|
cancel(response: t.ResponseRef, options?: t.RealtimeOperationOptions): Promise<void>;
|
|
71
71
|
/** Replaces the labels later replies carry; a reply already started keeps
|
|
72
72
|
* its own. Resolves once Prism confirms the change. */
|
package/dist/realtime/session.js
CHANGED
|
@@ -403,11 +403,19 @@ export class RealtimeSession {
|
|
|
403
403
|
}
|
|
404
404
|
async sendText(value, options = {}) {
|
|
405
405
|
text(value);
|
|
406
|
-
|
|
406
|
+
const metadata = p.requestMetadata(options.metadata, {
|
|
407
|
+
prism_cause: "user_text",
|
|
408
|
+
});
|
|
409
|
+
return this.operation(options, (signal) => this.create({
|
|
410
|
+
prism_input_text: value,
|
|
411
|
+
metadata,
|
|
412
|
+
}, signal, p.requests.text));
|
|
407
413
|
}
|
|
408
414
|
async requestReply(options = {}) {
|
|
409
415
|
const body = {
|
|
410
|
-
metadata: {
|
|
416
|
+
metadata: p.requestMetadata(options.metadata, {
|
|
417
|
+
prism_cause: "proactive",
|
|
418
|
+
}),
|
|
411
419
|
};
|
|
412
420
|
if (options.instruction != null) {
|
|
413
421
|
text(options.instruction);
|
|
@@ -498,6 +506,10 @@ export class RealtimeSession {
|
|
|
498
506
|
}
|
|
499
507
|
async continueReply(parent, options = {}) {
|
|
500
508
|
const ref = { ...parent };
|
|
509
|
+
const metadata = p.requestMetadata(options.metadata, {
|
|
510
|
+
prism_cause: "tool_continuation",
|
|
511
|
+
prism_parent_response_id: ref.responseId,
|
|
512
|
+
});
|
|
501
513
|
const state = this.response(ref);
|
|
502
514
|
return this.operation(options, async (signal) => {
|
|
503
515
|
const ready = scope([signal], this.timeouts.readyS, new t.RealtimeAdmissionTimeout("Tool results or parent completion did not arrive before readyS expired"));
|
|
@@ -522,10 +534,7 @@ export class RealtimeSession {
|
|
|
522
534
|
}
|
|
523
535
|
return (await this.request(p.requests.create, {
|
|
524
536
|
response: {
|
|
525
|
-
metadata
|
|
526
|
-
prism_cause: "tool_continuation",
|
|
527
|
-
prism_parent_response_id: ref.responseId,
|
|
528
|
-
},
|
|
537
|
+
metadata,
|
|
529
538
|
},
|
|
530
539
|
}, signal, undefined, state)).response;
|
|
531
540
|
});
|
|
@@ -677,6 +686,9 @@ export class RealtimeSession {
|
|
|
677
686
|
throw new RimeStreamError("Tool result acknowledgment names another call");
|
|
678
687
|
}
|
|
679
688
|
switch (payload.kind) {
|
|
689
|
+
case "session.idle_timeout":
|
|
690
|
+
this.fail(new t.RealtimeIdleTimeout(payload.idleTimeoutS));
|
|
691
|
+
return;
|
|
680
692
|
case "session.created":
|
|
681
693
|
if (this.sessionId === null) {
|
|
682
694
|
this.sessionId = payload.session.id;
|
|
@@ -1,7 +1,83 @@
|
|
|
1
1
|
import WebSocket from "ws";
|
|
2
2
|
import { RimeAuthenticationError, RimeResourceLimitError, RimeStreamError, RimeUnavailableError, } from "../errors.js";
|
|
3
3
|
import { Deferred } from "./async.js";
|
|
4
|
-
|
|
4
|
+
const months = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");
|
|
5
|
+
const dayName = "(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)";
|
|
6
|
+
const monthName = `(?:${months.join("|")})`;
|
|
7
|
+
const clock = "([0-9]{2}):([0-9]{2}):([0-9]{2})";
|
|
8
|
+
const imfDate = new RegExp(`^${dayName}, ([0-9]{2}) (${monthName}) ([0-9]{4}) ${clock} GMT$`);
|
|
9
|
+
const rfc850Date = new RegExp(`^(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), ([0-9]{2})-(${monthName})-([0-9]{2}) ${clock} GMT$`);
|
|
10
|
+
const asctimeDate = new RegExp(`^${dayName} (${monthName}) ([0-9]{2}| [0-9]) ${clock} ([0-9]{4})$`);
|
|
11
|
+
function httpDate(value, now) {
|
|
12
|
+
let parts = imfDate.exec(value);
|
|
13
|
+
let shortYear = false;
|
|
14
|
+
if (!parts) {
|
|
15
|
+
parts = rfc850Date.exec(value);
|
|
16
|
+
shortYear = parts !== null;
|
|
17
|
+
}
|
|
18
|
+
if (!parts) {
|
|
19
|
+
const legacy = asctimeDate.exec(value);
|
|
20
|
+
if (!legacy)
|
|
21
|
+
return null;
|
|
22
|
+
parts = [
|
|
23
|
+
legacy[0],
|
|
24
|
+
legacy[2],
|
|
25
|
+
legacy[1],
|
|
26
|
+
legacy[6],
|
|
27
|
+
legacy[3],
|
|
28
|
+
legacy[4],
|
|
29
|
+
legacy[5],
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
const day = Number(parts[1]);
|
|
33
|
+
const month = months.indexOf(parts[2]);
|
|
34
|
+
let year = Number(parts[3]);
|
|
35
|
+
const hour = Number(parts[4]);
|
|
36
|
+
const minute = Number(parts[5]);
|
|
37
|
+
const second = Number(parts[6]);
|
|
38
|
+
if (shortYear) {
|
|
39
|
+
const current = new Date(now);
|
|
40
|
+
const limit = [
|
|
41
|
+
current.getUTCFullYear() + 50,
|
|
42
|
+
current.getUTCMonth(),
|
|
43
|
+
current.getUTCDate(),
|
|
44
|
+
current.getUTCHours(),
|
|
45
|
+
current.getUTCMinutes(),
|
|
46
|
+
current.getUTCSeconds(),
|
|
47
|
+
];
|
|
48
|
+
year += Math.floor(limit[0] / 100) * 100;
|
|
49
|
+
const candidate = [year, month, day, hour, minute, second];
|
|
50
|
+
const difference = candidate.findIndex((part, index) => part !== limit[index]);
|
|
51
|
+
if (difference !== -1 && candidate[difference] > limit[difference])
|
|
52
|
+
year -= 100;
|
|
53
|
+
}
|
|
54
|
+
// Use setters so years 0000–0099 aren't silently changed to 1900–1999.
|
|
55
|
+
const date = new Date(0);
|
|
56
|
+
date.setUTCFullYear(year, month, day);
|
|
57
|
+
date.setUTCHours(hour, minute, second, 0);
|
|
58
|
+
if (year < 1 ||
|
|
59
|
+
date.getUTCFullYear() !== year ||
|
|
60
|
+
date.getUTCMonth() !== month ||
|
|
61
|
+
date.getUTCDate() !== day ||
|
|
62
|
+
date.getUTCHours() !== hour ||
|
|
63
|
+
date.getUTCMinutes() !== minute ||
|
|
64
|
+
date.getUTCSeconds() !== second)
|
|
65
|
+
return null;
|
|
66
|
+
return date.getTime();
|
|
67
|
+
}
|
|
68
|
+
function retryAfter(values) {
|
|
69
|
+
if (values?.length !== 1 || values[0].length > 256)
|
|
70
|
+
return null;
|
|
71
|
+
const value = values[0].trim();
|
|
72
|
+
if (/^[0-9]+$/.test(value)) {
|
|
73
|
+
const seconds = Number(value);
|
|
74
|
+
return Number.isFinite(seconds) ? seconds : null;
|
|
75
|
+
}
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const date = httpDate(value, now);
|
|
78
|
+
return date === null ? null : Math.max(0, (date - now) / 1000);
|
|
79
|
+
}
|
|
80
|
+
function handshakeError(status, body, requestId, retryAfterSeconds) {
|
|
5
81
|
let errorType = RimeUnavailableError;
|
|
6
82
|
let reason = "Realtime endpoint rejected the connection";
|
|
7
83
|
if ([401, 403].includes(status)) {
|
|
@@ -35,7 +111,10 @@ function handshakeError(status, body, requestId) {
|
|
|
35
111
|
// Invalid response bodies do not change the HTTP error category.
|
|
36
112
|
}
|
|
37
113
|
}
|
|
38
|
-
return new errorType(message, requestId
|
|
114
|
+
return new errorType(message, requestId, {
|
|
115
|
+
statusCode: status,
|
|
116
|
+
retryAfterSeconds,
|
|
117
|
+
});
|
|
39
118
|
}
|
|
40
119
|
/** Private transport. The public declarations do not require ws types. */
|
|
41
120
|
export class RealtimeConnection {
|
|
@@ -74,7 +153,7 @@ export class RealtimeConnection {
|
|
|
74
153
|
clearTimeout(timer);
|
|
75
154
|
this.refusal = undefined;
|
|
76
155
|
const id = response.headers["x-request-id"];
|
|
77
|
-
this.failure(handshakeError(response.statusCode ?? 0, complete ? Buffer.concat(chunks) : Buffer.alloc(0), typeof id === "string" ? id : null));
|
|
156
|
+
this.failure(handshakeError(response.statusCode ?? 0, complete ? Buffer.concat(chunks) : Buffer.alloc(0), typeof id === "string" ? id : null, retryAfter(response.headersDistinct["retry-after"])));
|
|
78
157
|
response.destroy();
|
|
79
158
|
request.destroy();
|
|
80
159
|
this.socket.terminate();
|
|
@@ -104,10 +183,10 @@ export class RealtimeConnection {
|
|
|
104
183
|
}
|
|
105
184
|
this.onMessage(data.toString());
|
|
106
185
|
});
|
|
107
|
-
this.socket.on("close", () => {
|
|
186
|
+
this.socket.on("close", (code) => {
|
|
108
187
|
this.refusal?.();
|
|
109
188
|
this.ended.resolve();
|
|
110
|
-
this.failure(new RimeStreamError("Realtime connection closed; reconnect is not automatic"));
|
|
189
|
+
this.failure(new RimeStreamError("Realtime connection closed; reconnect is not automatic", null, { closeCode: code === 1005 || code === 1006 ? null : code }));
|
|
111
190
|
});
|
|
112
191
|
}
|
|
113
192
|
failure(error) {
|
package/dist/realtime/types.d.ts
CHANGED
|
@@ -87,7 +87,11 @@ export interface RealtimeUpdateOptions extends RealtimeOperationOptions {
|
|
|
87
87
|
readonly voice?: string;
|
|
88
88
|
readonly interruptOnSpeech?: boolean;
|
|
89
89
|
}
|
|
90
|
-
export interface
|
|
90
|
+
export interface ReplyRequestOptions extends RealtimeOperationOptions {
|
|
91
|
+
/** Labels for this reply. Request labels override matching session labels. */
|
|
92
|
+
readonly metadata?: Labels | null;
|
|
93
|
+
}
|
|
94
|
+
export interface ReplyOptions extends ReplyRequestOptions {
|
|
91
95
|
readonly instruction?: string | null;
|
|
92
96
|
readonly toolCall?: ToolCallRef | null;
|
|
93
97
|
}
|
|
@@ -178,6 +182,11 @@ export interface NormalizedRealtimeFault extends RealtimeFault {
|
|
|
178
182
|
}
|
|
179
183
|
export declare class RealtimeAdmissionTimeout extends RimeTimeoutError {
|
|
180
184
|
}
|
|
185
|
+
/** Prism closed the conversation after this many idle seconds. */
|
|
186
|
+
export declare class RealtimeIdleTimeout extends RimeTimeoutError {
|
|
187
|
+
readonly idleTimeoutS: number;
|
|
188
|
+
constructor(idleTimeoutS: number);
|
|
189
|
+
}
|
|
181
190
|
export declare class RimeRealtimeError extends RimeError {
|
|
182
191
|
readonly fault: NormalizedRealtimeFault;
|
|
183
192
|
constructor(fault: RealtimeFault);
|
|
@@ -244,6 +253,8 @@ export interface ResponseStarted {
|
|
|
244
253
|
readonly cause: "speech" | "text" | "proactive" | "tools" | "unknown";
|
|
245
254
|
readonly parent: ResponseRef | null;
|
|
246
255
|
readonly inputItemId: string | null;
|
|
256
|
+
/** Saved nudge instruction; pass this ID to deleteItem to remove it. */
|
|
257
|
+
readonly instructionItemId?: string | null;
|
|
247
258
|
/** The session's labels when the reply began. Prism's `prism_` keys are
|
|
248
259
|
* left out. */
|
|
249
260
|
readonly metadata: Labels;
|
|
@@ -295,6 +306,12 @@ export interface ResponseTruncation {
|
|
|
295
306
|
/** Oldest retained item; null when no earlier item was retained. */
|
|
296
307
|
readonly firstKeptItemId: string | null;
|
|
297
308
|
}
|
|
309
|
+
export interface ResponseUsage {
|
|
310
|
+
readonly inputTokens: number;
|
|
311
|
+
readonly outputTokens: number;
|
|
312
|
+
readonly totalTokens: number;
|
|
313
|
+
readonly contextWindow: number;
|
|
314
|
+
}
|
|
298
315
|
export interface ResponseEnded {
|
|
299
316
|
/** Settings revision published by the server; null when unavailable.
|
|
300
317
|
* Optional on caller-created values for compatibility. */
|
|
@@ -302,6 +319,8 @@ export interface ResponseEnded {
|
|
|
302
319
|
/** Null when the server reports no exclusions or the information is unavailable.
|
|
303
320
|
* Optional on caller-created values for compatibility. */
|
|
304
321
|
readonly truncation?: ResponseTruncation | null;
|
|
322
|
+
/** Null when Prism did not count tokens. */
|
|
323
|
+
readonly usage?: ResponseUsage | null;
|
|
305
324
|
readonly kind: "response.ended";
|
|
306
325
|
readonly response: ResponseRef;
|
|
307
326
|
readonly status: "completed" | "cancelled" | "failed" | "unknown";
|
package/dist/realtime/types.js
CHANGED
|
@@ -2,6 +2,14 @@ import { RimeError, RimeTimeoutError } from "../errors.js";
|
|
|
2
2
|
import { normalizeFault } from "./faults.js";
|
|
3
3
|
export class RealtimeAdmissionTimeout extends RimeTimeoutError {
|
|
4
4
|
}
|
|
5
|
+
/** Prism closed the conversation after this many idle seconds. */
|
|
6
|
+
export class RealtimeIdleTimeout extends RimeTimeoutError {
|
|
7
|
+
idleTimeoutS;
|
|
8
|
+
constructor(idleTimeoutS) {
|
|
9
|
+
super(`Realtime session idle for ${idleTimeoutS} seconds`);
|
|
10
|
+
this.idleTimeoutS = idleTimeoutS;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
5
13
|
export class RimeRealtimeError extends RimeError {
|
|
6
14
|
fault;
|
|
7
15
|
constructor(fault) {
|
package/docs/realtime.md
CHANGED
|
@@ -294,6 +294,12 @@ instruction, tool call, and signal in one object. `update` returns
|
|
|
294
294
|
`getHistory` returns `Promise<readonly HistoryItem[]>`. The other methods return
|
|
295
295
|
`Promise<void>`.
|
|
296
296
|
|
|
297
|
+
Pass `metadata: { step: "3" }` in the options for `sendText`, `requestReply`, or
|
|
298
|
+
`continueReply` to label only that reply. Request labels replace matching
|
|
299
|
+
session labels in Prism's response. The SDK adds the required `prism_` fields;
|
|
300
|
+
caller keys cannot use that prefix. Omitting `metadata` keeps the existing
|
|
301
|
+
request shape. Replies to speech use the session labels.
|
|
302
|
+
|
|
297
303
|
`sendText` and `addMessage` require nonblank text of at most 4,000 Unicode
|
|
298
304
|
characters. `addMessage` accepts `"user"` and `"assistant"` roles. `createItem`
|
|
299
305
|
also accepts `"system"` messages and allows blank message text, with the same
|
|
@@ -397,12 +403,12 @@ are exported from `@rimelabs/sdk`.
|
|
|
397
403
|
| `input.committed` | `itemId` |
|
|
398
404
|
| `transcript.delta`, `transcript.final` | `itemId` and `delta` or `text` |
|
|
399
405
|
| `transcript.failed` | `itemId`, `error` |
|
|
400
|
-
| `response.started` | `response`, `cause`, nullable `parent` and `
|
|
406
|
+
| `response.started` | `response`, `cause`, nullable `parent`, `inputItemId`, and `instructionItemId`, `inputItemIds` (the user items it answers), `metadata` (your own keys) |
|
|
401
407
|
| `message.started` | `output` |
|
|
402
408
|
| `text.delta`, `text.done` | `output` and `delta` or `text` |
|
|
403
409
|
| `audio.delta`, `audio.done` | `output`; a delta also has `audio.data` and a complete `audio.format` |
|
|
404
410
|
| `tool.call` | `call`, `itemId`, `name`, parsed `arguments` |
|
|
405
|
-
| `response.ended` | `response`, `status`, nullable `reason` |
|
|
411
|
+
| `response.ended` | `response`, `status`, nullable `reason` and `usage` |
|
|
406
412
|
| `response.abandoned` | `response`; the SDK requests cancellation after the requesting caller aborted. |
|
|
407
413
|
| `error` | `error`, a `RealtimeFault` |
|
|
408
414
|
|
|
@@ -446,6 +452,20 @@ The voice examples report actual playback.
|
|
|
446
452
|
|
|
447
453
|
## Timeouts and failures
|
|
448
454
|
|
|
455
|
+
`RimeError` exposes `statusCode` for a refused HTTP upgrade, `closeCode` for a
|
|
456
|
+
received WebSocket close code, and `retryAfterSeconds` for the server's requested
|
|
457
|
+
delay. For example, a busy endpoint can return `statusCode=503` and
|
|
458
|
+
`retryAfterSeconds=2`. Missing values are `null`; zero is a valid delay. The
|
|
459
|
+
existing `requestId` retains the server's request ID on an HTTP refusal.
|
|
460
|
+
Invalid or duplicate `Retry-After` headers are ignored. HTTP dates become a delay
|
|
461
|
+
relative to the client clock, with past dates becoming zero.
|
|
462
|
+
|
|
463
|
+
Error categories stay the same. A WebSocket closure uses `RimeStreamError`;
|
|
464
|
+
no received close code means `closeCode=null`, including a lost connection or
|
|
465
|
+
an empty close frame. These fields require a release with structured connection
|
|
466
|
+
diagnostics. The SDK does not retry startup automatically. These fields do not
|
|
467
|
+
make replay of an accepted request safe.
|
|
468
|
+
|
|
449
469
|
Configure positive, finite seconds through `timeouts`. `connectS` bounds the
|
|
450
470
|
WebSocket handshake and initial session event. `readyS` bounds turn admission,
|
|
451
471
|
tool readiness, and waiting for generation to end before a playback report.
|
|
@@ -460,6 +480,10 @@ the session remains usable. An unknown request outcome closes the connection and
|
|
|
460
480
|
is never replayed. The SDK retries typed-turn admission only after named refusals
|
|
461
481
|
that confirm the request made no change.
|
|
462
482
|
|
|
483
|
+
`RealtimeIdleTimeout` means Prism closed an idle session. Its `idleTimeoutS`
|
|
484
|
+
is the limit reported by Prism. Pending methods and the event iterator reject
|
|
485
|
+
with this error. Reconnect to start a new conversation.
|
|
486
|
+
|
|
463
487
|
Protocol faults appear as `error` events and can also reject an affected method
|
|
464
488
|
with `RimeRealtimeError`. Its `.fault` has `code`, `message`, `scope`, nullable
|
|
465
489
|
`requestId`, `responseId`, `itemId`, `correlationId`, `parameter`, and a `callIds`
|
|
@@ -616,6 +640,14 @@ This event can arrive after `response.ended`. It has no response reference and d
|
|
|
616
640
|
not require the SDK to retain that response. `text.done` still reports generated
|
|
617
641
|
text. Add `item.truncated` to exhaustive switches on `SessionEvent.payload.kind`.
|
|
618
642
|
|
|
643
|
+
## Response usage and saved nudge instructions
|
|
644
|
+
|
|
645
|
+
`ResponseEnded.usage` contains `inputTokens`, `outputTokens`, `totalTokens`,
|
|
646
|
+
and `contextWindow` when Prism counted the reply's tokens. It is `null` when
|
|
647
|
+
the count is unavailable. For a nudge with an instruction,
|
|
648
|
+
`ResponseStarted.instructionItemId` names the saved instruction. Pass that ID
|
|
649
|
+
to `deleteItem` to remove it from later history.
|
|
650
|
+
|
|
619
651
|
## History excluded from a reply
|
|
620
652
|
|
|
621
653
|
Available in the next SDK release. `ResponseEnded.truncation` exposes the server's
|