@meshagent/meshagent 0.47.0 → 0.47.1
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 +5 -0
- package/dist/browser/agent.js +6 -6
- package/dist/browser/meshagent-client.d.ts +2 -1
- package/dist/browser/meshagent-client.js +1 -0
- package/dist/browser/messaging-client.d.ts +72 -1
- package/dist/browser/messaging-client.js +302 -1
- package/dist/browser/participant-token.d.ts +1 -0
- package/dist/browser/participant-token.js +3 -0
- package/dist/browser/room-client.d.ts +2 -1
- package/dist/browser/room-client.js +25 -12
- package/dist/esm/agent.js +6 -6
- package/dist/esm/meshagent-client.d.ts +2 -1
- package/dist/esm/meshagent-client.js +1 -0
- package/dist/esm/messaging-client.d.ts +72 -1
- package/dist/esm/messaging-client.js +301 -1
- package/dist/esm/participant-token.d.ts +1 -0
- package/dist/esm/participant-token.js +3 -0
- package/dist/esm/room-client.d.ts +2 -1
- package/dist/esm/room-client.js +25 -12
- package/dist/node/agent.js +6 -6
- package/dist/node/meshagent-client.d.ts +2 -1
- package/dist/node/meshagent-client.js +1 -0
- package/dist/node/messaging-client.d.ts +72 -1
- package/dist/node/messaging-client.js +302 -1
- package/dist/node/participant-token.d.ts +1 -0
- package/dist/node/participant-token.js +3 -0
- package/dist/node/room-client.d.ts +2 -1
- package/dist/node/room-client.js +25 -12
- package/package.json +1 -1
package/dist/esm/agent.js
CHANGED
|
@@ -511,10 +511,10 @@ class _RemoteToolkitWrapper {
|
|
|
511
511
|
return false;
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
|
-
|
|
514
|
+
_sendToolCallResponseChunk(messageId, toolCallId, chunk) {
|
|
515
515
|
const [header, payload] = unpackMessage(chunk.pack());
|
|
516
516
|
try {
|
|
517
|
-
|
|
517
|
+
this.client.protocol.sendNowait("room.tool_call_response_chunk", packMessage({ tool_call_id: toolCallId, chunk: header }, payload.length > 0 ? payload : undefined), { id: messageId });
|
|
518
518
|
return true;
|
|
519
519
|
}
|
|
520
520
|
catch (error) {
|
|
@@ -615,10 +615,10 @@ class _RemoteToolkitWrapper {
|
|
|
615
615
|
return;
|
|
616
616
|
for await (const chunk of output.stream) {
|
|
617
617
|
this.toolkit.validateOutputContent(tool, chunk);
|
|
618
|
-
if (!
|
|
618
|
+
if (!this._sendToolCallResponseChunk(messageId, toolCallId, chunk))
|
|
619
619
|
return;
|
|
620
620
|
}
|
|
621
|
-
|
|
621
|
+
this._sendToolCallResponseChunk(messageId, toolCallId, new ControlContent({ method: "close" }));
|
|
622
622
|
return;
|
|
623
623
|
}
|
|
624
624
|
throw new Error(`tool ${toolName} returned unsupported output`);
|
|
@@ -629,9 +629,9 @@ class _RemoteToolkitWrapper {
|
|
|
629
629
|
return;
|
|
630
630
|
}
|
|
631
631
|
if (!(error instanceof InvalidToolDataException)) {
|
|
632
|
-
|
|
632
|
+
this._sendToolCallResponseChunk(messageId, toolCallId, new ErrorContent({ text: String(error) }));
|
|
633
633
|
}
|
|
634
|
-
|
|
634
|
+
this._sendToolCallResponseChunk(messageId, toolCallId, new ControlContent({
|
|
635
635
|
method: "close",
|
|
636
636
|
statusCode: error instanceof InvalidToolDataException ? ControlCloseStatus.INVALID_DATA : undefined,
|
|
637
637
|
message: error instanceof InvalidToolDataException ? error.message : undefined,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ApiScope } from "./participant-token.js";
|
|
2
2
|
export type ProjectRole = "member" | "admin" | "developer" | "room_creator" | "room_inventory" | "room_manager" | "session_inventory" | "agent_creator" | "agent_inventory" | "agent_manager" | "repository_creator" | "repository_inventory" | "repository_manager" | "feed_creator" | "feed_inventory" | "feed_manager" | "oauth_client_creator" | "oauth_client_inventory" | "oauth_client_manager" | "api_key_creator" | "api_key_inventory" | "api_key_manager" | "service_creator" | "service_inventory" | "service_manager" | "service_account_creator" | "service_account_inventory" | "service_account_manager" | "participant_token_creator" | "mailbox_creator" | "mailbox_inventory" | "mailbox_manager" | "route_creator" | "route_inventory" | "route_manager" | "scheduled_task_creator" | "scheduled_task_inventory" | "scheduled_task_manager" | "feed_subscription_creator" | "feed_subscription_inventory" | "feed_subscription_manager" | "llm_logger_creator" | "llm_logger_inventory" | "llm_logger_manager" | "llm_proxy_user" | "usage_reporter" | "billing_manager" | "group_manager";
|
|
3
3
|
export type ResourceRole = "viewer" | "operator" | "developer" | "admin";
|
|
4
|
+
export type RoomRole = "site_user" | ResourceRole;
|
|
4
5
|
export type FeedRole = "reader" | "subscriber" | "publisher" | "manager";
|
|
5
6
|
export type SecretRole = "use_proxy";
|
|
6
|
-
export type AccessRole = ProjectRole |
|
|
7
|
+
export type AccessRole = ProjectRole | RoomRole | FeedRole | SecretRole | "list";
|
|
7
8
|
export type AccessSubjectType = "user" | "group" | "agent" | "service_account" | "userset";
|
|
8
9
|
export type AccessResourceType = "project" | "room" | "agent" | "group" | "repository" | "feed" | "secret";
|
|
9
10
|
export interface AccessSubject {
|
|
@@ -654,6 +654,7 @@ export class Meshagent {
|
|
|
654
654
|
const parsedSubject = this.parseAccessSubject(data.subject);
|
|
655
655
|
const parsedDirectRoles = Array.isArray(data.direct_roles)
|
|
656
656
|
? data.direct_roles.filter((item) => item === "member" ||
|
|
657
|
+
item === "site_user" ||
|
|
657
658
|
item === "viewer" ||
|
|
658
659
|
item === "operator" ||
|
|
659
660
|
item === "developer" ||
|
|
@@ -1,8 +1,72 @@
|
|
|
1
1
|
import { EventEmitter } from "./event-emitter.js";
|
|
2
2
|
import { Participant, RemoteParticipant } from "./participant.js";
|
|
3
|
+
import { Content } from "./response.js";
|
|
3
4
|
import { RoomClient } from "./room-client.js";
|
|
4
|
-
import { RoomMessageEvent } from "./room-event.js";
|
|
5
|
+
import { RoomMessage, RoomMessageEvent } from "./room-event.js";
|
|
5
6
|
type MessagePayload = Record<string, unknown>;
|
|
7
|
+
export type MessagingStreamEvent = {
|
|
8
|
+
kind: "message";
|
|
9
|
+
message: RoomMessage;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "client_disconnected";
|
|
12
|
+
streamId: string;
|
|
13
|
+
participantId: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "closed";
|
|
16
|
+
streamId: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
message?: string;
|
|
19
|
+
};
|
|
20
|
+
declare class MessagingStreamInput {
|
|
21
|
+
private readonly items;
|
|
22
|
+
private signal;
|
|
23
|
+
private active;
|
|
24
|
+
private closed;
|
|
25
|
+
private error;
|
|
26
|
+
enqueue(content: Content, { wait }?: {
|
|
27
|
+
wait?: boolean;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
close(error?: unknown): void;
|
|
30
|
+
fail(error: unknown): void;
|
|
31
|
+
stream(): AsyncIterable<Content>;
|
|
32
|
+
}
|
|
33
|
+
export declare class MessagingStream implements AsyncIterable<MessagingStreamEvent> {
|
|
34
|
+
readonly streamId: string;
|
|
35
|
+
readonly remoteParticipantId: string;
|
|
36
|
+
private readonly input;
|
|
37
|
+
private readonly output;
|
|
38
|
+
private readonly inputDone;
|
|
39
|
+
private readonly onClosed;
|
|
40
|
+
private readonly events;
|
|
41
|
+
private eventSignal;
|
|
42
|
+
private state;
|
|
43
|
+
constructor({ streamId, remoteParticipantId, input, output, inputClosed, onClosed, }: {
|
|
44
|
+
streamId: string;
|
|
45
|
+
remoteParticipantId: string;
|
|
46
|
+
input: MessagingStreamInput;
|
|
47
|
+
output: AsyncIterator<Content>;
|
|
48
|
+
inputClosed?: Promise<void>;
|
|
49
|
+
onClosed: () => void;
|
|
50
|
+
});
|
|
51
|
+
get closed(): boolean;
|
|
52
|
+
private push;
|
|
53
|
+
private finish;
|
|
54
|
+
private consumeOutput;
|
|
55
|
+
private content;
|
|
56
|
+
sendMessageNowait(params: {
|
|
57
|
+
type: string;
|
|
58
|
+
message: MessagePayload;
|
|
59
|
+
attachment?: Uint8Array;
|
|
60
|
+
}): void;
|
|
61
|
+
sendMessage(params: {
|
|
62
|
+
type: string;
|
|
63
|
+
message: MessagePayload;
|
|
64
|
+
attachment?: Uint8Array;
|
|
65
|
+
}): Promise<void>;
|
|
66
|
+
close(): Promise<void>;
|
|
67
|
+
clientDisconnected(participantId: string): void;
|
|
68
|
+
[Symbol.asyncIterator](): AsyncIterator<MessagingStreamEvent>;
|
|
69
|
+
}
|
|
6
70
|
export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
|
|
7
71
|
private readonly client;
|
|
8
72
|
private readonly _messageHandler;
|
|
@@ -11,6 +75,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
|
|
|
11
75
|
private _messageQueued;
|
|
12
76
|
private _sendTask;
|
|
13
77
|
private readonly _sendOperations;
|
|
78
|
+
private readonly _streams;
|
|
14
79
|
private _messageQueueClosed;
|
|
15
80
|
private _desiredEnabled;
|
|
16
81
|
private _online;
|
|
@@ -64,6 +129,12 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
|
|
|
64
129
|
message: MessagePayload;
|
|
65
130
|
attachment?: Uint8Array;
|
|
66
131
|
}): Promise<void>;
|
|
132
|
+
stream({ to, type, message, attachment, }: {
|
|
133
|
+
to: Participant;
|
|
134
|
+
type: string;
|
|
135
|
+
message: MessagePayload;
|
|
136
|
+
attachment?: Uint8Array;
|
|
137
|
+
}): Promise<MessagingStream>;
|
|
67
138
|
getParticipants(): RemoteParticipant[];
|
|
68
139
|
getParticipant(id: string): RemoteParticipant | null;
|
|
69
140
|
getParticipantByName(name: string): RemoteParticipant | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Completer } from "./completer.js";
|
|
2
2
|
import { EventEmitter } from "./event-emitter.js";
|
|
3
3
|
import { RemoteParticipant } from "./participant.js";
|
|
4
|
-
import { JsonContent } from "./response.js";
|
|
4
|
+
import { ControlContent, JsonContent } from "./response.js";
|
|
5
5
|
import { RoomMessage, RoomMessageEvent } from "./room-event.js";
|
|
6
6
|
import { RoomServerException } from "./room-server-client.js";
|
|
7
7
|
import { splitMessageHeader, splitMessagePayload } from "./utils.js";
|
|
@@ -19,6 +19,255 @@ function bytesToBase64(bytes) {
|
|
|
19
19
|
}
|
|
20
20
|
return globalScope.btoa(binary);
|
|
21
21
|
}
|
|
22
|
+
function base64ToBytes(value) {
|
|
23
|
+
if (globalScope.Buffer != null) {
|
|
24
|
+
return new Uint8Array(globalScope.Buffer.from(value, "base64"));
|
|
25
|
+
}
|
|
26
|
+
const atob = globalThis.atob;
|
|
27
|
+
if (atob == null) {
|
|
28
|
+
throw new Error("base64 decoding is not available in this runtime");
|
|
29
|
+
}
|
|
30
|
+
const binary = atob(value);
|
|
31
|
+
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
32
|
+
}
|
|
33
|
+
class MessagingStreamInput {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.items = [];
|
|
36
|
+
this.signal = null;
|
|
37
|
+
this.active = null;
|
|
38
|
+
this.closed = false;
|
|
39
|
+
this.error = null;
|
|
40
|
+
}
|
|
41
|
+
enqueue(content, { wait = false } = {}) {
|
|
42
|
+
if (this.closed) {
|
|
43
|
+
return Promise.reject(this.error ?? new RoomServerException("the messaging stream is closed"));
|
|
44
|
+
}
|
|
45
|
+
const sent = wait ? new Completer() : undefined;
|
|
46
|
+
this.items.push({ content, sent });
|
|
47
|
+
this.signal?.resolve();
|
|
48
|
+
this.signal = null;
|
|
49
|
+
return sent?.fut ?? Promise.resolve();
|
|
50
|
+
}
|
|
51
|
+
close(error = new RoomServerException("the messaging stream is closed")) {
|
|
52
|
+
if (this.closed) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.closed = true;
|
|
56
|
+
this.error = error;
|
|
57
|
+
this.active?.sent?.reject(error);
|
|
58
|
+
this.active = null;
|
|
59
|
+
for (const item of this.items.splice(0)) {
|
|
60
|
+
item.sent?.reject(error);
|
|
61
|
+
}
|
|
62
|
+
this.signal?.resolve();
|
|
63
|
+
this.signal = null;
|
|
64
|
+
}
|
|
65
|
+
fail(error) {
|
|
66
|
+
this.close(error);
|
|
67
|
+
}
|
|
68
|
+
async *stream() {
|
|
69
|
+
try {
|
|
70
|
+
while (true) {
|
|
71
|
+
while (this.items.length === 0 && !this.closed) {
|
|
72
|
+
this.signal ?? (this.signal = new Completer());
|
|
73
|
+
await this.signal.fut;
|
|
74
|
+
}
|
|
75
|
+
const item = this.items.shift();
|
|
76
|
+
if (item == null) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.active = item;
|
|
80
|
+
yield item.content;
|
|
81
|
+
item.sent?.resolve();
|
|
82
|
+
this.active = null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
if (this.active != null && this.closed) {
|
|
87
|
+
this.active.sent?.reject(this.error ?? new RoomServerException("the messaging stream is closed"));
|
|
88
|
+
this.active = null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class MessagingStream {
|
|
94
|
+
constructor({ streamId, remoteParticipantId, input, output, inputClosed, onClosed, }) {
|
|
95
|
+
this.events = [];
|
|
96
|
+
this.eventSignal = null;
|
|
97
|
+
this.state = "accepted";
|
|
98
|
+
this.streamId = streamId;
|
|
99
|
+
this.remoteParticipantId = remoteParticipantId;
|
|
100
|
+
this.input = input;
|
|
101
|
+
this.output = output;
|
|
102
|
+
this.inputDone = Promise.resolve(inputClosed).catch((error) => {
|
|
103
|
+
this.input.fail(error);
|
|
104
|
+
this.push({
|
|
105
|
+
kind: "closed",
|
|
106
|
+
streamId: this.streamId,
|
|
107
|
+
reason: "error",
|
|
108
|
+
message: error instanceof Error ? error.message : String(error),
|
|
109
|
+
});
|
|
110
|
+
void this.output.return?.();
|
|
111
|
+
this.finish();
|
|
112
|
+
});
|
|
113
|
+
this.onClosed = onClosed;
|
|
114
|
+
void this.consumeOutput();
|
|
115
|
+
}
|
|
116
|
+
get closed() {
|
|
117
|
+
return this.state === "terminal";
|
|
118
|
+
}
|
|
119
|
+
push(event) {
|
|
120
|
+
if (this.state !== "accepted") {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.events.push(event);
|
|
124
|
+
this.eventSignal?.resolve();
|
|
125
|
+
this.eventSignal = null;
|
|
126
|
+
}
|
|
127
|
+
finish() {
|
|
128
|
+
if (this.state === "terminal") {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.state = "terminal";
|
|
132
|
+
this.input.close();
|
|
133
|
+
this.eventSignal?.resolve();
|
|
134
|
+
this.eventSignal = null;
|
|
135
|
+
void this.inputDone.finally(this.onClosed);
|
|
136
|
+
}
|
|
137
|
+
async consumeOutput() {
|
|
138
|
+
try {
|
|
139
|
+
while (true) {
|
|
140
|
+
const next = await this.output.next();
|
|
141
|
+
if (next.done) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (next.value instanceof ControlContent && next.value.method === "close") {
|
|
145
|
+
this.push({
|
|
146
|
+
kind: "client_disconnected",
|
|
147
|
+
streamId: this.streamId,
|
|
148
|
+
participantId: this.remoteParticipantId,
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (!(next.value instanceof JsonContent)) {
|
|
153
|
+
throw new RoomServerException("unexpected chunk from messaging.stream");
|
|
154
|
+
}
|
|
155
|
+
const value = next.value.json;
|
|
156
|
+
const kind = value["kind"];
|
|
157
|
+
if (kind === "message") {
|
|
158
|
+
const type = value["type"];
|
|
159
|
+
const message = value["message"];
|
|
160
|
+
if (typeof type !== "string" || typeof message !== "object" || message == null || Array.isArray(message)) {
|
|
161
|
+
throw new RoomServerException("invalid message chunk from messaging.stream");
|
|
162
|
+
}
|
|
163
|
+
const encodedAttachment = value["attachment_base64"];
|
|
164
|
+
this.push({
|
|
165
|
+
kind: "message",
|
|
166
|
+
message: new RoomMessage({
|
|
167
|
+
fromParticipantId: this.remoteParticipantId,
|
|
168
|
+
type,
|
|
169
|
+
message: message,
|
|
170
|
+
attachment: typeof encodedAttachment === "string" && encodedAttachment !== ""
|
|
171
|
+
? base64ToBytes(encodedAttachment)
|
|
172
|
+
: undefined,
|
|
173
|
+
}),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else if (kind === "client_disconnected" && typeof value["participant_id"] === "string") {
|
|
177
|
+
this.push({
|
|
178
|
+
kind,
|
|
179
|
+
streamId: this.streamId,
|
|
180
|
+
participantId: value["participant_id"],
|
|
181
|
+
});
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
else if (kind === "closed") {
|
|
185
|
+
this.push({
|
|
186
|
+
kind,
|
|
187
|
+
streamId: this.streamId,
|
|
188
|
+
reason: typeof value["reason"] === "string" ? value["reason"] : "closed",
|
|
189
|
+
message: typeof value["message"] === "string" ? value["message"] : undefined,
|
|
190
|
+
});
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw new RoomServerException("unexpected chunk from messaging.stream");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
this.input.fail(error);
|
|
200
|
+
this.push({
|
|
201
|
+
kind: "closed",
|
|
202
|
+
streamId: this.streamId,
|
|
203
|
+
reason: "error",
|
|
204
|
+
message: error instanceof Error ? error.message : String(error),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
this.finish();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
content({ type, message, attachment, }) {
|
|
212
|
+
return new JsonContent({
|
|
213
|
+
json: {
|
|
214
|
+
type,
|
|
215
|
+
message_json: JSON.stringify(message),
|
|
216
|
+
...(attachment == null ? {} : { attachment_base64: bytesToBase64(attachment) }),
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
sendMessageNowait(params) {
|
|
221
|
+
if (this.state !== "accepted") {
|
|
222
|
+
throw new RoomServerException("the messaging stream is closed");
|
|
223
|
+
}
|
|
224
|
+
void this.input.enqueue(this.content(params));
|
|
225
|
+
}
|
|
226
|
+
async sendMessage(params) {
|
|
227
|
+
if (this.state !== "accepted") {
|
|
228
|
+
throw new RoomServerException("the messaging stream is closed");
|
|
229
|
+
}
|
|
230
|
+
await this.input.enqueue(this.content(params), { wait: true });
|
|
231
|
+
}
|
|
232
|
+
async close() {
|
|
233
|
+
if (this.state === "terminal") {
|
|
234
|
+
await this.inputDone;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.input.close();
|
|
238
|
+
try {
|
|
239
|
+
await this.inputDone;
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
await this.output.return?.();
|
|
243
|
+
this.finish();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
clientDisconnected(participantId) {
|
|
247
|
+
if (this.state === "terminal") {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
this.push({
|
|
251
|
+
kind: "client_disconnected",
|
|
252
|
+
streamId: this.streamId,
|
|
253
|
+
participantId,
|
|
254
|
+
});
|
|
255
|
+
this.finish();
|
|
256
|
+
}
|
|
257
|
+
async *[Symbol.asyncIterator]() {
|
|
258
|
+
while (true) {
|
|
259
|
+
while (this.events.length === 0 && this.state !== "terminal") {
|
|
260
|
+
this.eventSignal ?? (this.eventSignal = new Completer());
|
|
261
|
+
await this.eventSignal.fut;
|
|
262
|
+
}
|
|
263
|
+
const event = this.events.shift();
|
|
264
|
+
if (event == null) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
yield event;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
22
271
|
export class MessagingClient extends EventEmitter {
|
|
23
272
|
constructor({ room }) {
|
|
24
273
|
super();
|
|
@@ -28,6 +277,7 @@ export class MessagingClient extends EventEmitter {
|
|
|
28
277
|
this._messageQueued = null;
|
|
29
278
|
this._sendTask = null;
|
|
30
279
|
this._sendOperations = new Set();
|
|
280
|
+
this._streams = new Set();
|
|
31
281
|
this._messageQueueClosed = false;
|
|
32
282
|
this._desiredEnabled = false;
|
|
33
283
|
this._online = false;
|
|
@@ -93,6 +343,7 @@ export class MessagingClient extends EventEmitter {
|
|
|
93
343
|
await sendTask;
|
|
94
344
|
}
|
|
95
345
|
await Promise.all(this._sendOperations);
|
|
346
|
+
await Promise.all([...this._streams].map(async (stream) => stream.close()));
|
|
96
347
|
this._desiredEnabled = false;
|
|
97
348
|
this._clearCurrentConnectionState();
|
|
98
349
|
}
|
|
@@ -156,6 +407,9 @@ export class MessagingClient extends EventEmitter {
|
|
|
156
407
|
}
|
|
157
408
|
}
|
|
158
409
|
_onRoomDisconnect({ reason: _reason }) {
|
|
410
|
+
for (const stream of [...this._streams]) {
|
|
411
|
+
stream.clientDisconnected(this.client.localParticipant?.id ?? stream.remoteParticipantId);
|
|
412
|
+
}
|
|
159
413
|
this._clearCurrentConnectionState();
|
|
160
414
|
}
|
|
161
415
|
_onRoomReconnect() {
|
|
@@ -348,6 +602,49 @@ export class MessagingClient extends EventEmitter {
|
|
|
348
602
|
throw error;
|
|
349
603
|
}
|
|
350
604
|
}
|
|
605
|
+
async stream({ to, type, message, attachment, }) {
|
|
606
|
+
const input = new MessagingStreamInput();
|
|
607
|
+
void input.enqueue(new JsonContent({
|
|
608
|
+
json: {
|
|
609
|
+
to_participant_id: to.id,
|
|
610
|
+
type,
|
|
611
|
+
message_json: JSON.stringify(message),
|
|
612
|
+
...(attachment == null ? {} : { attachment_base64: bytesToBase64(attachment) }),
|
|
613
|
+
},
|
|
614
|
+
}));
|
|
615
|
+
const outputResult = await this.client.invokeToolCall({
|
|
616
|
+
toolkit: "messaging",
|
|
617
|
+
tool: "stream",
|
|
618
|
+
input: input.stream(),
|
|
619
|
+
streamInput: true,
|
|
620
|
+
});
|
|
621
|
+
if (outputResult.kind !== "stream") {
|
|
622
|
+
input.close();
|
|
623
|
+
throw new RoomServerException("unexpected return type from messaging.stream");
|
|
624
|
+
}
|
|
625
|
+
const outputIterable = outputResult.stream;
|
|
626
|
+
const output = outputIterable[Symbol.asyncIterator]();
|
|
627
|
+
const accepted = await output.next();
|
|
628
|
+
if (accepted.done
|
|
629
|
+
|| !(accepted.value instanceof JsonContent)
|
|
630
|
+
|| accepted.value.json["kind"] !== "accepted"
|
|
631
|
+
|| typeof accepted.value.json["stream_id"] !== "string") {
|
|
632
|
+
input.close();
|
|
633
|
+
await output.return?.();
|
|
634
|
+
throw new RoomServerException("messaging.stream did not acknowledge acceptance");
|
|
635
|
+
}
|
|
636
|
+
let stream;
|
|
637
|
+
stream = new MessagingStream({
|
|
638
|
+
streamId: accepted.value.json["stream_id"],
|
|
639
|
+
remoteParticipantId: to.id,
|
|
640
|
+
input,
|
|
641
|
+
output,
|
|
642
|
+
inputClosed: outputResult.inputClosed,
|
|
643
|
+
onClosed: () => this._streams.delete(stream),
|
|
644
|
+
});
|
|
645
|
+
this._streams.add(stream);
|
|
646
|
+
return stream;
|
|
647
|
+
}
|
|
351
648
|
getParticipants() {
|
|
352
649
|
return this.remoteParticipants;
|
|
353
650
|
}
|
|
@@ -441,6 +738,9 @@ export class MessagingClient extends EventEmitter {
|
|
|
441
738
|
this._wakeMessageQueue();
|
|
442
739
|
this._drainQueuedMessages({ error });
|
|
443
740
|
this._desiredEnabled = false;
|
|
741
|
+
for (const stream of [...this._streams]) {
|
|
742
|
+
stream.clientDisconnected(this.client.localParticipant?.id ?? stream.remoteParticipantId);
|
|
743
|
+
}
|
|
444
744
|
this._clearCurrentConnectionState();
|
|
445
745
|
this.client.protocol.removeHandler("messaging.send", this._messageHandler);
|
|
446
746
|
super.dispose();
|
|
@@ -404,6 +404,7 @@ export declare class ParticipantToken {
|
|
|
404
404
|
addTunnelGrant(ports: number[]): void;
|
|
405
405
|
addRoleGrant(role: string): void;
|
|
406
406
|
addRoomGrant(roomName: string): void;
|
|
407
|
+
addSiteGrant(roomName: string): void;
|
|
407
408
|
addApiGrant(grant: ApiScope): void;
|
|
408
409
|
grantScope(name: string): string | ApiScope | undefined;
|
|
409
410
|
getApiGrant(): ApiScope | undefined;
|
|
@@ -1294,6 +1294,9 @@ export class ParticipantToken {
|
|
|
1294
1294
|
addRoomGrant(roomName) {
|
|
1295
1295
|
this.grants.push(new ParticipantGrant({ name: "room", scope: roomName }));
|
|
1296
1296
|
}
|
|
1297
|
+
addSiteGrant(roomName) {
|
|
1298
|
+
this.grants.push(new ParticipantGrant({ name: "site", scope: roomName }));
|
|
1299
|
+
}
|
|
1297
1300
|
addApiGrant(grant) {
|
|
1298
1301
|
for (const existingGrant of this.grants) {
|
|
1299
1302
|
if (existingGrant.name === "api") {
|
|
@@ -190,6 +190,7 @@ export declare class RoomClient {
|
|
|
190
190
|
_sendLocalAttributesNowait(attributes: Record<string, unknown>): void;
|
|
191
191
|
_resendLocalAttributesNowait(): void;
|
|
192
192
|
sendRequest(type: string, request: RequestHeader, data?: Uint8Array, afterSend?: () => void): Promise<Content>;
|
|
193
|
+
private _dispatchRequest;
|
|
193
194
|
call(params: {
|
|
194
195
|
name: string;
|
|
195
196
|
url: string;
|
|
@@ -249,7 +250,7 @@ export declare class RoomClient {
|
|
|
249
250
|
participantId?: string;
|
|
250
251
|
onBehalfOfId?: string;
|
|
251
252
|
}): Promise<AsyncIterable<Content>>;
|
|
252
|
-
private
|
|
253
|
+
private _dispatchToolCallRequestChunk;
|
|
253
254
|
private _streamInvokeToolRequestChunks;
|
|
254
255
|
private _decodeToolCallContent;
|
|
255
256
|
private _handleToolCallResponseChunk;
|
package/dist/esm/room-client.js
CHANGED
|
@@ -1143,6 +1143,11 @@ export class RoomClient {
|
|
|
1143
1143
|
this._sendLocalAttributesNowait(attributes);
|
|
1144
1144
|
}
|
|
1145
1145
|
async sendRequest(type, request, data, afterSend) {
|
|
1146
|
+
const response = this._dispatchRequest(type, request, data);
|
|
1147
|
+
afterSend?.();
|
|
1148
|
+
return await response;
|
|
1149
|
+
}
|
|
1150
|
+
_dispatchRequest(type, request, data) {
|
|
1146
1151
|
this._raiseIfTerminal();
|
|
1147
1152
|
if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
|
|
1148
1153
|
throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
|
|
@@ -1151,9 +1156,8 @@ export class RoomClient {
|
|
|
1151
1156
|
const completer = new Completer();
|
|
1152
1157
|
this._pendingRequests.set(requestId, completer);
|
|
1153
1158
|
try {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
return await completer.fut;
|
|
1159
|
+
this._protocolInstance.sendNowait(type, packMessage(request, data), { id: requestId });
|
|
1160
|
+
return completer.fut;
|
|
1157
1161
|
}
|
|
1158
1162
|
catch (error) {
|
|
1159
1163
|
this._pendingRequests.delete(requestId);
|
|
@@ -1259,7 +1263,6 @@ export class RoomClient {
|
|
|
1259
1263
|
let requestTask;
|
|
1260
1264
|
if (params.streamInput === true) {
|
|
1261
1265
|
request["arguments"] = { type: "control", method: "open" };
|
|
1262
|
-
requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1263
1266
|
}
|
|
1264
1267
|
else {
|
|
1265
1268
|
const input = params.input;
|
|
@@ -1276,9 +1279,14 @@ export class RoomClient {
|
|
|
1276
1279
|
if (params.onBehalfOfId != null) {
|
|
1277
1280
|
request["on_behalf_of_id"] = params.onBehalfOfId;
|
|
1278
1281
|
}
|
|
1282
|
+
const responseRequest = this._dispatchRequest("room.invoke_tool", request, requestData);
|
|
1283
|
+
params.afterSend?.();
|
|
1284
|
+
if (params.streamInput === true) {
|
|
1285
|
+
requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1286
|
+
}
|
|
1279
1287
|
try {
|
|
1280
1288
|
const response = await Promise.race([
|
|
1281
|
-
|
|
1289
|
+
responseRequest,
|
|
1282
1290
|
preOpenError.fut,
|
|
1283
1291
|
]);
|
|
1284
1292
|
this._toolCallPreOpenErrors.delete(toolCallId);
|
|
@@ -1333,9 +1341,10 @@ export class RoomClient {
|
|
|
1333
1341
|
if (params.onBehalfOfId != null) {
|
|
1334
1342
|
request["on_behalf_of_id"] = params.onBehalfOfId;
|
|
1335
1343
|
}
|
|
1344
|
+
const responseRequest = this._dispatchRequest("room.invoke_tool", request);
|
|
1336
1345
|
const requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1337
1346
|
try {
|
|
1338
|
-
const response = await
|
|
1347
|
+
const response = await responseRequest;
|
|
1339
1348
|
await requestTask;
|
|
1340
1349
|
if (response instanceof ControlContent && response.method === "open") {
|
|
1341
1350
|
throw new RoomServerException(`unexpected return type from ${params.toolkit}.${params.tool}`);
|
|
@@ -1366,6 +1375,7 @@ export class RoomClient {
|
|
|
1366
1375
|
if (params.onBehalfOfId != null) {
|
|
1367
1376
|
request["on_behalf_of_id"] = params.onBehalfOfId;
|
|
1368
1377
|
}
|
|
1378
|
+
const responseRequest = this._dispatchRequest("room.invoke_tool", request);
|
|
1369
1379
|
const requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1370
1380
|
void requestTask.catch((error) => {
|
|
1371
1381
|
const stream = this._toolCallStreams.get(toolCallId);
|
|
@@ -1379,7 +1389,7 @@ export class RoomClient {
|
|
|
1379
1389
|
let response;
|
|
1380
1390
|
try {
|
|
1381
1391
|
response = await Promise.race([
|
|
1382
|
-
|
|
1392
|
+
responseRequest,
|
|
1383
1393
|
preOpenError.fut,
|
|
1384
1394
|
]);
|
|
1385
1395
|
}
|
|
@@ -1401,24 +1411,27 @@ export class RoomClient {
|
|
|
1401
1411
|
},
|
|
1402
1412
|
};
|
|
1403
1413
|
}
|
|
1404
|
-
|
|
1414
|
+
_dispatchToolCallRequestChunk(toolCallId, chunk) {
|
|
1415
|
+
this._raiseIfTerminal();
|
|
1416
|
+
if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
|
|
1417
|
+
throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
|
|
1418
|
+
}
|
|
1405
1419
|
const packed = chunk.pack();
|
|
1406
1420
|
const request = {
|
|
1407
1421
|
tool_call_id: toolCallId,
|
|
1408
1422
|
chunk: JSON.parse(splitMessageHeader(packed)),
|
|
1409
1423
|
};
|
|
1410
1424
|
const payload = splitMessagePayload(packed);
|
|
1411
|
-
|
|
1425
|
+
this._protocolInstance.sendNowait("room.tool_call_request_chunk", packMessage(request, payload.length > 0 ? payload : undefined));
|
|
1412
1426
|
}
|
|
1413
1427
|
async _streamInvokeToolRequestChunks(toolCallId, input) {
|
|
1414
|
-
await Promise.resolve();
|
|
1415
1428
|
try {
|
|
1416
1429
|
for await (const item of input) {
|
|
1417
|
-
|
|
1430
|
+
this._dispatchToolCallRequestChunk(toolCallId, item);
|
|
1418
1431
|
}
|
|
1419
1432
|
}
|
|
1420
1433
|
finally {
|
|
1421
|
-
|
|
1434
|
+
this._dispatchToolCallRequestChunk(toolCallId, new ControlContent({ method: "close" }));
|
|
1422
1435
|
}
|
|
1423
1436
|
}
|
|
1424
1437
|
_decodeToolCallContent(params) {
|