mandala-computer-mcp 0.11.0 → 0.13.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/README.md +159 -39
- package/dist/api.d.ts +9 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +15 -4
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/credits.d.ts +187 -0
- package/dist/credits.d.ts.map +1 -0
- package/dist/credits.js +119 -0
- package/dist/credits.js.map +1 -0
- package/dist/errors.d.ts +92 -26
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +206 -35
- package/dist/errors.js.map +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +30 -8
- package/dist/format.js.map +1 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +82 -8
- package/dist/http.js.map +1 -1
- package/dist/limits.d.ts +2 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +2 -0
- package/dist/limits.js.map +1 -1
- package/dist/paths.d.ts +42 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +46 -0
- package/dist/paths.js.map +1 -1
- package/dist/poll.d.ts +1 -1
- package/dist/poll.js +1 -1
- package/dist/server.d.ts +41 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +129 -5
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +20 -4
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +5 -0
- package/dist/session.js.map +1 -1
- package/dist/stdio.d.ts.map +1 -1
- package/dist/stdio.js +11 -1
- package/dist/stdio.js.map +1 -1
- package/dist/tool-filters.d.ts +3 -2
- package/dist/tool-filters.d.ts.map +1 -1
- package/dist/tool-filters.js +3 -1
- package/dist/tool-filters.js.map +1 -1
- package/dist/tools/account.d.ts.map +1 -1
- package/dist/tools/account.js +10 -3
- package/dist/tools/account.js.map +1 -1
- package/dist/tools/activities.d.ts.map +1 -1
- package/dist/tools/activities.js +4 -0
- package/dist/tools/activities.js.map +1 -1
- package/dist/tools/agent.d.ts +12 -4
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/agent.js +292 -132
- package/dist/tools/agent.js.map +1 -1
- package/dist/tools/chat.d.ts +11 -2
- package/dist/tools/chat.d.ts.map +1 -1
- package/dist/tools/chat.js +19 -9
- package/dist/tools/chat.js.map +1 -1
- package/dist/tools/computers.d.ts.map +1 -1
- package/dist/tools/computers.js +92 -11
- package/dist/tools/computers.js.map +1 -1
- package/dist/tools/credits.d.ts +9 -0
- package/dist/tools/credits.d.ts.map +1 -0
- package/dist/tools/credits.js +53 -0
- package/dist/tools/credits.js.map +1 -0
- package/dist/tools/guest.d.ts.map +1 -1
- package/dist/tools/guest.js +6 -7
- package/dist/tools/guest.js.map +1 -1
- package/dist/tools/input.d.ts.map +1 -1
- package/dist/tools/input.js +51 -18
- package/dist/tools/input.js.map +1 -1
- package/dist/tools/operations.js +2 -2
- package/dist/tools/operations.js.map +1 -1
- package/dist/tools/publicurls.d.ts +3 -0
- package/dist/tools/publicurls.d.ts.map +1 -0
- package/dist/tools/publicurls.js +287 -0
- package/dist/tools/publicurls.js.map +1 -0
- package/dist/tools/snapshots.d.ts.map +1 -1
- package/dist/tools/snapshots.js +1 -0
- package/dist/tools/snapshots.js.map +1 -1
- package/dist/tools/ssh.d.ts.map +1 -1
- package/dist/tools/ssh.js +4 -2
- package/dist/tools/ssh.js.map +1 -1
- package/dist/tools/webhooks.d.ts.map +1 -1
- package/dist/tools/webhooks.js +32 -23
- package/dist/tools/webhooks.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,7 +96,9 @@ right answer at all, that it costs money until it is suspended or stopped, that
|
|
|
96
96
|
which refusals are worth a second try. It is a description of *when and how*,
|
|
97
97
|
not a second client; once the server is installed it stays out of the way.
|
|
98
98
|
`MANDALA_MODEL_KEY`, if exported alongside, is passed through and turns on
|
|
99
|
-
`run_agent` when the configured filters permit it.
|
|
99
|
+
`run_agent` when the configured filters permit it. Without it, `run_agent` runs
|
|
100
|
+
on the account's AI credits when they can pay (see [Agents on AI
|
|
101
|
+
credits](#agents-on-ai-credits)).
|
|
100
102
|
|
|
101
103
|
To use an environment key instead of a saved profile:
|
|
102
104
|
|
|
@@ -170,9 +172,17 @@ Parameter and response-mode support remains a separate contract.
|
|
|
170
172
|
|
|
171
173
|
**Lifecycle** — `create_computer`, `start_computer`, `stop_computer`,
|
|
172
174
|
`suspend_computer`, `restart_computer`, `update_computer`, `clone_computer`,
|
|
173
|
-
`delete_computer`, `move_computer`, `list_moves`, `get_operation`,
|
|
175
|
+
`delete_computer`, `move_computer_to_workspace`, `move_computer`, `list_moves`, `get_operation`,
|
|
174
176
|
`list_operations`, `wait_for_operation` — see [Lifecycle operations](#lifecycle-operations)
|
|
175
177
|
|
|
178
|
+
`move_computer_to_workspace` changes workspace membership and who can access a computer.
|
|
179
|
+
It requires an account-wide member or owner credential and explicit `computer_id` and
|
|
180
|
+
`workspace_id` arguments (`null` means unassigned). The selected computer and default
|
|
181
|
+
workspace are not used. The computer must be stopped, with no saved session, snapshots
|
|
182
|
+
or snapshot history copies, secret bindings, or proxy credentials. Refusals leave
|
|
183
|
+
those resources intact; the tool never removes them to force a move. This is separate
|
|
184
|
+
from `move_computer`, which relocates a computer to different hardware.
|
|
185
|
+
|
|
176
186
|
**Driving the desktop** — `screenshot`, `click`, `type_text`, `paste_text`,
|
|
177
187
|
`press_key`, `scroll`, `drag`, `move_mouse`, `mouse_button`, `cursor_position`,
|
|
178
188
|
`wait`
|
|
@@ -228,7 +238,18 @@ which says nothing about the path; `isTransient` is false for both.
|
|
|
228
238
|
`rename_workspace`, `delete_workspace`. Minting and revoking API keys are
|
|
229
239
|
deliberately not tools — see [Who you are, and API keys](#who-you-are-and-api-keys).
|
|
230
240
|
|
|
231
|
-
**
|
|
241
|
+
**Deliberately not tools** — five API operations, each because it would put a
|
|
242
|
+
credential in a model's context: minting and revoking API keys (above), and the
|
|
243
|
+
three browser-connection routes (create, renew and revoke). A browser
|
|
244
|
+
connection is a raw capability to drive the guest's browser; the TypeScript
|
|
245
|
+
and Python SDKs' browser drivers create, renew and revoke it and keep it to
|
|
246
|
+
themselves. Every other API operation has a tool.
|
|
247
|
+
|
|
248
|
+
**Every tool refuses an argument it does not declare.** A misspelt or unknown
|
|
249
|
+
key is an input error naming the key, and nothing is sent — so a misspelt flag
|
|
250
|
+
can never be dropped and the call go ahead without it.
|
|
251
|
+
|
|
252
|
+
**Spending** — `get_usage`, `get_credits`
|
|
232
253
|
|
|
233
254
|
**Being told somewhere else** — `list_webhooks`, `create_webhook`,
|
|
234
255
|
`get_webhook`, `update_webhook`, `rotate_webhook_secret`, `test_webhook`,
|
|
@@ -249,6 +270,25 @@ account) or bound to another account answers as if there were no such key, and
|
|
|
249
270
|
the person removes it from the dashboard. A workspace-scoped key can read keys
|
|
250
271
|
but not add or remove them.
|
|
251
272
|
|
|
273
|
+
**Showing an app on the internet** — `list_public_urls`, `create_public_url`,
|
|
274
|
+
`update_public_url`, `delete_public_url`. A port inside a computer served at
|
|
275
|
+
`https://<label>.<base_domain>` (the domain is in the `list_public_urls`
|
|
276
|
+
answer, e.g. `mandala.dev`), on 443 with no port in the address. **Public by
|
|
277
|
+
default: anyone with the link can open it**; `access: "private"` requires an API
|
|
278
|
+
key of this account as `Authorization: Bearer`, which never reaches the app. The
|
|
279
|
+
app must listen on `0.0.0.0`, not `127.0.0.1`. Labels that read as the
|
|
280
|
+
platform's or another company's address are refused. A deleted URL's label stays
|
|
281
|
+
with the account: no other account can ever take it, and the account may use it
|
|
282
|
+
again unless the platform has blocked it. A computer over its plan's limit
|
|
283
|
+
serves only its oldest URLs, and the listing marks the rest.
|
|
284
|
+
|
|
285
|
+
A browser opening a new account's URL may first see a one-time notice page. It
|
|
286
|
+
goes to any request that looks like a browser opening a page — a navigation by
|
|
287
|
+
its fetch metadata, or, without fetch metadata, `Accept: text/html` from a
|
|
288
|
+
`Mozilla/` user agent — so a program sending browser headers sees it too. A
|
|
289
|
+
client that sets headers skips it with `mandala-skip-warning: 1`; in the
|
|
290
|
+
computer's own browser, where `open_url` cannot send headers, click Continue.
|
|
291
|
+
|
|
252
292
|
**Secrets** — `list_secrets`, `get_secret`, `create_secret`, `set_secret`,
|
|
253
293
|
`replace_secret`, `delete_secret` for the account's secret store, and
|
|
254
294
|
`get_computer_secrets`, `set_computer_secrets` and `create_computer`'s `secrets`
|
|
@@ -300,9 +340,11 @@ before a request is sent — replaces the setting whole, and `null` removes it.
|
|
|
300
340
|
says "its egress proxy is waiting for credentials; connections are closed until
|
|
301
341
|
they arrive".
|
|
302
342
|
|
|
303
|
-
**Delegating** — `run_agent`, `run_agent_chat`, registered
|
|
343
|
+
**Delegating** — `run_agent`, `run_agent_chat`, registered when a model key is present:
|
|
304
344
|
`MANDALA_MODEL_KEY` on stdio, or the caller's own `X-Model-Key` header over HTTP.
|
|
305
|
-
|
|
345
|
+
Without a key, `run_agent` alone is registered when the account's AI credits can
|
|
346
|
+
pay for a run (see [Agents on AI credits](#agents-on-ai-credits)). Both must also
|
|
347
|
+
survive the configured filters.
|
|
306
348
|
|
|
307
349
|
### Tool filters
|
|
308
350
|
|
|
@@ -325,7 +367,7 @@ with an error listing all valid tags.
|
|
|
325
367
|
| --- | --- |
|
|
326
368
|
| `account` | `get_account`, `whoami`, `list_api_keys`, `list_workspaces`, `get_workspace`, `list_workspace_members`, `create_workspace`, `rename_workspace`, `delete_workspace` |
|
|
327
369
|
| `computers` | `list_computers`, `get_computer`, `use_computer`, `wait_for_computer`, `get_desktop_url`, `list_sizes` |
|
|
328
|
-
| `lifecycle` | `create_computer`, `start_computer`, `stop_computer`, `suspend_computer`, `restart_computer`, `update_computer`, `clone_computer`, `delete_computer`, `move_computer`, `list_moves`, `get_operation`, `list_operations`, `wait_for_operation` |
|
|
370
|
+
| `lifecycle` | `create_computer`, `start_computer`, `stop_computer`, `suspend_computer`, `restart_computer`, `update_computer`, `clone_computer`, `delete_computer`, `move_computer_to_workspace`, `move_computer`, `list_moves`, `get_operation`, `list_operations`, `wait_for_operation` |
|
|
329
371
|
| `input` | `screenshot`, `click`, `type_text`, `paste_text`, `press_key`, `scroll`, `drag`, `move_mouse`, `mouse_button`, `cursor_position`, `wait` |
|
|
330
372
|
| `guest` | `exec`, `exec_poll`, `exec_kill`, `open_url`, `list_windows`, `window_action`, `read_clipboard`, `write_clipboard` |
|
|
331
373
|
| `files` | `list_directory`, `read_file`, `write_file`, `wait_for_file_change` |
|
|
@@ -335,9 +377,10 @@ with an error listing all valid tags.
|
|
|
335
377
|
| `snapshots` | All snapshot tools listed above, including `get_retention` |
|
|
336
378
|
| `templates` | `list_templates`, all your-own-template tools and all build tools listed above |
|
|
337
379
|
| `events` | `wait_for_event`, `poll_events`, `wait_for_file_change` |
|
|
338
|
-
| `usage` | `get_usage` |
|
|
380
|
+
| `usage` | `get_usage`, `get_credits` |
|
|
339
381
|
| `webhooks` | All webhook tools listed above |
|
|
340
382
|
| `ssh` | All SSH tools listed above |
|
|
383
|
+
| `public_urls` | `list_public_urls`, `create_public_url`, `update_public_url`, `delete_public_url` |
|
|
341
384
|
| `secrets` | `list_secrets`, `get_secret`, `create_secret`, `set_secret`, `replace_secret`, `delete_secret`, `get_computer_secrets`, `set_computer_secrets` |
|
|
342
385
|
| `agent` | `run_agent`, `run_agent_chat` |
|
|
343
386
|
| `activities` | `list_activities`, `get_activity`, `get_activity_results` |
|
|
@@ -346,7 +389,8 @@ with an error listing all valid tags.
|
|
|
346
389
|
The selected tags form a union, then intersect with read-only and the existing
|
|
347
390
|
lifecycle and model-key restrictions. `MANDALA_NO_LIFECYCLE=1` still withholds
|
|
348
391
|
its five tools even when their tags are selected; selecting `agent` cannot
|
|
349
|
-
enable
|
|
392
|
+
enable `run_agent_chat` without a per-session model key, nor `run_agent` without
|
|
393
|
+
one or credits that can pay. Both agent tools are
|
|
350
394
|
withheld by read-only, but remain available with lifecycle disabled alone.
|
|
351
395
|
`MANDALA_TAGS=files MANDALA_READ_ONLY=1` exposes only `list_directory`.
|
|
352
396
|
An `agent` selection with read-only is a valid empty tool list.
|
|
@@ -364,7 +408,7 @@ does not read the environment itself.
|
|
|
364
408
|
### Lifecycle operations
|
|
365
409
|
|
|
366
410
|
Every accepted create, clone, start, stop, suspend, restart, snapshot restore,
|
|
367
|
-
resize, move and delete records a lifecycle operation, and the tool that made the call
|
|
411
|
+
resize, host move and delete records a lifecycle operation, and the tool that made the call
|
|
368
412
|
says its `operation_id` — in its sentence, as `(operation op_…)`, and in the
|
|
369
413
|
JSON. `move_computer` carries it onto the outcome it reports. It is absent where
|
|
370
414
|
the platform could not record one; the call happened either way.
|
|
@@ -477,8 +521,10 @@ one is refused (403), so none of them can touch the workspace this server's own
|
|
|
477
521
|
key stands in. `delete_workspace` needs `confirm: true` and REVOKES every API
|
|
478
522
|
key confined to the workspace, whoever holds it — a person's CI or another agent
|
|
479
523
|
may be using one — and answers how many. Only an empty workspace can be
|
|
480
|
-
deleted: one that still holds computers is refused (409),
|
|
481
|
-
nothing is deleted or revoked.
|
|
524
|
+
deleted: one that still holds computers or active secrets is refused (409),
|
|
525
|
+
saying how many, and nothing is deleted or revoked. Move its computers out with
|
|
526
|
+
`move_computer_to_workspace` (or delete them) and delete its secrets with
|
|
527
|
+
`delete_secret`, then send it again.
|
|
482
528
|
None of the three is offered to a read-only session (`MANDALA_READ_ONLY`).
|
|
483
529
|
|
|
484
530
|
An account-wide key can work in one workspace without a key confined to it:
|
|
@@ -552,18 +598,28 @@ refuses a suspended computer and names `start_computer`, where the SDKs'
|
|
|
552
598
|
`waitForGuest` resumes it.
|
|
553
599
|
|
|
554
600
|
**A screenshot need not be the whole screen.** `screenshot` takes `region` (a
|
|
555
|
-
crop, in
|
|
601
|
+
crop, in full-size capture pixels before any scaling), `scale` (0 to 1),
|
|
556
602
|
`format` (`png` or `jpeg`) and `quality` (JPEG, 1-100). A cropped or scaled
|
|
557
603
|
picture is in its own pixel space, so the tool says alongside it how to turn a
|
|
558
604
|
position in it back into screen coordinates.
|
|
559
605
|
|
|
606
|
+
Live screenshots also return a `capture` name and the capture's original size,
|
|
607
|
+
before cropping or scaling. Use that size instead of the computer record's
|
|
608
|
+
`resolution`, which can differ. To crop a frame you already measured, send its
|
|
609
|
+
`capture` with `region`; omit `fresh` or set it to `false`. Without `capture`,
|
|
610
|
+
screenshots remain fresh by default. `fresh: true` cannot be combined with
|
|
611
|
+
`capture`. If the capture is no longer held (`stale_capture`), take a new
|
|
612
|
+
screenshot without `capture` or `region`, then remeasure the region and use the
|
|
613
|
+
new capture name. Saved frames of suspended computers cannot be pinned this way.
|
|
614
|
+
|
|
560
615
|
**Ten clicks need not be ten screenshots.** Driving the desktop one tool at a
|
|
561
616
|
time — `screenshot`, `click`, `screenshot` — puts an image in the calling
|
|
562
617
|
model's context for every step. `run_agent` hands a task in plain language to
|
|
563
618
|
the platform's own loop instead, which screenshots, decides and clicks inside
|
|
564
619
|
the platform and answers with a sentence and the list of what it did. It is
|
|
565
|
-
registered
|
|
566
|
-
and bills that key for the run
|
|
620
|
+
registered when a model key is present (see [Configuration](#configuration)),
|
|
621
|
+
and bills that key for the run, or else when the account's AI credits can pay
|
|
622
|
+
(see [Agents on AI credits](#agents-on-ai-credits)). `max_steps` bounds the WORK rather than the
|
|
567
623
|
bill: a step is one action on the desktop, one model reply can ask for several
|
|
568
624
|
and spends a step on each, a paused turn costs tokens and no step, and not every
|
|
569
625
|
step takes a screenshot. It defaults to 20 and is capped at 100 here.
|
|
@@ -919,12 +975,14 @@ does not.
|
|
|
919
975
|
**screenshots deliberately do not**, so a loop that only watches can see its own
|
|
920
976
|
machine go down under it.
|
|
921
977
|
|
|
922
|
-
**A stop
|
|
923
|
-
|
|
924
|
-
changes" dialog
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
978
|
+
**A stop asks first, then forces.** `stop_computer` asks the guest to shut
|
|
979
|
+
down and gives it up to 20 seconds; a guest still up after that — a hung X
|
|
980
|
+
session, a modal "unsaved changes" dialog, a service that ignores its own
|
|
981
|
+
shutdown — is forced off by the platform, so an ordinary stop ends stopped and
|
|
982
|
+
can take up to about a minute to answer. `force: true` skips the asking and the
|
|
983
|
+
wait and pulls the power at once — the equivalent of holding the button in — and
|
|
984
|
+
whatever the guest had not written to disk goes with it. It saves 20 seconds,
|
|
985
|
+
not a failed stop, so leave it out unless the computer must be off immediately.
|
|
928
986
|
|
|
929
987
|
**Purging snapshots is bound to the set you were shown.** Deleting a computer
|
|
930
988
|
keeps its snapshots by default. To destroy them too, read `snapshot_holdings`
|
|
@@ -984,8 +1042,13 @@ inside its boot window) clear, so the same call works in a moment;
|
|
|
984
1042
|
`unavailable`, `running`, `unsupported`, `exists` and `revoked` do not. A 409
|
|
985
1043
|
does not mean "wait": `exec`, input and the clipboard on a stopped computer
|
|
986
1044
|
answer 409 `unavailable`, and `start_computer` is what fixes that, while
|
|
987
|
-
`running` needs the computer stopped first.
|
|
988
|
-
|
|
1045
|
+
`running` needs the computer stopped first. A 409 with no `reason` is
|
|
1046
|
+
unclassified, and is treated as one that does not clear — a label that is taken,
|
|
1047
|
+
a computer at its public URL limit, the webhook cap, an SSH key already
|
|
1048
|
+
registered — unless its `code` is one the platform documents as passing
|
|
1049
|
+
(`idempotency_in_progress`, or `WORKSPACE_MOVING` while the move settles). The
|
|
1050
|
+
platform's own error messages come through unedited, because they are written to
|
|
1051
|
+
be acted on.
|
|
989
1052
|
|
|
990
1053
|
HTTP failures preserve their actual response status. An unsupported method on a
|
|
991
1054
|
known path is `MethodNotAllowedError` (405), with the received `Allow` value when
|
|
@@ -1000,7 +1063,10 @@ same way. So `isTransient` is false for it whatever `reason` it carries, the
|
|
|
1000
1063
|
tool's answer says to read the current state first, and `error.method` records
|
|
1001
1064
|
the method. A `reason` this version does not
|
|
1002
1065
|
know, such as a new word, is treated as no classification. `reasonKind` returns
|
|
1003
|
-
`undefined` for it, and the status decides
|
|
1066
|
+
`undefined` for it, and the status decides — which, for a 409, is no: a 409 is
|
|
1067
|
+
transient only when its `reason` clears or its `code` is
|
|
1068
|
+
`idempotency_in_progress` or `WORKSPACE_MOVING` (with no `reason` saying
|
|
1069
|
+
otherwise). `APIError.code` carries the platform's code.
|
|
1004
1070
|
|
|
1005
1071
|
The secret store has typed calls on `api.secrets`: `list`, `create`, `get`,
|
|
1006
1072
|
`replace` and `delete`. Each answer is decoded strictly to the documented
|
|
@@ -1041,9 +1107,11 @@ intermediaries and connection failures may supply none of them. Existing
|
|
|
1041
1107
|
constructor arguments retain their meanings; an optional trailing
|
|
1042
1108
|
`APIErrorMetadata` object adds these three fields, and `method`.
|
|
1043
1109
|
|
|
1044
|
-
MCP error results include supplied `reason`, `request_id`, `allow`,
|
|
1045
|
-
`www_authenticate` and `retry_after_ms` as labelled JSON metadata.
|
|
1046
|
-
|
|
1110
|
+
MCP error results include supplied `code`, `reason`, `request_id`, `allow`,
|
|
1111
|
+
`www_authenticate` and `retry_after_ms` as labelled JSON metadata. `code` is the
|
|
1112
|
+
platform's machine-readable code (`LABEL_TAKEN`, `WORKSPACE_MOVING`, …), the
|
|
1113
|
+
word to switch on rather than the sentence. Diagnostic
|
|
1114
|
+
strings are limited to 128, 128, 256, 512 and 512 characters respectively; an
|
|
1047
1115
|
oversized field is omitted with a notice, so a shortened Allow is never
|
|
1048
1116
|
presented as complete. Tool-specific warnings about partial work, retained
|
|
1049
1117
|
publication, execution reads and explicit template continuation still apply.
|
|
@@ -1372,7 +1440,7 @@ address.
|
|
|
1372
1440
|
| `MANDALA_PROFILE` | Local saved profile; `--profile` overrides it. Otherwise the file default is selected. Ignored by HTTP. |
|
|
1373
1441
|
| `MANDALA_BASE_URL` | With a saved profile, must match its stored base. Otherwise defaults to `https://app.mandala.computer/api/v1`. |
|
|
1374
1442
|
| `MANDALA_COMPUTER_ID` | Bind a computer at startup, so `use_computer` is not needed. **stdio only** — under `--http` it is ignored rather than bound into every caller's session, since it names a machine on the operator's account. |
|
|
1375
|
-
| `MANDALA_MODEL_KEY` | An Anthropic key. Enables `run_agent` and `run_agent_chat` when filters permit them, which runs the platform's own loop on that key. **stdio only** — under `--http` each caller sends their own as `X-Model-Key`, and this variable is ignored. |
|
|
1443
|
+
| `MANDALA_MODEL_KEY` | An Anthropic or OpenAI key. Enables `run_agent` and `run_agent_chat` when filters permit them, which runs the platform's own loop on that key. Without it, `run_agent` runs on the account's AI credits when they can pay. **stdio only** — under `--http` each caller sends their own as `X-Model-Key`, and this variable is ignored. |
|
|
1376
1444
|
| `MANDALA_NO_LIFECYCLE` | `1`, `true`, `yes` or `on` withholds `create_computer`, `clone_computer`, `clone_snapshot`, `delete_computer` and `delete_snapshot` — every tool that makes a computer or destroys one. `0`, `false`, `no`, `off` or unset leaves them registered. Any other value is **refused at startup** rather than read as off: a typo here would otherwise leave those tools in place on a server whose operator believes they are gone. The `--no-lifecycle` flag reads the same vocabulary and refuses the same way, except that it has no spelling for *unset*: `--no-lifecycle=` is refused rather than ignored, so a launcher template whose variable did not expand stops instead of quietly leaving the tools registered. |
|
|
1377
1445
|
| `PORT`, `HOST` | For `--http`. Default `3000`, `127.0.0.1`. |
|
|
1378
1446
|
| `MANDALA_READ_ONLY` | Keep only tools annotated `readOnlyHint: true`; strict boolean parsing as described under Tool filters. |
|
|
@@ -1397,9 +1465,54 @@ none of which is true of `MANDALA_API_KEY`.
|
|
|
1397
1465
|
`run_agent` deserves a note. It hands a task to the platform's own agent loop,
|
|
1398
1466
|
which drives the computer inside the platform and answers with a sentence. Worth
|
|
1399
1467
|
it when a stretch of pixel work would otherwise cost the calling model a
|
|
1400
|
-
screenshot per step — ten clicks stop being ten images. It bills your
|
|
1468
|
+
screenshot per step — ten clicks stop being ten images. It bills your selected provider
|
|
1401
1469
|
key, and the platform never stores that key.
|
|
1402
1470
|
|
|
1471
|
+
Both `run_agent` and `run_agent_chat` accept `provider: "openai"` to use
|
|
1472
|
+
`gpt-6.1-sol` by default, or infer OpenAI from a recognized GPT model name.
|
|
1473
|
+
Set `MANDALA_MODEL_KEY` (stdio) or `X-Model-Key` (HTTP) to the matching provider
|
|
1474
|
+
key. Custom model names require an explicit `provider`; omitting model and
|
|
1475
|
+
provider preserves the Anthropic default. OpenAI is BYOK only and stores
|
|
1476
|
+
Responses continuations at OpenAI; tasks, screenshots and tool results go to
|
|
1477
|
+
that provider. A native OpenAI action batch must fit the remaining step and
|
|
1478
|
+
API budget before it begins. Partial failures stop the run without replaying input.
|
|
1479
|
+
|
|
1480
|
+
### Agents on AI credits
|
|
1481
|
+
|
|
1482
|
+
Without a model key, `run_agent` can run on the account's Mandala AI credits.
|
|
1483
|
+
The server reads `GET /credits` on the session's own API key and registers
|
|
1484
|
+
`run_agent` only when the account is not frozen and has at least $0.25
|
|
1485
|
+
available, which is what a run's first model call reserves. On stdio that read
|
|
1486
|
+
happens once, at startup. Over HTTP it happens per session, at initialize, with
|
|
1487
|
+
that caller's bearer token; a caller who sends `X-Model-Key` is not asked, and no
|
|
1488
|
+
operator key or setting is ever used. Any failure of the read — a refusal (a
|
|
1489
|
+
workspace-scoped key cannot read the account-wide ledger), an error, a timeout or
|
|
1490
|
+
a record that does not parse — leaves `run_agent` out. A session started
|
|
1491
|
+
unfunded does not gain the tool when credits arrive later; reconnect, or restart
|
|
1492
|
+
a stdio server.
|
|
1493
|
+
|
|
1494
|
+
On credits `run_agent` takes `max_cost_usd` (0.25 to 20; the platform defaults
|
|
1495
|
+
to 2), the most a run may start spending. The last model call can go past it,
|
|
1496
|
+
and a run that reaches it ends with `stop: "max_cost"`. It does not take
|
|
1497
|
+
`system` or `provider`: a run on credits uses the platform's own prompt and
|
|
1498
|
+
Anthropic, with `claude-sonnet-5-5` by default and `claude-opus-5-5` on request.
|
|
1499
|
+
The result reports `cost_usd`, the run's charge so far, and
|
|
1500
|
+
`credits_remaining_usd`, the balance the last step reported. A run whose credits
|
|
1501
|
+
run out partway ends with `stop: "credits_exhausted"`, and a run that cannot
|
|
1502
|
+
reserve its first call is refused `402` with a `top_up_url`; the tool reports
|
|
1503
|
+
that as the account's credits running out, with the billing page, rather than as
|
|
1504
|
+
a plan limit or the model provider's billing error. The platform reports its
|
|
1505
|
+
AI service failing a run on credits as `Mandala AI is unavailable` over the
|
|
1506
|
+
provider's status. On such a run that sentence, at any status, and any other
|
|
1507
|
+
`402`, are worded as the service failing, not as the caller's credential, the
|
|
1508
|
+
computer, the request or a model key. `run_agent_chat` is never registered
|
|
1509
|
+
without a model key: the platform runs that route only on the caller's own key.
|
|
1510
|
+
|
|
1511
|
+
`get_credits` reads the ledger: available, balance, held, debt, whether the
|
|
1512
|
+
account is frozen, this period's plan grant, the unexpired lots and one page of
|
|
1513
|
+
the journal, newest first (`before` and `limit` page through it). Amounts are
|
|
1514
|
+
integer USD micros. It needs an account-wide key.
|
|
1515
|
+
|
|
1403
1516
|
### Passive directories, activity history and signals
|
|
1404
1517
|
|
|
1405
1518
|
`list_directory` takes an exact absolute guest `path`. Unicode, spaces and
|
|
@@ -1441,14 +1554,14 @@ or that a task succeeded. Unsupported (501) and unavailable (503) responses
|
|
|
1441
1554
|
remain errors, never empty history or new checkpoints. There is no watcher,
|
|
1442
1555
|
guest action, retry loop or automatic checkpoint cache in this tool.
|
|
1443
1556
|
|
|
1444
|
-
### JSON chat with your own
|
|
1557
|
+
### JSON chat with your own model key
|
|
1445
1558
|
|
|
1446
|
-
`run_agent_chat` drives the selected computer using the same BYOK Anthropic loop
|
|
1559
|
+
`run_agent_chat` drives the selected computer using the same BYOK Anthropic or OpenAI loop
|
|
1447
1560
|
as `run_agent`. It accepts a nonempty array of textual OpenAI-shaped `messages`,
|
|
1448
1561
|
including string content or arrays of `{type:"text",text:"..."}` parts. The
|
|
1449
1562
|
**last user message** supplies the task; system messages supply standing
|
|
1450
1563
|
instructions. Earlier user/assistant conversation is not replayed. Optional
|
|
1451
|
-
`model`
|
|
1564
|
+
`model` selects a computer-capable Anthropic or OpenAI model. `max_steps` is 1–100,
|
|
1452
1565
|
default 20. This is computer control, not hosted general-purpose inference or a
|
|
1453
1566
|
chat UI; it adds no key storage or model billing service.
|
|
1454
1567
|
|
|
@@ -1482,7 +1595,9 @@ caller is a `401` or `403` carrying `reason: "revoked"`, and only that gets
|
|
|
1482
1595
|
account advice. A `402`, `504` or `529` is the model provider's own status for
|
|
1483
1596
|
the configured model key (its billing, timeout or overloaded error), so the
|
|
1484
1597
|
advice is to check the model-provider account, not the Mandala plan; a `403`
|
|
1485
|
-
without `revoked` may be the provider's permission error for that key. The
|
|
1598
|
+
without `revoked` may be the provider's permission error for that key. The one
|
|
1599
|
+
`402` that is Mandala's own carries a `top_up_url`: a run on AI credits the
|
|
1600
|
+
account cannot cover, worded as such. The
|
|
1486
1601
|
exception is a refusal `run_agent_chat` is given before any run started — a flat
|
|
1487
1602
|
`{error: string}` body, from the role gate, a bad body, a suspension or the
|
|
1488
1603
|
meter: nothing ran, and it keeps the usual role and plan advice every other tool
|
|
@@ -1511,8 +1626,13 @@ overall deadline and an 8 MiB body ceiling, then exercises the real MCP tools
|
|
|
1511
1626
|
and requires request evidence for every published `/api/v1` operation. Every
|
|
1512
1627
|
exercise variant must succeed and dispatch a request, including later variants
|
|
1513
1628
|
of a tool that already dispatched successfully.
|
|
1514
|
-
Non-v1 operations are explicitly excluded and reported.
|
|
1515
|
-
|
|
1629
|
+
Non-v1 operations are explicitly excluded and reported. Protocol forms are
|
|
1630
|
+
reported but not required, since no tool sends them: `OPTIONS` (the CORS
|
|
1631
|
+
preflight) and a `HEAD` published beside a `GET` at the same URL (that `GET`
|
|
1632
|
+
without its body). A `HEAD` with no such `GET` is required like any other
|
|
1633
|
+
operation.
|
|
1634
|
+
The check uses OpenAPI server inheritance and literal-path precedence, not the
|
|
1635
|
+
local route allowlist.
|
|
1516
1636
|
Each path is appended to its effective server base; repeated prefixes are not
|
|
1517
1637
|
removed. Fully prefixed paths work with an absent or root server.
|
|
1518
1638
|
It fails on a blocked fetch, redirect, invalid document or missing operation;
|
|
@@ -1520,11 +1640,10 @@ there is no fixture fallback, credential requirement or skip branch.
|
|
|
1520
1640
|
|
|
1521
1641
|
The committed OpenAPI fixture is synthetic, assembled from the public MCP route
|
|
1522
1642
|
inventory, and is never presented as a downloaded publication. Offline green
|
|
1523
|
-
proves deterministic implementation coverage only.
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
every subsequent head must pass the gate independently. These counts are
|
|
1643
|
+
proves deterministic implementation coverage only. Each `published-openapi` run
|
|
1644
|
+
logs the publication's digest and how many operations it matched with how many
|
|
1645
|
+
requests from how many tools; a result applies to that commit and that
|
|
1646
|
+
publication, and every head must pass the gate independently. Those counts are
|
|
1528
1647
|
observations, never fixed thresholds or exemptions. A blocked or red public gate
|
|
1529
1648
|
must not be merged. Parameters and response modes remain separate contracts,
|
|
1530
1649
|
with documented parameter exceptions and JSON-only chat support.
|
|
@@ -1580,6 +1699,7 @@ several names. Where a client has no way to do it, the cell says so with —.
|
|
|
1580
1699
|
| The usage window | `usage.read({ from, to })` | `usage.read(since=…, until=…)`, or `from_=` and `to=` | `get_usage` with `from` and `to` | `usage --from … --to …` | — |
|
|
1581
1700
|
| Change a computer (`PATCH`) | `update({ … })` | `rename()`, `resize()`, `set_idle_suspend()`, `set_browser_proxy()`, `set_egress_proxy()` | `update_computer` | `computers rename`, `resize`, `idle-suspend`, `browser-proxy set`/`clear`, `egress-proxy set`/`clear` | `browser-proxy set`/`clear`, `egress-proxy set`/`clear` |
|
|
1582
1701
|
| Wait until the computer is ready | `waitForGuest()`, `waitForDesktop()` | `wait_for_guest()`, `wait_for_desktop()` | `wait_for_computer` with `until: "guest"`, which on Linux also waits for the desktop session | `computers wait --until guest` or `--until desktop` | — |
|
|
1702
|
+
| A screenshot, fresh or cached | `screenshot(width, { fresh, capture })`: cached unless `fresh: true` | `screenshot(fresh=…, capture=…)`: cached unless `fresh=True` | `screenshot`: **fresh by default** unless `capture` is given; `fresh: false` for the cache | `computers screenshot --fresh` | — |
|
|
1583
1703
|
| The windows after an input action | `{ context: true }` on an input method, e.g. `click(x, y, [], { context: true })` | `context=True` on an input method, e.g. `click(x, y, context=True)` | `context: true` on an input tool | — | — |
|
|
1584
1704
|
|
|
1585
1705
|
## Security
|
package/dist/api.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Agent } from 'undici';
|
|
|
2
2
|
import { type SecretStore } from './secret-store.js';
|
|
3
3
|
export { isSecretStoreRoute } from './secret-errors.js';
|
|
4
4
|
export declare const DEFAULT_BASE_URL = "https://app.mandala.computer/api/v1";
|
|
5
|
-
/**
|
|
5
|
+
/** The caller's provider key, forwarded for the hosted agent routes. */
|
|
6
6
|
export declare const MODEL_KEY_HEADER = "X-Model-Key";
|
|
7
7
|
/**
|
|
8
8
|
* The header every lifecycle call carries so that sending it again cannot do
|
|
@@ -90,6 +90,13 @@ export type Bytes = {
|
|
|
90
90
|
* than a capture of its screen.
|
|
91
91
|
*/
|
|
92
92
|
frame?: string;
|
|
93
|
+
/** X-GC-Capture: the live screenshot's reusable capture name. */
|
|
94
|
+
capture?: string;
|
|
95
|
+
/** X-GC-Capture-Size: the capture's own pixels, before cropping or scaling. */
|
|
96
|
+
captureSize?: {
|
|
97
|
+
width: number;
|
|
98
|
+
height: number;
|
|
99
|
+
};
|
|
93
100
|
};
|
|
94
101
|
/**
|
|
95
102
|
* The longest foreground guest exec waits 600 seconds before it answers.
|
|
@@ -210,7 +217,7 @@ export declare class Api {
|
|
|
210
217
|
* Routes where an empty body IS the answer use `send`.
|
|
211
218
|
*/
|
|
212
219
|
json<T = unknown>(method: string, path: string, opts?: RequestOptions): Promise<T>;
|
|
213
|
-
/**
|
|
220
|
+
/** JSON decoding plus observed status, for operations requiring a specific success status. */
|
|
214
221
|
jsonWithStatus<T>(method: string, path: string, opts?: RequestOptions): Promise<{
|
|
215
222
|
status: number;
|
|
216
223
|
value: T;
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAmE,MAAM,QAAQ,CAAC;AAsBhG,OAAO,EAAsB,KAAK,WAAW,EAA0B,MAAM,mBAAmB,CAAC;AAGjG,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,eAAO,MAAM,gBAAgB,wCAAwC,CAAC;AAEtE,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -7,7 +7,7 @@ import { DOCUMENTED_REASONS, secretListOf, secretOf } from './secret-store.js';
|
|
|
7
7
|
import { SERVER_VERSION } from './version.js';
|
|
8
8
|
export { isSecretStoreRoute } from './secret-errors.js';
|
|
9
9
|
export const DEFAULT_BASE_URL = 'https://app.mandala.computer/api/v1';
|
|
10
|
-
/**
|
|
10
|
+
/** The caller's provider key, forwarded for the hosted agent routes. */
|
|
11
11
|
export const MODEL_KEY_HEADER = 'X-Model-Key';
|
|
12
12
|
/**
|
|
13
13
|
* The header every lifecycle call carries so that sending it again cannot do
|
|
@@ -66,6 +66,14 @@ function responseMetadata(resp) {
|
|
|
66
66
|
wwwAuthenticate: resp.headers.get('www-authenticate') ?? undefined,
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
function captureSizeFrom(value) {
|
|
70
|
+
if (!value || !/^[1-9]\d*x[1-9]\d*$/.test(value))
|
|
71
|
+
return undefined;
|
|
72
|
+
const [width, height] = value.split('x').map(Number);
|
|
73
|
+
return Number.isSafeInteger(width) && Number.isSafeInteger(height)
|
|
74
|
+
? { width, height }
|
|
75
|
+
: undefined;
|
|
76
|
+
}
|
|
69
77
|
/**
|
|
70
78
|
* How much of an event stream will be held while waiting for a boundary.
|
|
71
79
|
*
|
|
@@ -574,15 +582,16 @@ export class Api {
|
|
|
574
582
|
}
|
|
575
583
|
return body;
|
|
576
584
|
}
|
|
577
|
-
/**
|
|
585
|
+
/** JSON decoding plus observed status, for operations requiring a specific success status. */
|
|
578
586
|
async jsonWithStatus(method, path, opts = {}) {
|
|
579
587
|
return this.#guard(method, path, opts, () => this.#jsonWithStatusRaw(method, path, opts));
|
|
580
588
|
}
|
|
581
589
|
async #jsonWithStatusRaw(method, path, opts = {}) {
|
|
582
590
|
const resp = await this.#fetch(method, path, opts);
|
|
583
591
|
const value = await this.#decode(resp, method, path, opts.signal ?? this.#signal);
|
|
584
|
-
if (value === undefined || value === null)
|
|
585
|
-
throw new MandalaError(
|
|
592
|
+
if (value === undefined || value === null) {
|
|
593
|
+
throw new MandalaError(`${method} ${path} answered ${resp.status} without the expected JSON response; the outcome could not be confirmed`);
|
|
594
|
+
}
|
|
586
595
|
return { status: resp.status, value };
|
|
587
596
|
}
|
|
588
597
|
/** Complete bounded responses for immutable retained protocols; never a successful prefix. */
|
|
@@ -754,6 +763,8 @@ export class Api {
|
|
|
754
763
|
unrangeable: (resp.headers.get('accept-ranges') ?? '').trim().toLowerCase() === 'none',
|
|
755
764
|
window,
|
|
756
765
|
frame: resp.headers.get('x-gc-frame')?.trim().toLowerCase() || undefined,
|
|
766
|
+
capture: resp.headers.get('x-gc-capture')?.match(/^[a-f0-9]{16}$/)?.[0],
|
|
767
|
+
captureSize: captureSizeFrom(resp.headers.get('x-gc-capture-size')),
|
|
757
768
|
};
|
|
758
769
|
}
|
|
759
770
|
// --- the account's secret store (OPL-4984) ------------------------------
|