@meshagent/meshagent 0.39.5 → 0.39.7
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 +9 -0
- package/README.md +84 -4
- package/dist/browser/containers-client.d.ts +1 -0
- package/dist/browser/containers-client.js +5 -0
- package/dist/browser/datasets-client.d.ts +21 -0
- package/dist/browser/datasets-client.js +26 -0
- package/dist/browser/meshagent-client.d.ts +3 -0
- package/dist/esm/containers-client.d.ts +1 -0
- package/dist/esm/containers-client.js +5 -0
- package/dist/esm/datasets-client.d.ts +21 -0
- package/dist/esm/datasets-client.js +26 -0
- package/dist/esm/meshagent-client.d.ts +3 -0
- package/dist/node/containers-client.d.ts +1 -0
- package/dist/node/containers-client.js +5 -0
- package/dist/node/datasets-client.d.ts +21 -0
- package/dist/node/datasets-client.js +26 -0
- package/dist/node/meshagent-client.d.ts +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [0.39.7]
|
|
2
|
+
- Updated Meshagent JS/TS package manifests so inter-package dependencies are aligned to the new Meshagent version (`@meshagent/*` packages now depend on the updated `^0.39.6` versions).
|
|
3
|
+
|
|
4
|
+
## [0.39.6]
|
|
5
|
+
- 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.
|
|
6
|
+
- 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.
|
|
7
|
+
- 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.
|
|
8
|
+
- Unit tests were updated to verify the new import/export request payload shapes and defaults.
|
|
9
|
+
|
|
1
10
|
## [0.39.5]
|
|
2
11
|
- Stability
|
|
3
12
|
|
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
|
-
|
|
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 --
|
|
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/)
|
|
@@ -878,11 +878,16 @@ class ContainersClient {
|
|
|
878
878
|
throw this.unexpectedResponseError("list");
|
|
879
879
|
}
|
|
880
880
|
const nameRaw = entry["name"];
|
|
881
|
+
const portsRaw = entry["ports"];
|
|
881
882
|
const serviceIdRaw = entry["service_id"];
|
|
883
|
+
if (!Array.isArray(portsRaw) || !portsRaw.every((port) => typeof port === "number" && Number.isInteger(port))) {
|
|
884
|
+
throw this.unexpectedResponseError("list");
|
|
885
|
+
}
|
|
882
886
|
items.push({
|
|
883
887
|
id,
|
|
884
888
|
image,
|
|
885
889
|
name: typeof nameRaw === "string" ? nameRaw : undefined,
|
|
890
|
+
ports: portsRaw,
|
|
886
891
|
startedBy: {
|
|
887
892
|
id: startedById,
|
|
888
893
|
name: startedByName,
|
|
@@ -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",
|
|
@@ -147,6 +147,7 @@ export interface ServiceMetadata {
|
|
|
147
147
|
annotations?: Record<string, string> | null;
|
|
148
148
|
}
|
|
149
149
|
export interface ContainerSpec {
|
|
150
|
+
private?: boolean | null;
|
|
150
151
|
command?: string | null;
|
|
151
152
|
working_dir?: string | null;
|
|
152
153
|
image: string;
|
|
@@ -154,6 +155,8 @@ export interface ContainerSpec {
|
|
|
154
155
|
secrets?: string[];
|
|
155
156
|
pull_secret?: string | null;
|
|
156
157
|
storage?: ContainerMountSpec;
|
|
158
|
+
on_demand?: boolean | null;
|
|
159
|
+
writable_root_fs?: boolean | null;
|
|
157
160
|
}
|
|
158
161
|
export interface ExternalServiceSpec {
|
|
159
162
|
url: string;
|
|
@@ -878,11 +878,16 @@ class ContainersClient {
|
|
|
878
878
|
throw this.unexpectedResponseError("list");
|
|
879
879
|
}
|
|
880
880
|
const nameRaw = entry["name"];
|
|
881
|
+
const portsRaw = entry["ports"];
|
|
881
882
|
const serviceIdRaw = entry["service_id"];
|
|
883
|
+
if (!Array.isArray(portsRaw) || !portsRaw.every((port) => typeof port === "number" && Number.isInteger(port))) {
|
|
884
|
+
throw this.unexpectedResponseError("list");
|
|
885
|
+
}
|
|
882
886
|
items.push({
|
|
883
887
|
id,
|
|
884
888
|
image,
|
|
885
889
|
name: typeof nameRaw === "string" ? nameRaw : undefined,
|
|
890
|
+
ports: portsRaw,
|
|
886
891
|
startedBy: {
|
|
887
892
|
id: startedById,
|
|
888
893
|
name: startedByName,
|
|
@@ -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",
|
|
@@ -147,6 +147,7 @@ export interface ServiceMetadata {
|
|
|
147
147
|
annotations?: Record<string, string> | null;
|
|
148
148
|
}
|
|
149
149
|
export interface ContainerSpec {
|
|
150
|
+
private?: boolean | null;
|
|
150
151
|
command?: string | null;
|
|
151
152
|
working_dir?: string | null;
|
|
152
153
|
image: string;
|
|
@@ -154,6 +155,8 @@ export interface ContainerSpec {
|
|
|
154
155
|
secrets?: string[];
|
|
155
156
|
pull_secret?: string | null;
|
|
156
157
|
storage?: ContainerMountSpec;
|
|
158
|
+
on_demand?: boolean | null;
|
|
159
|
+
writable_root_fs?: boolean | null;
|
|
157
160
|
}
|
|
158
161
|
export interface ExternalServiceSpec {
|
|
159
162
|
url: string;
|
|
@@ -878,11 +878,16 @@ class ContainersClient {
|
|
|
878
878
|
throw this.unexpectedResponseError("list");
|
|
879
879
|
}
|
|
880
880
|
const nameRaw = entry["name"];
|
|
881
|
+
const portsRaw = entry["ports"];
|
|
881
882
|
const serviceIdRaw = entry["service_id"];
|
|
883
|
+
if (!Array.isArray(portsRaw) || !portsRaw.every((port) => typeof port === "number" && Number.isInteger(port))) {
|
|
884
|
+
throw this.unexpectedResponseError("list");
|
|
885
|
+
}
|
|
882
886
|
items.push({
|
|
883
887
|
id,
|
|
884
888
|
image,
|
|
885
889
|
name: typeof nameRaw === "string" ? nameRaw : undefined,
|
|
890
|
+
ports: portsRaw,
|
|
886
891
|
startedBy: {
|
|
887
892
|
id: startedById,
|
|
888
893
|
name: startedByName,
|
|
@@ -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",
|
|
@@ -147,6 +147,7 @@ export interface ServiceMetadata {
|
|
|
147
147
|
annotations?: Record<string, string> | null;
|
|
148
148
|
}
|
|
149
149
|
export interface ContainerSpec {
|
|
150
|
+
private?: boolean | null;
|
|
150
151
|
command?: string | null;
|
|
151
152
|
working_dir?: string | null;
|
|
152
153
|
image: string;
|
|
@@ -154,6 +155,8 @@ export interface ContainerSpec {
|
|
|
154
155
|
secrets?: string[];
|
|
155
156
|
pull_secret?: string | null;
|
|
156
157
|
storage?: ContainerMountSpec;
|
|
158
|
+
on_demand?: boolean | null;
|
|
159
|
+
writable_root_fs?: boolean | null;
|
|
157
160
|
}
|
|
158
161
|
export interface ExternalServiceSpec {
|
|
159
162
|
url: string;
|