@relevanceai/sdk 3.0.2 → 3.1.0
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/LICENSE +1 -1
- package/README.md +49 -649
- package/esm/agent.js +4 -0
- package/esm/client.d.ts +1 -1
- package/esm/message/agent.d.ts +12 -0
- package/esm/message/agent.js +14 -0
- package/esm/message/stream.d.ts +15 -0
- package/esm/message/stream.js +11 -0
- package/esm/message/task.d.ts +12 -5
- package/esm/message/task.js +11 -3
- package/esm/region.d.ts +1 -0
- package/esm/region.js +3 -0
- package/esm/task/agent-strategy.js +12 -5
- package/esm/task/stream.d.ts +24 -0
- package/esm/task/stream.js +151 -0
- package/esm/task/task.d.ts +3 -1
- package/esm/task/task.js +50 -2
- package/esm/task/workforce-strategy.js +12 -5
- package/esm/workforce.js +1 -0
- package/package.json +1 -1
- package/script/agent.js +4 -0
- package/script/client.d.ts +1 -1
- package/script/message/agent.d.ts +12 -0
- package/script/message/agent.js +14 -0
- package/script/message/stream.d.ts +15 -0
- package/script/message/stream.js +16 -0
- package/script/message/task.d.ts +12 -5
- package/script/message/task.js +11 -3
- package/script/region.d.ts +1 -0
- package/script/region.js +4 -0
- package/script/task/agent-strategy.js +12 -5
- package/script/task/stream.d.ts +24 -0
- package/script/task/stream.js +155 -0
- package/script/task/task.d.ts +3 -1
- package/script/task/task.js +50 -2
- package/script/task/workforce-strategy.js +12 -5
- package/script/workforce.js +1 -0
package/script/message/task.d.ts
CHANGED
|
@@ -4,9 +4,11 @@ import type { ToolMessage } from "./tool.js";
|
|
|
4
4
|
import type { UserMessage } from "./user.js";
|
|
5
5
|
import type { WorkforceAgentMessage } from "./workforce-agent.js";
|
|
6
6
|
import type { WorkforceAgentHandoverMessage } from "./workforce-agent-handover.js";
|
|
7
|
-
|
|
7
|
+
import type { ThinkingMessage } from "./stream.js";
|
|
8
|
+
import type { TypingMessage } from "./stream.js";
|
|
9
|
+
export type AnyTaskMessage = AgentMessage | AgentErrorMessage | ThinkingMessage | TypingMessage | ToolMessage | UserMessage | WorkforceAgentMessage | WorkforceAgentHandoverMessage;
|
|
8
10
|
export type TaskMessageType = AnyTaskMessage["type"];
|
|
9
|
-
interface MessageContent {
|
|
11
|
+
export interface MessageContent {
|
|
10
12
|
type: AnyTaskMessage["type"];
|
|
11
13
|
}
|
|
12
14
|
export interface TaskMessageData<C extends MessageContent = MessageContent> {
|
|
@@ -54,10 +56,15 @@ export declare abstract class GenericMessage<C extends MessageContent = MessageC
|
|
|
54
56
|
*/
|
|
55
57
|
isUser(): this is UserMessage;
|
|
56
58
|
/**
|
|
57
|
-
* Returns if the message
|
|
59
|
+
* Returns if the message is agent thinking.
|
|
58
60
|
*
|
|
59
61
|
* @returns {boolean}
|
|
60
62
|
*/
|
|
61
|
-
|
|
63
|
+
isThinking(): this is ThinkingMessage;
|
|
64
|
+
/**
|
|
65
|
+
* Returns if the message is agent typing.
|
|
66
|
+
*
|
|
67
|
+
* @returns {boolean}
|
|
68
|
+
*/
|
|
69
|
+
isTyping(): this is TypingMessage;
|
|
62
70
|
}
|
|
63
|
-
export {};
|
package/script/message/task.js
CHANGED
|
@@ -55,12 +55,20 @@ class GenericMessage {
|
|
|
55
55
|
return this.type === "user-message";
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
|
-
* Returns if the message
|
|
58
|
+
* Returns if the message is agent thinking.
|
|
59
59
|
*
|
|
60
60
|
* @returns {boolean}
|
|
61
61
|
*/
|
|
62
|
-
|
|
63
|
-
return this.type === "agent-
|
|
62
|
+
isThinking() {
|
|
63
|
+
return this.type === "agent-thinking";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Returns if the message is agent typing.
|
|
67
|
+
*
|
|
68
|
+
* @returns {boolean}
|
|
69
|
+
*/
|
|
70
|
+
isTyping() {
|
|
71
|
+
return this.type === "agent-typing";
|
|
64
72
|
}
|
|
65
73
|
}
|
|
66
74
|
exports.GenericMessage = GenericMessage;
|
package/script/region.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export declare const REGION_US = "bcbe5a";
|
|
|
3
3
|
export declare const REGION_EU = "d7b62b";
|
|
4
4
|
export declare const REGION_AU = "f1db6c";
|
|
5
5
|
export declare function regionBaseURL(region: Region): string;
|
|
6
|
+
export declare function regionStreamingURL(region: Region, token: string): string;
|
package/script/region.js
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.REGION_AU = exports.REGION_EU = exports.REGION_US = void 0;
|
|
4
4
|
exports.regionBaseURL = regionBaseURL;
|
|
5
|
+
exports.regionStreamingURL = regionStreamingURL;
|
|
5
6
|
exports.REGION_US = "bcbe5a";
|
|
6
7
|
exports.REGION_EU = "d7b62b";
|
|
7
8
|
exports.REGION_AU = "f1db6c";
|
|
8
9
|
function regionBaseURL(region) {
|
|
9
10
|
return `https://api-${region}.stack.tryrelevance.com`;
|
|
10
11
|
}
|
|
12
|
+
function regionStreamingURL(region, token) {
|
|
13
|
+
return `https://${region}.streaming.tryrelevance.com/v1/stream?authorization=Bearer+${token}`;
|
|
14
|
+
}
|
|
@@ -25,15 +25,22 @@ class AgentStrategy {
|
|
|
25
25
|
return this.agent;
|
|
26
26
|
}
|
|
27
27
|
async getMetadata() {
|
|
28
|
-
const
|
|
28
|
+
const url = `/agents/${this.agent.id}/tasks/${this.id}/metadata?include_streaming_token=true`;
|
|
29
|
+
const res = await this.client.fetch(url);
|
|
29
30
|
return {
|
|
30
31
|
id: this.id,
|
|
31
32
|
region: this.client.region,
|
|
32
33
|
project: this.client.project,
|
|
33
|
-
name: metadata.conversation.title,
|
|
34
|
-
status: (0, agent_js_1.stateToStatus)(metadata.conversation.state),
|
|
35
|
-
createdAt: new Date(metadata.insert_date),
|
|
36
|
-
updatedAt: new Date(metadata.update_date),
|
|
34
|
+
name: res.metadata.conversation.title,
|
|
35
|
+
status: (0, agent_js_1.stateToStatus)(res.metadata.conversation.state),
|
|
36
|
+
createdAt: new Date(res.metadata.insert_date),
|
|
37
|
+
updatedAt: new Date(res.metadata.update_date),
|
|
38
|
+
streamingToken: res.streaming_token
|
|
39
|
+
? {
|
|
40
|
+
token: res.streaming_token.token,
|
|
41
|
+
expiresAt: res.streaming_token.expiry_time_ms,
|
|
42
|
+
}
|
|
43
|
+
: undefined,
|
|
37
44
|
};
|
|
38
45
|
}
|
|
39
46
|
async getMessages({ after = new Date(0) } = {}) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Emitter } from "../emitter.js";
|
|
2
|
+
import { type Region } from "../region.js";
|
|
3
|
+
import type { TaskStrategy } from "./task.js";
|
|
4
|
+
export type StreamingToken = {
|
|
5
|
+
token: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
};
|
|
8
|
+
export type StreamDetail = {
|
|
9
|
+
content: string;
|
|
10
|
+
documentId: string;
|
|
11
|
+
};
|
|
12
|
+
type TaskStreamEventMap = {
|
|
13
|
+
thinking: StreamDetail;
|
|
14
|
+
typing: StreamDetail;
|
|
15
|
+
};
|
|
16
|
+
export declare class TaskStream extends Emitter<TaskStreamEventMap> {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(strategy: TaskStrategy<any>, metadata: {
|
|
19
|
+
region: Region;
|
|
20
|
+
streamingToken: StreamingToken;
|
|
21
|
+
});
|
|
22
|
+
close(): void;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaskStream = void 0;
|
|
4
|
+
const emitter_js_1 = require("../emitter.js");
|
|
5
|
+
const region_js_1 = require("../region.js");
|
|
6
|
+
class TaskStream extends emitter_js_1.Emitter {
|
|
7
|
+
#strategy;
|
|
8
|
+
#region;
|
|
9
|
+
#token;
|
|
10
|
+
#closed = false;
|
|
11
|
+
#refreshTimer = null;
|
|
12
|
+
#source = null;
|
|
13
|
+
#fetchController = null;
|
|
14
|
+
constructor(strategy, metadata) {
|
|
15
|
+
super();
|
|
16
|
+
this.#strategy = strategy;
|
|
17
|
+
this.#region = metadata.region;
|
|
18
|
+
this.#token = metadata.streamingToken;
|
|
19
|
+
this.#connect();
|
|
20
|
+
}
|
|
21
|
+
close() {
|
|
22
|
+
this.#closed = true;
|
|
23
|
+
this.#clearRefreshTimer();
|
|
24
|
+
this.#disconnect();
|
|
25
|
+
}
|
|
26
|
+
#connect() {
|
|
27
|
+
if (this.#closed)
|
|
28
|
+
return;
|
|
29
|
+
this.#scheduleRefresh();
|
|
30
|
+
if (typeof EventSource !== "undefined") {
|
|
31
|
+
this.#connectEventSource();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
this.#connectFetch();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
#disconnect() {
|
|
38
|
+
this.#clearRefreshTimer();
|
|
39
|
+
if (this.#source) {
|
|
40
|
+
this.#source.close();
|
|
41
|
+
this.#source = null;
|
|
42
|
+
}
|
|
43
|
+
if (this.#fetchController) {
|
|
44
|
+
this.#fetchController.abort();
|
|
45
|
+
this.#fetchController = null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
#connectEventSource() {
|
|
49
|
+
const url = (0, region_js_1.regionStreamingURL)(this.#region, this.#token.token);
|
|
50
|
+
const source = new EventSource(url);
|
|
51
|
+
this.#source = source;
|
|
52
|
+
source.addEventListener("message", (event) => {
|
|
53
|
+
this.#handleData(event.data);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
#connectFetch() {
|
|
57
|
+
const url = (0, region_js_1.regionStreamingURL)(this.#region, this.#token.token);
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
this.#fetchController = controller;
|
|
60
|
+
void (async () => {
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetch(url, {
|
|
63
|
+
headers: { Accept: "text/event-stream" },
|
|
64
|
+
signal: controller.signal,
|
|
65
|
+
});
|
|
66
|
+
if (!response.ok || !response.body)
|
|
67
|
+
return;
|
|
68
|
+
const reader = response.body.getReader();
|
|
69
|
+
const decoder = new TextDecoder();
|
|
70
|
+
let buffer = "";
|
|
71
|
+
while (true) {
|
|
72
|
+
const { done, value } = await reader.read();
|
|
73
|
+
if (done)
|
|
74
|
+
break;
|
|
75
|
+
buffer += decoder.decode(value, { stream: true });
|
|
76
|
+
const { events, remainder } = this.#parseSSE(buffer);
|
|
77
|
+
buffer = remainder;
|
|
78
|
+
for (const data of events) {
|
|
79
|
+
this.#handleData(data);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// aborted or network error — ignore if closed
|
|
85
|
+
}
|
|
86
|
+
})();
|
|
87
|
+
}
|
|
88
|
+
#parseSSE(buffer) {
|
|
89
|
+
const events = [];
|
|
90
|
+
const blocks = buffer.split("\n\n");
|
|
91
|
+
const remainder = blocks.pop(); // last chunk may be incomplete
|
|
92
|
+
for (const block of blocks) {
|
|
93
|
+
for (const line of block.split("\n")) {
|
|
94
|
+
if (line.startsWith("data:")) {
|
|
95
|
+
events.push(line.slice(5).trimStart());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { events, remainder };
|
|
100
|
+
}
|
|
101
|
+
#handleData(raw) {
|
|
102
|
+
try {
|
|
103
|
+
const data = JSON.parse(raw);
|
|
104
|
+
switch (data.type) {
|
|
105
|
+
case "thinking":
|
|
106
|
+
this.dispatchEvent(new CustomEvent("thinking", {
|
|
107
|
+
detail: { content: data.content, documentId: data.documentId },
|
|
108
|
+
}));
|
|
109
|
+
break;
|
|
110
|
+
case "text":
|
|
111
|
+
this.dispatchEvent(new CustomEvent("typing", {
|
|
112
|
+
detail: { content: data.content, documentId: data.documentId },
|
|
113
|
+
}));
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// ignore malformed JSON
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
#scheduleRefresh() {
|
|
122
|
+
this.#clearRefreshTimer();
|
|
123
|
+
const delay = this.#token.expiresAt - Date.now() - 30_000;
|
|
124
|
+
if (delay <= 0)
|
|
125
|
+
return; // already expired or about to
|
|
126
|
+
this.#refreshTimer = setTimeout(() => this.#refresh(), delay);
|
|
127
|
+
}
|
|
128
|
+
#clearRefreshTimer() {
|
|
129
|
+
if (this.#refreshTimer !== null) {
|
|
130
|
+
clearTimeout(this.#refreshTimer);
|
|
131
|
+
this.#refreshTimer = null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async #refresh() {
|
|
135
|
+
if (this.#closed)
|
|
136
|
+
return;
|
|
137
|
+
try {
|
|
138
|
+
const metadata = await this.#strategy.getMetadata();
|
|
139
|
+
if (this.#closed)
|
|
140
|
+
return;
|
|
141
|
+
if (!metadata.streamingToken) {
|
|
142
|
+
this.close();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this.#region = metadata.region;
|
|
146
|
+
this.#token = metadata.streamingToken;
|
|
147
|
+
this.#disconnect();
|
|
148
|
+
this.#connect();
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// refresh failed — try again on next schedule
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.TaskStream = TaskStream;
|
package/script/task/task.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ import type { Region } from "../region.js";
|
|
|
4
4
|
import type { Workforce } from "../workforce.js";
|
|
5
5
|
import type { Agent } from "../agent.js";
|
|
6
6
|
import type { AgentErrorMessage } from "../message/agent-error.js";
|
|
7
|
+
import { type StreamingToken } from "./stream.js";
|
|
7
8
|
export type TaskStatus = "not-started" | "idle" | "paused" | "queued" | "running" | "action" | "completed" | "cancelled" | "error";
|
|
9
|
+
export type { StreamingToken };
|
|
8
10
|
export interface TaskMetadata {
|
|
9
11
|
id: string;
|
|
10
12
|
region: Region;
|
|
@@ -13,6 +15,7 @@ export interface TaskMetadata {
|
|
|
13
15
|
name: string;
|
|
14
16
|
createdAt: Date;
|
|
15
17
|
updatedAt: Date;
|
|
18
|
+
streamingToken?: StreamingToken;
|
|
16
19
|
}
|
|
17
20
|
type TaskEventMap = {
|
|
18
21
|
updated: undefined;
|
|
@@ -56,4 +59,3 @@ export declare class Task<S extends Agent | Workforce, E extends TaskEventMap =
|
|
|
56
59
|
handleEvent: (event: CustomEvent<E[K]>) => void;
|
|
57
60
|
} | null, options?: boolean | AddEventListenerOptions): void;
|
|
58
61
|
}
|
|
59
|
-
export {};
|
package/script/task/task.js
CHANGED
|
@@ -4,6 +4,8 @@ exports.Task = exports.resetBackoffDuration = void 0;
|
|
|
4
4
|
const emitter_js_1 = require("../emitter.js");
|
|
5
5
|
const utils_js_1 = require("../utils.js");
|
|
6
6
|
const event_js_1 = require("../event.js");
|
|
7
|
+
const stream_js_1 = require("../message/stream.js");
|
|
8
|
+
const stream_js_2 = require("./stream.js");
|
|
7
9
|
exports.resetBackoffDuration = Symbol("resetBackoffDuration");
|
|
8
10
|
const backoffStartingDuration = 1_000;
|
|
9
11
|
const backoffMaxDuration = 60_000;
|
|
@@ -13,6 +15,7 @@ class Task extends emitter_js_1.Emitter {
|
|
|
13
15
|
backoffDuration = 0;
|
|
14
16
|
strategy;
|
|
15
17
|
#metadata;
|
|
18
|
+
#stream = null;
|
|
16
19
|
constructor(metadata, strategy) {
|
|
17
20
|
super();
|
|
18
21
|
this.strategy = strategy;
|
|
@@ -54,6 +57,33 @@ class Task extends emitter_js_1.Emitter {
|
|
|
54
57
|
return false;
|
|
55
58
|
}
|
|
56
59
|
}
|
|
60
|
+
#connectStream() {
|
|
61
|
+
const stream = new stream_js_2.TaskStream(this.strategy, {
|
|
62
|
+
region: this.#metadata.region,
|
|
63
|
+
streamingToken: this.#metadata.streamingToken,
|
|
64
|
+
});
|
|
65
|
+
stream.addEventListener("thinking", (event) => {
|
|
66
|
+
this.dispatchEvent(new event_js_1.TaskMessageEvent(new stream_js_1.ThinkingMessage({
|
|
67
|
+
item_id: event.detail.documentId,
|
|
68
|
+
insert_date_: new Date().toISOString(),
|
|
69
|
+
content: {
|
|
70
|
+
type: "agent-thinking",
|
|
71
|
+
text: event.detail.content,
|
|
72
|
+
},
|
|
73
|
+
})));
|
|
74
|
+
});
|
|
75
|
+
stream.addEventListener("typing", (event) => {
|
|
76
|
+
this.dispatchEvent(new event_js_1.TaskMessageEvent(new stream_js_1.TypingMessage({
|
|
77
|
+
item_id: event.detail.documentId,
|
|
78
|
+
insert_date_: new Date().toISOString(),
|
|
79
|
+
content: {
|
|
80
|
+
type: "agent-typing",
|
|
81
|
+
text: event.detail.content,
|
|
82
|
+
},
|
|
83
|
+
})));
|
|
84
|
+
});
|
|
85
|
+
this.#stream = stream;
|
|
86
|
+
}
|
|
57
87
|
#subscribe() {
|
|
58
88
|
if (this.subscribed) {
|
|
59
89
|
return;
|
|
@@ -62,9 +92,12 @@ class Task extends emitter_js_1.Emitter {
|
|
|
62
92
|
this.subscribed = subscribed; // subscribed ref
|
|
63
93
|
const isSubscribed = () => !subscribed.signal.aborted;
|
|
64
94
|
this.backoffDuration = backoffStartingDuration;
|
|
65
|
-
const cursor = new Date();
|
|
95
|
+
const cursor = new Date(this.#metadata.createdAt);
|
|
66
96
|
const emitted = new Set();
|
|
67
97
|
const pending = new Map();
|
|
98
|
+
if (this.#metadata.streamingToken) {
|
|
99
|
+
this.#connectStream();
|
|
100
|
+
}
|
|
68
101
|
void (async () => {
|
|
69
102
|
while (isSubscribed()) {
|
|
70
103
|
try {
|
|
@@ -81,6 +114,9 @@ class Task extends emitter_js_1.Emitter {
|
|
|
81
114
|
hasChanges = true;
|
|
82
115
|
}
|
|
83
116
|
this.#metadata = metadata;
|
|
117
|
+
if (!this.#stream && metadata.streamingToken) {
|
|
118
|
+
this.#connectStream();
|
|
119
|
+
}
|
|
84
120
|
if (messages.length) {
|
|
85
121
|
for (const message of messages) {
|
|
86
122
|
if (emitted.has(message.id)) {
|
|
@@ -107,7 +143,17 @@ class Task extends emitter_js_1.Emitter {
|
|
|
107
143
|
this.dispatchEvent(new event_js_1.TaskMessageEvent(message));
|
|
108
144
|
break;
|
|
109
145
|
}
|
|
110
|
-
case "agent-message":
|
|
146
|
+
case "agent-message": {
|
|
147
|
+
if (message.isAgent() && message.isGenerating()) {
|
|
148
|
+
pending.set(message.id, message);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
emitted.add(message.id);
|
|
152
|
+
pending.delete(message.id);
|
|
153
|
+
hasChanges = true;
|
|
154
|
+
this.dispatchEvent(new event_js_1.TaskMessageEvent(message));
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
111
157
|
case "user-message":
|
|
112
158
|
hasChanges = true;
|
|
113
159
|
emitted.add(message.id);
|
|
@@ -143,6 +189,8 @@ class Task extends emitter_js_1.Emitter {
|
|
|
143
189
|
})();
|
|
144
190
|
}
|
|
145
191
|
unsubscribe() {
|
|
192
|
+
this.#stream?.close();
|
|
193
|
+
this.#stream = null;
|
|
146
194
|
this.subscribed?.abort();
|
|
147
195
|
this.subscribed = null;
|
|
148
196
|
this.backoff?.abort();
|
|
@@ -81,15 +81,22 @@ class WorkforceStrategy {
|
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
async getMetadata() {
|
|
84
|
-
const
|
|
84
|
+
const url = `/workforce/tasks/${this.id}/metadata?include_streaming_token=true`;
|
|
85
|
+
const res = await this.client.fetch(url);
|
|
85
86
|
return {
|
|
86
87
|
id: this.id,
|
|
87
88
|
region: this.client.region,
|
|
88
89
|
project: this.client.project,
|
|
89
|
-
name: metadata.title,
|
|
90
|
-
status: WorkforceStrategy.convertStatus(metadata.state),
|
|
91
|
-
createdAt: new Date(metadata.insert_date),
|
|
92
|
-
updatedAt: new Date(metadata.update_date),
|
|
90
|
+
name: res.metadata.title,
|
|
91
|
+
status: WorkforceStrategy.convertStatus(res.metadata.state),
|
|
92
|
+
createdAt: new Date(res.metadata.insert_date),
|
|
93
|
+
updatedAt: new Date(res.metadata.update_date),
|
|
94
|
+
streamingToken: res.streaming_token
|
|
95
|
+
? {
|
|
96
|
+
token: res.streaming_token.token,
|
|
97
|
+
expiresAt: res.streaming_token.expiry_time_ms,
|
|
98
|
+
}
|
|
99
|
+
: undefined,
|
|
93
100
|
};
|
|
94
101
|
}
|
|
95
102
|
}
|