@meshagent/meshagent 0.46.3 → 0.47.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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.47.0]
2
+ - Improved TypeScript messaging clients so room delivery order and startup/presence behavior stay consistent.
3
+ - Moved managed-agent client routing onto the Rust tunnel path and hardened agent chat-client event handling.
4
+ - Added a `test:rust-process-e2e` entry point for the agents-ts package and expanded live chat/process-agent coverage.
5
+ - Finished aligning CLI pagination behavior across feeds, rooms, mailboxes, scheduled tasks, and shared helpers.
6
+
1
7
  ## [0.46.3]
2
8
  - `LivekitProtocolChannel.sendData` now clones outgoing `Uint8Array` payloads before publishing, avoiding shared-buffer mutation issues.
3
9
 
@@ -29,6 +29,12 @@ export interface RoomConnectionInfo {
29
29
  projectId: string;
30
30
  roomUrl: string;
31
31
  }
32
+ export interface AgentConnectionInfo {
33
+ jwt: string;
34
+ agentName: string;
35
+ projectId: string;
36
+ agentUrl: string;
37
+ }
32
38
  export declare class RoomSession {
33
39
  readonly id: string;
34
40
  readonly roomId?: string | null;
@@ -559,6 +565,7 @@ export declare class Meshagent {
559
565
  private parseTransaction;
560
566
  private parseOAuthClient;
561
567
  private parseRoomConnectionInfo;
568
+ private parseAgentConnectionInfo;
562
569
  private encodePathComponent;
563
570
  upload({ projectId, path, data }: {
564
571
  projectId: string;
@@ -908,6 +915,7 @@ export declare class Meshagent {
908
915
  subjectId: string;
909
916
  }): Promise<void>;
910
917
  connectRoom(projectId: string, room: string): Promise<RoomConnectionInfo>;
918
+ connectAgent(projectId: string, agentName: string): Promise<AgentConnectionInfo>;
911
919
  listRooms(projectId: string, options?: {
912
920
  pageSize?: number;
913
921
  continuationToken?: string;
@@ -822,6 +822,25 @@ class Meshagent {
822
822
  }
823
823
  return { jwt, roomName: roomNameValue, projectId: projectIdValue, roomUrl: roomUrlValue };
824
824
  }
825
+ parseAgentConnectionInfo(data) {
826
+ if (!data || typeof data !== "object") {
827
+ throw new requirement_js_1.RoomException("Invalid agent connection payload");
828
+ }
829
+ const { jwt, agent_name: agentNameRaw, agentName, project_id: projectIdRaw, projectId, agent_url: agentUrlRaw, agentUrl } = data;
830
+ const agentNameValue = typeof agentName === "string" ? agentName : agentNameRaw;
831
+ const projectIdValue = typeof projectId === "string" ? projectId : projectIdRaw;
832
+ const agentUrlValue = typeof agentUrl === "string" ? agentUrl : agentUrlRaw;
833
+ if (typeof jwt !== "string" || typeof agentNameValue !== "string" || typeof projectIdValue !== "string" || typeof agentUrlValue !== "string") {
834
+ throw new requirement_js_1.RoomException("Invalid agent connection payload: missing fields");
835
+ }
836
+ const parsedUrl = new URL(agentUrlValue);
837
+ const legacySuffix = `/accounts/projects/${encodeURIComponent(projectIdValue)}/agents/${encodeURIComponent(agentNameValue)}/messages`;
838
+ if (parsedUrl.pathname.endsWith(legacySuffix)) {
839
+ const prefix = parsedUrl.pathname.slice(0, -legacySuffix.length);
840
+ parsedUrl.pathname = `${prefix}/agents/${encodeURIComponent(projectIdValue)}/${encodeURIComponent(agentNameValue)}/messages`;
841
+ }
842
+ return { jwt, agentName: agentNameValue, projectId: projectIdValue, agentUrl: parsedUrl.toString() };
843
+ }
825
844
  encodePathComponent(value) {
826
845
  return encodeURIComponent(value);
827
846
  }
@@ -1847,6 +1866,14 @@ class Meshagent {
1847
1866
  });
1848
1867
  return this.parseRoomConnectionInfo(data);
1849
1868
  }
1869
+ async connectAgent(projectId, agentName) {
1870
+ const data = await this.request(`/accounts/projects/${projectId}/agents/${encodeURIComponent(agentName)}/connect`, {
1871
+ method: "POST",
1872
+ json: {},
1873
+ action: "connect agent",
1874
+ });
1875
+ return this.parseAgentConnectionInfo(data);
1876
+ }
1850
1877
  async listRooms(projectId, options = {}) {
1851
1878
  const { pageSize = 50, continuationToken, filter, view } = options;
1852
1879
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
@@ -10,6 +10,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
10
10
  private readonly _messageQueue;
11
11
  private _messageQueued;
12
12
  private _sendTask;
13
+ private readonly _sendOperations;
13
14
  private _messageQueueClosed;
14
15
  private _desiredEnabled;
15
16
  private _online;
@@ -42,6 +43,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
42
43
  private _dropQueuedMessage;
43
44
  private _drainQueuedMessages;
44
45
  private _sendMessages;
46
+ private _sendQueuedMessage;
45
47
  sendMessage({ to, type, message, attachment, ignoreOffline, }: {
46
48
  to: Participant;
47
49
  type: string;
@@ -30,6 +30,7 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
30
30
  this._messageQueue = [];
31
31
  this._messageQueued = null;
32
32
  this._sendTask = null;
33
+ this._sendOperations = new Set();
33
34
  this._messageQueueClosed = false;
34
35
  this._desiredEnabled = false;
35
36
  this._online = false;
@@ -59,11 +60,12 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
59
60
  }
60
61
  return input;
61
62
  }
62
- async _invoke({ operation, input, }) {
63
+ async _invoke({ operation, input, afterSend, }) {
63
64
  await this.client.invokeContent({
64
65
  toolkit: "messaging",
65
66
  tool: operation,
66
67
  input: new response_js_1.JsonContent({ json: input }),
68
+ afterSend,
67
69
  });
68
70
  }
69
71
  _invokeNowait({ operation, input, }) {
@@ -93,6 +95,7 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
93
95
  if (sendTask != null) {
94
96
  await sendTask;
95
97
  }
98
+ await Promise.all(this._sendOperations);
96
99
  this._desiredEnabled = false;
97
100
  this._clearCurrentConnectionState();
98
101
  }
@@ -238,34 +241,52 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
238
241
  });
239
242
  continue;
240
243
  }
241
- try {
242
- await this._invoke({
243
- operation: "send",
244
- input: this._messageInput({
245
- toParticipantId: resolvedTo.id,
246
- type: message.type,
247
- message: message.message,
248
- attachment: message.attachment,
249
- }),
250
- });
251
- if (message.completer != null && !message.completer.completed) {
252
- message.completer.complete();
253
- }
244
+ const dispatched = new completer_js_1.Completer();
245
+ const operation = this._sendQueuedMessage({
246
+ message,
247
+ resolvedTo,
248
+ afterSend: () => dispatched.resolve(),
249
+ });
250
+ this._sendOperations.add(operation);
251
+ void operation.then(() => {
252
+ this._sendOperations.delete(operation);
253
+ if (!dispatched.completed)
254
+ dispatched.resolve();
255
+ }, () => {
256
+ this._sendOperations.delete(operation);
257
+ if (!dispatched.completed)
258
+ dispatched.resolve();
259
+ });
260
+ await dispatched.fut;
261
+ }
262
+ }
263
+ async _sendQueuedMessage({ message, resolvedTo, afterSend, }) {
264
+ try {
265
+ await this._invoke({
266
+ operation: "send",
267
+ input: this._messageInput({
268
+ toParticipantId: resolvedTo.id,
269
+ type: message.type,
270
+ message: message.message,
271
+ attachment: message.attachment,
272
+ }),
273
+ afterSend,
274
+ });
275
+ if (message.completer != null && !message.completer.completed) {
276
+ message.completer.complete();
254
277
  }
255
- catch (error) {
256
- if (error instanceof room_server_client_js_1.RoomServerException) {
257
- const wrapped = this.client._coerceMessageSendError(error);
258
- if (wrapped.message === "the participant was not found") {
259
- this._markParticipantOffline(message.to);
260
- this._dropQueuedMessage({ message, error: wrapped });
261
- continue;
262
- }
263
- this._dropQueuedMessage({ message, error: wrapped });
264
- continue;
265
- }
266
- if (message.completer != null && !message.completer.completed) {
267
- message.completer.completeError(error);
278
+ }
279
+ catch (error) {
280
+ if (error instanceof room_server_client_js_1.RoomServerException) {
281
+ const wrapped = this.client._coerceMessageSendError(error);
282
+ if (wrapped.message === "the participant was not found") {
283
+ this._markParticipantOffline(message.to);
268
284
  }
285
+ this._dropQueuedMessage({ message, error: wrapped });
286
+ return;
287
+ }
288
+ if (message.completer != null && !message.completer.completed) {
289
+ message.completer.completeError(error);
269
290
  }
270
291
  }
271
292
  }
@@ -189,7 +189,7 @@ export declare class RoomClient {
189
189
  }): void;
190
190
  _sendLocalAttributesNowait(attributes: Record<string, unknown>): void;
191
191
  _resendLocalAttributesNowait(): void;
192
- sendRequest(type: string, request: RequestHeader, data?: Uint8Array): Promise<Content>;
192
+ sendRequest(type: string, request: RequestHeader, data?: Uint8Array, afterSend?: () => void): Promise<Content>;
193
193
  call(params: {
194
194
  name: string;
195
195
  url: string;
@@ -216,6 +216,7 @@ export declare class RoomClient {
216
216
  input?: InvokeInput;
217
217
  participantId?: string;
218
218
  onBehalfOfId?: string;
219
+ afterSend?: () => void;
219
220
  }): Promise<Content>;
220
221
  invokeToolCall(params: {
221
222
  toolkit: string;
@@ -224,6 +225,7 @@ export declare class RoomClient {
224
225
  streamInput?: boolean;
225
226
  participantId?: string;
226
227
  onBehalfOfId?: string;
228
+ afterSend?: () => void;
227
229
  }): Promise<{
228
230
  kind: "content";
229
231
  content: Content;
@@ -1146,7 +1146,7 @@ class RoomClient {
1146
1146
  }
1147
1147
  this._sendLocalAttributesNowait(attributes);
1148
1148
  }
1149
- async sendRequest(type, request, data) {
1149
+ async sendRequest(type, request, data, afterSend) {
1150
1150
  this._raiseIfTerminal();
1151
1151
  if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
1152
1152
  throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
@@ -1156,6 +1156,7 @@ class RoomClient {
1156
1156
  this._pendingRequests.set(requestId, completer);
1157
1157
  try {
1158
1158
  await this._protocolInstance.send(type, (0, utils_js_1.packMessage)(request, data), requestId);
1159
+ afterSend?.();
1159
1160
  return await completer.fut;
1160
1161
  }
1161
1162
  catch (error) {
@@ -1239,6 +1240,7 @@ class RoomClient {
1239
1240
  input: this._normalizeInvokeInput(params.input ?? params.arguments),
1240
1241
  participantId: params.participantId,
1241
1242
  onBehalfOfId: params.onBehalfOfId,
1243
+ afterSend: params.afterSend,
1242
1244
  });
1243
1245
  if (output.kind !== "content") {
1244
1246
  throw new room_server_client_js_1.RoomServerException("unexpected streamed output from " + params.toolkit + "." + params.tool);
@@ -1280,7 +1282,7 @@ class RoomClient {
1280
1282
  }
1281
1283
  try {
1282
1284
  const response = await Promise.race([
1283
- this.sendRequest("room.invoke_tool", request, requestData),
1285
+ this.sendRequest("room.invoke_tool", request, requestData, params.afterSend),
1284
1286
  preOpenError.fut,
1285
1287
  ]);
1286
1288
  this._toolCallPreOpenErrors.delete(toolCallId);
@@ -29,6 +29,12 @@ export interface RoomConnectionInfo {
29
29
  projectId: string;
30
30
  roomUrl: string;
31
31
  }
32
+ export interface AgentConnectionInfo {
33
+ jwt: string;
34
+ agentName: string;
35
+ projectId: string;
36
+ agentUrl: string;
37
+ }
32
38
  export declare class RoomSession {
33
39
  readonly id: string;
34
40
  readonly roomId?: string | null;
@@ -559,6 +565,7 @@ export declare class Meshagent {
559
565
  private parseTransaction;
560
566
  private parseOAuthClient;
561
567
  private parseRoomConnectionInfo;
568
+ private parseAgentConnectionInfo;
562
569
  private encodePathComponent;
563
570
  upload({ projectId, path, data }: {
564
571
  projectId: string;
@@ -908,6 +915,7 @@ export declare class Meshagent {
908
915
  subjectId: string;
909
916
  }): Promise<void>;
910
917
  connectRoom(projectId: string, room: string): Promise<RoomConnectionInfo>;
918
+ connectAgent(projectId: string, agentName: string): Promise<AgentConnectionInfo>;
911
919
  listRooms(projectId: string, options?: {
912
920
  pageSize?: number;
913
921
  continuationToken?: string;
@@ -817,6 +817,25 @@ export class Meshagent {
817
817
  }
818
818
  return { jwt, roomName: roomNameValue, projectId: projectIdValue, roomUrl: roomUrlValue };
819
819
  }
820
+ parseAgentConnectionInfo(data) {
821
+ if (!data || typeof data !== "object") {
822
+ throw new RoomException("Invalid agent connection payload");
823
+ }
824
+ const { jwt, agent_name: agentNameRaw, agentName, project_id: projectIdRaw, projectId, agent_url: agentUrlRaw, agentUrl } = data;
825
+ const agentNameValue = typeof agentName === "string" ? agentName : agentNameRaw;
826
+ const projectIdValue = typeof projectId === "string" ? projectId : projectIdRaw;
827
+ const agentUrlValue = typeof agentUrl === "string" ? agentUrl : agentUrlRaw;
828
+ if (typeof jwt !== "string" || typeof agentNameValue !== "string" || typeof projectIdValue !== "string" || typeof agentUrlValue !== "string") {
829
+ throw new RoomException("Invalid agent connection payload: missing fields");
830
+ }
831
+ const parsedUrl = new URL(agentUrlValue);
832
+ const legacySuffix = `/accounts/projects/${encodeURIComponent(projectIdValue)}/agents/${encodeURIComponent(agentNameValue)}/messages`;
833
+ if (parsedUrl.pathname.endsWith(legacySuffix)) {
834
+ const prefix = parsedUrl.pathname.slice(0, -legacySuffix.length);
835
+ parsedUrl.pathname = `${prefix}/agents/${encodeURIComponent(projectIdValue)}/${encodeURIComponent(agentNameValue)}/messages`;
836
+ }
837
+ return { jwt, agentName: agentNameValue, projectId: projectIdValue, agentUrl: parsedUrl.toString() };
838
+ }
820
839
  encodePathComponent(value) {
821
840
  return encodeURIComponent(value);
822
841
  }
@@ -1842,6 +1861,14 @@ export class Meshagent {
1842
1861
  });
1843
1862
  return this.parseRoomConnectionInfo(data);
1844
1863
  }
1864
+ async connectAgent(projectId, agentName) {
1865
+ const data = await this.request(`/accounts/projects/${projectId}/agents/${encodeURIComponent(agentName)}/connect`, {
1866
+ method: "POST",
1867
+ json: {},
1868
+ action: "connect agent",
1869
+ });
1870
+ return this.parseAgentConnectionInfo(data);
1871
+ }
1845
1872
  async listRooms(projectId, options = {}) {
1846
1873
  const { pageSize = 50, continuationToken, filter, view } = options;
1847
1874
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
@@ -10,6 +10,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
10
10
  private readonly _messageQueue;
11
11
  private _messageQueued;
12
12
  private _sendTask;
13
+ private readonly _sendOperations;
13
14
  private _messageQueueClosed;
14
15
  private _desiredEnabled;
15
16
  private _online;
@@ -42,6 +43,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
42
43
  private _dropQueuedMessage;
43
44
  private _drainQueuedMessages;
44
45
  private _sendMessages;
46
+ private _sendQueuedMessage;
45
47
  sendMessage({ to, type, message, attachment, ignoreOffline, }: {
46
48
  to: Participant;
47
49
  type: string;
@@ -27,6 +27,7 @@ export class MessagingClient extends EventEmitter {
27
27
  this._messageQueue = [];
28
28
  this._messageQueued = null;
29
29
  this._sendTask = null;
30
+ this._sendOperations = new Set();
30
31
  this._messageQueueClosed = false;
31
32
  this._desiredEnabled = false;
32
33
  this._online = false;
@@ -56,11 +57,12 @@ export class MessagingClient extends EventEmitter {
56
57
  }
57
58
  return input;
58
59
  }
59
- async _invoke({ operation, input, }) {
60
+ async _invoke({ operation, input, afterSend, }) {
60
61
  await this.client.invokeContent({
61
62
  toolkit: "messaging",
62
63
  tool: operation,
63
64
  input: new JsonContent({ json: input }),
65
+ afterSend,
64
66
  });
65
67
  }
66
68
  _invokeNowait({ operation, input, }) {
@@ -90,6 +92,7 @@ export class MessagingClient extends EventEmitter {
90
92
  if (sendTask != null) {
91
93
  await sendTask;
92
94
  }
95
+ await Promise.all(this._sendOperations);
93
96
  this._desiredEnabled = false;
94
97
  this._clearCurrentConnectionState();
95
98
  }
@@ -235,34 +238,52 @@ export class MessagingClient extends EventEmitter {
235
238
  });
236
239
  continue;
237
240
  }
238
- try {
239
- await this._invoke({
240
- operation: "send",
241
- input: this._messageInput({
242
- toParticipantId: resolvedTo.id,
243
- type: message.type,
244
- message: message.message,
245
- attachment: message.attachment,
246
- }),
247
- });
248
- if (message.completer != null && !message.completer.completed) {
249
- message.completer.complete();
250
- }
241
+ const dispatched = new Completer();
242
+ const operation = this._sendQueuedMessage({
243
+ message,
244
+ resolvedTo,
245
+ afterSend: () => dispatched.resolve(),
246
+ });
247
+ this._sendOperations.add(operation);
248
+ void operation.then(() => {
249
+ this._sendOperations.delete(operation);
250
+ if (!dispatched.completed)
251
+ dispatched.resolve();
252
+ }, () => {
253
+ this._sendOperations.delete(operation);
254
+ if (!dispatched.completed)
255
+ dispatched.resolve();
256
+ });
257
+ await dispatched.fut;
258
+ }
259
+ }
260
+ async _sendQueuedMessage({ message, resolvedTo, afterSend, }) {
261
+ try {
262
+ await this._invoke({
263
+ operation: "send",
264
+ input: this._messageInput({
265
+ toParticipantId: resolvedTo.id,
266
+ type: message.type,
267
+ message: message.message,
268
+ attachment: message.attachment,
269
+ }),
270
+ afterSend,
271
+ });
272
+ if (message.completer != null && !message.completer.completed) {
273
+ message.completer.complete();
251
274
  }
252
- catch (error) {
253
- if (error instanceof RoomServerException) {
254
- const wrapped = this.client._coerceMessageSendError(error);
255
- if (wrapped.message === "the participant was not found") {
256
- this._markParticipantOffline(message.to);
257
- this._dropQueuedMessage({ message, error: wrapped });
258
- continue;
259
- }
260
- this._dropQueuedMessage({ message, error: wrapped });
261
- continue;
262
- }
263
- if (message.completer != null && !message.completer.completed) {
264
- message.completer.completeError(error);
275
+ }
276
+ catch (error) {
277
+ if (error instanceof RoomServerException) {
278
+ const wrapped = this.client._coerceMessageSendError(error);
279
+ if (wrapped.message === "the participant was not found") {
280
+ this._markParticipantOffline(message.to);
265
281
  }
282
+ this._dropQueuedMessage({ message, error: wrapped });
283
+ return;
284
+ }
285
+ if (message.completer != null && !message.completer.completed) {
286
+ message.completer.completeError(error);
266
287
  }
267
288
  }
268
289
  }
@@ -189,7 +189,7 @@ export declare class RoomClient {
189
189
  }): void;
190
190
  _sendLocalAttributesNowait(attributes: Record<string, unknown>): void;
191
191
  _resendLocalAttributesNowait(): void;
192
- sendRequest(type: string, request: RequestHeader, data?: Uint8Array): Promise<Content>;
192
+ sendRequest(type: string, request: RequestHeader, data?: Uint8Array, afterSend?: () => void): Promise<Content>;
193
193
  call(params: {
194
194
  name: string;
195
195
  url: string;
@@ -216,6 +216,7 @@ export declare class RoomClient {
216
216
  input?: InvokeInput;
217
217
  participantId?: string;
218
218
  onBehalfOfId?: string;
219
+ afterSend?: () => void;
219
220
  }): Promise<Content>;
220
221
  invokeToolCall(params: {
221
222
  toolkit: string;
@@ -224,6 +225,7 @@ export declare class RoomClient {
224
225
  streamInput?: boolean;
225
226
  participantId?: string;
226
227
  onBehalfOfId?: string;
228
+ afterSend?: () => void;
227
229
  }): Promise<{
228
230
  kind: "content";
229
231
  content: Content;
@@ -1142,7 +1142,7 @@ export class RoomClient {
1142
1142
  }
1143
1143
  this._sendLocalAttributesNowait(attributes);
1144
1144
  }
1145
- async sendRequest(type, request, data) {
1145
+ async sendRequest(type, request, data, afterSend) {
1146
1146
  this._raiseIfTerminal();
1147
1147
  if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
1148
1148
  throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
@@ -1152,6 +1152,7 @@ export class RoomClient {
1152
1152
  this._pendingRequests.set(requestId, completer);
1153
1153
  try {
1154
1154
  await this._protocolInstance.send(type, packMessage(request, data), requestId);
1155
+ afterSend?.();
1155
1156
  return await completer.fut;
1156
1157
  }
1157
1158
  catch (error) {
@@ -1235,6 +1236,7 @@ export class RoomClient {
1235
1236
  input: this._normalizeInvokeInput(params.input ?? params.arguments),
1236
1237
  participantId: params.participantId,
1237
1238
  onBehalfOfId: params.onBehalfOfId,
1239
+ afterSend: params.afterSend,
1238
1240
  });
1239
1241
  if (output.kind !== "content") {
1240
1242
  throw new RoomServerException("unexpected streamed output from " + params.toolkit + "." + params.tool);
@@ -1276,7 +1278,7 @@ export class RoomClient {
1276
1278
  }
1277
1279
  try {
1278
1280
  const response = await Promise.race([
1279
- this.sendRequest("room.invoke_tool", request, requestData),
1281
+ this.sendRequest("room.invoke_tool", request, requestData, params.afterSend),
1280
1282
  preOpenError.fut,
1281
1283
  ]);
1282
1284
  this._toolCallPreOpenErrors.delete(toolCallId);
@@ -29,6 +29,12 @@ export interface RoomConnectionInfo {
29
29
  projectId: string;
30
30
  roomUrl: string;
31
31
  }
32
+ export interface AgentConnectionInfo {
33
+ jwt: string;
34
+ agentName: string;
35
+ projectId: string;
36
+ agentUrl: string;
37
+ }
32
38
  export declare class RoomSession {
33
39
  readonly id: string;
34
40
  readonly roomId?: string | null;
@@ -559,6 +565,7 @@ export declare class Meshagent {
559
565
  private parseTransaction;
560
566
  private parseOAuthClient;
561
567
  private parseRoomConnectionInfo;
568
+ private parseAgentConnectionInfo;
562
569
  private encodePathComponent;
563
570
  upload({ projectId, path, data }: {
564
571
  projectId: string;
@@ -908,6 +915,7 @@ export declare class Meshagent {
908
915
  subjectId: string;
909
916
  }): Promise<void>;
910
917
  connectRoom(projectId: string, room: string): Promise<RoomConnectionInfo>;
918
+ connectAgent(projectId: string, agentName: string): Promise<AgentConnectionInfo>;
911
919
  listRooms(projectId: string, options?: {
912
920
  pageSize?: number;
913
921
  continuationToken?: string;
@@ -822,6 +822,25 @@ class Meshagent {
822
822
  }
823
823
  return { jwt, roomName: roomNameValue, projectId: projectIdValue, roomUrl: roomUrlValue };
824
824
  }
825
+ parseAgentConnectionInfo(data) {
826
+ if (!data || typeof data !== "object") {
827
+ throw new requirement_js_1.RoomException("Invalid agent connection payload");
828
+ }
829
+ const { jwt, agent_name: agentNameRaw, agentName, project_id: projectIdRaw, projectId, agent_url: agentUrlRaw, agentUrl } = data;
830
+ const agentNameValue = typeof agentName === "string" ? agentName : agentNameRaw;
831
+ const projectIdValue = typeof projectId === "string" ? projectId : projectIdRaw;
832
+ const agentUrlValue = typeof agentUrl === "string" ? agentUrl : agentUrlRaw;
833
+ if (typeof jwt !== "string" || typeof agentNameValue !== "string" || typeof projectIdValue !== "string" || typeof agentUrlValue !== "string") {
834
+ throw new requirement_js_1.RoomException("Invalid agent connection payload: missing fields");
835
+ }
836
+ const parsedUrl = new URL(agentUrlValue);
837
+ const legacySuffix = `/accounts/projects/${encodeURIComponent(projectIdValue)}/agents/${encodeURIComponent(agentNameValue)}/messages`;
838
+ if (parsedUrl.pathname.endsWith(legacySuffix)) {
839
+ const prefix = parsedUrl.pathname.slice(0, -legacySuffix.length);
840
+ parsedUrl.pathname = `${prefix}/agents/${encodeURIComponent(projectIdValue)}/${encodeURIComponent(agentNameValue)}/messages`;
841
+ }
842
+ return { jwt, agentName: agentNameValue, projectId: projectIdValue, agentUrl: parsedUrl.toString() };
843
+ }
825
844
  encodePathComponent(value) {
826
845
  return encodeURIComponent(value);
827
846
  }
@@ -1847,6 +1866,14 @@ class Meshagent {
1847
1866
  });
1848
1867
  return this.parseRoomConnectionInfo(data);
1849
1868
  }
1869
+ async connectAgent(projectId, agentName) {
1870
+ const data = await this.request(`/accounts/projects/${projectId}/agents/${encodeURIComponent(agentName)}/connect`, {
1871
+ method: "POST",
1872
+ json: {},
1873
+ action: "connect agent",
1874
+ });
1875
+ return this.parseAgentConnectionInfo(data);
1876
+ }
1850
1877
  async listRooms(projectId, options = {}) {
1851
1878
  const { pageSize = 50, continuationToken, filter, view } = options;
1852
1879
  const data = await this.request(`/accounts/projects/${projectId}/rooms`, {
@@ -10,6 +10,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
10
10
  private readonly _messageQueue;
11
11
  private _messageQueued;
12
12
  private _sendTask;
13
+ private readonly _sendOperations;
13
14
  private _messageQueueClosed;
14
15
  private _desiredEnabled;
15
16
  private _online;
@@ -42,6 +43,7 @@ export declare class MessagingClient extends EventEmitter<RoomMessageEvent> {
42
43
  private _dropQueuedMessage;
43
44
  private _drainQueuedMessages;
44
45
  private _sendMessages;
46
+ private _sendQueuedMessage;
45
47
  sendMessage({ to, type, message, attachment, ignoreOffline, }: {
46
48
  to: Participant;
47
49
  type: string;
@@ -30,6 +30,7 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
30
30
  this._messageQueue = [];
31
31
  this._messageQueued = null;
32
32
  this._sendTask = null;
33
+ this._sendOperations = new Set();
33
34
  this._messageQueueClosed = false;
34
35
  this._desiredEnabled = false;
35
36
  this._online = false;
@@ -59,11 +60,12 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
59
60
  }
60
61
  return input;
61
62
  }
62
- async _invoke({ operation, input, }) {
63
+ async _invoke({ operation, input, afterSend, }) {
63
64
  await this.client.invokeContent({
64
65
  toolkit: "messaging",
65
66
  tool: operation,
66
67
  input: new response_js_1.JsonContent({ json: input }),
68
+ afterSend,
67
69
  });
68
70
  }
69
71
  _invokeNowait({ operation, input, }) {
@@ -93,6 +95,7 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
93
95
  if (sendTask != null) {
94
96
  await sendTask;
95
97
  }
98
+ await Promise.all(this._sendOperations);
96
99
  this._desiredEnabled = false;
97
100
  this._clearCurrentConnectionState();
98
101
  }
@@ -238,34 +241,52 @@ class MessagingClient extends event_emitter_js_1.EventEmitter {
238
241
  });
239
242
  continue;
240
243
  }
241
- try {
242
- await this._invoke({
243
- operation: "send",
244
- input: this._messageInput({
245
- toParticipantId: resolvedTo.id,
246
- type: message.type,
247
- message: message.message,
248
- attachment: message.attachment,
249
- }),
250
- });
251
- if (message.completer != null && !message.completer.completed) {
252
- message.completer.complete();
253
- }
244
+ const dispatched = new completer_js_1.Completer();
245
+ const operation = this._sendQueuedMessage({
246
+ message,
247
+ resolvedTo,
248
+ afterSend: () => dispatched.resolve(),
249
+ });
250
+ this._sendOperations.add(operation);
251
+ void operation.then(() => {
252
+ this._sendOperations.delete(operation);
253
+ if (!dispatched.completed)
254
+ dispatched.resolve();
255
+ }, () => {
256
+ this._sendOperations.delete(operation);
257
+ if (!dispatched.completed)
258
+ dispatched.resolve();
259
+ });
260
+ await dispatched.fut;
261
+ }
262
+ }
263
+ async _sendQueuedMessage({ message, resolvedTo, afterSend, }) {
264
+ try {
265
+ await this._invoke({
266
+ operation: "send",
267
+ input: this._messageInput({
268
+ toParticipantId: resolvedTo.id,
269
+ type: message.type,
270
+ message: message.message,
271
+ attachment: message.attachment,
272
+ }),
273
+ afterSend,
274
+ });
275
+ if (message.completer != null && !message.completer.completed) {
276
+ message.completer.complete();
254
277
  }
255
- catch (error) {
256
- if (error instanceof room_server_client_js_1.RoomServerException) {
257
- const wrapped = this.client._coerceMessageSendError(error);
258
- if (wrapped.message === "the participant was not found") {
259
- this._markParticipantOffline(message.to);
260
- this._dropQueuedMessage({ message, error: wrapped });
261
- continue;
262
- }
263
- this._dropQueuedMessage({ message, error: wrapped });
264
- continue;
265
- }
266
- if (message.completer != null && !message.completer.completed) {
267
- message.completer.completeError(error);
278
+ }
279
+ catch (error) {
280
+ if (error instanceof room_server_client_js_1.RoomServerException) {
281
+ const wrapped = this.client._coerceMessageSendError(error);
282
+ if (wrapped.message === "the participant was not found") {
283
+ this._markParticipantOffline(message.to);
268
284
  }
285
+ this._dropQueuedMessage({ message, error: wrapped });
286
+ return;
287
+ }
288
+ if (message.completer != null && !message.completer.completed) {
289
+ message.completer.completeError(error);
269
290
  }
270
291
  }
271
292
  }
@@ -189,7 +189,7 @@ export declare class RoomClient {
189
189
  }): void;
190
190
  _sendLocalAttributesNowait(attributes: Record<string, unknown>): void;
191
191
  _resendLocalAttributesNowait(): void;
192
- sendRequest(type: string, request: RequestHeader, data?: Uint8Array): Promise<Content>;
192
+ sendRequest(type: string, request: RequestHeader, data?: Uint8Array, afterSend?: () => void): Promise<Content>;
193
193
  call(params: {
194
194
  name: string;
195
195
  url: string;
@@ -216,6 +216,7 @@ export declare class RoomClient {
216
216
  input?: InvokeInput;
217
217
  participantId?: string;
218
218
  onBehalfOfId?: string;
219
+ afterSend?: () => void;
219
220
  }): Promise<Content>;
220
221
  invokeToolCall(params: {
221
222
  toolkit: string;
@@ -224,6 +225,7 @@ export declare class RoomClient {
224
225
  streamInput?: boolean;
225
226
  participantId?: string;
226
227
  onBehalfOfId?: string;
228
+ afterSend?: () => void;
227
229
  }): Promise<{
228
230
  kind: "content";
229
231
  content: Content;
@@ -1146,7 +1146,7 @@ class RoomClient {
1146
1146
  }
1147
1147
  this._sendLocalAttributesNowait(attributes);
1148
1148
  }
1149
- async sendRequest(type, request, data) {
1149
+ async sendRequest(type, request, data, afterSend) {
1150
1150
  this._raiseIfTerminal();
1151
1151
  if (this._entered && !this._connected && !this._allowDisconnectedRequests) {
1152
1152
  throw this._disconnectedError({ baseMessage: "room connection is disconnected" });
@@ -1156,6 +1156,7 @@ class RoomClient {
1156
1156
  this._pendingRequests.set(requestId, completer);
1157
1157
  try {
1158
1158
  await this._protocolInstance.send(type, (0, utils_js_1.packMessage)(request, data), requestId);
1159
+ afterSend?.();
1159
1160
  return await completer.fut;
1160
1161
  }
1161
1162
  catch (error) {
@@ -1239,6 +1240,7 @@ class RoomClient {
1239
1240
  input: this._normalizeInvokeInput(params.input ?? params.arguments),
1240
1241
  participantId: params.participantId,
1241
1242
  onBehalfOfId: params.onBehalfOfId,
1243
+ afterSend: params.afterSend,
1242
1244
  });
1243
1245
  if (output.kind !== "content") {
1244
1246
  throw new room_server_client_js_1.RoomServerException("unexpected streamed output from " + params.toolkit + "." + params.tool);
@@ -1280,7 +1282,7 @@ class RoomClient {
1280
1282
  }
1281
1283
  try {
1282
1284
  const response = await Promise.race([
1283
- this.sendRequest("room.invoke_tool", request, requestData),
1285
+ this.sendRequest("room.invoke_tool", request, requestData, params.afterSend),
1284
1286
  preOpenError.fut,
1285
1287
  ]);
1286
1288
  this._toolCallPreOpenErrors.delete(toolCallId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent",
3
- "version": "0.46.3",
3
+ "version": "0.47.0",
4
4
  "description": "Meshagent Client",
5
5
  "homepage": "https://github.com/meshagent/meshagent-ts",
6
6
  "scripts": {