@shardflux/sdk 0.14.0 → 0.16.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 +85 -23
- package/README.md +226 -7
- package/dist/account.d.ts +2 -0
- package/dist/account.js +6 -0
- package/dist/cell.d.ts +27 -0
- package/dist/cell.js +71 -0
- package/dist/client.d.ts +54 -5
- package/dist/client.js +100 -7
- package/dist/computer.d.ts +153 -0
- package/dist/computer.js +229 -0
- package/dist/errors.d.ts +5 -1
- package/dist/errors.js +9 -0
- package/dist/executions.d.ts +2 -6
- package/dist/executions.js +9 -0
- package/dist/exit-code.d.ts +7 -0
- package/dist/exit-code.js +12 -0
- package/dist/generated/app-api.d.ts +1055 -119
- package/dist/generated/cell-api.d.ts +334 -0
- package/dist/http.d.ts +7 -1
- package/dist/http.js +34 -13
- package/dist/index.d.ts +13 -6
- package/dist/index.js +7 -2
- package/dist/ports.d.ts +7 -0
- package/dist/ports.js +1 -1
- package/dist/progress.d.ts +2 -2
- package/dist/progress.js +1 -1
- package/dist/templates.d.ts +12 -0
- package/dist/templates.js +9 -0
- package/dist/testing/index.d.ts +62 -0
- package/dist/testing/index.js +585 -0
- package/dist/testing/seed.d.ts +433 -0
- package/dist/testing/seed.js +449 -0
- package/dist/tools.d.ts +21 -3
- package/dist/tools.js +113 -22
- package/dist/tunnel-assets/linux-amd64.gz +0 -0
- package/dist/tunnel-assets/linux-arm64.gz +0 -0
- package/dist/tunnel-assets.d.ts +10 -0
- package/dist/tunnel-assets.js +11 -0
- package/dist/tunnel-packet.d.ts +3 -0
- package/dist/tunnel-packet.js +43 -0
- package/dist/tunnel-pty.d.ts +86 -0
- package/dist/tunnel-pty.js +243 -0
- package/dist/tunnels.d.ts +47 -0
- package/dist/tunnels.js +454 -0
- package/dist/workspace-ref.d.ts +87 -0
- package/dist/workspace-ref.js +173 -0
- package/dist/workspace.d.ts +40 -1
- package/dist/workspace.js +111 -2
- package/package.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.14.0 — 2026-10-04 (not yet published)
|
|
4
|
-
|
|
5
|
-
- Opt-in `workspaceTools(workspace, { prewake: true })` input-start hooks prepare VM tools while their input streams. Default tools, offline reads and file-first workspaces install no hook.
|
|
6
|
-
|
|
7
3
|
Every API the README shows is available from the version named here. Breaking changes ship in minor releases and are
|
|
8
4
|
marked **Breaking**.
|
|
9
5
|
|
|
10
|
-
## 0.
|
|
6
|
+
## 0.16.0 (not yet published)
|
|
7
|
+
|
|
8
|
+
- Add `@shardflux/sdk/testing`: `createFakeShardflux` supplies an isolated in-memory transport beneath real SDK handles, refs and errors, with scripted commands, a virtual clock, fault controls and captured response shapes. A shared scenario manifest runs against the fake and live API.
|
|
9
|
+
|
|
10
|
+
- Add opt-in persistent workspace idle deletion retention, workspace/project setters and projected deletion times.
|
|
11
|
+
|
|
12
|
+
- Accelerate reverse tunnels with a bounded, acknowledged binary WebSocket stream, 64 KiB frames and batched credits. Select `auto`, `pty` or `exec` transport; reconnect preserves byte offsets. Opt-in binary PTY output accepts larger blocks for file transfers.
|
|
13
|
+
|
|
14
|
+
- Add opt-in resize controls to grow named resources only and return the held server answer without polling a pending operation.
|
|
15
|
+
- Expose typed stored workspace caps and preserve nullable grants. Fixed memory without an explicit size uses the template default.
|
|
16
|
+
|
|
17
|
+
- `WorkspaceRef.turn(fn, { afterSeconds: 0 })` and `Workspace.turn()` hint without waiting and request idle suspension when the body settles, including errors.
|
|
18
|
+
- Computer `act()` avoids an extra screenshot after `screenshot`/`zoom`. Viewer links are reused by kind with more than 60 seconds left; `fresh: true` remints, and `stopStream()` clears them.
|
|
19
|
+
- `computerToolset(ws, { beforeAction })` and `workspaceTools(ws, { computer: { beforeAction } })` check each action immediately before execution; refusal answers that action with an error and skips the rest.
|
|
20
|
+
- The default pooled transport honors environment HTTP(S) proxies and NO_PROXY. `SHARDFLUX_BASE_URL` aliases `SHARDFLUX_API_URL`, which takes precedence.
|
|
21
|
+
- Exec and execution results expose `exitCodePosix`. Missing cell file paths with `path_not_found` raise `FileNotFoundError`, distinct from workspace deletion and protocol errors.
|
|
22
|
+
- Embed live desktop viewers and port previews in a web app with an explicit HTTPS origin allowlist and partitioned browser sessions.
|
|
23
|
+
|
|
24
|
+
- Add `workspace.tunnels.reverse({ remotePort, target, bindAddress?, signal? })`: a private workspace TCP listener forwarded to this machine, with binary multiplexing, bounded backpressure, half-close, transport reconnection, suspend/resume, statistics and deterministic close.
|
|
25
|
+
|
|
26
|
+
- Add `ws.upgrade({ at })`, `upgradeAvailable` and `upgradePending`. An opt-in cold start preserves the workspace disk; `next_resume` schedules it. Lifecycle cold boot reasons include `upgraded`.
|
|
27
|
+
|
|
28
|
+
### Integration testing
|
|
29
|
+
|
|
30
|
+
## 0.15.0 — 2026-10-04
|
|
31
|
+
|
|
32
|
+
### Workspaces by key
|
|
33
|
+
|
|
34
|
+
Additive (contracts §46). A workspace named by its key, created on its first use, with no lifecycle code:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { workspace } from '@shardflux/sdk';
|
|
38
|
+
const run = await workspace('acme/thread-42', { template: 'default' }).exec('python3 -c "print(40 + 2)"');
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- `cloud.workspace(key, params)` and module-level `workspace(key, params)` return a `WorkspaceRef` without a request.
|
|
42
|
+
Its first call opens the key (one held request); concurrent first calls share it, a failed open is retried by the
|
|
43
|
+
next call, and a workspace deleted under the ref is opened again by the call after the one that met the deletion.
|
|
44
|
+
- `WorkspaceRef`: `exec(command)` (a string runs through `bash -lc`, an argv array without a shell), `files`,
|
|
45
|
+
`executions`, `tools()` (definitions from the key's grants before any VM; the first tool call opens), `open()` (the
|
|
46
|
+
`Workspace`), `cell()`, `hint()` (starts the open), `key`, `created`, `mode`. `create: false` never creates (404
|
|
47
|
+
`not_found` for an unknown key).
|
|
48
|
+
- `new Shardflux()` reads `SHARDFLUX_API_KEY` and `SHARDFLUX_API_URL` when `apiKey` / `baseUrl` are not passed.
|
|
49
|
+
- `workspace.created`: whether the `open()` that returned it created the workspace (the API's new `created` field).
|
|
50
|
+
- `template: 'default'` opens the platform default template (`python-node-browser`) on any client version.
|
|
51
|
+
- `workspaceTools()` takes a `ToolTarget`: a `Workspace` or a `WorkspaceRef`.
|
|
52
|
+
|
|
53
|
+
### Computer use
|
|
54
|
+
|
|
55
|
+
Additive. A desktop in the workspace that agents drive with screenshots, clicks and keystrokes (contracts §45).
|
|
56
|
+
|
|
57
|
+
- `workspace.computer`: `act(actions, { screenshot, settleMs, format, quality })` runs a batch of Claude's computer
|
|
58
|
+
toolset actions in order (the first failure stops it; the rest come back `skipped`), `screenshot()`, `status()`,
|
|
59
|
+
`start({ width, height })`, `stop()`, `stream({ interactive, ttlSeconds })` (a signed link to the viewer; it exposes
|
|
60
|
+
port 61002, or 61003 when interactive) and `stopStream()`.
|
|
61
|
+
- `computerToolset(workspace)` / `COMPUTER_TOOLSET`: answers Claude's `computer_toolset_20260801` calls of a model turn
|
|
62
|
+
with one batch; every `tool_result` echoes `toolset_name: "computer"`.
|
|
63
|
+
- `workspaceTools()` adds, when the token grants `computer`, the `computer` tool (one action per call) and
|
|
64
|
+
`computer_batch` (up to 50 actions in one call, with each action's result, a zoom's image and one screenshot after
|
|
65
|
+
them). Both take `screenshot: false`, `settle_ms`, and `format: "jpeg"` with `quality`.
|
|
66
|
+
- `open({ computerUse })`, `workspace.setComputerUse(true | false | null)`, `workspace.computerUse`,
|
|
67
|
+
`cloud.workspaces.setComputerUse(id, enabled)`. Tool tokens carry `computer` while the switch is on; a computer call
|
|
68
|
+
whose cached token predates the switch is sent again with a fresh token.
|
|
69
|
+
- `cloud.templates.setComputerUse(slug, enabled, { organizationId })` switches it for every workspace of one of your
|
|
70
|
+
templates. `ToolName` includes `computer`; template views carry `computer_use`.
|
|
71
|
+
|
|
72
|
+
## 0.14.0 — 2026-10-04
|
|
73
|
+
|
|
74
|
+
- Opt-in `workspaceTools(workspace, { prewake: true })` input-start hooks prepare VM tools while their input streams. Default tools, offline reads and file-first workspaces install no hook.
|
|
11
75
|
|
|
12
76
|
### Sign up from an agent
|
|
13
77
|
|
|
@@ -117,7 +181,7 @@ gives a static allocation of `memory_mib`. Reopening an existing workspace with
|
|
|
117
181
|
keeps its stored mode; a fork without caps inherits its source's. The SDK's requests do not change;
|
|
118
182
|
`workspace.memory` and `workspace.allocationMode` report the mode the workspace got.
|
|
119
183
|
|
|
120
|
-
## 0.13.1
|
|
184
|
+
## 0.13.1 — 2026-10-03
|
|
121
185
|
|
|
122
186
|
Patch, additive: the transport, a documented value, a fix for tool calls across a move and self-healing workspaces.
|
|
123
187
|
`@shardflux/cli` 0.8.1, `@shardflux/mcp` 0.7.1 and the `shardflux` bundle 0.10.1 follow (`^0.13.1`).
|
|
@@ -174,7 +238,7 @@ failing with `409 conflict` (`workspace_not_running`).
|
|
|
174
238
|
runs; new token)`.
|
|
175
239
|
- The CLI, the MCP server and the `shardflux` bundle get it through their `^0.13.0` dependency.
|
|
176
240
|
|
|
177
|
-
## 0.13.0
|
|
241
|
+
## 0.13.0 — 2026-10-02
|
|
178
242
|
|
|
179
243
|
### Elastic memory
|
|
180
244
|
|
|
@@ -284,14 +348,12 @@ template's newest published version, picked up at its next cold boot or resume.
|
|
|
284
348
|
- The cancel that `exec.run` sends when its `signal` aborts passes `killGraceMs` capped at 60000, so a larger
|
|
285
349
|
`killGraceMs` still cancels the command.
|
|
286
350
|
|
|
287
|
-
## 0.12.0
|
|
351
|
+
## 0.12.0 — 2026-09-30
|
|
288
352
|
|
|
289
353
|
Completed exec output streams are drained before releasing their HTTP connections, with a bounded cleanup if a peer does not close.
|
|
290
354
|
|
|
291
355
|
Pooled HTTP/1.1 on Node 26 with pinned undici 8.10.2; custom fetch stays unchanged. Labels on open/list and setLabels, typed idle(), keepalive() and setIdlePolicy(). Protocol errors carry source; isWorkspaceGone recognizes only an explicit API workspace_deleted refusal. Exec sessions accept stdin_open and offset-addressed exec.input. Failed workspaces recover through resume/auto-wake with the same ID. Completed deletions free keys for new IDs.
|
|
292
356
|
|
|
293
|
-
Requires the QM integration backend release for labels, failed recovery, key reuse and pipe stdin. No production deployment has occurred from this branch.
|
|
294
|
-
|
|
295
357
|
### Instant suspend: durable storage in the result
|
|
296
358
|
|
|
297
359
|
Additive. A suspend returns as soon as the workspace is sealed on its host; the copy lands in durable storage right
|
|
@@ -316,7 +378,7 @@ after. This release reads that from the result and can wait for it.
|
|
|
316
378
|
Requires the instant-suspend cell release for `durable: false` results; against other servers every succeeded suspend
|
|
317
379
|
is already durable and `durable: true` resolves at once.
|
|
318
380
|
|
|
319
|
-
## 0.11.1
|
|
381
|
+
## 0.11.1 — 2026-09-30
|
|
320
382
|
|
|
321
383
|
Wording: messages and JSDoc say what to do, without internals (no behaviour change).
|
|
322
384
|
|
|
@@ -330,7 +392,7 @@ Wording: messages and JSDoc say what to do, without internals (no behaviour chan
|
|
|
330
392
|
`SHARDFLUX_HTTP_KEEPALIVE=1`.
|
|
331
393
|
- The `formatTiming()` example is a production resume (413 ms).
|
|
332
394
|
|
|
333
|
-
## 0.11.0
|
|
395
|
+
## 0.11.0 — 2026-09-29
|
|
334
396
|
|
|
335
397
|
### A resume that restarted processes says so (cold boot)
|
|
336
398
|
|
|
@@ -353,17 +415,17 @@ the resume's result through; this release reads it.
|
|
|
353
415
|
- The new `ServerTiming` fields are optional in the type (always set by the SDK), so timings built by hand still
|
|
354
416
|
type-check. No return type or behaviour changes: a wake that cold-booted still resolves `true`.
|
|
355
417
|
|
|
356
|
-
## 0.10.2
|
|
418
|
+
## 0.10.2 — 2026-09-29
|
|
357
419
|
|
|
358
420
|
Fix: the SDK reports 0.10.2. 0.10.1 was published reporting 0.10.0, its previous version; the build now
|
|
359
421
|
fails when `SDK_VERSION` differs from package.json.
|
|
360
422
|
|
|
361
|
-
## 0.10.1
|
|
423
|
+
## 0.10.1 — 2026-09-29
|
|
362
424
|
|
|
363
425
|
Public support: package metadata and the README now link to the [shared bug tracker](https://github.com/shardfluxdev/community/issues),
|
|
364
426
|
feature requests, and private support/security reporting.
|
|
365
427
|
|
|
366
|
-
## 0.10.0
|
|
428
|
+
## 0.10.0 — 2026-09-29
|
|
367
429
|
|
|
368
430
|
### A command that could not start rejects exec.run() (ExecStartError)
|
|
369
431
|
|
|
@@ -411,7 +473,7 @@ from the API's OpenAPI); the account client's `setSpendPolicy()` gains the overa
|
|
|
411
473
|
|
|
412
474
|
- `workspace.suspendWhenIdle({ afterSeconds, idempotencyKey? })` and `cloud.workspaces.suspendWhenIdle(id, {
|
|
413
475
|
afterSeconds })` (POST /v1/workspaces/{id}/suspend-when-idle): the workspace is suspended once it has been idle for
|
|
414
|
-
`afterSeconds` (30..3600), counted from the later of its last work and the request. Meant for the end of an agent
|
|
476
|
+
`afterSeconds` (0..3600 since the 2026-09-30 API release, commit `2b2f5e658`; originally 30..3600), counted from the later of its last work and the request. Meant for the end of an agent
|
|
415
477
|
turn. A running command, an attached stream or a keepalive postpones it; the next tool call or a resume cancels it.
|
|
416
478
|
Resolves with `{ suspendRequest, operation, workspace }`: `operation` is the suspend already in progress, if any
|
|
417
479
|
(then nothing is recorded).
|
|
@@ -421,7 +483,7 @@ from the API's OpenAPI); the account client's `setSpendPolicy()` gains the overa
|
|
|
421
483
|
count as the next turn and cancel the request.
|
|
422
484
|
- Types `SuspendRequest`, `SuspendWhenIdleOptions`, `SuspendWhenIdleResult`, `SuspendWhenIdleResponse`.
|
|
423
485
|
|
|
424
|
-
## 0.9.0
|
|
486
|
+
## 0.9.0 — 2026-09-29
|
|
425
487
|
|
|
426
488
|
Elastic compute (decision 0007): file tools and wake hints for parked workspaces. Additive; older APIs and cell
|
|
427
489
|
gateways keep working (the new calls answer 404 there).
|
|
@@ -617,7 +679,7 @@ behavior is the automatic version check (below), which makes one background requ
|
|
|
617
679
|
- New exports: `FeedbackCategory`, `FeedbackContext`, `FeedbackReceipt`, `SendFeedbackParams`, `AccountFeedbackParams`,
|
|
618
680
|
`FEEDBACK_CATEGORIES`, `FEEDBACK_MESSAGE_MAX_LENGTH`.
|
|
619
681
|
|
|
620
|
-
## 0.8.0
|
|
682
|
+
## 0.8.0 — 2026-09-28
|
|
621
683
|
|
|
622
684
|
Types only; nothing changes at run time and the API is unchanged.
|
|
623
685
|
|
|
@@ -637,7 +699,7 @@ Types only; nothing changes at run time and the API is unchanged.
|
|
|
637
699
|
- Checked at compile time against `@anthropic-ai/sdk` 0.128.0 and `openai` 7.23.0 (devDependencies only; the SDK still
|
|
638
700
|
has no runtime dependencies).
|
|
639
701
|
|
|
640
|
-
## 0.7.0
|
|
702
|
+
## 0.7.0 — 2026-09-28
|
|
641
703
|
|
|
642
704
|
Needs an API with the template editor; every new field is additive and older fields are unchanged.
|
|
643
705
|
|
|
@@ -725,7 +787,7 @@ docs/decisions/0006-tool-call-capture.md (shared with the Python SDK 0.3.0).
|
|
|
725
787
|
- **Breaking (types only):** `LifecyclePhase` gains `capture_flush`; an exhaustive `switch` over phases without a
|
|
726
788
|
`default` case needs the new member.
|
|
727
789
|
|
|
728
|
-
## 0.6.2
|
|
790
|
+
## 0.6.2 — 2026-09-28
|
|
729
791
|
|
|
730
792
|
### Starts that wait for capacity end
|
|
731
793
|
|
|
@@ -740,7 +802,7 @@ boot (and bill) long after every wait had given up.
|
|
|
740
802
|
- `onProgress`: a `capacity_pending` `phase` event carries `deadlineAt` when the API reports it.
|
|
741
803
|
- Docs: waits no longer say a pending start continues indefinitely.
|
|
742
804
|
|
|
743
|
-
## 0.6.1
|
|
805
|
+
## 0.6.1 — 2026-09-28
|
|
744
806
|
|
|
745
807
|
- `formatTiming()` joined two phases that followed each other with `∥` (ran together) when their 0.1 ms times summed
|
|
746
808
|
with a floating-point error (1000.2 + 300.1 > 1300.3); it now prints `→`.
|
|
@@ -750,7 +812,7 @@ boot (and bill) long after every wait had given up.
|
|
|
750
812
|
belonged to no phase (a 1 s wait could show `queued 0 ms`).
|
|
751
813
|
- README: the timing example is the formatter's real output (durations under a second print in ms).
|
|
752
814
|
|
|
753
|
-
## 0.6.0
|
|
815
|
+
## 0.6.0 — 2026-09-28
|
|
754
816
|
|
|
755
817
|
### Lifecycle calls: requested or finished
|
|
756
818
|
|
|
@@ -801,7 +863,7 @@ boot (and bill) long after every wait had given up.
|
|
|
801
863
|
create, capture state, test instances, publish, discard).
|
|
802
864
|
- `ShardfluxApiError.reason` (`details.reason`), with `KnownErrorReason`.
|
|
803
865
|
|
|
804
|
-
## 0.5.0
|
|
866
|
+
## 0.5.0 — 2026-09-26
|
|
805
867
|
|
|
806
868
|
First public release: `Shardflux` client, `workspaces.open/get/list/listAll`, lifecycle calls returning operations,
|
|
807
869
|
`waitForOperation()`, the cell client (`exec`, `files`, `pty`, `processes`, `git`, `browser`), `workspaceTools()` with
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @shardflux/sdk
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for [Shardflux](https://shardflux.dev):
|
|
3
|
+
TypeScript SDK for [Shardflux](https://shardflux.dev): serverless VMs for AI agents.
|
|
4
4
|
|
|
5
5
|
Open a persistent workspace by key, run commands and move files in it, suspend it when idle, resume
|
|
6
6
|
it later with its disk and memory intact, and fork it. Hand your agent framework-neutral workspace
|
|
@@ -10,8 +10,9 @@ tool calls into the workspace ([tool-call capture](#tool-call-capture-070)).
|
|
|
10
10
|
> **Compatibility.** The API is versioned (`/v1`). Breaking changes ship only in minor releases and are marked
|
|
11
11
|
> **Breaking** in the changelog (see [Compatibility](#compatibility)).
|
|
12
12
|
|
|
13
|
-
> **Versions.** This README describes 0.
|
|
14
|
-
> **(0.
|
|
13
|
+
> **Versions.** This README describes 0.15.0. Anything marked **(0.15.0+)** is not in 0.14.x, **(0.14.0+)** not in 0.13.x,
|
|
14
|
+
> **(0.13.0+)** not in 0.12.x, **(0.12.0+)** not in 0.11.x, **(0.11.0+)** not in 0.10.x, **(0.10.0+)** not in 0.9.0, **(0.9.0+)** not in 0.8.x,
|
|
15
|
+
> **(0.8.0+)** not in 0.7.x, **(0.7.0+)** not in 0.6.x and **(0.6.0+)** not in 0.5.0; [CHANGELOG.md](./CHANGELOG.md) lists what each version added. Check yours with
|
|
15
16
|
> `npm ls @shardflux/sdk` or the exported `SDK_VERSION`.
|
|
16
17
|
|
|
17
18
|
- ESM only, Node.js 24 or later. Reading a YAML template file uses the optional peer
|
|
@@ -19,6 +20,34 @@ tool calls into the workspace ([tool-call capture](#tool-call-capture-070)).
|
|
|
19
20
|
- Typed from the published OpenAPI documents.
|
|
20
21
|
- Retries, idempotency keys, operation polling and tool-token refresh are handled for you.
|
|
21
22
|
|
|
23
|
+
## Test your integration (0.16.0+)
|
|
24
|
+
|
|
25
|
+
Use the same client calls in fast, isolated tests with `@shardflux/sdk/testing`:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { createFakeShardflux } from '@shardflux/sdk/testing';
|
|
29
|
+
|
|
30
|
+
const cloud = createFakeShardflux({
|
|
31
|
+
onExec: (request) => ({ stdout: `ran ${request.argv.join(' ')}\n`, exitCode: 0 }),
|
|
32
|
+
});
|
|
33
|
+
const ref = cloud.workspace('acme/test', { template: 'python-node-browser' });
|
|
34
|
+
const result = await ref.exec(['python3', '-V'], { sessionId: 'version-check' });
|
|
35
|
+
await ref.files.write('/home/user/result.txt', result.stdout);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The fake returns real SDK workspace handles, refs and errors. Workspace lifecycle calls, labels, paginated lists,
|
|
39
|
+
files, command output, desktop actions and port lists use an isolated in-memory store. Command results come from
|
|
40
|
+
`onExec`; returning `null` leaves a command running for `cloud.testing.completeCommand(id, sessionId, result)`.
|
|
41
|
+
Unscripted commands and unimplemented routes raise `FakeUnsupportedError`.
|
|
42
|
+
|
|
43
|
+
Control state with `cloud.testing.setFaults(id, { busy: true, failed: true, legacyLayout: true })`,
|
|
44
|
+
`computerUnavailable`, `deleted`, `resizeRefusal` (`shrink_not_supported` or `resize_not_available`), and
|
|
45
|
+
`memoryLimitMib` (a plan clamp). Set `cloud.testing.quota` to `retained_state` or `concurrent_workspaces`.
|
|
46
|
+
`cloud.testing.advance(milliseconds)` drives idle deadlines; `latencyMs` and `sleep` inject request latency.
|
|
47
|
+
`cloud.testing.inspect(id)` returns a copy of the raw workspace view. Each fake has its own state.
|
|
48
|
+
Import the testing subpath when building tests; the main SDK entry keeps its existing runtime dependencies.
|
|
49
|
+
|
|
50
|
+
|
|
22
51
|
## Support and bug reports
|
|
23
52
|
|
|
24
53
|
[Report a bug](https://github.com/shardfluxdev/community/issues/new?template=bug_report.yml) or
|
|
@@ -30,6 +59,29 @@ For usage, account, billing, or private support, email [shardflux@heliosone.fi](
|
|
|
30
59
|
Report vulnerabilities through [private security reporting](https://github.com/shardfluxdev/community/security/advisories/new).
|
|
31
60
|
See the [support guide](https://github.com/shardfluxdev/community/blob/main/SUPPORT.md) for all reporting options.
|
|
32
61
|
|
|
62
|
+
## Reverse tunnels (0.16.0+)
|
|
63
|
+
|
|
64
|
+
Forward a workspace TCP port to a service on the machine running your SDK:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
const tunnel = await workspace.tunnels.reverse({ remotePort: 8081, target: 'localhost:8081' });
|
|
68
|
+
try {
|
|
69
|
+
// Commands in the workspace can call http://127.0.0.1:8081.
|
|
70
|
+
console.log(tunnel.stats);
|
|
71
|
+
} finally {
|
|
72
|
+
await tunnel.close();
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The guest listener binds to `127.0.0.1` by default; `bindAddress: '0.0.0.0'` selects all guest interfaces.
|
|
77
|
+
The target is dialed from this machine. TCP binary data, concurrent connections and half-close are preserved;
|
|
78
|
+
network reconnection resumes the tunnel while the handle is open. `closed` reports completion or failure,
|
|
79
|
+
`sessionId` identifies the forwarder, and `stats` counts connections, bytes in each direction and reconnects.
|
|
80
|
+
An open tunnel keeps the workspace awake; close it when callbacks are finished. For persistent workspaces, explicit suspend/resume preserves
|
|
81
|
+
an open tunnel. The caller needs `exec` and `files` access.
|
|
82
|
+
|
|
83
|
+
The tunnel selects a streaming transport automatically when `pty` permission is granted. Choose `transport: 'pty'` or `transport: 'exec'` in the SDK, or `--transport pty|exec` in the CLI, to select it explicitly. The handle reports `transport`.
|
|
84
|
+
|
|
33
85
|
## Install
|
|
34
86
|
|
|
35
87
|
```sh
|
|
@@ -41,6 +93,33 @@ npm install @shardflux/sdk
|
|
|
41
93
|
Create a project API key in the Shardflux console (`sfk_<key id>_<secret>`) and keep it on the
|
|
42
94
|
server. API keys are server credentials: never put one in a browser bundle.
|
|
43
95
|
|
|
96
|
+
```ts
|
|
97
|
+
import { workspace } from '@shardflux/sdk';
|
|
98
|
+
|
|
99
|
+
const ws = workspace('customer-42/main', { template: 'default' }); // reads SHARDFLUX_API_KEY; no request yet
|
|
100
|
+
|
|
101
|
+
// 1. Run a command: the first call creates the workspace. Check that it worked.
|
|
102
|
+
const run = await ws.exec('python3 -c "print(40 + 2)"');
|
|
103
|
+
if (run.exitCode !== 0) throw new Error(`python3 exited ${run.exitCode}: ${run.stderr}`);
|
|
104
|
+
console.log(run.stdout.trim()); // 42
|
|
105
|
+
|
|
106
|
+
// 2. Write a file, then suspend the workspace and wait until the suspend has finished.
|
|
107
|
+
await ws.files.write('/home/user/notes.txt', 'hello from the SDK\n');
|
|
108
|
+
await (await ws.open()).suspend({ wait: true }); // resolves once suspended
|
|
109
|
+
|
|
110
|
+
// 3. The same key again: the workspace wakes, and the file is still there.
|
|
111
|
+
const again = workspace('customer-42/main', { template: 'default' });
|
|
112
|
+
console.log(await again.files.readText('/home/user/notes.txt')); // hello from the SDK
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The key names the workspace **(0.15.0+)**: the first call creates it, later calls (from any process) reuse it, and it
|
|
116
|
+
suspends when idle and wakes on the next call with its files, packages and processes. There is no create call and no
|
|
117
|
+
lifecycle code to write. See [Workspaces by key](#workspaces-by-key-0150).
|
|
118
|
+
|
|
119
|
+
### Open, suspend and resume
|
|
120
|
+
|
|
121
|
+
The same workspace with every step explicit:
|
|
122
|
+
|
|
44
123
|
```ts
|
|
45
124
|
import { Shardflux, formatTiming } from '@shardflux/sdk';
|
|
46
125
|
|
|
@@ -70,6 +149,48 @@ installed packages and running processes are still there. The same program is in
|
|
|
70
149
|
With 0.5.0, wait for the suspend by its operation instead:
|
|
71
150
|
`await cloud.workspaces.waitForOperation((await workspace.suspend()).id)`.
|
|
72
151
|
|
|
152
|
+
## Workspaces by key (0.15.0+)
|
|
153
|
+
|
|
154
|
+
`workspace(key, params)` (or `cloud.workspace(key, params)` on your own client) names a workspace by the identifier your
|
|
155
|
+
application already has: a user, a thread, a repository, a customer. It makes no request. Its first call opens the key:
|
|
156
|
+
the workspace is created from `params.template` on first use and resumed afterwards, in one request that also brings
|
|
157
|
+
back its tool token. Later calls go straight to the workspace.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { workspace } from '@shardflux/sdk';
|
|
161
|
+
|
|
162
|
+
const ws = workspace(`acme/${threadId}`, { template: 'default' });
|
|
163
|
+
|
|
164
|
+
await ws.exec('pip install requests && python3 app.py'); // a string runs through bash -lc
|
|
165
|
+
await ws.exec(['python3', '-c', 'print(42)']); // an argv array runs without a shell
|
|
166
|
+
await ws.files.write('/home/user/notes.txt', 'hello\n');
|
|
167
|
+
console.log(await ws.files.readText('/home/user/notes.txt'));
|
|
168
|
+
|
|
169
|
+
ws.created; // true when this ref's open created the workspace
|
|
170
|
+
const full = await ws.open(); // the Workspace: suspend, fork, ports, computer, capture
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
- `params` are `open()`'s without the key: `template` is required (`'default'` is the platform default template,
|
|
174
|
+
`python-node-browser`), plus `secrets`, `inputs`, `caps`, `labels`, `idlePolicy`, `lifetime`, `computerUse`,
|
|
175
|
+
`agentLabel`, `tools`.
|
|
176
|
+
- Calls made while the first open runs share it. A failed open is not kept: the next call opens again.
|
|
177
|
+
- `create: false` never creates: the first call finds the key's workspace and fails with 404 `not_found` when it has
|
|
178
|
+
none.
|
|
179
|
+
- A workspace deleted under the ref (`isWorkspaceGone(err)`, 409 `workspace_deleted`) fails the call that meets it;
|
|
180
|
+
the next call opens the key again, which creates a new workspace.
|
|
181
|
+
- `ws.hint()` starts the open early, for example when your model starts a tool call.
|
|
182
|
+
|
|
183
|
+
**In an agent.** The tools exist before the workspace does; the model's first tool call creates it:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { toAnthropicTools, executeToolCall, workspace } from '@shardflux/sdk';
|
|
187
|
+
|
|
188
|
+
const tools = await workspace(`acme/${threadId}`, { template: 'default' }).tools(); // reads the key's grants
|
|
189
|
+
const anthropicTools = toAnthropicTools(tools);
|
|
190
|
+
// for each tool_use block the model returns:
|
|
191
|
+
const output = await executeToolCall(tools, block);
|
|
192
|
+
```
|
|
193
|
+
|
|
73
194
|
## Configuration
|
|
74
195
|
|
|
75
196
|
```ts
|
|
@@ -82,8 +203,9 @@ const cloud = new Shardflux({
|
|
|
82
203
|
});
|
|
83
204
|
```
|
|
84
205
|
|
|
85
|
-
|
|
86
|
-
|
|
206
|
+
`new Shardflux()` with no `apiKey` reads `SHARDFLUX_API_KEY`, and with no `baseUrl` reads `SHARDFLUX_API_URL`
|
|
207
|
+
**(0.15.0+)**; options you pass win. A missing key throws when the client is created. The module-level `workspace()`
|
|
208
|
+
uses such a client, created on its first call.
|
|
87
209
|
|
|
88
210
|
## Commands and files
|
|
89
211
|
|
|
@@ -451,6 +573,53 @@ const hook = await ws.ports.createCallbackUrl(3000); // register `${h
|
|
|
451
573
|
- `close(port)` stops the port's tokens, links and callback URL at once (also when the port is exposed again).
|
|
452
574
|
- By id, without reading the workspace: `cloud.workspaces.ports(id)`.
|
|
453
575
|
|
|
576
|
+
### Computer use (0.15.0+)
|
|
577
|
+
|
|
578
|
+
A desktop in the workspace for agents that operate GUI software: a screen, a mouse and a keyboard. Switch it on for a
|
|
579
|
+
workspace (or for every workspace of your template); the platform starts the desktop on the first call that needs it.
|
|
580
|
+
|
|
581
|
+
```ts
|
|
582
|
+
const ws = await cloud.workspaces.open({ key: 'agent/42', template: 'python-node-browser', computerUse: true });
|
|
583
|
+
|
|
584
|
+
const shot = await ws.computer.screenshot(); // { format: 'png', width: 1280, height: 800, data }
|
|
585
|
+
await ws.computer.act([
|
|
586
|
+
{ action: 'left_click', coordinate: [640, 400] },
|
|
587
|
+
{ action: 'type', text: 'hello' },
|
|
588
|
+
{ action: 'key', text: 'Return' },
|
|
589
|
+
], { screenshot: true }); // one round trip for the whole batch and a look
|
|
590
|
+
|
|
591
|
+
const { url } = await ws.computer.stream(); // a private link to watch the screen live
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
With Claude, answer the computer toolset directly:
|
|
595
|
+
|
|
596
|
+
```ts
|
|
597
|
+
import { computerToolset } from '@shardflux/sdk';
|
|
598
|
+
|
|
599
|
+
const computer = computerToolset(ws);
|
|
600
|
+
const msg = await anthropic.messages.create({ model: 'claude-opus-5-5', max_tokens: 16000, tools: [computer.definition], messages });
|
|
601
|
+
messages.push({ role: 'assistant', content: msg.content });
|
|
602
|
+
messages.push({ role: 'user', content: await computer.run(msg.content) });
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
- The actions are Claude's computer toolset members with their parameters: `screenshot`, `zoom`, `left_click`,
|
|
606
|
+
`right_click`, `middle_click`, `double_click`, `triple_click`, `left_click_drag`, `mouse_move`, `left_mouse_down`,
|
|
607
|
+
`left_mouse_up`, `cursor_position`, `scroll`, `type`, `key`, `hold_key`, `wait`. A batch runs in order and stops at
|
|
608
|
+
the first failure; later actions come back `skipped`.
|
|
609
|
+
- `computer.run(content)` sends every computer call of a model turn as one batch and returns one `tool_result` per call
|
|
610
|
+
(each with `toolset_name: "computer"`), with a screenshot on the last one when the turn did not end with a look.
|
|
611
|
+
- `workspaceTools()` includes, for any model while the workspace's computer use is on, a `computer` tool (one action
|
|
612
|
+
per call, answered with a screenshot) and `computer_batch` (several actions in one call, with each action's result
|
|
613
|
+
and one screenshot after them). Both take `screenshot: false` to skip the image, `settle_ms`, and `format: "jpeg"`
|
|
614
|
+
with `quality` for smaller images.
|
|
615
|
+
- `act(actions, { screenshot, settleMs, format, quality })` takes the same options.
|
|
616
|
+
- Commands the agent runs see the desktop: `exec` of `chromium https://example.com &` opens the browser on it.
|
|
617
|
+
- `stream({ interactive })` returns a signed link (view only by default; `interactive: true` lets the viewer use the
|
|
618
|
+
mouse and keyboard); `stopStream()` ends every view. Streaming uses inbound ports.
|
|
619
|
+
- `ws.setComputerUse(true | false | null)` sets the workspace's own switch (null follows the template);
|
|
620
|
+
`ws.computerUse` reads `{ enabled, workspace, template, available }`. `status()`, `start({ width, height })` and
|
|
621
|
+
`stop()` manage the desktop directly.
|
|
622
|
+
|
|
454
623
|
### Timing and progress (0.6.0+)
|
|
455
624
|
|
|
456
625
|
Every open, wake and waited lifecycle call is traced. `workspace.lastTiming` (and `err.timing` when the call fails)
|
|
@@ -710,7 +879,9 @@ it: add paths, never remove them. A build reports the list its version declares
|
|
|
710
879
|
## Agent tools
|
|
711
880
|
|
|
712
881
|
`workspaceTools(workspace)` returns tools with a name, a description, a JSON Schema for the
|
|
713
|
-
parameters and an `execute` function.
|
|
882
|
+
parameters and an `execute` function. It takes a `Workspace` or **(0.15.0+)** a `WorkspaceRef`, whose
|
|
883
|
+
`await ref.tools(opts)` builds them from the API key's grants before the workspace exists (see
|
|
884
|
+
[Workspaces by key](#workspaces-by-key-0150)). Export them for your model provider and dispatch its tool
|
|
714
885
|
calls:
|
|
715
886
|
|
|
716
887
|
```ts
|
|
@@ -735,7 +906,8 @@ Your agent loop and model calls stay in your application; the workspace is the c
|
|
|
735
906
|
act on.
|
|
736
907
|
|
|
737
908
|
The tools are `exec`, `read_file`, `write_file`, `list_files`, `search_files` and `edit_file` (0.9.0+), the process,
|
|
738
|
-
terminal, git and browser tools,
|
|
909
|
+
terminal, git and browser tools, and `computer` (0.15.0+, while the workspace's computer use is on), filtered by the
|
|
910
|
+
tools your key grants. `edit_file` replaces exact text; when the
|
|
739
911
|
model passes no `expected_revision` it reads the file's revision first, so a change made in between fails the edit
|
|
740
912
|
instead of being overwritten. Each call first sends `workspace.hint()` without waiting for it (`hint: false` turns
|
|
741
913
|
that off, e.g. when you send the hint yourself as the model starts a tool call), except `read_file`, `list_files` and
|
|
@@ -1209,3 +1381,50 @@ const tools = workspaceTools(workspace, { prewake: true });
|
|
|
1209
1381
|
// In your model stream's tool-input-start handler:
|
|
1210
1382
|
tools.find(tool => tool.name === toolName)?.onInputStart?.();
|
|
1211
1383
|
```
|
|
1384
|
+
|
|
1385
|
+
Resize controls (0.16.0+): `workspace.resize({ memoryMib: 6144, diskGib: 2, atLeast: true, wait: false })` grows
|
|
1386
|
+
only resources that need more capacity and returns the held server answer with its operation. `workspace.caps` exposes
|
|
1387
|
+
typed stored caps for later starts. A pending operation carries per-resource results once the resize has decided
|
|
1388
|
+
them. Fixed memory without `memory_mib` uses the template default, bounded by the plan and template.
|
|
1389
|
+
|
|
1390
|
+
## New in 0.16.0
|
|
1391
|
+
|
|
1392
|
+
`ref.turn(async (ref) => { ... })` (also `workspace.turn`) sends a wake hint without waiting, returns the body's result, and requests `suspendWhenIdle({ afterSeconds: 0 })` when it settles, including on error. Pass `{ afterSeconds: 60 }` to keep the workspace warm for a billed minute. Use persistent workspaces for resumable turns.
|
|
1393
|
+
|
|
1394
|
+
Computer batches ending in `screenshot` or `zoom` return that action's image without an extra screenshot. `computer.stream()` reuses a link of the same kind with more than 60 seconds left; `{ fresh: true }` mints one, and `stopStream()` clears the cache. Gate each action with `computerToolset(ws, { beforeAction })` or `workspaceTools(ws, { computer: { beforeAction } })`: return `false`, a refusal string, or throw to answer that action with an error and skip the remaining actions. Hooks may be async.
|
|
1395
|
+
|
|
1396
|
+
Exec results expose `exitCodePosix`: timeout 124, canceled 130, nonnegative exit code, 128 + signal, otherwise 1. `FileNotFoundError` is a `ShardfluxApiError` for cell `path_not_found` replies. The default transport honors `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` and `NODE_USE_ENV_PROXY`. `SHARDFLUX_BASE_URL` aliases `SHARDFLUX_API_URL`; `SHARDFLUX_API_URL` wins.
|
|
1397
|
+
|
|
1398
|
+
## Embed a live viewer (0.16.0+)
|
|
1399
|
+
|
|
1400
|
+
Watch the desktop or a port preview inside your web app. Choose 1–10 distinct HTTPS origins, then use the returned URL as the iframe source.
|
|
1401
|
+
|
|
1402
|
+
```ts
|
|
1403
|
+
const { url } = await ws.computer.stream({ embed: { origins: ['https://app.example.com'] } });
|
|
1404
|
+
const preview = await ws.ports.link(3000, { embed: { origins: ['https://app.example.com'] } });
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
```html
|
|
1408
|
+
<iframe src="RETURNED_LINK_URL" title="Watch the agent" style="width:100%;height:600px;border:0"></iframe>
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
The browser session is partitioned by the top-level site. Each origin is exactly a scheme and host with an optional port, such as `https://app.example.com:8443`. The viewer permits framing by those origins; interactive viewing uses the same allowlist.
|
|
1412
|
+
|
|
1413
|
+
## Idle deletion retention (0.16.0+)
|
|
1414
|
+
|
|
1415
|
+
Keep one persistent workspace per conversation and delete it automatically after 14 idle days:
|
|
1416
|
+
|
|
1417
|
+
```ts
|
|
1418
|
+
const ws = await cloud.workspaces.open({ key: 'chat/42', template: 'python-node-browser', retention: { delete_after_idle_days: 14 } });
|
|
1419
|
+
await ws.setRetention({ delete_after_idle_days: 30 });
|
|
1420
|
+
await cloud.projects.setRetention((await cloud.me()).api_key!.project_id, { delete_after_idle_days: 14, labels: { app: 'chat' } });
|
|
1421
|
+
await ws.setRetention(null); // follow the project default
|
|
1422
|
+
```
|
|
1423
|
+
|
|
1424
|
+
`cloud.workspace(key, { template, retention })` accepts the same policy. `ws.retention` shows its effective days
|
|
1425
|
+
and projected `delete_at`. All project selector labels must match exactly; a workspace's own policy wins.
|
|
1426
|
+
Calls and ongoing work postpone deletion. Without a policy, your workspace stays until you delete it.
|
|
1427
|
+
|
|
1428
|
+
## Workspace upgrade (0.16.0+)
|
|
1429
|
+
|
|
1430
|
+
`await ws.upgrade({ at: "now", wait: true })` keeps files, installed package files and home while cold starting on the supported current layout and base. `at: "next_resume"` schedules it for the next resume. Memory and running processes end at the cold start. Read `ws.upgradeAvailable` and `ws.upgradePending` for the target.
|
package/dist/account.d.ts
CHANGED
|
@@ -277,6 +277,8 @@ export declare class AccountProjectsApi {
|
|
|
277
277
|
name: string;
|
|
278
278
|
slug?: string;
|
|
279
279
|
}): Promise<Project>;
|
|
280
|
+
getRetention(projectId: string): Promise<import('./client.js').ProjectRetentionPolicy | null>;
|
|
281
|
+
setRetention(projectId: string, policy: import('./client.js').ProjectRetentionPolicy | null): Promise<import('./client.js').ProjectRetentionPolicy | null>;
|
|
280
282
|
get(projectId: string): Promise<Project>;
|
|
281
283
|
}
|
|
282
284
|
/** Every tool permission an API key can carry (pass it as `toolPermissions` for a key with every tool). */
|
package/dist/account.js
CHANGED
|
@@ -280,6 +280,12 @@ export class AccountProjectsApi {
|
|
|
280
280
|
create(organizationId, params) {
|
|
281
281
|
return json(this.#core, 'POST', `/v1/organizations/${enc(organizationId)}/projects`, { json: { name: params.name, ...(params.slug === undefined ? {} : { slug: params.slug }) } });
|
|
282
282
|
}
|
|
283
|
+
getRetention(projectId) {
|
|
284
|
+
return json(this.#core, 'GET', `/v1/projects/${enc(projectId)}/retention`);
|
|
285
|
+
}
|
|
286
|
+
setRetention(projectId, policy) {
|
|
287
|
+
return json(this.#core, 'PUT', `/v1/projects/${enc(projectId)}/retention`, { json: policy });
|
|
288
|
+
}
|
|
283
289
|
get(projectId) {
|
|
284
290
|
return json(this.#core, 'GET', `/v1/projects/${enc(projectId)}`);
|
|
285
291
|
}
|
package/dist/cell.d.ts
CHANGED
|
@@ -147,6 +147,16 @@ export type GitCommitRequest = S['GitCommitRequest'];
|
|
|
147
147
|
export type GitResult = S['GitResult'];
|
|
148
148
|
export type GitStatus = S['GitStatus'];
|
|
149
149
|
export type BrowserScreenshotRequest = S['BrowserScreenshotRequest'];
|
|
150
|
+
/** Contracts §45 (0.15.0+): the workspace desktop. */
|
|
151
|
+
export type ComputerAction = S['ComputerAction'];
|
|
152
|
+
export type ComputerActionName = ComputerAction['action'];
|
|
153
|
+
export type ComputerActionsRequest = S['ComputerActionsRequest'];
|
|
154
|
+
export type ComputerActionsResult = S['ComputerActionsResult'];
|
|
155
|
+
export type ComputerActionResult = S['ComputerActionResult'];
|
|
156
|
+
export type ComputerImage = S['ComputerImage'];
|
|
157
|
+
export type ComputerStatus = S['ComputerStatus'];
|
|
158
|
+
export type ComputerStartRequest = S['ComputerStartRequest'];
|
|
159
|
+
export type ComputerStreamInfo = S['ComputerStream'];
|
|
150
160
|
export type BrowserContentRequest = S['BrowserContentRequest'];
|
|
151
161
|
export type BrowserContent = S['BrowserContent'];
|
|
152
162
|
export type Signal = S['SignalValue'];
|
|
@@ -238,6 +248,8 @@ export declare const CAPTURE_BARRIER: unique symbol;
|
|
|
238
248
|
export interface RunResult {
|
|
239
249
|
sessionId: string;
|
|
240
250
|
exitCode: number | null;
|
|
251
|
+
/** POSIX status: timeout 124, canceled 130, exit code, 128 + signal, otherwise 1. */
|
|
252
|
+
exitCodePosix: number;
|
|
241
253
|
termSignal: number | null;
|
|
242
254
|
timedOut: boolean;
|
|
243
255
|
canceled: boolean;
|
|
@@ -530,6 +542,21 @@ export declare class CellClient {
|
|
|
530
542
|
status: (path: string) => Promise<GitStatus>;
|
|
531
543
|
commit: (req: GitCommitRequest) => Promise<GitResult>;
|
|
532
544
|
};
|
|
545
|
+
readonly computer: {
|
|
546
|
+
status: () => Promise<ComputerStatus>;
|
|
547
|
+
start: (req?: ComputerStartRequest) => Promise<ComputerStatus>;
|
|
548
|
+
stop: () => Promise<void>;
|
|
549
|
+
/**
|
|
550
|
+
* Runs a batch of actions in order (the first failure stops it; the rest are reported `skipped`), then a screenshot
|
|
551
|
+
* when `screenshot` is set. Waits and key holds may take up to 300 s per batch.
|
|
552
|
+
*/
|
|
553
|
+
act: (req: ComputerActionsRequest, signal?: AbortSignal) => Promise<ComputerActionsResult>;
|
|
554
|
+
/** Starts the viewer in the guest; expose the returned port and open a link to `path` (Workspace.computer.stream does both). */
|
|
555
|
+
streamStart: (req?: {
|
|
556
|
+
interactive?: boolean;
|
|
557
|
+
}) => Promise<ComputerStreamInfo>;
|
|
558
|
+
streamStop: () => Promise<void>;
|
|
559
|
+
};
|
|
533
560
|
readonly browser: {
|
|
534
561
|
screenshot: (req: BrowserScreenshotRequest) => Promise<Uint8Array>;
|
|
535
562
|
content: (req: BrowserContentRequest) => Promise<BrowserContent>;
|