@meshagent/meshagent 0.39.4 → 0.39.6

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,12 @@
1
+ ## [0.39.6]
2
+ - Chat thread message sending now supports an “agent messages” mode: it selects participants that advertise agent-message support and sends `agent-message` payloads using `meshagent.agent.turn.start` / `meshagent.agent.turn.steer` types (including turn/thread scoping), with Promise-based sending and cancellation when recipients never materialize.
3
+ - Chat UI/logic now determines the correct outbound message type (chat vs steer) and turn context from thread status, and passes that into message sending.
4
+ - DatasetsClient now adds strongly typed `importFromStorage` and `exportToStorage` APIs with dataset storage format + import mode options, optional `namespace`/`branch` scoping, and `batch_size` support that is omitted when unset.
5
+ - Unit tests were updated to verify the new import/export request payload shapes and defaults.
6
+
7
+ ## [0.39.5]
8
+ - Stability
9
+
1
10
  ## [0.39.4]
2
11
  - Updated the Node/TS React dev package dependency graph to the newer `@meshagent/meshagent` and `@meshagent/meshagent-react` versions (`^0.38.4`) and upgraded supporting UI dependencies (including `shadcn` `^4.5.0`, `radix-ui` `^1.4.3`, and `lucide-react` `^0.525.0`).
3
12
  - Updated build tooling in the React dev package (new `build:js` / `build:types` scripts using TS configs) to match the updated packaging workflow.
package/README.md CHANGED
@@ -6,7 +6,6 @@ MeshAgent is your platform to create, deploy, and manage AI agents collaborative
6
6
 
7
7
  MeshAgent removes the infrastructure headaches of building and shipping AI Agents. It spins up secure, real-time "Rooms" that connect humans, agents, and shared context -- letting you launch, share, and refine agents in hours instead of weeks.
8
8
 
9
-
10
9
  ---
11
10
 
12
11
  **Documentation**: [docs.meshagent.com](https://docs.meshagent.com/)
@@ -23,6 +22,31 @@ Install the MeshAgent CLI, connect it to your account, then run a minimal toolki
23
22
 
24
23
  ### 1. Install the MeshAgent CLI
25
24
 
25
+ If you are using a Python-based install path, MeshAgent currently requires **Python 3.13**. Python 3.14 is not supported yet, and earlier versions are not tested.
26
+
27
+ If you do not already have Python 3.13, the simplest setup is:
28
+
29
+ #### Install uv on Linux or macOS
30
+ ```bash
31
+ curl -LsSf https://astral.sh/uv/install.sh | sh
32
+ ```
33
+
34
+ #### or Install uv on windows (PowerShell):
35
+ ```bash
36
+ powershelliwr -useb https://astral.sh/uv/install.ps1 | iex
37
+ ```
38
+
39
+
40
+ #### Download and manage Python 3.13
41
+ ```bash
42
+ uv python install 3.13
43
+ ```
44
+
45
+ #### Verify the version
46
+ ```bash
47
+ uv run --python 3.13 python --version
48
+ ```
49
+
26
50
  Use the install path that matches your environment:
27
51
 
28
52
  ```bash
@@ -34,8 +58,7 @@ brew install meshagent
34
58
  choco install meshagent
35
59
 
36
60
  # Other platforms
37
- pipx install "meshagent[cli]" --include-deps
38
- pipx ensurepath
61
+ uv tool install --python 3.13 "meshagent[cli]"
39
62
  ```
40
63
 
41
64
  Then sign in and activate a project:
@@ -144,11 +167,68 @@ main().catch((error) => {
144
167
  ### 4. Run the example
145
168
 
146
169
  ```bash
147
- meshagent room connect --project-id <project-id> --room <room-name> -- node example.js
170
+ meshagent room connect --room <your-room-name> -- node example.js
148
171
  ```
149
172
 
150
173
  `meshagent room connect` starts the local Node process with the MeshAgent room environment already configured, so `RoomClient()` can connect without any extra setup in your code. If you already activated a project with `meshagent setup`, you can omit `--project-id`.
151
174
 
175
+ ## Deploy With a Dockerfile
176
+
177
+ For deployment, package your toolkit as a long-running Node process. Use the same `RoomClient` and `startHostedToolkit` setup from the local example, but do not invoke the tool and exit; keep the process alive until it receives `SIGTERM` or `SIGINT`.
178
+
179
+ Create a `Dockerfile` for your toolkit service:
180
+
181
+ ```dockerfile
182
+ FROM node:22-slim
183
+
184
+ WORKDIR /app
185
+ COPY package*.json ./
186
+ RUN npm ci --omit=dev
187
+ COPY . .
188
+
189
+ CMD ["node", "service.js"]
190
+ ```
191
+
192
+ Build and push the image to a registry that MeshAgent can pull:
193
+
194
+ ```bash
195
+ docker buildx build . \
196
+ -t "<REGISTRY>/<NAMESPACE>/simple-echo-toolkit:<TAG>" \
197
+ --platform linux/amd64 \
198
+ --push
199
+ ```
200
+
201
+ Then create a `meshagent.yaml` service manifest that runs the image and injects a room token:
202
+
203
+ ```yaml
204
+ kind: Service
205
+ version: v1
206
+ metadata:
207
+ name: simple-echo-toolkit
208
+ description: "Simple Echo Toolkit hosted from a Node container"
209
+ annotations:
210
+ meshagent.service.id: simple-echo-toolkit
211
+ agents:
212
+ - name: simple-echo-toolkit
213
+ description: "Hosts the Simple Echo Toolkit"
214
+ container:
215
+ image: "<REGISTRY>/<NAMESPACE>/simple-echo-toolkit:<TAG>"
216
+ command: node service.js
217
+ environment:
218
+ - name: MESHAGENT_TOKEN
219
+ token:
220
+ identity: simple-echo-toolkit
221
+ ```
222
+
223
+ Validate and deploy it to a room:
224
+
225
+ ```bash
226
+ meshagent service validate --file meshagent.yaml
227
+ meshagent service create --file meshagent.yaml --room <your-room-name>
228
+ ```
229
+
230
+ After the service starts, the toolkit name you passed to `new Toolkit({ name: ... })` is available in that room.
231
+
152
232
  ## Next Steps and Examples
153
233
 
154
234
  To see examples of agents in action and to start building your own agents check out the MeshAgent docs at [docs.meshagent.com](https://docs.meshagent.com/)
@@ -1,6 +1,8 @@
1
1
  import { Schema, Table } from "apache-arrow";
2
2
  import { RoomClient } from "./room-client";
3
3
  export type CreateMode = "create" | "overwrite" | "create_if_not_exists";
4
+ export type DatasetStorageFormat = "auto" | "json" | "arrow" | "csv" | "tsv" | "parquet" | "excel";
5
+ export type DatasetImportMode = "create" | "replace" | "merge";
4
6
  export interface TableRef {
5
7
  name: string;
6
8
  namespace?: string[];
@@ -222,6 +224,25 @@ export declare class DatasetsClient {
222
224
  namespace?: string[];
223
225
  branch?: string;
224
226
  }): Promise<void>;
227
+ importFromStorage({ table, path, mode, format, on, sheet, batchSize, namespace, branch }: {
228
+ table: string;
229
+ path: string;
230
+ mode?: DatasetImportMode;
231
+ format?: DatasetStorageFormat;
232
+ on?: string;
233
+ sheet?: string;
234
+ batchSize?: number;
235
+ namespace?: string[];
236
+ branch?: string;
237
+ }): Promise<void>;
238
+ exportToStorage({ table, path, format, namespace, branch, version }: {
239
+ table: string;
240
+ path: string;
241
+ format: DatasetStorageFormat;
242
+ namespace?: string[];
243
+ branch?: string;
244
+ version?: number;
245
+ }): Promise<void>;
225
246
  dropIndex({ table, name, namespace, branch }: {
226
247
  table: string;
227
248
  name: string;
@@ -870,6 +870,32 @@ class DatasetsClient {
870
870
  },
871
871
  });
872
872
  }
873
+ async importFromStorage({ table, path, mode = "create", format = "auto", on, sheet, batchSize, namespace, branch }) {
874
+ const input = {
875
+ table,
876
+ path,
877
+ mode,
878
+ format,
879
+ on: on ?? null,
880
+ sheet: sheet ?? null,
881
+ namespace: namespace ?? null,
882
+ branch: branch ?? null,
883
+ };
884
+ if (batchSize != null) {
885
+ input.batch_size = batchSize;
886
+ }
887
+ await this.invoke("import_storage", input);
888
+ }
889
+ async exportToStorage({ table, path, format, namespace, branch, version }) {
890
+ await this.invoke("export_storage", {
891
+ table,
892
+ path,
893
+ format,
894
+ namespace: namespace ?? null,
895
+ branch: branch ?? null,
896
+ version: version ?? null,
897
+ });
898
+ }
873
899
  async dropIndex({ table, name, namespace, branch }) {
874
900
  await this.room.invoke({
875
901
  toolkit: "dataset",
@@ -85,7 +85,8 @@ export declare class RoomClient {
85
85
  private _roomName;
86
86
  private _roomUrl;
87
87
  private _sessionId;
88
- private static readonly RECONNECT_RETRY_INTERVAL_MS;
88
+ private static readonly RECONNECT_RETRY_BASE_DELAY_MS;
89
+ private static readonly RECONNECT_RETRY_MAX_DELAY_MS;
89
90
  private readonly _handleRoomReadyBound;
90
91
  private readonly _handleRoomStatusBound;
91
92
  private readonly _handleParticipantBound;
@@ -151,6 +152,7 @@ export declare class RoomClient {
151
152
  private _completeReconnect;
152
153
  private _replaceProtocol;
153
154
  private _remainingReconnectTimeout;
155
+ private _reconnectRetryDelay;
154
156
  private _attemptInitialProtocolStartup;
155
157
  private _attemptReconnect;
156
158
  private _formatDuration;
@@ -29,6 +29,12 @@ class ProtocolStartupFailure extends Error {
29
29
  this.reason = reason;
30
30
  }
31
31
  }
32
+ function isRetryableStartupClose({ kind, reason, }) {
33
+ if (kind === protocol_1.ProtocolCloseKind.ERROR) {
34
+ return true;
35
+ }
36
+ return (reason ?? "").toLowerCase().includes("1013");
37
+ }
32
38
  class RoomClientTerminalState {
33
39
  constructor({ requestMessage, toolCallMessage, messageSendMessage, }) {
34
40
  this.requestMessage = requestMessage;
@@ -655,7 +661,8 @@ class RoomClient {
655
661
  }
656
662
  catch (error) {
657
663
  if (error instanceof ProtocolStartupFailure) {
658
- if (error.kind !== protocol_1.ProtocolCloseKind.ERROR || this._reconnectTimeout === 0) {
664
+ if (!isRetryableStartupClose({ kind: error.kind, reason: error.reason })
665
+ || this._reconnectTimeout === 0) {
659
666
  this._setStartupTerminalState({
660
667
  closeKind: error.kind,
661
668
  closeReason: error.reason,
@@ -691,7 +698,8 @@ class RoomClient {
691
698
  }
692
699
  const closeKind = this._protocolInstance.closeKind;
693
700
  const protocolCloseReason = normalizeCloseReason(this._protocolInstance.closeReason);
694
- if (closeKind != null && closeKind !== protocol_1.ProtocolCloseKind.ERROR) {
701
+ if (closeKind != null
702
+ && !isRetryableStartupClose({ kind: closeKind, reason: protocolCloseReason })) {
695
703
  this._setStartupTerminalState({
696
704
  closeKind,
697
705
  closeReason: protocolCloseReason,
@@ -770,6 +778,9 @@ class RoomClient {
770
778
  const remaining = deadline - Date.now();
771
779
  return remaining <= 0 ? 0 : remaining;
772
780
  }
781
+ _reconnectRetryDelay({ retryCount }) {
782
+ return Math.min(RoomClient.RECONNECT_RETRY_MAX_DELAY_MS, RoomClient.RECONNECT_RETRY_BASE_DELAY_MS * (2 ** retryCount));
783
+ }
773
784
  async _attemptInitialProtocolStartup({ protocol, remaining, }) {
774
785
  void protocol;
775
786
  if (remaining == null) {
@@ -865,11 +876,13 @@ class RoomClient {
865
876
  };
866
877
  const deadline = this._reconnectTimeout == null ? null : Date.now() + this._reconnectTimeout;
867
878
  let firstAttempt = true;
879
+ let retryCount = 0;
868
880
  while (!this._closing) {
869
881
  if (firstAttempt) {
870
882
  firstAttempt = false;
871
883
  if (this._reconnectTimeout == null) {
872
- await new Promise((resolve) => setTimeout(resolve, RoomClient.RECONNECT_RETRY_INTERVAL_MS));
884
+ await new Promise((resolve) => setTimeout(resolve, this._reconnectRetryDelay({ retryCount })));
885
+ retryCount += 1;
873
886
  }
874
887
  }
875
888
  else {
@@ -877,12 +890,14 @@ class RoomClient {
877
890
  if (remaining != null && remaining === 0) {
878
891
  return this._timedOutRetryResult({ disconnectReason: failureReason });
879
892
  }
893
+ const backoffDelay = this._reconnectRetryDelay({ retryCount });
880
894
  const delay = remaining == null
881
- ? RoomClient.RECONNECT_RETRY_INTERVAL_MS
882
- : Math.min(remaining, RoomClient.RECONNECT_RETRY_INTERVAL_MS);
895
+ ? backoffDelay
896
+ : Math.min(remaining, backoffDelay);
883
897
  if (delay > 0) {
884
898
  await new Promise((resolve) => setTimeout(resolve, delay));
885
899
  }
900
+ retryCount += 1;
886
901
  }
887
902
  const remaining = this._remainingReconnectTimeout(deadline);
888
903
  if (remaining != null && remaining === 0) {
@@ -917,7 +932,7 @@ class RoomClient {
917
932
  if (error instanceof ProtocolStartupFailure) {
918
933
  recordFailureReason(error.reason);
919
934
  await this._closeProtocol(nextProtocol);
920
- if (error.kind !== protocol_1.ProtocolCloseKind.ERROR) {
935
+ if (!isRetryableStartupClose({ kind: error.kind, reason: error.reason })) {
921
936
  return {
922
937
  connected: false,
923
938
  closeKind: error.kind,
@@ -1430,4 +1445,5 @@ class RoomClient {
1430
1445
  }
1431
1446
  }
1432
1447
  exports.RoomClient = RoomClient;
1433
- RoomClient.RECONNECT_RETRY_INTERVAL_MS = 1000;
1448
+ RoomClient.RECONNECT_RETRY_BASE_DELAY_MS = 500;
1449
+ RoomClient.RECONNECT_RETRY_MAX_DELAY_MS = 30000;
@@ -1,6 +1,8 @@
1
1
  import { Schema, Table } from "apache-arrow";
2
2
  import { RoomClient } from "./room-client";
3
3
  export type CreateMode = "create" | "overwrite" | "create_if_not_exists";
4
+ export type DatasetStorageFormat = "auto" | "json" | "arrow" | "csv" | "tsv" | "parquet" | "excel";
5
+ export type DatasetImportMode = "create" | "replace" | "merge";
4
6
  export interface TableRef {
5
7
  name: string;
6
8
  namespace?: string[];
@@ -222,6 +224,25 @@ export declare class DatasetsClient {
222
224
  namespace?: string[];
223
225
  branch?: string;
224
226
  }): Promise<void>;
227
+ importFromStorage({ table, path, mode, format, on, sheet, batchSize, namespace, branch }: {
228
+ table: string;
229
+ path: string;
230
+ mode?: DatasetImportMode;
231
+ format?: DatasetStorageFormat;
232
+ on?: string;
233
+ sheet?: string;
234
+ batchSize?: number;
235
+ namespace?: string[];
236
+ branch?: string;
237
+ }): Promise<void>;
238
+ exportToStorage({ table, path, format, namespace, branch, version }: {
239
+ table: string;
240
+ path: string;
241
+ format: DatasetStorageFormat;
242
+ namespace?: string[];
243
+ branch?: string;
244
+ version?: number;
245
+ }): Promise<void>;
225
246
  dropIndex({ table, name, namespace, branch }: {
226
247
  table: string;
227
248
  name: string;
@@ -870,6 +870,32 @@ class DatasetsClient {
870
870
  },
871
871
  });
872
872
  }
873
+ async importFromStorage({ table, path, mode = "create", format = "auto", on, sheet, batchSize, namespace, branch }) {
874
+ const input = {
875
+ table,
876
+ path,
877
+ mode,
878
+ format,
879
+ on: on ?? null,
880
+ sheet: sheet ?? null,
881
+ namespace: namespace ?? null,
882
+ branch: branch ?? null,
883
+ };
884
+ if (batchSize != null) {
885
+ input.batch_size = batchSize;
886
+ }
887
+ await this.invoke("import_storage", input);
888
+ }
889
+ async exportToStorage({ table, path, format, namespace, branch, version }) {
890
+ await this.invoke("export_storage", {
891
+ table,
892
+ path,
893
+ format,
894
+ namespace: namespace ?? null,
895
+ branch: branch ?? null,
896
+ version: version ?? null,
897
+ });
898
+ }
873
899
  async dropIndex({ table, name, namespace, branch }) {
874
900
  await this.room.invoke({
875
901
  toolkit: "dataset",
@@ -85,7 +85,8 @@ export declare class RoomClient {
85
85
  private _roomName;
86
86
  private _roomUrl;
87
87
  private _sessionId;
88
- private static readonly RECONNECT_RETRY_INTERVAL_MS;
88
+ private static readonly RECONNECT_RETRY_BASE_DELAY_MS;
89
+ private static readonly RECONNECT_RETRY_MAX_DELAY_MS;
89
90
  private readonly _handleRoomReadyBound;
90
91
  private readonly _handleRoomStatusBound;
91
92
  private readonly _handleParticipantBound;
@@ -151,6 +152,7 @@ export declare class RoomClient {
151
152
  private _completeReconnect;
152
153
  private _replaceProtocol;
153
154
  private _remainingReconnectTimeout;
155
+ private _reconnectRetryDelay;
154
156
  private _attemptInitialProtocolStartup;
155
157
  private _attemptReconnect;
156
158
  private _formatDuration;
@@ -29,6 +29,12 @@ class ProtocolStartupFailure extends Error {
29
29
  this.reason = reason;
30
30
  }
31
31
  }
32
+ function isRetryableStartupClose({ kind, reason, }) {
33
+ if (kind === protocol_1.ProtocolCloseKind.ERROR) {
34
+ return true;
35
+ }
36
+ return (reason ?? "").toLowerCase().includes("1013");
37
+ }
32
38
  class RoomClientTerminalState {
33
39
  constructor({ requestMessage, toolCallMessage, messageSendMessage, }) {
34
40
  this.requestMessage = requestMessage;
@@ -655,7 +661,8 @@ class RoomClient {
655
661
  }
656
662
  catch (error) {
657
663
  if (error instanceof ProtocolStartupFailure) {
658
- if (error.kind !== protocol_1.ProtocolCloseKind.ERROR || this._reconnectTimeout === 0) {
664
+ if (!isRetryableStartupClose({ kind: error.kind, reason: error.reason })
665
+ || this._reconnectTimeout === 0) {
659
666
  this._setStartupTerminalState({
660
667
  closeKind: error.kind,
661
668
  closeReason: error.reason,
@@ -691,7 +698,8 @@ class RoomClient {
691
698
  }
692
699
  const closeKind = this._protocolInstance.closeKind;
693
700
  const protocolCloseReason = normalizeCloseReason(this._protocolInstance.closeReason);
694
- if (closeKind != null && closeKind !== protocol_1.ProtocolCloseKind.ERROR) {
701
+ if (closeKind != null
702
+ && !isRetryableStartupClose({ kind: closeKind, reason: protocolCloseReason })) {
695
703
  this._setStartupTerminalState({
696
704
  closeKind,
697
705
  closeReason: protocolCloseReason,
@@ -770,6 +778,9 @@ class RoomClient {
770
778
  const remaining = deadline - Date.now();
771
779
  return remaining <= 0 ? 0 : remaining;
772
780
  }
781
+ _reconnectRetryDelay({ retryCount }) {
782
+ return Math.min(RoomClient.RECONNECT_RETRY_MAX_DELAY_MS, RoomClient.RECONNECT_RETRY_BASE_DELAY_MS * (2 ** retryCount));
783
+ }
773
784
  async _attemptInitialProtocolStartup({ protocol, remaining, }) {
774
785
  void protocol;
775
786
  if (remaining == null) {
@@ -865,11 +876,13 @@ class RoomClient {
865
876
  };
866
877
  const deadline = this._reconnectTimeout == null ? null : Date.now() + this._reconnectTimeout;
867
878
  let firstAttempt = true;
879
+ let retryCount = 0;
868
880
  while (!this._closing) {
869
881
  if (firstAttempt) {
870
882
  firstAttempt = false;
871
883
  if (this._reconnectTimeout == null) {
872
- await new Promise((resolve) => setTimeout(resolve, RoomClient.RECONNECT_RETRY_INTERVAL_MS));
884
+ await new Promise((resolve) => setTimeout(resolve, this._reconnectRetryDelay({ retryCount })));
885
+ retryCount += 1;
873
886
  }
874
887
  }
875
888
  else {
@@ -877,12 +890,14 @@ class RoomClient {
877
890
  if (remaining != null && remaining === 0) {
878
891
  return this._timedOutRetryResult({ disconnectReason: failureReason });
879
892
  }
893
+ const backoffDelay = this._reconnectRetryDelay({ retryCount });
880
894
  const delay = remaining == null
881
- ? RoomClient.RECONNECT_RETRY_INTERVAL_MS
882
- : Math.min(remaining, RoomClient.RECONNECT_RETRY_INTERVAL_MS);
895
+ ? backoffDelay
896
+ : Math.min(remaining, backoffDelay);
883
897
  if (delay > 0) {
884
898
  await new Promise((resolve) => setTimeout(resolve, delay));
885
899
  }
900
+ retryCount += 1;
886
901
  }
887
902
  const remaining = this._remainingReconnectTimeout(deadline);
888
903
  if (remaining != null && remaining === 0) {
@@ -917,7 +932,7 @@ class RoomClient {
917
932
  if (error instanceof ProtocolStartupFailure) {
918
933
  recordFailureReason(error.reason);
919
934
  await this._closeProtocol(nextProtocol);
920
- if (error.kind !== protocol_1.ProtocolCloseKind.ERROR) {
935
+ if (!isRetryableStartupClose({ kind: error.kind, reason: error.reason })) {
921
936
  return {
922
937
  connected: false,
923
938
  closeKind: error.kind,
@@ -1430,4 +1445,5 @@ class RoomClient {
1430
1445
  }
1431
1446
  }
1432
1447
  exports.RoomClient = RoomClient;
1433
- RoomClient.RECONNECT_RETRY_INTERVAL_MS = 1000;
1448
+ RoomClient.RECONNECT_RETRY_BASE_DELAY_MS = 500;
1449
+ RoomClient.RECONNECT_RETRY_MAX_DELAY_MS = 30000;
@@ -1,6 +1,8 @@
1
1
  import { Schema, Table } from "apache-arrow";
2
2
  import { RoomClient } from "./room-client";
3
3
  export type CreateMode = "create" | "overwrite" | "create_if_not_exists";
4
+ export type DatasetStorageFormat = "auto" | "json" | "arrow" | "csv" | "tsv" | "parquet" | "excel";
5
+ export type DatasetImportMode = "create" | "replace" | "merge";
4
6
  export interface TableRef {
5
7
  name: string;
6
8
  namespace?: string[];
@@ -222,6 +224,25 @@ export declare class DatasetsClient {
222
224
  namespace?: string[];
223
225
  branch?: string;
224
226
  }): Promise<void>;
227
+ importFromStorage({ table, path, mode, format, on, sheet, batchSize, namespace, branch }: {
228
+ table: string;
229
+ path: string;
230
+ mode?: DatasetImportMode;
231
+ format?: DatasetStorageFormat;
232
+ on?: string;
233
+ sheet?: string;
234
+ batchSize?: number;
235
+ namespace?: string[];
236
+ branch?: string;
237
+ }): Promise<void>;
238
+ exportToStorage({ table, path, format, namespace, branch, version }: {
239
+ table: string;
240
+ path: string;
241
+ format: DatasetStorageFormat;
242
+ namespace?: string[];
243
+ branch?: string;
244
+ version?: number;
245
+ }): Promise<void>;
225
246
  dropIndex({ table, name, namespace, branch }: {
226
247
  table: string;
227
248
  name: string;
@@ -870,6 +870,32 @@ class DatasetsClient {
870
870
  },
871
871
  });
872
872
  }
873
+ async importFromStorage({ table, path, mode = "create", format = "auto", on, sheet, batchSize, namespace, branch }) {
874
+ const input = {
875
+ table,
876
+ path,
877
+ mode,
878
+ format,
879
+ on: on ?? null,
880
+ sheet: sheet ?? null,
881
+ namespace: namespace ?? null,
882
+ branch: branch ?? null,
883
+ };
884
+ if (batchSize != null) {
885
+ input.batch_size = batchSize;
886
+ }
887
+ await this.invoke("import_storage", input);
888
+ }
889
+ async exportToStorage({ table, path, format, namespace, branch, version }) {
890
+ await this.invoke("export_storage", {
891
+ table,
892
+ path,
893
+ format,
894
+ namespace: namespace ?? null,
895
+ branch: branch ?? null,
896
+ version: version ?? null,
897
+ });
898
+ }
873
899
  async dropIndex({ table, name, namespace, branch }) {
874
900
  await this.room.invoke({
875
901
  toolkit: "dataset",
@@ -85,7 +85,8 @@ export declare class RoomClient {
85
85
  private _roomName;
86
86
  private _roomUrl;
87
87
  private _sessionId;
88
- private static readonly RECONNECT_RETRY_INTERVAL_MS;
88
+ private static readonly RECONNECT_RETRY_BASE_DELAY_MS;
89
+ private static readonly RECONNECT_RETRY_MAX_DELAY_MS;
89
90
  private readonly _handleRoomReadyBound;
90
91
  private readonly _handleRoomStatusBound;
91
92
  private readonly _handleParticipantBound;
@@ -151,6 +152,7 @@ export declare class RoomClient {
151
152
  private _completeReconnect;
152
153
  private _replaceProtocol;
153
154
  private _remainingReconnectTimeout;
155
+ private _reconnectRetryDelay;
154
156
  private _attemptInitialProtocolStartup;
155
157
  private _attemptReconnect;
156
158
  private _formatDuration;
@@ -29,6 +29,12 @@ class ProtocolStartupFailure extends Error {
29
29
  this.reason = reason;
30
30
  }
31
31
  }
32
+ function isRetryableStartupClose({ kind, reason, }) {
33
+ if (kind === protocol_1.ProtocolCloseKind.ERROR) {
34
+ return true;
35
+ }
36
+ return (reason ?? "").toLowerCase().includes("1013");
37
+ }
32
38
  class RoomClientTerminalState {
33
39
  constructor({ requestMessage, toolCallMessage, messageSendMessage, }) {
34
40
  this.requestMessage = requestMessage;
@@ -655,7 +661,8 @@ class RoomClient {
655
661
  }
656
662
  catch (error) {
657
663
  if (error instanceof ProtocolStartupFailure) {
658
- if (error.kind !== protocol_1.ProtocolCloseKind.ERROR || this._reconnectTimeout === 0) {
664
+ if (!isRetryableStartupClose({ kind: error.kind, reason: error.reason })
665
+ || this._reconnectTimeout === 0) {
659
666
  this._setStartupTerminalState({
660
667
  closeKind: error.kind,
661
668
  closeReason: error.reason,
@@ -691,7 +698,8 @@ class RoomClient {
691
698
  }
692
699
  const closeKind = this._protocolInstance.closeKind;
693
700
  const protocolCloseReason = normalizeCloseReason(this._protocolInstance.closeReason);
694
- if (closeKind != null && closeKind !== protocol_1.ProtocolCloseKind.ERROR) {
701
+ if (closeKind != null
702
+ && !isRetryableStartupClose({ kind: closeKind, reason: protocolCloseReason })) {
695
703
  this._setStartupTerminalState({
696
704
  closeKind,
697
705
  closeReason: protocolCloseReason,
@@ -770,6 +778,9 @@ class RoomClient {
770
778
  const remaining = deadline - Date.now();
771
779
  return remaining <= 0 ? 0 : remaining;
772
780
  }
781
+ _reconnectRetryDelay({ retryCount }) {
782
+ return Math.min(RoomClient.RECONNECT_RETRY_MAX_DELAY_MS, RoomClient.RECONNECT_RETRY_BASE_DELAY_MS * (2 ** retryCount));
783
+ }
773
784
  async _attemptInitialProtocolStartup({ protocol, remaining, }) {
774
785
  void protocol;
775
786
  if (remaining == null) {
@@ -865,11 +876,13 @@ class RoomClient {
865
876
  };
866
877
  const deadline = this._reconnectTimeout == null ? null : Date.now() + this._reconnectTimeout;
867
878
  let firstAttempt = true;
879
+ let retryCount = 0;
868
880
  while (!this._closing) {
869
881
  if (firstAttempt) {
870
882
  firstAttempt = false;
871
883
  if (this._reconnectTimeout == null) {
872
- await new Promise((resolve) => setTimeout(resolve, RoomClient.RECONNECT_RETRY_INTERVAL_MS));
884
+ await new Promise((resolve) => setTimeout(resolve, this._reconnectRetryDelay({ retryCount })));
885
+ retryCount += 1;
873
886
  }
874
887
  }
875
888
  else {
@@ -877,12 +890,14 @@ class RoomClient {
877
890
  if (remaining != null && remaining === 0) {
878
891
  return this._timedOutRetryResult({ disconnectReason: failureReason });
879
892
  }
893
+ const backoffDelay = this._reconnectRetryDelay({ retryCount });
880
894
  const delay = remaining == null
881
- ? RoomClient.RECONNECT_RETRY_INTERVAL_MS
882
- : Math.min(remaining, RoomClient.RECONNECT_RETRY_INTERVAL_MS);
895
+ ? backoffDelay
896
+ : Math.min(remaining, backoffDelay);
883
897
  if (delay > 0) {
884
898
  await new Promise((resolve) => setTimeout(resolve, delay));
885
899
  }
900
+ retryCount += 1;
886
901
  }
887
902
  const remaining = this._remainingReconnectTimeout(deadline);
888
903
  if (remaining != null && remaining === 0) {
@@ -917,7 +932,7 @@ class RoomClient {
917
932
  if (error instanceof ProtocolStartupFailure) {
918
933
  recordFailureReason(error.reason);
919
934
  await this._closeProtocol(nextProtocol);
920
- if (error.kind !== protocol_1.ProtocolCloseKind.ERROR) {
935
+ if (!isRetryableStartupClose({ kind: error.kind, reason: error.reason })) {
921
936
  return {
922
937
  connected: false,
923
938
  closeKind: error.kind,
@@ -1430,4 +1445,5 @@ class RoomClient {
1430
1445
  }
1431
1446
  }
1432
1447
  exports.RoomClient = RoomClient;
1433
- RoomClient.RECONNECT_RETRY_INTERVAL_MS = 1000;
1448
+ RoomClient.RECONNECT_RETRY_BASE_DELAY_MS = 500;
1449
+ RoomClient.RECONNECT_RETRY_MAX_DELAY_MS = 30000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshagent/meshagent",
3
- "version": "0.39.4",
3
+ "version": "0.39.6",
4
4
  "description": "Meshagent Client",
5
5
  "homepage": "https://github.com/meshagent/meshagent-ts",
6
6
  "scripts": {