@agentorg/computer 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -139,7 +139,7 @@ A computer at `--access terminal` has two surfaces you can open live, as a WebSo
139
139
 
140
140
  A computer with `--browser` has a third:
141
141
 
142
- - **`browser`** (protocol `screencast@1`): its browser, on the same page the agent works on. Binary messages are JPEG frames of the page shown. Text messages are JSON: the service sends `tabs`, `viewport`, `dialog`, `file-chooser`, `choice` and `driver`, and an `operate` socket sends `mouse`, `key`, `text`, `dialog`, `files`, `choice`, `tab`, `navigate` and `release`. `openapi.yaml` has each one's fields. A page's own dialogs, file choosers and select lists aren't in the frames, so they arrive as events for you to show and answer. Operating it makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had the browser. You stop being the driver when you send `release`, close the socket, or send nothing for 60 seconds.
142
+ - **`browser`** (protocol `screencast@1`): its browser, on the same page the agent works on. Binary messages are JPEG frames of the page shown. Text messages are JSON: the service sends `tabs`, `viewport`, `dialog`, `file-chooser`, `choice` and `driver`, and an `operate` socket sends `mouse`, `key`, `text`, `dialog`, `files`, `choice`, `tab`, `navigate` and `release`. `openapi.yaml` has each one's fields. A page's own dialogs, file choosers and select lists aren't in the frames, so they arrive as events for you to show and answer. Opening it to operate makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had the browser. You stop being the driver when you send `release`, close the socket, or send nothing for 60 seconds, and sending input takes it again.
143
143
 
144
144
  `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.pty.connect({ onData })` and `computer.commands.watch(onEvent)`, and the CLI with `agentcomputer live <id> --surface terminal --mode operate`.
145
145
 
@@ -3759,7 +3759,6 @@ import { isMainThread as isMainThread2 } from "node:worker_threads";
3759
3759
 
3760
3760
  // src/browser-host.ts
3761
3761
  import { mkdtempSync, rmSync } from "node:fs";
3762
- import { tmpdir } from "node:os";
3763
3762
  import { join, sep } from "node:path";
3764
3763
 
3765
3764
  // src/playwright.ts
@@ -3773,8 +3772,9 @@ var playwright = () => {
3773
3772
  // src/browser-host.ts
3774
3773
  var sandboxFor = (options) => options.sandbox ?? (process.platform !== "linux" || !options.executable && !["chromium", "chrome-for-testing"].includes(options.channel ?? "chrome"));
3775
3774
  async function hostBrowser(options) {
3776
- const run3 = mkdtempSync(join(tmpdir(), "agentcomputer-"));
3775
+ const run3 = mkdtempSync(join("/tmp", "agentcomputer-"));
3777
3776
  process.env.XDG_RUNTIME_DIR = run3;
3777
+ process.env.TMPDIR = run3;
3778
3778
  const context = await playwright().chromium.launchPersistentContext(options.profile, {
3779
3779
  headless: true,
3780
3780
  chromiumSandbox: sandboxFor(options),
@@ -66315,6 +66315,7 @@ async function startScreencast(page, onFrame) {
66315
66315
  // src/browser-live.ts
66316
66316
  var WAIT_MS = 25e3;
66317
66317
  var IDLE_MS = 6e4;
66318
+ var TITLE_CHECK_MS = 1e3;
66318
66319
  var STEP_MS = 2e3;
66319
66320
  var MAX_BUFFERED = 4 * 1024 * 1024;
66320
66321
  var sleep3 = (ms) => new Promise((done) => setTimeout(done, ms));
@@ -66337,6 +66338,10 @@ var BrowserLive = class {
66337
66338
  #lastInput = 0;
66338
66339
  #agentWaiting = 0;
66339
66340
  #answeredChooser = false;
66341
+ /** The tabs last sent, to send them again only when something about them changed. */
66342
+ #lastTabs = "";
66343
+ #titles;
66344
+ #checking = false;
66340
66345
  #steps = Promise.resolve();
66341
66346
  constructor(endpoint) {
66342
66347
  this.#endpoint = endpoint;
@@ -66369,6 +66374,10 @@ var BrowserLive = class {
66369
66374
  // ---- The person's side
66370
66375
  open(ws, mode) {
66371
66376
  this.#sockets.set(ws, mode);
66377
+ if (mode === "operate") {
66378
+ this.#driver = ws;
66379
+ this.#lastInput = Date.now();
66380
+ }
66372
66381
  ws.on("close", () => this.#left(ws));
66373
66382
  ws.on("message", (data, binary) => {
66374
66383
  if (binary || this.#sockets.get(ws) !== "operate") return;
@@ -66418,6 +66427,7 @@ var BrowserLive = class {
66418
66427
  void this.#show(page);
66419
66428
  });
66420
66429
  await this.#show(context.pages().at(-1) ?? await context.newPage());
66430
+ this.#titles = setInterval(() => void this.#checkTabs(), TITLE_CHECK_MS);
66421
66431
  return viewer;
66422
66432
  })();
66423
66433
  await this.#viewer;
@@ -66425,6 +66435,9 @@ var BrowserLive = class {
66425
66435
  async #end() {
66426
66436
  const viewer = this.#viewer;
66427
66437
  this.#viewer = void 0;
66438
+ clearInterval(this.#titles);
66439
+ this.#titles = void 0;
66440
+ this.#lastTabs = "";
66428
66441
  await this.#stopCast?.();
66429
66442
  this.#stopCast = void 0;
66430
66443
  this.#shown = void 0;
@@ -66499,7 +66512,7 @@ var BrowserLive = class {
66499
66512
  }
66500
66513
  await this.#tabs();
66501
66514
  }
66502
- async #tabs(only) {
66515
+ async #tabList() {
66503
66516
  const tabs = await Promise.all(
66504
66517
  [...this.#ids].map(async ([page, id]) => ({
66505
66518
  id,
@@ -66507,14 +66520,28 @@ var BrowserLive = class {
66507
66520
  title: await within(page.title(), STEP_MS).catch(() => void 0) ?? ""
66508
66521
  }))
66509
66522
  );
66510
- const message = {
66511
- type: "tabs",
66512
- tabs,
66513
- shown: (this.#shown && this.#ids.get(this.#shown)) ?? null
66514
- };
66523
+ return { type: "tabs", tabs, shown: (this.#shown && this.#ids.get(this.#shown)) ?? null };
66524
+ }
66525
+ async #tabs(only) {
66526
+ const message = await this.#tabList();
66527
+ this.#lastTabs = JSON.stringify(message);
66515
66528
  if (only) this.#send(only, message);
66516
66529
  else this.#broadcast(message);
66517
66530
  }
66531
+ /** Send the tabs again if anything about them changed, such as a title. */
66532
+ async #checkTabs() {
66533
+ if (this.#checking) return;
66534
+ this.#checking = true;
66535
+ try {
66536
+ const message = await this.#tabList();
66537
+ const text2 = JSON.stringify(message);
66538
+ if (text2 === this.#lastTabs) return;
66539
+ this.#lastTabs = text2;
66540
+ this.#broadcast(message);
66541
+ } finally {
66542
+ this.#checking = false;
66543
+ }
66544
+ }
66518
66545
  /** Each step in order, none waiting on another for long: a dialog blocks the page's input. */
66519
66546
  #step(work) {
66520
66547
  this.#steps = this.#steps.then(() => within(work(), STEP_MS)).catch(() => {
@@ -67185,7 +67212,7 @@ async function forward(url3, authorization, request, response) {
67185
67212
  }
67186
67213
 
67187
67214
  // src/handlers.ts
67188
- var VERSION2 = "0.0.5";
67215
+ var VERSION2 = "0.0.7";
67189
67216
  function createHandlers(computers) {
67190
67217
  return {
67191
67218
  getInfo: async () => ({ version: VERSION2, isolation: computers.isolation }),
@@ -84160,7 +84187,7 @@ var OPENAPI = {
84160
84187
  "openapi": "3.1.0",
84161
84188
  "info": {
84162
84189
  "title": "AgentComputer",
84163
- "version": "0.0.5",
84190
+ "version": "0.0.7",
84164
84191
  "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.",
84165
84192
  "license": {
84166
84193
  "name": "Apache-2.0",
@@ -84824,7 +84851,7 @@ var OPENAPI = {
84824
84851
  "terminal",
84825
84852
  "browser"
84826
84853
  ],
84827
- "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Operating it makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds."
84854
+ "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Opening it to operate makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds, and sending input takes it again."
84828
84855
  },
84829
84856
  "LiveMode": {
84830
84857
  "type": "string",
@@ -84915,7 +84942,7 @@ var OPENAPI = {
84915
84942
  "oneOf": [
84916
84943
  {
84917
84944
  "type": "object",
84918
- "description": "The open tabs, and which one the frames are of.",
84945
+ "description": "The open tabs, and which one the frames are of, sent again whenever a tab opens, closes, navigates or changes its title.",
84919
84946
  "required": [
84920
84947
  "type",
84921
84948
  "tabs",
@@ -85846,7 +85873,7 @@ var OPERATIONS = [
85846
85873
  "terminal",
85847
85874
  "browser"
85848
85875
  ],
85849
- "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Operating it makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds."
85876
+ "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Opening it to operate makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds, and sending input takes it again."
85850
85877
  },
85851
85878
  "protocol": {
85852
85879
  "type": "string"
@@ -86386,7 +86413,7 @@ var OPERATIONS = [
86386
86413
  "terminal",
86387
86414
  "browser"
86388
86415
  ],
86389
- "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Operating it makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds."
86416
+ "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Opening it to operate makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds, and sending input takes it again."
86390
86417
  },
86391
86418
  "mode": {
86392
86419
  "allOf": [
@@ -86432,7 +86459,7 @@ var OPERATIONS = [
86432
86459
  "terminal",
86433
86460
  "browser"
86434
86461
  ],
86435
- "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Operating it makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds."
86462
+ "description": "commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Opening it to operate makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds, and sending input takes it again."
86436
86463
  },
86437
86464
  "mode": {
86438
86465
  "type": "string",
@@ -248,7 +248,7 @@ export interface components {
248
248
  };
249
249
  };
250
250
  /**
251
- * @description commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Operating it makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds.
251
+ * @description commands: the agent's commands as they run, read-only, in commands@1. terminal: a shell of your own in its workspace, as its user, in pty@1. 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. Opening it to operate makes you the driver: the agent's browser calls wait up to 25 seconds while you are, then answer that a person has or had it. You stop being the driver when you send release, close the socket, or send nothing for 60 seconds, and sending input takes it again.
252
252
  * @enum {string}
253
253
  */
254
254
  Surface: "commands" | "terminal" | "browser";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentorg/computer",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
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": {