@meshagent/meshagent 0.47.0 → 0.48.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/CHANGELOG.md +12 -0
- package/dist/browser/agent.js +6 -6
- package/dist/browser/containers-client.d.ts +1 -0
- package/dist/browser/containers-client.js +34 -0
- package/dist/browser/entrypoint.d.ts +1 -0
- package/dist/browser/entrypoint.js +3 -3
- package/dist/browser/index.d.ts +1 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/meshagent-client.d.ts +9 -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/mounts-client.d.ts +21 -0
- package/dist/browser/mounts-client.js +82 -0
- package/dist/browser/participant-token.d.ts +1 -0
- package/dist/browser/participant-token.js +3 -0
- package/dist/browser/room-client.d.ts +4 -1
- package/dist/browser/room-client.js +27 -12
- package/dist/esm/agent.js +6 -6
- package/dist/esm/containers-client.d.ts +1 -0
- package/dist/esm/containers-client.js +34 -0
- package/dist/esm/entrypoint.d.ts +1 -0
- package/dist/esm/entrypoint.js +3 -3
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/meshagent-client.d.ts +9 -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/mounts-client.d.ts +21 -0
- package/dist/esm/mounts-client.js +78 -0
- package/dist/esm/participant-token.d.ts +1 -0
- package/dist/esm/participant-token.js +3 -0
- package/dist/esm/room-client.d.ts +4 -1
- package/dist/esm/room-client.js +27 -12
- package/dist/node/agent.js +6 -6
- package/dist/node/containers-client.d.ts +1 -0
- package/dist/node/containers-client.js +34 -0
- package/dist/node/entrypoint.d.ts +1 -0
- package/dist/node/entrypoint.js +3 -3
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/meshagent-client.d.ts +9 -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/mounts-client.d.ts +21 -0
- package/dist/node/mounts-client.js +82 -0
- package/dist/node/participant-token.d.ts +1 -0
- package/dist/node/participant-token.js +3 -0
- package/dist/node/room-client.d.ts +4 -1
- package/dist/node/room-client.js +27 -12
- package/package.json +1 -1
|
@@ -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();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RoomClient } from "./room-client.js";
|
|
2
|
+
export interface MountedVolumeConsumer {
|
|
3
|
+
kind: "room" | "container";
|
|
4
|
+
containerId?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface MountedVolume {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
required: boolean;
|
|
10
|
+
description: string;
|
|
11
|
+
metadata: Record<string, unknown>;
|
|
12
|
+
annotations: Record<string, string>;
|
|
13
|
+
storageClass: "standard" | "juice" | "zerofs";
|
|
14
|
+
maxSizeMb?: number;
|
|
15
|
+
consumers: MountedVolumeConsumer[];
|
|
16
|
+
}
|
|
17
|
+
export declare class MountsClient {
|
|
18
|
+
private readonly room;
|
|
19
|
+
constructor(room: RoomClient);
|
|
20
|
+
list(): Promise<MountedVolume[]>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { JsonContent } from "./response.js";
|
|
2
|
+
import { RoomServerException } from "./room-server-client.js";
|
|
3
|
+
function isRecord(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function parseMountedVolume(value) {
|
|
7
|
+
if (!isRecord(value)
|
|
8
|
+
|| typeof value["id"] !== "string"
|
|
9
|
+
|| typeof value["name"] !== "string"
|
|
10
|
+
|| typeof value["required"] !== "boolean") {
|
|
11
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
12
|
+
}
|
|
13
|
+
const metadata = isRecord(value["metadata"]) ? value["metadata"] : {};
|
|
14
|
+
const rawAnnotations = isRecord(value["annotations"]) ? value["annotations"] : {};
|
|
15
|
+
const annotations = {};
|
|
16
|
+
for (const [key, item] of Object.entries(rawAnnotations)) {
|
|
17
|
+
if (typeof item === "string") {
|
|
18
|
+
annotations[key] = item;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const rawConsumers = value["consumers"] ?? [];
|
|
22
|
+
if (!Array.isArray(rawConsumers)) {
|
|
23
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
24
|
+
}
|
|
25
|
+
const consumers = rawConsumers.map((consumer) => {
|
|
26
|
+
if (!isRecord(consumer)
|
|
27
|
+
|| (consumer["kind"] !== "room" && consumer["kind"] !== "container")
|
|
28
|
+
|| (consumer["kind"] === "container" && typeof consumer["container_id"] !== "string")
|
|
29
|
+
|| (consumer["kind"] === "room" && consumer["container_id"] !== undefined)) {
|
|
30
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
kind: consumer["kind"],
|
|
34
|
+
containerId: typeof consumer["container_id"] === "string"
|
|
35
|
+
? consumer["container_id"]
|
|
36
|
+
: undefined,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
const storageClass = value["storage_class"] ?? "standard";
|
|
40
|
+
if (storageClass !== "standard" && storageClass !== "juice" && storageClass !== "zerofs") {
|
|
41
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
42
|
+
}
|
|
43
|
+
const maxSizeMb = value["max_size_mb"];
|
|
44
|
+
if (maxSizeMb !== undefined && (typeof maxSizeMb !== "number" || !Number.isInteger(maxSizeMb) || maxSizeMb <= 0)) {
|
|
45
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
id: value["id"],
|
|
49
|
+
name: value["name"],
|
|
50
|
+
required: value["required"],
|
|
51
|
+
description: typeof value["description"] === "string" ? value["description"] : "",
|
|
52
|
+
metadata,
|
|
53
|
+
annotations,
|
|
54
|
+
storageClass,
|
|
55
|
+
maxSizeMb,
|
|
56
|
+
consumers,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export class MountsClient {
|
|
60
|
+
constructor(room) {
|
|
61
|
+
this.room = room;
|
|
62
|
+
}
|
|
63
|
+
async list() {
|
|
64
|
+
const response = await this.room.invokeContent({
|
|
65
|
+
toolkit: "mounts",
|
|
66
|
+
tool: "list",
|
|
67
|
+
input: {},
|
|
68
|
+
});
|
|
69
|
+
if (!(response instanceof JsonContent)) {
|
|
70
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
71
|
+
}
|
|
72
|
+
const volumes = response.json["volumes"];
|
|
73
|
+
if (!Array.isArray(volumes)) {
|
|
74
|
+
throw new RoomServerException("unexpected return type from mounts.list");
|
|
75
|
+
}
|
|
76
|
+
return volumes.map(parseMountedVolume);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -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") {
|
|
@@ -4,6 +4,7 @@ import { DeveloperClient } from "./developer-client.js";
|
|
|
4
4
|
import { type EventHandler, type EventName } from "./event-emitter.js";
|
|
5
5
|
import { MessagingClient } from "./messaging-client.js";
|
|
6
6
|
import { MemoryClient } from "./memory-client.js";
|
|
7
|
+
import { MountsClient } from "./mounts-client.js";
|
|
7
8
|
import { LocalParticipant } from "./participant.js";
|
|
8
9
|
import { Protocol, ProtocolCloseKind, type MessageHandler, type ProtocolFactory } from "./protocol.js";
|
|
9
10
|
import { QueuesClient } from "./queues-client.js";
|
|
@@ -59,6 +60,7 @@ export declare class RoomClient {
|
|
|
59
60
|
readonly containers: ContainersClient;
|
|
60
61
|
readonly memory: MemoryClient;
|
|
61
62
|
readonly services: ServicesClient;
|
|
63
|
+
readonly mounts: MountsClient;
|
|
62
64
|
_protocolInstance: Protocol;
|
|
63
65
|
_entered: boolean;
|
|
64
66
|
_allowDisconnectedRequests: boolean;
|
|
@@ -190,6 +192,7 @@ export declare class RoomClient {
|
|
|
190
192
|
_sendLocalAttributesNowait(attributes: Record<string, unknown>): void;
|
|
191
193
|
_resendLocalAttributesNowait(): void;
|
|
192
194
|
sendRequest(type: string, request: RequestHeader, data?: Uint8Array, afterSend?: () => void): Promise<Content>;
|
|
195
|
+
private _dispatchRequest;
|
|
193
196
|
call(params: {
|
|
194
197
|
name: string;
|
|
195
198
|
url: string;
|
|
@@ -249,7 +252,7 @@ export declare class RoomClient {
|
|
|
249
252
|
participantId?: string;
|
|
250
253
|
onBehalfOfId?: string;
|
|
251
254
|
}): Promise<AsyncIterable<Content>>;
|
|
252
|
-
private
|
|
255
|
+
private _dispatchToolCallRequestChunk;
|
|
253
256
|
private _streamInvokeToolRequestChunks;
|
|
254
257
|
private _decodeToolCallContent;
|
|
255
258
|
private _handleToolCallResponseChunk;
|
package/dist/esm/room-client.js
CHANGED
|
@@ -5,6 +5,7 @@ import { DeveloperClient } from "./developer-client.js";
|
|
|
5
5
|
import { EventEmitter } from "./event-emitter.js";
|
|
6
6
|
import { MessagingClient } from "./messaging-client.js";
|
|
7
7
|
import { MemoryClient } from "./memory-client.js";
|
|
8
|
+
import { MountsClient } from "./mounts-client.js";
|
|
8
9
|
import { LocalParticipant } from "./participant.js";
|
|
9
10
|
import { ProtocolCloseException, ProtocolCloseKind, ProtocolHandshakeException, ProtocolReconnectUnsupportedException, WebSocketClientProtocol, } from "./protocol.js";
|
|
10
11
|
import { QueuesClient } from "./queues-client.js";
|
|
@@ -257,6 +258,7 @@ export class RoomClient {
|
|
|
257
258
|
this.containers = new ContainersClient({ room: this });
|
|
258
259
|
this.memory = new MemoryClient({ room: this });
|
|
259
260
|
this.services = new ServicesClient({ room: this });
|
|
261
|
+
this.mounts = new MountsClient(this);
|
|
260
262
|
}
|
|
261
263
|
static withIAP({ url = "./.well-known/meshagent/room/connect", reconnectTimeout = null, } = {}) {
|
|
262
264
|
return new RoomClient({
|
|
@@ -1143,6 +1145,11 @@ export class RoomClient {
|
|
|
1143
1145
|
this._sendLocalAttributesNowait(attributes);
|
|
1144
1146
|
}
|
|
1145
1147
|
async sendRequest(type, request, data, afterSend) {
|
|
1148
|
+
const response = this._dispatchRequest(type, request, data);
|
|
1149
|
+
afterSend?.();
|
|
1150
|
+
return await response;
|
|
1151
|
+
}
|
|
1152
|
+
_dispatchRequest(type, request, data) {
|
|
1146
1153
|
this._raiseIfTerminal();
|
|
1147
1154
|
if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
|
|
1148
1155
|
throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
|
|
@@ -1151,9 +1158,8 @@ export class RoomClient {
|
|
|
1151
1158
|
const completer = new Completer();
|
|
1152
1159
|
this._pendingRequests.set(requestId, completer);
|
|
1153
1160
|
try {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
return await completer.fut;
|
|
1161
|
+
this._protocolInstance.sendNowait(type, packMessage(request, data), { id: requestId });
|
|
1162
|
+
return completer.fut;
|
|
1157
1163
|
}
|
|
1158
1164
|
catch (error) {
|
|
1159
1165
|
this._pendingRequests.delete(requestId);
|
|
@@ -1259,7 +1265,6 @@ export class RoomClient {
|
|
|
1259
1265
|
let requestTask;
|
|
1260
1266
|
if (params.streamInput === true) {
|
|
1261
1267
|
request["arguments"] = { type: "control", method: "open" };
|
|
1262
|
-
requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1263
1268
|
}
|
|
1264
1269
|
else {
|
|
1265
1270
|
const input = params.input;
|
|
@@ -1276,9 +1281,14 @@ export class RoomClient {
|
|
|
1276
1281
|
if (params.onBehalfOfId != null) {
|
|
1277
1282
|
request["on_behalf_of_id"] = params.onBehalfOfId;
|
|
1278
1283
|
}
|
|
1284
|
+
const responseRequest = this._dispatchRequest("room.invoke_tool", request, requestData);
|
|
1285
|
+
params.afterSend?.();
|
|
1286
|
+
if (params.streamInput === true) {
|
|
1287
|
+
requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1288
|
+
}
|
|
1279
1289
|
try {
|
|
1280
1290
|
const response = await Promise.race([
|
|
1281
|
-
|
|
1291
|
+
responseRequest,
|
|
1282
1292
|
preOpenError.fut,
|
|
1283
1293
|
]);
|
|
1284
1294
|
this._toolCallPreOpenErrors.delete(toolCallId);
|
|
@@ -1333,9 +1343,10 @@ export class RoomClient {
|
|
|
1333
1343
|
if (params.onBehalfOfId != null) {
|
|
1334
1344
|
request["on_behalf_of_id"] = params.onBehalfOfId;
|
|
1335
1345
|
}
|
|
1346
|
+
const responseRequest = this._dispatchRequest("room.invoke_tool", request);
|
|
1336
1347
|
const requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1337
1348
|
try {
|
|
1338
|
-
const response = await
|
|
1349
|
+
const response = await responseRequest;
|
|
1339
1350
|
await requestTask;
|
|
1340
1351
|
if (response instanceof ControlContent && response.method === "open") {
|
|
1341
1352
|
throw new RoomServerException(`unexpected return type from ${params.toolkit}.${params.tool}`);
|
|
@@ -1366,6 +1377,7 @@ export class RoomClient {
|
|
|
1366
1377
|
if (params.onBehalfOfId != null) {
|
|
1367
1378
|
request["on_behalf_of_id"] = params.onBehalfOfId;
|
|
1368
1379
|
}
|
|
1380
|
+
const responseRequest = this._dispatchRequest("room.invoke_tool", request);
|
|
1369
1381
|
const requestTask = this._streamInvokeToolRequestChunks(toolCallId, params.input);
|
|
1370
1382
|
void requestTask.catch((error) => {
|
|
1371
1383
|
const stream = this._toolCallStreams.get(toolCallId);
|
|
@@ -1379,7 +1391,7 @@ export class RoomClient {
|
|
|
1379
1391
|
let response;
|
|
1380
1392
|
try {
|
|
1381
1393
|
response = await Promise.race([
|
|
1382
|
-
|
|
1394
|
+
responseRequest,
|
|
1383
1395
|
preOpenError.fut,
|
|
1384
1396
|
]);
|
|
1385
1397
|
}
|
|
@@ -1401,24 +1413,27 @@ export class RoomClient {
|
|
|
1401
1413
|
},
|
|
1402
1414
|
};
|
|
1403
1415
|
}
|
|
1404
|
-
|
|
1416
|
+
_dispatchToolCallRequestChunk(toolCallId, chunk) {
|
|
1417
|
+
this._raiseIfTerminal();
|
|
1418
|
+
if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
|
|
1419
|
+
throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
|
|
1420
|
+
}
|
|
1405
1421
|
const packed = chunk.pack();
|
|
1406
1422
|
const request = {
|
|
1407
1423
|
tool_call_id: toolCallId,
|
|
1408
1424
|
chunk: JSON.parse(splitMessageHeader(packed)),
|
|
1409
1425
|
};
|
|
1410
1426
|
const payload = splitMessagePayload(packed);
|
|
1411
|
-
|
|
1427
|
+
this._protocolInstance.sendNowait("room.tool_call_request_chunk", packMessage(request, payload.length > 0 ? payload : undefined));
|
|
1412
1428
|
}
|
|
1413
1429
|
async _streamInvokeToolRequestChunks(toolCallId, input) {
|
|
1414
|
-
await Promise.resolve();
|
|
1415
1430
|
try {
|
|
1416
1431
|
for await (const item of input) {
|
|
1417
|
-
|
|
1432
|
+
this._dispatchToolCallRequestChunk(toolCallId, item);
|
|
1418
1433
|
}
|
|
1419
1434
|
}
|
|
1420
1435
|
finally {
|
|
1421
|
-
|
|
1436
|
+
this._dispatchToolCallRequestChunk(toolCallId, new ControlContent({ method: "close" }));
|
|
1422
1437
|
}
|
|
1423
1438
|
}
|
|
1424
1439
|
_decodeToolCallContent(params) {
|
package/dist/node/agent.js
CHANGED
|
@@ -530,10 +530,10 @@ class _RemoteToolkitWrapper {
|
|
|
530
530
|
return false;
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
|
-
|
|
533
|
+
_sendToolCallResponseChunk(messageId, toolCallId, chunk) {
|
|
534
534
|
const [header, payload] = (0, utils_js_1.unpackMessage)(chunk.pack());
|
|
535
535
|
try {
|
|
536
|
-
|
|
536
|
+
this.client.protocol.sendNowait("room.tool_call_response_chunk", (0, utils_js_1.packMessage)({ tool_call_id: toolCallId, chunk: header }, payload.length > 0 ? payload : undefined), { id: messageId });
|
|
537
537
|
return true;
|
|
538
538
|
}
|
|
539
539
|
catch (error) {
|
|
@@ -634,10 +634,10 @@ class _RemoteToolkitWrapper {
|
|
|
634
634
|
return;
|
|
635
635
|
for await (const chunk of output.stream) {
|
|
636
636
|
this.toolkit.validateOutputContent(tool, chunk);
|
|
637
|
-
if (!
|
|
637
|
+
if (!this._sendToolCallResponseChunk(messageId, toolCallId, chunk))
|
|
638
638
|
return;
|
|
639
639
|
}
|
|
640
|
-
|
|
640
|
+
this._sendToolCallResponseChunk(messageId, toolCallId, new response_js_1.ControlContent({ method: "close" }));
|
|
641
641
|
return;
|
|
642
642
|
}
|
|
643
643
|
throw new Error(`tool ${toolName} returned unsupported output`);
|
|
@@ -648,9 +648,9 @@ class _RemoteToolkitWrapper {
|
|
|
648
648
|
return;
|
|
649
649
|
}
|
|
650
650
|
if (!(error instanceof InvalidToolDataException)) {
|
|
651
|
-
|
|
651
|
+
this._sendToolCallResponseChunk(messageId, toolCallId, new response_js_1.ErrorContent({ text: String(error) }));
|
|
652
652
|
}
|
|
653
|
-
|
|
653
|
+
this._sendToolCallResponseChunk(messageId, toolCallId, new response_js_1.ControlContent({
|
|
654
654
|
method: "close",
|
|
655
655
|
statusCode: error instanceof InvalidToolDataException ? response_js_1.ControlCloseStatus.INVALID_DATA : undefined,
|
|
656
656
|
message: error instanceof InvalidToolDataException ? error.message : undefined,
|