@agentorg/computer 0.0.11 → 0.0.12
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 +19 -3
- package/dist/THIRD_PARTY_LICENSES.txt +1 -1
- package/dist/agentcomputer.js +169 -64
- package/dist/types/generated/schema.d.ts +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ That prints the computer's `computerID`, its endpoints and its `accessToken`, on
|
|
|
22
22
|
`agentcomputer serve --isolation container` makes each computer a container of its own, which needs Docker on the same machine. The service follows your `DOCKER_HOST` or current context and never changes them.
|
|
23
23
|
|
|
24
24
|
- The image holds AgentExec, Playwright MCP and a headless Chromium. It is `ghcr.io/uniac-ai/agentcomputer/computer` at the service's version; `--image` names another.
|
|
25
|
-
- `--workspace` is mounted at `/workspace`, read-only at `--access read`, and nothing else of the machine is visible. Docker has to be able to share that folder. Without `--workspace`, the service makes one.
|
|
25
|
+
- `--workspace` is mounted at `/workspace`, read-only at `--access read`, and nothing else of the machine is visible. The computer is told that folder's path on the machine and the machine's name, which `about` answers. Docker has to be able to share that folder. Without `--workspace`, the service makes one.
|
|
26
26
|
- It runs as the user who started the service, with no capabilities.
|
|
27
27
|
- `stop` stops the container and keeps it, so what was installed in it is there at `start`. `kill` removes it. Starting a stopped computer uses the image it was made from.
|
|
28
28
|
|
|
@@ -30,11 +30,27 @@ That prints the computer's `computerID`, its endpoints and its `accessToken`, on
|
|
|
30
30
|
|
|
31
31
|
| `--access` | Tools at the `computer` endpoint |
|
|
32
32
|
| ---------- | --------------------------------------------------------- |
|
|
33
|
-
| `read` | `read`, `list`, `search`
|
|
33
|
+
| `read` | `about`, `read`, `list`, `search` |
|
|
34
34
|
| `files` | Those, and `edit` |
|
|
35
35
|
| `terminal` | Those, and `exec_command`, `write_stdin`, `list_sessions` |
|
|
36
36
|
| `none` | No `computer` endpoint; needs `--browser` |
|
|
37
37
|
|
|
38
|
+
`about` tells the agent what a person looking at the computer reads. It takes nothing and answers JSON text, `{"rows": [...]}`, each row a `label` and a `value`, with `"path": true` on a value that is a path and `"caution": true` on one to be read as a caution; a row that is neither has neither. The rows come in this order:
|
|
39
|
+
|
|
40
|
+
| `label` | `value` |
|
|
41
|
+
| ----------- | ----------------------------------------------------------------------------------------- |
|
|
42
|
+
| `Where` | The machine's own name |
|
|
43
|
+
| `Folder` | The workspace's path on that machine, as a path |
|
|
44
|
+
| `Reaches` | `Read-only files`, `Files`, or `Files and terminal`; with a browser, `, Browser` after it |
|
|
45
|
+
| `Isolation` | `None: it acts as you`, as a caution, or `A container of its own` |
|
|
46
|
+
| `CPU` | Used, of all the machine's CPUs, as a whole percentage: `37%` |
|
|
47
|
+
| `Memory` | Used of the machine's total, counted in 1024s and written GB: `9.2 of 16 GB` |
|
|
48
|
+
| `Disk` | Used of total, of the volume the workspace is on, counted in 1000s: `212 of 494 GB` |
|
|
49
|
+
|
|
50
|
+
- **In a container** the agent's commands find the folder somewhere else, so `Folder` says both and is not marked as a path: `/home/me/Research on the machine, mounted at /workspace in it`. CPU and Memory there are the computer's own; with no isolation they are the whole machine's.
|
|
51
|
+
- **The last three** are a reading of its load taken over half a second when it is asked, in the same way the `load` surface reads. They come together, or not at all where a reading can't be taken.
|
|
52
|
+
- **Not every computer has it.** One with no `computer` endpoint has no `about`. One in a container made by an earlier version keeps the program it was made with: `about` is listed among its tools and isn't there until it is killed and made again.
|
|
53
|
+
|
|
38
54
|
The file tools stay inside the workspace. That's a check, not a boundary. Below `terminal`, the browser's `browser_run_code_unsafe` tool is hidden and refused, because it would otherwise be a terminal. The service enforces all of this, whatever the client does.
|
|
39
55
|
|
|
40
56
|
`--browser` drives the Google Chrome installed on the machine, in a profile of the computer's own. `serve --browser-name` and `--browser-path` choose another. The browser has no debug port: a small host process starts it and shares it on a Unix socket in a folder only its user can enter, which the agent's tools and the live view both use. It lives as long as its computer does: a client that ends its session or goes away leaves the browser and its pages as they are, and the agent's `browser_close` is refused. Only an agent with `--access terminal` can stop it, with `browser_run_code_unsafe` or from its terminal.
|
|
@@ -169,7 +185,7 @@ Every running computer has one more, to watch only:
|
|
|
169
185
|
- **`load`** (protocol `metrics@1`): how busy it is. The service sends a reading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later: `{"type":"reading","scope":"machine","cpuUsedPct":37.2,"memUsed":…,"memTotal":…,"diskUsed":…,"diskTotal":…}`, in bytes. `openapi.yaml` has each field, as `LoadReading`.
|
|
170
186
|
- **`scope` says whose numbers they are.** A computer in a container reads its own (`computer`), against the machine's totals, since a container has no limit of its own. A computer with no isolation has no edge to measure at, so it reads the whole machine's (`machine`), as every other computer of that service does; so does a container that can't read its own.
|
|
171
187
|
- **The disk is the volume its workspace is on,** not the workspace's own size.
|
|
172
|
-
- **Nothing depends on it.** Nothing is read while nobody watches, a reading that can't be taken is left out, and a socket that hasn't read the one before is not sent the next.
|
|
188
|
+
- **Nothing depends on it.** Nothing is read while nobody watches or asks, a reading that can't be taken is left out, and a socket that hasn't read the one before is not sent the next.
|
|
173
189
|
|
|
174
190
|
`POST /v1/computers/{computerID}/live` with `{ "surface": "terminal", "mode": "operate" }` gives a ticket: a `url` to open once within a minute, which needs no token. A request with an `Origin` header is refused unless `serve --allow-origin` names that origin, so a page can't open one. The SDK does the same with `computer.terminals.connect({ onEvent })`, or gives the ticket alone with `computer.liveSession("files")` or `computer.liveSession("browser", "operate")`, and the CLI with `agentcomputer live <id> --surface terminal --mode operate`.
|
|
175
191
|
|
package/dist/agentcomputer.js
CHANGED
|
@@ -3849,7 +3849,8 @@ async function serveBrowserMcp(options) {
|
|
|
3849
3849
|
import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
|
|
3850
3850
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
3851
3851
|
import { connect } from "node:net";
|
|
3852
|
-
import {
|
|
3852
|
+
import { hostname as hostname4 } from "node:os";
|
|
3853
|
+
import { join as join8 } from "node:path";
|
|
3853
3854
|
import { createInterface as createInterface2 } from "node:readline";
|
|
3854
3855
|
import { Readable as Readable3 } from "node:stream";
|
|
3855
3856
|
import { promisify as promisify2 } from "node:util";
|
|
@@ -5806,9 +5807,9 @@ var asciiTabOrNewline = /[\t\n\r]/g;
|
|
|
5806
5807
|
function stripTabAndNewline(value) {
|
|
5807
5808
|
return value.replace(asciiTabOrNewline, "");
|
|
5808
5809
|
}
|
|
5809
|
-
function urlHostnameOk(url3,
|
|
5810
|
-
|
|
5811
|
-
return
|
|
5810
|
+
function urlHostnameOk(url3, hostname5) {
|
|
5811
|
+
hostname5.lastIndex = 0;
|
|
5812
|
+
return hostname5.test(url3.hostname);
|
|
5812
5813
|
}
|
|
5813
5814
|
function urlProtocolOk(url3, protocol) {
|
|
5814
5815
|
protocol.lastIndex = 0;
|
|
@@ -24148,8 +24149,8 @@ function applyPostAuth(clientId, clientSecret, params) {
|
|
|
24148
24149
|
function applyPublicAuth(clientId, params) {
|
|
24149
24150
|
params.set("client_id", clientId);
|
|
24150
24151
|
}
|
|
24151
|
-
function isLoopbackHost(
|
|
24152
|
-
return
|
|
24152
|
+
function isLoopbackHost(hostname5) {
|
|
24153
|
+
return hostname5 === "localhost" || hostname5.endsWith(".localhost") || hostname5 === "127.0.0.1" || hostname5 === "[::1]" || hostname5 === "::1";
|
|
24153
24154
|
}
|
|
24154
24155
|
function assertSecureTokenEndpoint(tokenEndpoint) {
|
|
24155
24156
|
const url3 = new URL(String(tokenEndpoint));
|
|
@@ -28158,6 +28159,7 @@ import { join as join7 } from "node:path";
|
|
|
28158
28159
|
// src/runtime.ts
|
|
28159
28160
|
import { chmodSync as chmodSync2, existsSync, statSync as statSync2 } from "node:fs";
|
|
28160
28161
|
import { createRequire as createRequire3 } from "node:module";
|
|
28162
|
+
import { hostname as hostname3 } from "node:os";
|
|
28161
28163
|
import { basename as basename2, dirname as dirname3, join as join6 } from "node:path";
|
|
28162
28164
|
|
|
28163
28165
|
// node_modules/@agentorg/exec/dist/lib.js
|
|
@@ -31928,9 +31930,9 @@ var asciiTabOrNewline2 = /[\t\n\r]/g;
|
|
|
31928
31930
|
function stripTabAndNewline2(value) {
|
|
31929
31931
|
return value.replace(asciiTabOrNewline2, "");
|
|
31930
31932
|
}
|
|
31931
|
-
function urlHostnameOk2(url22,
|
|
31932
|
-
|
|
31933
|
-
return
|
|
31933
|
+
function urlHostnameOk2(url22, hostname32) {
|
|
31934
|
+
hostname32.lastIndex = 0;
|
|
31935
|
+
return hostname32.test(url22.hostname);
|
|
31934
31936
|
}
|
|
31935
31937
|
function urlProtocolOk2(url22, protocol) {
|
|
31936
31938
|
protocol.lastIndex = 0;
|
|
@@ -66541,9 +66543,30 @@ var Answered = {
|
|
|
66541
66543
|
var YieldTime = external_exports.number().int().positive().optional();
|
|
66542
66544
|
var MaxTokens = external_exports.number().int().positive().optional();
|
|
66543
66545
|
var READ_ONLY = { readOnlyHint: true };
|
|
66544
|
-
|
|
66546
|
+
var TOOLS = [
|
|
66547
|
+
"exec_command",
|
|
66548
|
+
"write_stdin",
|
|
66549
|
+
"list_sessions",
|
|
66550
|
+
"read",
|
|
66551
|
+
"list",
|
|
66552
|
+
"search",
|
|
66553
|
+
"edit"
|
|
66554
|
+
];
|
|
66555
|
+
function createServer2(root, sessions, version22, level, extraTools = []) {
|
|
66545
66556
|
const server = new McpServer({ name: "agentexec", version: version22 });
|
|
66546
66557
|
const files = createFiles(root);
|
|
66558
|
+
for (const { name, description, readOnly, call } of extraTools)
|
|
66559
|
+
server.registerTool(
|
|
66560
|
+
name,
|
|
66561
|
+
{ description, ...readOnly ? { annotations: READ_ONLY } : {} },
|
|
66562
|
+
async () => {
|
|
66563
|
+
try {
|
|
66564
|
+
return text(String(await call()));
|
|
66565
|
+
} catch (error62) {
|
|
66566
|
+
return { isError: true, ...text(error62 instanceof Error ? error62.message : String(error62)) };
|
|
66567
|
+
}
|
|
66568
|
+
}
|
|
66569
|
+
);
|
|
66547
66570
|
if (level === "terminal") {
|
|
66548
66571
|
server.registerTool(
|
|
66549
66572
|
"exec_command",
|
|
@@ -66654,7 +66677,7 @@ function createServer2(root, sessions, version22, level) {
|
|
|
66654
66677
|
);
|
|
66655
66678
|
return server;
|
|
66656
66679
|
}
|
|
66657
|
-
var VERSION = "0.0.
|
|
66680
|
+
var VERSION = "0.0.6";
|
|
66658
66681
|
function createAgentExec(options) {
|
|
66659
66682
|
const root = realpathSync(resolve3(options.workspace));
|
|
66660
66683
|
const level = options.level ?? "read";
|
|
@@ -66671,9 +66694,15 @@ function createAgentExec(options) {
|
|
|
66671
66694
|
options.pty
|
|
66672
66695
|
);
|
|
66673
66696
|
const host = createHostFiles(root, level);
|
|
66697
|
+
const extraTools = [...options.extraTools ?? []];
|
|
66698
|
+
const names = new Set(TOOLS);
|
|
66699
|
+
for (const { name } of extraTools) {
|
|
66700
|
+
if (names.has(name)) throw new Error(`There is already a tool called ${name}.`);
|
|
66701
|
+
names.add(name);
|
|
66702
|
+
}
|
|
66674
66703
|
return {
|
|
66675
66704
|
async handle(request, response, body) {
|
|
66676
|
-
const server = createServer2(root, sessions, VERSION, level);
|
|
66705
|
+
const server = createServer2(root, sessions, VERSION, level, extraTools);
|
|
66677
66706
|
const transport = new NodeStreamableHTTPServerTransport({ sessionIdGenerator: void 0 });
|
|
66678
66707
|
response.once("close", () => {
|
|
66679
66708
|
void transport.close();
|
|
@@ -66703,6 +66732,48 @@ function createAgentExec(options) {
|
|
|
66703
66732
|
};
|
|
66704
66733
|
}
|
|
66705
66734
|
|
|
66735
|
+
// src/about.ts
|
|
66736
|
+
var REACHES = {
|
|
66737
|
+
read: "Read-only files",
|
|
66738
|
+
files: "Files",
|
|
66739
|
+
terminal: "Files and terminal"
|
|
66740
|
+
};
|
|
66741
|
+
var GIB = 1024 ** 3;
|
|
66742
|
+
var GB = 1e3 ** 3;
|
|
66743
|
+
var tenths = (count) => String(Math.round(count * 10) / 10);
|
|
66744
|
+
var whole = (count) => String(Math.round(count));
|
|
66745
|
+
function aboutTool(facts, load) {
|
|
66746
|
+
return {
|
|
66747
|
+
name: "about",
|
|
66748
|
+
description: 'What this computer is, in the words a person looking at it reads: where it is, its folder, what it reaches, how it is isolated and how loaded it is. Takes nothing. Answers JSON text: {"rows": [{"label": "Where", "value": "..."}]}, with "path": true on a value that is a path and "caution": true on one to be read as a caution.',
|
|
66749
|
+
readOnly: true,
|
|
66750
|
+
async call() {
|
|
66751
|
+
const { outside, inside: inside2 } = facts.workspace;
|
|
66752
|
+
const rows = [
|
|
66753
|
+
{ label: "Where", value: facts.machine },
|
|
66754
|
+
// In a container its commands find the folder somewhere else, so the row says both.
|
|
66755
|
+
inside2 === outside ? { label: "Folder", value: outside, path: true } : { label: "Folder", value: `${outside} on the machine, mounted at ${inside2} in it` },
|
|
66756
|
+
{ label: "Reaches", value: REACHES[facts.access] + (facts.browser ? ", Browser" : "") },
|
|
66757
|
+
facts.contained ? { label: "Isolation", value: "A container of its own" } : { label: "Isolation", value: "None: it acts as you", caution: true }
|
|
66758
|
+
];
|
|
66759
|
+
const reading = await load.now();
|
|
66760
|
+
if (reading)
|
|
66761
|
+
rows.push(
|
|
66762
|
+
{ label: "CPU", value: `${whole(reading.cpuUsedPct)}%` },
|
|
66763
|
+
{
|
|
66764
|
+
label: "Memory",
|
|
66765
|
+
value: `${tenths(reading.memUsed / GIB)} of ${tenths(reading.memTotal / GIB)} GB`
|
|
66766
|
+
},
|
|
66767
|
+
{
|
|
66768
|
+
label: "Disk",
|
|
66769
|
+
value: `${whole(reading.diskUsed / GB)} of ${whole(reading.diskTotal / GB)} GB`
|
|
66770
|
+
}
|
|
66771
|
+
);
|
|
66772
|
+
return JSON.stringify({ rows });
|
|
66773
|
+
}
|
|
66774
|
+
};
|
|
66775
|
+
}
|
|
66776
|
+
|
|
66706
66777
|
// src/screencast.ts
|
|
66707
66778
|
var FIRST_FRAME_MS = 500;
|
|
66708
66779
|
var RESTARTS = 3;
|
|
@@ -67123,7 +67194,7 @@ var MAX_BUFFERED2 = 4 * 1024 * 1024;
|
|
|
67123
67194
|
var MAX_UPLOADS = 64;
|
|
67124
67195
|
var reason2 = (error62) => error62 instanceof Error ? error62.message : String(error62);
|
|
67125
67196
|
var text2 = (value) => typeof value === "string";
|
|
67126
|
-
var
|
|
67197
|
+
var whole2 = (value) => Number.isSafeInteger(value);
|
|
67127
67198
|
var sleep4 = (ms) => new Promise((done) => setTimeout(done, ms));
|
|
67128
67199
|
var FilesLive = class {
|
|
67129
67200
|
#files;
|
|
@@ -67242,7 +67313,7 @@ var FilesLive = class {
|
|
|
67242
67313
|
awaited = "refused";
|
|
67243
67314
|
if (mode !== "operate") throw new Error("This socket watches: it can't write.");
|
|
67244
67315
|
const { path, offset, length, last } = request;
|
|
67245
|
-
if (!text2(path) || !
|
|
67316
|
+
if (!text2(path) || !whole2(offset) || offset < 0 || !whole2(length) || length < 0 || length > MAX_PART || typeof last !== "boolean")
|
|
67246
67317
|
throw new Error(
|
|
67247
67318
|
"A write names a path, where it starts, 0 to 1,048,576 bytes, and last."
|
|
67248
67319
|
);
|
|
@@ -67439,6 +67510,7 @@ import { readFile as readFile2 } from "node:fs/promises";
|
|
|
67439
67510
|
import { availableParallelism, cpus, freemem, totalmem } from "node:os";
|
|
67440
67511
|
import { promisify } from "node:util";
|
|
67441
67512
|
var EVERY_MS = 2e3;
|
|
67513
|
+
var ONCE_MS = 500;
|
|
67442
67514
|
var run = promisify(execFile);
|
|
67443
67515
|
var numberOf = (text3, name) => Number(new RegExp(`^${name}\\s+(\\d+)`, "m").exec(text3)?.[1]);
|
|
67444
67516
|
async function disk(folder) {
|
|
@@ -67477,6 +67549,18 @@ async function cgroup() {
|
|
|
67477
67549
|
memUsed: Number(current) - numberOf(memory, "inactive_file")
|
|
67478
67550
|
};
|
|
67479
67551
|
}
|
|
67552
|
+
function readingOf(before, sample, volume) {
|
|
67553
|
+
const share = (sample.cpu.used - before.used) / (sample.cpu.total - before.total) || 0;
|
|
67554
|
+
const reading = {
|
|
67555
|
+
type: "reading",
|
|
67556
|
+
scope: sample.scope,
|
|
67557
|
+
cpuUsedPct: Math.round(Math.min(Math.max(share, 0), 1) * 1e3) / 10,
|
|
67558
|
+
memUsed: sample.memUsed,
|
|
67559
|
+
memTotal: totalmem(),
|
|
67560
|
+
...volume
|
|
67561
|
+
};
|
|
67562
|
+
return Number.isFinite(reading.cpuUsedPct + reading.memUsed) ? reading : void 0;
|
|
67563
|
+
}
|
|
67480
67564
|
var LoadLive = class {
|
|
67481
67565
|
#folder;
|
|
67482
67566
|
#contained;
|
|
@@ -67510,28 +67594,33 @@ var LoadLive = class {
|
|
|
67510
67594
|
this.#timer = this.#before = this.#last = void 0;
|
|
67511
67595
|
for (const ws of this.#sockets) ws.close(1001, "It stopped.");
|
|
67512
67596
|
}
|
|
67597
|
+
/** Its own, inside a container that can read it; else the machine's. */
|
|
67598
|
+
#sample() {
|
|
67599
|
+
return this.#contained ? cgroup().catch(machine) : machine();
|
|
67600
|
+
}
|
|
67601
|
+
/** One reading for whoever asks once, taken over half a second. None where it can't be. */
|
|
67602
|
+
async now() {
|
|
67603
|
+
try {
|
|
67604
|
+
const before = await this.#sample();
|
|
67605
|
+
await new Promise((done) => setTimeout(done, ONCE_MS));
|
|
67606
|
+
return readingOf(before.cpu, await this.#sample(), await disk(this.#folder));
|
|
67607
|
+
} catch {
|
|
67608
|
+
return void 0;
|
|
67609
|
+
}
|
|
67610
|
+
}
|
|
67513
67611
|
/** One at a time, and for the watching it began under: a reading taken too late is left. */
|
|
67514
67612
|
async #read() {
|
|
67515
67613
|
const timer = this.#timer;
|
|
67516
67614
|
if (this.#reading) return;
|
|
67517
67615
|
this.#reading = true;
|
|
67518
67616
|
try {
|
|
67519
|
-
const sample = await
|
|
67617
|
+
const sample = await this.#sample();
|
|
67520
67618
|
const volume = await disk(this.#folder);
|
|
67521
67619
|
if (this.#timer !== timer) return;
|
|
67522
67620
|
const before = this.#before;
|
|
67523
67621
|
this.#before = sample.cpu;
|
|
67524
|
-
|
|
67525
|
-
|
|
67526
|
-
const reading = {
|
|
67527
|
-
type: "reading",
|
|
67528
|
-
scope: sample.scope,
|
|
67529
|
-
cpuUsedPct: Math.round(Math.min(Math.max(share, 0), 1) * 1e3) / 10,
|
|
67530
|
-
memUsed: sample.memUsed,
|
|
67531
|
-
memTotal: totalmem(),
|
|
67532
|
-
...volume
|
|
67533
|
-
};
|
|
67534
|
-
if (!Number.isFinite(reading.cpuUsedPct + reading.memUsed)) return;
|
|
67622
|
+
const reading = before && readingOf(before, sample, volume);
|
|
67623
|
+
if (!reading) return;
|
|
67535
67624
|
this.#last = JSON.stringify(reading);
|
|
67536
67625
|
for (const ws of this.#sockets) if (ws.bufferedAmount === 0) ws.send(this.#last);
|
|
67537
67626
|
} catch {
|
|
@@ -67610,7 +67699,7 @@ var ProcessRuntime = class {
|
|
|
67610
67699
|
isolation = "none";
|
|
67611
67700
|
#config;
|
|
67612
67701
|
#contained;
|
|
67613
|
-
/** `contained` is for inside a container, where load
|
|
67702
|
+
/** `contained` is for inside a container, where the computer and its load are its own. */
|
|
67614
67703
|
constructor(config3, contained = false) {
|
|
67615
67704
|
this.#config = config3;
|
|
67616
67705
|
this.#contained = contained;
|
|
@@ -67622,13 +67711,27 @@ var ProcessRuntime = class {
|
|
|
67622
67711
|
async remove() {
|
|
67623
67712
|
}
|
|
67624
67713
|
async start(spec, folder, events) {
|
|
67714
|
+
const load = new LoadLive(spec.workspace ?? folder, this.#contained);
|
|
67625
67715
|
let exec;
|
|
67626
|
-
if (spec.access !== "none")
|
|
67716
|
+
if (spec.access !== "none") {
|
|
67717
|
+
const workspace = spec.workspace;
|
|
67718
|
+
const about = aboutTool(
|
|
67719
|
+
{
|
|
67720
|
+
machine: spec.outside?.machine ?? hostname3(),
|
|
67721
|
+
workspace: { outside: spec.outside?.workspace ?? workspace, inside: workspace },
|
|
67722
|
+
access: spec.access,
|
|
67723
|
+
browser: spec.browser,
|
|
67724
|
+
contained: this.#contained
|
|
67725
|
+
},
|
|
67726
|
+
load
|
|
67727
|
+
);
|
|
67627
67728
|
exec = createAgentExec({
|
|
67628
|
-
workspace
|
|
67729
|
+
workspace,
|
|
67629
67730
|
level: spec.access,
|
|
67630
|
-
pty: await loadPty()
|
|
67731
|
+
pty: await loadPty(),
|
|
67732
|
+
extraTools: [about]
|
|
67631
67733
|
});
|
|
67734
|
+
}
|
|
67632
67735
|
let browser;
|
|
67633
67736
|
let browserDown = false;
|
|
67634
67737
|
if (spec.browser) {
|
|
@@ -67656,8 +67759,7 @@ var ProcessRuntime = class {
|
|
|
67656
67759
|
browserLive = new BrowserLive(browser.endpoint);
|
|
67657
67760
|
browser.gate = browserLive;
|
|
67658
67761
|
}
|
|
67659
|
-
const
|
|
67660
|
-
const files = exec && new FilesLive(exec.files, spec.workspaceName ?? basename2(spec.workspace));
|
|
67762
|
+
const files = exec && new FilesLive(exec.files, basename2(spec.outside?.workspace ?? spec.workspace));
|
|
67661
67763
|
const live = new Live(exec, spec.access, load, files, browserLive);
|
|
67662
67764
|
const surfaces = live.surfaces();
|
|
67663
67765
|
return {
|
|
@@ -67688,7 +67790,8 @@ var ProcessRuntime = class {
|
|
|
67688
67790
|
// src/inside.ts
|
|
67689
67791
|
var INNER_PORT = 8e3;
|
|
67690
67792
|
var INNER_TOKEN_VARIABLE = "AGENTCOMPUTER_INNER_TOKEN";
|
|
67691
|
-
var
|
|
67793
|
+
var OUTSIDE_WORKSPACE_VARIABLE = "AGENTCOMPUTER_OUTSIDE_WORKSPACE";
|
|
67794
|
+
var OUTSIDE_MACHINE_VARIABLE = "AGENTCOMPUTER_OUTSIDE_MACHINE";
|
|
67692
67795
|
var BROWSER = "/opt/browsers/headless-shell";
|
|
67693
67796
|
async function serveInside(options) {
|
|
67694
67797
|
const token = process.env[INNER_TOKEN_VARIABLE];
|
|
@@ -67699,7 +67802,11 @@ async function serveInside(options) {
|
|
|
67699
67802
|
{
|
|
67700
67803
|
id: "inside",
|
|
67701
67804
|
...options,
|
|
67702
|
-
...options.access === "none" ? {} : { workspace: "/workspace"
|
|
67805
|
+
...options.access === "none" ? {} : { workspace: "/workspace" },
|
|
67806
|
+
outside: {
|
|
67807
|
+
workspace: process.env[OUTSIDE_WORKSPACE_VARIABLE],
|
|
67808
|
+
machine: process.env[OUTSIDE_MACHINE_VARIABLE]
|
|
67809
|
+
}
|
|
67703
67810
|
},
|
|
67704
67811
|
privateFolder(join7(homedir(), ".agentcomputer")),
|
|
67705
67812
|
{
|
|
@@ -67810,6 +67917,10 @@ var ContainerRuntime = class {
|
|
|
67810
67917
|
}
|
|
67811
67918
|
async #create(name, spec, token) {
|
|
67812
67919
|
const uid = process.getuid?.();
|
|
67920
|
+
const told = {
|
|
67921
|
+
[INNER_TOKEN_VARIABLE]: token,
|
|
67922
|
+
...spec.workspace ? { [OUTSIDE_WORKSPACE_VARIABLE]: spec.workspace, [OUTSIDE_MACHINE_VARIABLE]: hostname4() } : {}
|
|
67923
|
+
};
|
|
67813
67924
|
await docker(
|
|
67814
67925
|
[
|
|
67815
67926
|
"create",
|
|
@@ -67824,12 +67935,8 @@ var ContainerRuntime = class {
|
|
|
67824
67935
|
"no-new-privileges",
|
|
67825
67936
|
"--publish",
|
|
67826
67937
|
`127.0.0.1::${INNER_PORT}`,
|
|
67827
|
-
// By name, so the
|
|
67828
|
-
"--env",
|
|
67829
|
-
INNER_TOKEN_VARIABLE,
|
|
67830
|
-
// What its workspace is called, which in there is only /workspace. An image from before
|
|
67831
|
-
// this was told leaves it.
|
|
67832
|
-
...spec.workspace ? ["--env", WORKSPACE_NAME_VARIABLE] : [],
|
|
67938
|
+
// By name, so the values stay out of the command line other users can see.
|
|
67939
|
+
...Object.keys(told).flatMap((name2) => ["--env", name2]),
|
|
67833
67940
|
// Files it writes in the workspace belong to whoever runs the service.
|
|
67834
67941
|
...uid ? ["--user", `${uid}:${process.getgid?.()}`] : [],
|
|
67835
67942
|
...spec.workspace ? [
|
|
@@ -67842,11 +67949,7 @@ var ContainerRuntime = class {
|
|
|
67842
67949
|
spec.access,
|
|
67843
67950
|
...spec.browser ? ["--browser"] : []
|
|
67844
67951
|
],
|
|
67845
|
-
{
|
|
67846
|
-
...process.env,
|
|
67847
|
-
[INNER_TOKEN_VARIABLE]: token,
|
|
67848
|
-
...spec.workspace ? { [WORKSPACE_NAME_VARIABLE]: basename3(spec.workspace) } : {}
|
|
67849
|
-
}
|
|
67952
|
+
{ ...process.env, ...told }
|
|
67850
67953
|
);
|
|
67851
67954
|
}
|
|
67852
67955
|
/** The token between the service and this container, which a restart has to find again. */
|
|
@@ -67990,7 +68093,7 @@ async function forward(url3, authorization, request, response) {
|
|
|
67990
68093
|
}
|
|
67991
68094
|
|
|
67992
68095
|
// src/handlers.ts
|
|
67993
|
-
var VERSION2 = "0.0.
|
|
68096
|
+
var VERSION2 = "0.0.12";
|
|
67994
68097
|
function createHandlers(computers) {
|
|
67995
68098
|
return {
|
|
67996
68099
|
getInfo: async () => ({ version: VERSION2, isolation: computers.isolation }),
|
|
@@ -84631,10 +84734,12 @@ var NodeStreamableHTTPServerTransport2 = class {
|
|
|
84631
84734
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
84632
84735
|
import { appendFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
|
|
84633
84736
|
import { isAbsolute, join as join9, resolve as resolve4 } from "node:path";
|
|
84634
|
-
var
|
|
84635
|
-
|
|
84636
|
-
|
|
84637
|
-
|
|
84737
|
+
var READ = ["about", "read", "list", "search"];
|
|
84738
|
+
var FILES = [...READ, "edit"];
|
|
84739
|
+
var TOOLS2 = {
|
|
84740
|
+
read: READ,
|
|
84741
|
+
files: FILES,
|
|
84742
|
+
terminal: [...FILES, "exec_command", "write_stdin", "list_sessions"]
|
|
84638
84743
|
};
|
|
84639
84744
|
var MAX_LOG = 256 * 1024;
|
|
84640
84745
|
var MAX_TIMER_S = 2e6;
|
|
@@ -84733,7 +84838,7 @@ var Computers = class {
|
|
|
84733
84838
|
...this.#describe(stored),
|
|
84734
84839
|
uptimeSeconds: stored.state === "running" ? Math.round((Date.now() - Date.parse(stored.startedAt)) / 1e3) : 0,
|
|
84735
84840
|
tools: {
|
|
84736
|
-
computer: stored.access === "none" ? [] :
|
|
84841
|
+
computer: stored.access === "none" ? [] : TOOLS2[stored.access],
|
|
84737
84842
|
browser: live?.running?.browserTools ?? []
|
|
84738
84843
|
},
|
|
84739
84844
|
surfaces: live?.running?.surfaces ?? []
|
|
@@ -84953,7 +85058,7 @@ var OPENAPI = {
|
|
|
84953
85058
|
"openapi": "3.1.0",
|
|
84954
85059
|
"info": {
|
|
84955
85060
|
"title": "AgentComputer",
|
|
84956
|
-
"version": "0.0.
|
|
85061
|
+
"version": "0.0.12",
|
|
84957
85062
|
"description": "Computers for agents. This file is the source of truth: the HTTP API, the MCP control tools and the SDK are all generated from it. An operation with `x-mcp-tool` is also an MCP tool of that name.",
|
|
84958
85063
|
"license": {
|
|
84959
85064
|
"name": "Apache-2.0",
|
|
@@ -85405,7 +85510,7 @@ var OPENAPI = {
|
|
|
85405
85510
|
"files",
|
|
85406
85511
|
"terminal"
|
|
85407
85512
|
],
|
|
85408
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
85513
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
85409
85514
|
},
|
|
85410
85515
|
"ComputerState": {
|
|
85411
85516
|
"type": "string",
|
|
@@ -85618,7 +85723,7 @@ var OPENAPI = {
|
|
|
85618
85723
|
"browser",
|
|
85619
85724
|
"load"
|
|
85620
85725
|
],
|
|
85621
|
-
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
85726
|
+
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches or asks."
|
|
85622
85727
|
},
|
|
85623
85728
|
"LiveMode": {
|
|
85624
85729
|
"type": "string",
|
|
@@ -86795,7 +86900,7 @@ var OPERATIONS = [
|
|
|
86795
86900
|
"files",
|
|
86796
86901
|
"terminal"
|
|
86797
86902
|
],
|
|
86798
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
86903
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
86799
86904
|
},
|
|
86800
86905
|
"browser": {
|
|
86801
86906
|
"type": "boolean"
|
|
@@ -86884,7 +86989,7 @@ var OPERATIONS = [
|
|
|
86884
86989
|
"files",
|
|
86885
86990
|
"terminal"
|
|
86886
86991
|
],
|
|
86887
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
86992
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
86888
86993
|
},
|
|
86889
86994
|
"browser": {
|
|
86890
86995
|
"type": "boolean",
|
|
@@ -86954,7 +87059,7 @@ var OPERATIONS = [
|
|
|
86954
87059
|
"files",
|
|
86955
87060
|
"terminal"
|
|
86956
87061
|
],
|
|
86957
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87062
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
86958
87063
|
},
|
|
86959
87064
|
"browser": {
|
|
86960
87065
|
"type": "boolean"
|
|
@@ -87094,7 +87199,7 @@ var OPERATIONS = [
|
|
|
87094
87199
|
"files",
|
|
87095
87200
|
"terminal"
|
|
87096
87201
|
],
|
|
87097
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87202
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87098
87203
|
},
|
|
87099
87204
|
"browser": {
|
|
87100
87205
|
"type": "boolean"
|
|
@@ -87183,7 +87288,7 @@ var OPERATIONS = [
|
|
|
87183
87288
|
"browser",
|
|
87184
87289
|
"load"
|
|
87185
87290
|
],
|
|
87186
|
-
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
87291
|
+
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches or asks."
|
|
87187
87292
|
},
|
|
87188
87293
|
"protocol": {
|
|
87189
87294
|
"type": "string"
|
|
@@ -87325,7 +87430,7 @@ var OPERATIONS = [
|
|
|
87325
87430
|
"files",
|
|
87326
87431
|
"terminal"
|
|
87327
87432
|
],
|
|
87328
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87433
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87329
87434
|
},
|
|
87330
87435
|
"browser": {
|
|
87331
87436
|
"type": "boolean"
|
|
@@ -87449,7 +87554,7 @@ var OPERATIONS = [
|
|
|
87449
87554
|
"files",
|
|
87450
87555
|
"terminal"
|
|
87451
87556
|
],
|
|
87452
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87557
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87453
87558
|
},
|
|
87454
87559
|
"browser": {
|
|
87455
87560
|
"type": "boolean"
|
|
@@ -87578,7 +87683,7 @@ var OPERATIONS = [
|
|
|
87578
87683
|
"files",
|
|
87579
87684
|
"terminal"
|
|
87580
87685
|
],
|
|
87581
|
-
"description": "How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87686
|
+
"description": "How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden."
|
|
87582
87687
|
},
|
|
87583
87688
|
"browser": {
|
|
87584
87689
|
"type": "boolean"
|
|
@@ -87723,7 +87828,7 @@ var OPERATIONS = [
|
|
|
87723
87828
|
"browser",
|
|
87724
87829
|
"load"
|
|
87725
87830
|
],
|
|
87726
|
-
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
87831
|
+
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches or asks."
|
|
87727
87832
|
},
|
|
87728
87833
|
"mode": {
|
|
87729
87834
|
"allOf": [
|
|
@@ -87770,7 +87875,7 @@ var OPERATIONS = [
|
|
|
87770
87875
|
"browser",
|
|
87771
87876
|
"load"
|
|
87772
87877
|
],
|
|
87773
|
-
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches."
|
|
87878
|
+
"description": "terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches or asks."
|
|
87774
87879
|
},
|
|
87775
87880
|
"mode": {
|
|
87776
87881
|
"type": "string",
|
|
@@ -182,7 +182,7 @@ export interface components {
|
|
|
182
182
|
message: string;
|
|
183
183
|
};
|
|
184
184
|
/**
|
|
185
|
-
* @description How far it reaches into files and commands, each level containing the one before: `read` has read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden.
|
|
185
|
+
* @description How far it reaches into files and commands, each level containing the one before: `read` has about, read, list and search; `files` adds edit; `terminal` adds exec_command, write_stdin and list_sessions. Below terminal, the browser's code-running tool is hidden.
|
|
186
186
|
* @enum {string}
|
|
187
187
|
*/
|
|
188
188
|
Access: "none" | "read" | "files" | "terminal";
|
|
@@ -248,7 +248,7 @@ export interface components {
|
|
|
248
248
|
};
|
|
249
249
|
};
|
|
250
250
|
/**
|
|
251
|
-
* @description terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches.
|
|
251
|
+
* @description terminal: every terminal on it, the agent's commands and a person's shells alike, on one socket in terminal@1: text messages are TerminalEvent one way and TerminalInput the other. Watching reads them all; operating also opens a shell, types into any of them, the agent's included, sizes and stops them. files: its workspace's files, in files@1: text messages are FilesRequest one way and FilesAnswer the other, and a file's bytes travel as binary messages of at most 1,048,576 bytes. Watching lists and reads; operating also writes, which a computer with read access doesn't offer. browser: its browser, in screencast@1: binary messages are JPEG frames of the page shown, text messages are ScreencastEvent one way and ScreencastInput the other. Nobody waits for anybody: the agent's tools and a person's input act on the same browser at once. The page shown is each socket's own. A socket is shown each new tab as it opens, until it sends a tab input to show or open one; from then its page changes only when that page closes. load: how busy it is, in metrics@1, to watch only: a LoadReading every two seconds while a socket is open, the first two seconds after the first socket opens, and the last one at once to a socket that opens later. One that can't be taken is left out, and a socket that hasn't read the one before is not sent the next. Nothing is read while nobody watches or asks.
|
|
252
252
|
* @enum {string}
|
|
253
253
|
*/
|
|
254
254
|
Surface: "terminal" | "files" | "browser" | "load";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentorg/computer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "Computers for agents, as a service: a terminal, files and a browser over MCP",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"playwright-core": "1.65.0-alpha-2026-10-30"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@agentorg/exec": "0.0.
|
|
34
|
+
"@agentorg/exec": "0.0.6",
|
|
35
35
|
"@biomejs/biome": "2.6.5",
|
|
36
36
|
"@modelcontextprotocol/client": "2.4.0",
|
|
37
37
|
"@modelcontextprotocol/node": "2.1.2",
|