From bdb09f4b0c0373de586a562edd2d93fa926002f6 Mon Sep 17 00:00:00 2001 From: "rivet-docs-sync[bot]" Date: Wed, 21 Oct 2026 19:29:21 +0000 Subject: [PATCH] docs(agentos): sync from rivet-dev/agentos@86a0d36 --- .../docs/custom-software/publishing.mdx | 8 +- .../docs/content/docs/host-functions.mdx | 10 +- .../agentos/docs/content/docs/javascript.mdx | 39 ++- .../agentos/docs/content/docs/networking.mdx | 7 +- .../agentos/docs/content/docs/permissions.mdx | 38 +++ .../agentos/docs/content/docs/processes.mdx | 14 + vendor/agentos/docs/content/docs/python.mdx | 5 + .../docs/content/docs/quickstart-hosted.mdx | 302 ++++++------------ .../agentos/docs/content/docs/quickstart.mdx | 74 ++--- .../docs/content/docs/resource-limits.mdx | 20 ++ vendor/agentos/docs/content/docs/software.mdx | 115 ++++++- .../examples/embedded/config-reference.ts | 8 +- .../embedded/host-functions-javascript.ts | 12 + vendor/agentos/examples/embedded/package.json | 1 - .../examples/embedded/quickstart-configure.ts | 43 +++ .../agentos/examples/embedded/quickstart.ts | 56 +--- .../examples/embedded/software-install.ts | 19 +- .../examples/embedded/software-local.ts | 26 ++ vendor/agentos/examples/embedded/software.ts | 8 +- .../examples/js-networking/src/index.ts | 39 ++- .../examples/quickstart/bash/package.json | 1 - .../examples/quickstart/cron/package.json | 1 - .../quickstart/filesystem/package.json | 1 - .../agentos/examples/quickstart/git/README.md | 2 +- .../agentos/examples/quickstart/git/index.ts | 7 +- .../examples/quickstart/git/package.json | 1 - .../quickstart/hello-world/package.json | 1 - .../examples/quickstart/network/package.json | 1 - .../examples/quickstart/nodejs/package.json | 1 - .../agentos/examples/quickstart/package.json | 1 - .../quickstart/processes/package.json | 1 - .../quickstart/s3-filesystem/package.json | 1 - .../examples/quickstart/sandbox/package.json | 1 - 33 files changed, 481 insertions(+), 383 deletions(-) create mode 100644 vendor/agentos/examples/embedded/quickstart-configure.ts create mode 100644 vendor/agentos/examples/embedded/software-local.ts diff --git a/vendor/agentos/docs/content/docs/custom-software/publishing.mdx b/vendor/agentos/docs/content/docs/custom-software/publishing.mdx index a4888d60..e1867907 100644 --- a/vendor/agentos/docs/content/docs/custom-software/publishing.mdx +++ b/vendor/agentos/docs/content/docs/custom-software/publishing.mdx @@ -31,6 +31,8 @@ https://releases.rivet.dev/agent-os/latest/software/manifest.json ``` The same directory also holds `default-software.json`, the manifest of the -packages every VM installs by default. Consumers pass an artifact URL and -digest from the manifest directly to `software.install`; see -[Software](/agentos/docs/software#install-while-running). +packages every VM installs by default. The library resolves registry names such +as `{ registry: "git" }` against this manifest. To serve packages from a mirror, +copy the `/software/` layout and point `softwareRegistry.url` or +`AGENTOS_SOFTWARE_REGISTRY_URL` at its root; see +[Software](/agentos/docs/software#registry-packages). diff --git a/vendor/agentos/docs/content/docs/host-functions.mdx b/vendor/agentos/docs/content/docs/host-functions.mdx index 819abe25..74546a67 100644 --- a/vendor/agentos/docs/content/docs/host-functions.mdx +++ b/vendor/agentos/docs/content/docs/host-functions.mdx @@ -4,7 +4,7 @@ description: "Expose trusted host functions to guest programs in agentOS VMs as skill: true --- -Host functions expose JavaScript functions from your process to code running inside the VM. They run as in-process callbacks, so they are available in the library only, not on hosted VMs. Each function is defined with a Zod input schema and becomes an auto-generated CLI command at `/bin/agentos-{name}`, plus an async function that inline JavaScript can call directly. +Host functions expose JavaScript functions from your process to code running inside the VM. They run as in-process callbacks, so they are available in the library only, not on hosted VMs. Each function is defined with a Zod input schema and becomes an auto-generated CLI command at `/bin/agentos-{name}`, plus an async function that guest JavaScript can call directly. ## Getting started @@ -66,9 +66,13 @@ Missing required flag: --city ## Call host functions from JavaScript -Inline JavaScript and TypeScript get each collection as a frozen global, and each +Every guest Node process gets each collection as a frozen global, and each host function as an async function, so generated code calls your tools like any -other API. Keys written in camelCase become kebab-case commands and camelCase guest +other API. This covers inline `vm.javascript` and `vm.typescript` executions, +scripts started with `vm.process.spawn("node", ...)` or `vm.process.exec`, +`node` run from the guest shell, and child processes of guest Node. The globals +are defined before the entry script and its imports run, so a module can use +them at its top level. Keys written in camelCase become kebab-case commands and camelCase guest identifiers, so `orderStore.listOrders` is `agentos-order-store list-orders` on the CLI and `orderStore.listOrders(input)` in guest JavaScript. diff --git a/vendor/agentos/docs/content/docs/javascript.mdx b/vendor/agentos/docs/content/docs/javascript.mdx index 44447721..faac27bf 100644 --- a/vendor/agentos/docs/content/docs/javascript.mdx +++ b/vendor/agentos/docs/content/docs/javascript.mdx @@ -39,6 +39,10 @@ console.log(sum.value); // 3 Returning `undefined`, a function, a symbol, or a circular value fails with `evaluation_serialization_failed` rather than silently losing the value. +`evaluate()` returns as soon as the expression's promise settles and its +in-flight host calls finish. Work it leaves behind is released as described in +[Keep state between calls](#keep-state-between-calls). + ## Execute code `execute()` runs source and captures its output instead of returning a value. @@ -65,6 +69,11 @@ Executions are ephemeral, so capture stdio only when you want it: `"stderr"` for diagnostics, `"all"` for both streams. `onStdout`/`onStderr` stream live and work independently of capture. +Without a `contextId`, `execute()` behaves like `node -e`: it finishes when the +event loop is empty, so a ref'd timer or a listening server keeps it running +until `timeoutMs`. Call `unref()` on handles that must not hold it open, or use +`spawn` for long-lived work. + ## Pass data into code In the library, `inputs` hands host values to the guest as real objects, so data never gets @@ -79,9 +88,29 @@ calls. -A context runs one operation at a time, so reusing a busy `contextId` fails -immediately. Files, npm, Bash, and type checks may pass the same id, but they run -in fresh processes and never touch retained memory. +A call in a context completes when its top-level code, including any promise it +awaits, settles. It does not wait for work it leaves behind. Globals stay, so the +next call sees the state, but agentOS releases what would keep a Node process +alive: + +- **Ref'd timers and immediates** are cancelled and never run. A promise that + waits on one never settles. +- **Ref'd sockets, servers, and child processes** are closed. Pending I/O on them + fails with `ERR_AGENTOS_CONTEXT_HANDLE_RELEASED`, never a clean end. A `fetch` + that is still in flight rejects with that error as its `cause`, and reading a + stored `Response` body fails the same way. +- **Unref'd timers and handles** are left alone, but nothing runs between calls, + so they only make progress while a later call is running. + +The call's stderr names what was released. Errors raised during that cleanup, +such as an unhandled rejection from a released `fetch`, are written to the same +stderr and never change the call's result. Finish I/O inside one call, and run +long-lived servers with `spawn` instead of a context. + +A context runs one call at a time. A call made while another call in the same +context is still running fails immediately with `execution_busy`. Files, npm, +Bash, and type checks may pass the same id, but they run in fresh processes and +never touch retained memory. JavaScript defaults to `format: "module"`. Each call is a separate root ES module, so its imports, top-level declarations, and exports are scoped to that @@ -192,7 +221,9 @@ See [Filesystem](/agentos/docs/filesystem), [Processes & Shells](/agentos/docs/p ## Host functions Guest JavaScript calls [host functions](/agentos/docs/host-functions) as async globals, so host -credentials stay outside the VM. Host functions are library-only. +credentials stay outside the VM. The globals exist in every guest Node process, +whether it runs inline code, a spawned script, `node` from the shell, or a child +process. Host functions are library-only. diff --git a/vendor/agentos/docs/content/docs/networking.mdx b/vendor/agentos/docs/content/docs/networking.mdx index c8feb02a..f462e7ad 100644 --- a/vendor/agentos/docs/content/docs/networking.mdx +++ b/vendor/agentos/docs/content/docs/networking.mdx @@ -77,6 +77,7 @@ browsers, route requests through your application and forward them with Guest listeners and loopback traffic stay inside the VM. Outbound access is limited to the sidecar's default allowlist unless the `network` -[permission](/agentos/docs/permissions) scope allows more. Requests from the -host and previews enter the VM from the host side, so they are subject to -loopback confinement but not to the guest egress policy. +[permission](/agentos/docs/permissions) scope allows more. `network: "deny"` +removes that allowlist and keeps listeners and loopback working. Requests from +the host and previews enter the VM over VM-local loopback, so they are subject +to loopback confinement, not to the guest egress allowlist. diff --git a/vendor/agentos/docs/content/docs/permissions.mdx b/vendor/agentos/docs/content/docs/permissions.mdx index 23d22ec3..8eb0a86d 100644 --- a/vendor/agentos/docs/content/docs/permissions.mdx +++ b/vendor/agentos/docs/content/docs/permissions.mdx @@ -20,6 +20,44 @@ processes, environment, listeners, and loopback networking work, and outbound network access is limited to the sidecar's default allowlist. Library host functions are governed by the `hostFunction` scope. +## Network + +`network: "deny"` denies traffic that crosses the VM boundary and keeps +networking inside the VM working, like a container with no published ports. + +| Traffic | `network: "deny"` | +| --- | --- | +| Guest `listen()` on TCP or Unix sockets | Allowed | +| Guest connections to its own listeners over `127.0.0.1`, `localhost`, `::1`, or Unix sockets | Allowed | +| Host requests to guest servers with `fetch`, `httpRequest`, or previews | Allowed | +| DNS lookups | Denied | +| TCP connections and HTTP requests to any non-loopback address | Denied | +| The default allowlist of model provider endpoints | Denied | + +Guest listeners are never bound on the host, and guest loopback never reaches a +host loopback service unless that host port is listed in `loopbackExemptPorts`. +`network: "deny"` does not change either rule. + +`"deny"` is shorthand for this rule set. A rule set replaces the whole network +scope, so a custom rule set that should keep listeners and loopback working +must include these rules. Omit them to deny VM-local networking too. + +```json +{ + "network": { + "default": "deny", + "rules": [ + { "mode": "allow", "operations": ["listen"], "patterns": ["tcp://**", "unix:**"] }, + { + "mode": "allow", + "operations": ["http"], + "patterns": ["tcp://127.0.0.1:*", "tcp://localhost:*", "tcp://::1:*", "unix:**"] + } + ] + } +} +``` + See the [Security Model](/agentos/docs/security-model) for the trust boundary these policies enforce. diff --git a/vendor/agentos/docs/content/docs/processes.mdx b/vendor/agentos/docs/content/docs/processes.mdx index 838d091f..21bed9c7 100644 --- a/vendor/agentos/docs/content/docs/processes.mdx +++ b/vendor/agentos/docs/content/docs/processes.mdx @@ -70,10 +70,18 @@ commands or working directories are invalid input. | Wait for exit | `v1.process.wait` | `process.wait` | | Inspect | `v1.process.get`, `v1.process.list`, `v1.process.tree` | `process.get`, `process.list`, `process.tree` | +A library `process.spawn` keeps stdin open; pass `streamStdin: false` to give +the process EOF instead. +Writing to stdin after it is closed fails with `EBADF`, as on Linux. + Hosted operations take the process handle `{ generation, pid }`; library operations take the `pid`. A hosted handle from before a `v1.vm.restart` fails with `stale_generation`. +Writing to stdin after the process exits fails with `EPIPE`, as a write to a +pipe with no reader does on Linux. Closing stdin after the process exits +succeeds. + `get` and `list` report `startedAtMs` as a Unix timestamp in milliseconds. `tree` includes guest child processes as well as processes launched through the API, so it can show more than you started. Use the returned handle or `pid` @@ -138,3 +146,9 @@ Interactive terminals allocate a kernel PTY and start a shell attached to it. | Output | `terminal.output` and `terminal.exit` events, `v1.terminal.output.read` replay | `vm.onShellData`, `vm.onShellStderr`, `vm.onShellExit` | Hosted VMs also list open terminals with `v1.terminal.list`. + +The VM tracks each terminal's cursor and answers a program's cursor-position +query (`ESC[6n`) itself, as a terminal multiplexer does, so a shell keeps +running while no client is attached and several clients can watch one +terminal. The query is removed from the output that clients receive, so their +emulators never answer it. diff --git a/vendor/agentos/docs/content/docs/python.mdx b/vendor/agentos/docs/content/docs/python.mdx index 362c56a1..8e11844f 100644 --- a/vendor/agentos/docs/content/docs/python.mdx +++ b/vendor/agentos/docs/content/docs/python.mdx @@ -67,6 +67,11 @@ Executions are ephemeral, so capture stdio only when you want it: `"stderr"` for diagnostics, `"all"` for both streams. `onStdout`/`onStderr` stream live and work independently of capture. +The exit code follows CPython. `sys.exit()` and `SystemExit` set it: no +argument exits `0`, an integer exits with that code, and any other value is +printed to stderr and exits `1`. An uncaught exception prints a Python traceback +to stderr and exits `1`. + ## Pass data into code In the library, `inputs` hands host values to the guest as real objects, so data never gets diff --git a/vendor/agentos/docs/content/docs/quickstart-hosted.mdx b/vendor/agentos/docs/content/docs/quickstart-hosted.mdx index 46811123..8f295858 100644 --- a/vendor/agentos/docs/content/docs/quickstart-hosted.mdx +++ b/vendor/agentos/docs/content/docs/quickstart-hosted.mdx @@ -11,173 +11,84 @@ process instead, see the [library quickstart](/agentos/docs/quickstart). ## Which one should I use? -| | [Hosted](/agentos/docs/quickstart-hosted) | [Library](/agentos/docs/quickstart) | +| | [Library](/agentos/docs/quickstart) | [Hosted](/agentos/docs/quickstart-hosted) | |---|---|---| -| **Runs** | As a durable instance on Rivet Cloud or a [self-hosted](/agentos/docs/self-hosting) Docker image | Embedded inside your process as a library | -| **Lifecycle** | Durable, sleeps when idle unless a process is running; see [actor lifecycle](/actors/docs/lifecycle) | Ephemeral, runs until `dispose()` or process exit | -| **Package** | `@rivet-dev/agentos`, or plain HTTP | `@rivet-dev/agentos-core` | -| **VM identity** | A durable VM you create by key and reach by ID | A handle your process owns until `dispose()` | -| **Configuration** | Stored with the VM and versioned | Passed to `AgentOs.create()` | -| **Clients** | Your backend, or browsers with a scoped JWT | Your backend | -| **Host access** | None | Host functions, host mounts, external sandboxes | -| **Previews** | Expiring preview URLs | None | -| **Best for** | Long-lived VMs shared across clients | Embedding VMs in an existing backend | +| **Runs** | Inside your process | Durable instance on Rivet Cloud or [self-hosted](/agentos/docs/self-hosting) | +| **Lifecycle** | Runs until `dispose()` or process exit | Sleeps when idle unless a process is running | +| **Clients** | Your backend | Your backend, or browsers with a scoped JWT | +| **Preview URLs** | None | Expiring preview URLs | ## Create a VM -### Rivet Cloud - - + -Sign up at the [Rivet dashboard](https://dashboard.rivet.dev) and create a new project. +Create a project in the [Rivet dashboard](https://dashboard.rivet.dev) and +choose agentOS as the product. Set `RIVET_NAMESPACE` and `RIVET_TOKEN` from the +project. To run on your own infrastructure, see +[Self-Hosting](/agentos/docs/self-hosting). - + -When creating the project, choose agentOS as the product. +```bash +npm install @rivet-dev/agentos +``` - - +The client is optional. Every action is also a plain HTTP call. -Set `RIVET_NAMESPACE` and `RIVET_TOKEN` from your project, then create a VM by -ID from TypeScript or plain HTTP: + + ```ts TypeScript @nocheck -// npm install @rivet-dev/agentos import { createAgentOsClient } from "@rivet-dev/agentos"; const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" }); +// Creates the VM on first use and returns the same VM for the same key. const vm = client.agentOS.getOrCreate(["my-vm"]); -``` - -```bash HTTP -curl -X PUT "https://api.rivet.dev/actors?namespace=$RIVET_NAMESPACE" \ - -H "Authorization: Bearer $RIVET_TOKEN" \ - --json '{ - "name": "agentOS", - "key": "my-vm", - "runner_name_selector": "services", - "crash_policy": "sleep" - }' -# → { "actor": { "actor_id": "…" }, "created": true } -``` - - - - - -### Self-hosting - -See [Self-Hosting (Hosted)](/agentos/docs/self-hosting) to run hosted VMs on your own -infrastructure. - -## Show me the code - -### Run Bash Commands - - - -```ts TypeScript @nocheck const result = await vm.v1.process.run({ command: "sh", args: ["-c", "echo hello && ls /home/agentos"], options: { captureStdio: true }, }); - console.log(result.stdout); -``` - -```bash HTTP -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.process.run" \ - -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{ - "command": "sh", - "args": ["-c", "echo hello && ls /home/agentos"], - "options": { "captureStdio": true } - }]}' -``` - - -### Work With the Filesystem - - - -```ts TypeScript @nocheck await vm.v1.filesystem.writeFile({ path: "/home/agentos/hello.txt", content: "Hello, world!", }); -const file = await vm.v1.filesystem.readFile({ - path: "/home/agentos/hello.txt", +// Start a server and expose it through an expiring preview URL. +await vm.v1.filesystem.writeFile({ + path: "/home/agentos/server.js", + content: `require("node:http").createServer((req, res) => res.end("hello")).listen(3000);`, }); +await vm.v1.process.spawn({ command: "node", args: ["/home/agentos/server.js"] }); +const preview = await vm.v1.network.preview.create({ port: 3000, ttlMs: 60 * 60 * 1_000 }); ``` ```bash HTTP -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.filesystem.writeFile" \ - -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{ - "path": "/home/agentos/hello.txt", - "content": "Hello, world!" - }]}' +curl -X PUT "https://api.rivet.dev/actors?namespace=$RIVET_NAMESPACE" \ + -H "Authorization: Bearer $RIVET_TOKEN" \ + --json '{ + "name": "agentOS", + "key": "my-vm", + "runner_name_selector": "services", + "crash_policy": "sleep" + }' +# → { "actor": { "actor_id": "…" }, "created": true } curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.process.run" \ -H "x-rivet-token: $VM_TOKEN" \ --json '{"args": [{ - "command": "cat", - "args": ["/home/agentos/hello.txt"], + "command": "sh", + "args": ["-c", "echo hello && ls /home/agentos"], "options": { "captureStdio": true } }]}' -``` - - - -`v1.filesystem.readFile` returns raw bytes, which the JSON encoding of the HTTP -API cannot carry, so the HTTP example reads the file through a process. - -### Run a Dev Server & Create Preview URLs - -Start a Node.js server in the VM, then expose its port through a signed URL -that expires on its own, or revoke it early. A running server keeps the VM -awake. Open the preview at `/gateway/$VM_ID@$VM_TOKEN/request` followed by the -returned `path`, with a token that can reach the VM. - - - -```ts TypeScript @nocheck -await vm.v1.filesystem.writeFile({ - path: "/home/agentos/server.js", - content: `require("node:http") - .createServer((req, res) => res.end("hello")) - .listen(3000);`, -}); - -await vm.v1.process.spawn({ - command: "node", - args: ["/home/agentos/server.js"], -}); - -const preview = await vm.v1.network.preview.create({ - port: 3000, - ttlMs: 60 * 60 * 1_000, -}); - -await vm.v1.network.preview.expire({ token: preview.token }); -``` - -```bash HTTP -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.filesystem.writeFile" \ - -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{ - "path": "/home/agentos/server.js", - "content": "require(\"node:http\").createServer((req, res) => res.end(\"hello\")).listen(3000);" - }]}' curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.process.spawn" \ -H "x-rivet-token: $VM_TOKEN" \ @@ -187,106 +98,92 @@ curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.network.preview.create" \ -H "x-rivet-token: $VM_TOKEN" \ --json '{"args": [{"port": 3000, "ttlMs": 3600000}]}' # → { "output": { "path": "/preview/…/", "token": "…", … } } - -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.network.preview.expire" \ - -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{"token": "…"}]}' ``` -### Use the Language Runtimes +Open the preview at `/gateway/$VM_ID@$VM_TOKEN/request` followed by the +returned `path`. A running server keeps the VM awake. + + + -Run JavaScript, TypeScript, and Python directly, with npm and pip installs -built in. +Configuration is stored with the VM and versioned. Replace it with +`v1.config.set`, then restart the VM so filesystem and software changes take +effect. ```ts TypeScript @nocheck -await vm.v1.javascript.execute({ source: "console.log(1 + 2)" }); -await vm.v1.typescript.execute({ - source: "const n: number = 3; console.log(n)", -}); +const vm = client.agentOS.getOrCreate(["my-vm"]); -const { value } = await vm.v1.python.evaluate({ - expression: "21 * 2", +await vm.v1.config.set({ + config: { + // Keep files across sleep and restarts, and mount durable storage at /data. + filesystem: { + root: { type: "durable" }, + mounts: [{ path: "/data", backend: { type: "durable" } }], + }, + + // Environment variables for guest processes. + environment: { NODE_ENV: "production" }, + + // Deny network access except to one host. + permissions: { + network: { + default: "deny", + rules: [ + { + mode: "allow", + operations: ["*"], + patterns: ["dns://api.example.com", "tcp://api.example.com:*"], + }, + ], + }, + }, + }, }); + +// Filesystem and software changes apply after a restart. +await vm.v1.vm.restart({}); ``` ```bash HTTP -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.javascript.execute" \ - -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{"source": "console.log(1 + 2)"}]}' - -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.python.evaluate" \ +curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.config.set" \ -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{"expression": "21 * 2"}]}' -``` - - - -### Schedule Cron Jobs - - - -```ts TypeScript @nocheck -await vm.v1.cron.schedule({ - name: "cleanup", - expression: "0 * * * *", - command: "rm", - args: ["-rf", "/tmp/cache"], -}); -``` + --json '{"args": [{"config": { + "filesystem": { + "root": { "type": "durable" }, + "mounts": [{ "path": "/data", "backend": { "type": "durable" } }] + }, + "environment": { "NODE_ENV": "production" }, + "permissions": { + "network": { + "default": "deny", + "rules": [{ + "mode": "allow", + "operations": ["*"], + "patterns": ["dns://api.example.com", "tcp://api.example.com:*"] + }] + } + } + }}]}' -```bash HTTP -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.cron.schedule" \ +curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.vm.restart" \ -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{ - "name": "cleanup", - "expression": "0 * * * *", - "command": "rm", - "args": ["-rf", "/tmp/cache"] - }]}' + --json '{"args": [{}]}' ``` -### Install Software - -Install tools from the [software registry](/agentos/docs/registry/software) -while the VM is running. Packages are verified against their digest before -their commands appear on `/opt/agentos/bin`. - - - -```ts TypeScript @nocheck -// Registry packages are published next to a manifest with each release. -const base = "https://releases.rivet.dev/agent-os/latest/software/"; -const { artifacts } = await (await fetch(`${base}manifest.json`)).json(); -const ripgrep = artifacts.find((artifact: { name: string }) => artifact.name === "ripgrep"); - -const installed = await vm.v1.software.install({ - source: { url: new URL(ripgrep.path, base).href, digest: ripgrep.digest }, -}); -if (installed.config.state === "restart_required") { - await vm.v1.vm.restart({}); -} -``` - -```bash HTTP -curl "https://api.rivet.dev/gateway/$VM_ID/action/v1.software.install" \ - -H "x-rivet-token: $VM_TOKEN" \ - --json '{"args": [{ - "source": { - "url": "https://releases.rivet.dev/agent-os/latest/software/packages/ripgrep/.aospkg", - "digest": "sha256:" - } - }]}' -``` +See [Persistence](/agentos/docs/persistence), +[Permissions](/agentos/docs/permissions), and the +[Hosted HTTP API](/agentos/docs/hosted-api) for every config field. - + + -### Give Clients Direct Access With JWTs +## Give Clients Direct Access With JWTs Keep your admin token on the backend and issue a JWT scoped to one VM. Browsers and other untrusted clients can then call that VM directly, and @@ -347,4 +244,5 @@ EOF - See the [Hosted HTTP API](/agentos/docs/hosted-api) for configuration, events, errors, and every action. -- Keep files across restarts with [Persistence & Sleep](/agentos/docs/persistence). +- Install tools from the [software registry](/agentos/docs/software). +- Schedule commands with [Crons & Schedules](/agentos/docs/cron). diff --git a/vendor/agentos/docs/content/docs/quickstart.mdx b/vendor/agentos/docs/content/docs/quickstart.mdx index 86c529fc..3ae402d2 100644 --- a/vendor/agentos/docs/content/docs/quickstart.mdx +++ b/vendor/agentos/docs/content/docs/quickstart.mdx @@ -10,17 +10,12 @@ durable VMs by ID and control them over HTTP instead, see the ## Which one should I use? -| | [Hosted](/agentos/docs/quickstart-hosted) | [Library](/agentos/docs/quickstart) | +| | [Library](/agentos/docs/quickstart) | [Hosted](/agentos/docs/quickstart-hosted) | |---|---|---| -| **Runs** | As a durable instance on Rivet Cloud or a [self-hosted](/agentos/docs/self-hosting) Docker image | Embedded inside your process as a library | -| **Lifecycle** | Durable, sleeps when idle unless a process is running; see [actor lifecycle](/actors/docs/lifecycle) | Ephemeral, runs until `dispose()` or process exit | -| **Package** | `@rivet-dev/agentos`, or plain HTTP | `@rivet-dev/agentos-core` | -| **VM identity** | A durable VM you create by key and reach by ID | A handle your process owns until `dispose()` | -| **Configuration** | Stored with the VM and versioned | Passed to `AgentOs.create()` | -| **Clients** | Your backend, or browsers with a scoped JWT | Your backend | -| **Host access** | None | Host functions, host mounts, external sandboxes | -| **Previews** | Expiring preview URLs | None | -| **Best for** | Long-lived VMs shared across clients | Embedding VMs in an existing backend | +| **Runs** | Inside your process | Durable instance on Rivet Cloud or [self-hosted](/agentos/docs/self-hosting) | +| **Lifecycle** | Runs until `dispose()` or process exit | Sleeps when idle unless a process is running | +| **Clients** | Your backend | Your backend, or browsers with a scoped JWT | +| **Preview URLs** | None | Expiring preview URLs | ## Create a VM @@ -32,61 +27,32 @@ npm install @rivet-dev/agentos-core ``` - + - + The VM runs until `dispose()` is called or your process exits. - - -## Show me the code - -### Run Bash Commands - - - -### Work With the Filesystem - - - -### Run a Dev Server - -Start a Node.js server in the VM, then send it a request from your process. -The listener is not exposed on the host network. - - + -### Use the Language Runtimes +The filesystem is in memory by default. Pass options to `AgentOs.create()` to +persist it, attach other filesystems, and lock the VM down. -Run JavaScript, TypeScript, and Python directly, with npm and pip installs -built in. + - +See [Filesystem](/agentos/docs/filesystem), +[Persistence](/agentos/docs/persistence), +[Permissions](/agentos/docs/permissions), and +[Resource Limits](/agentos/docs/resource-limits). -### Schedule Cron Jobs - - - -### Install Software - -Install tools from the [software registry](/agentos/docs/registry/software) -while the VM is running. Packages are verified against their digest before -their commands appear on `/opt/agentos/bin`. - - - -### Persist Files - -The filesystem is in memory by default. Store the root filesystem in SQLite to -keep files across VM recreation. - - + + ## Next steps - Expose your own functions to guest code with [host functions](/agentos/docs/host-functions). -- Lock the VM down with [Permissions](/agentos/docs/permissions) and - [Resource Limits](/agentos/docs/resource-limits). +- Install tools from the [software registry](/agentos/docs/software). +- Run servers and send them requests with + [Networking & Previews](/agentos/docs/networking). diff --git a/vendor/agentos/docs/content/docs/resource-limits.mdx b/vendor/agentos/docs/content/docs/resource-limits.mdx index b7eb6b4a..b8b2b6f6 100644 --- a/vendor/agentos/docs/content/docs/resource-limits.mdx +++ b/vendor/agentos/docs/content/docs/resource-limits.mdx @@ -71,6 +71,26 @@ Library VMs share a sidecar process by default. Limits that apply to the whole process, such as `runtime.executor.maxActiveVms`, are set when creating a dedicated sidecar with `AgentOs.createSidecar()`, as in the example above. +Each library request to the sidecar must fit in one protocol frame. The sidecar +reports its frame limit (16 MiB) when the client connects, and the limit is not +configurable. The client rejects a larger request with `SidecarFrameTooLarge` +before it sends it, so the sidecar and the other VMs on it keep running. Binary +file content is base64-encoded, so one `writeFile` or `writeFiles` call carries +at most about 12 MiB of binary data. To move larger files, split them into +several files or mount a host directory. + +### Sidecar memory + +On Linux with glibc, the sidecar returns memory freed by a disposed VM's V8 +isolates to the OS shortly after disposal. + +The sidecar also keeps a pool of up to four pre-started V8 isolates so that +JavaScript and Python executions start faster. The pool stays resident while +the sidecar runs, at about 20 MiB per isolate. To cap it, set +`AGENTOS_V8_WARM_ISOLATES` to a value from `0` to `4` in the environment that +starts the sidecar. `0` disables the pool and trades memory for slower +execution starts. + ## Embedded API Limits apply to VMs created with `AgentOs.create()` and sidecars created with diff --git a/vendor/agentos/docs/content/docs/software.mdx b/vendor/agentos/docs/content/docs/software.mdx index 692e8642..15510eb3 100644 --- a/vendor/agentos/docs/content/docs/software.mdx +++ b/vendor/agentos/docs/content/docs/software.mdx @@ -13,17 +13,77 @@ Browse the available packages in the [registry](/agentos/docs/registry). ## Registry packages +Install a registry package by name. In the library, list +`{ registry: "git" }` in `software` when the VM is created, or call +`vm.software.install({ type: "registry", name: "git" })` while it is running. +See the examples under [Install while running](#install-while-running) and +[Install when the VM is created](#install-when-the-vm-is-created). + +A name resolves against the software manifest of one agentOS release, and the +package is installed from its URL with the manifest's digest, so the bytes are +verified before they are projected. Unknown names, missing releases, unreachable +manifests, and digest mismatches fail with an error instead of being skipped. + +- **Version.** By default a name resolves against the release that matches your + `@rivet-dev/agentos-core` version, so a client gets the software built with + it. Unreleased workspace and preview builds use `latest`. Pin one entry with + `{ registry: "git", version: "0.4.2" }` or + `{ type: "registry", name: "git", version: "0.4.2" }`, or every entry with + `softwareRegistry: { version }`. Pass `"latest"` for the newest release. +- **Mirrors.** Set `softwareRegistry: { url }` on `AgentOs.create()`, or the + `AGENTOS_SOFTWARE_REGISTRY_URL` environment variable, to a copy of the release + layout. The default is `https://releases.rivet.dev/agent-os/`. Mirrors must + use HTTPS, because the manifest supplies the digests packages are verified + against. A plain `http://` mirror is allowed only on a loopback address and + also needs `packageResolver: { allowInsecureLocalHttp: true }`, which sets + the download limits for registry and URL packages. +- **Network.** The manifest and package are downloaded by the host process, not + by the VM, so the VM's network permissions do not apply to them. +- **Caching.** Manifests are cached per release for the life of the process, + and `latest` is refreshed every five minutes. + +`resolveRegistrySoftware(name, { version })` returns the resolved `url` and +`digest` without installing anything. + +### Release manifest + Registry packages are published with each release under `https://releases.rivet.dev/agent-os//software/`, or `latest` for the newest release. Its `manifest.json` lists each package's name, digest, size, -and path relative to the manifest. Registry software is not installed from npm; -see [Publishing Software](/agentos/docs/custom-software/publishing). +and path relative to the manifest: + +```json +{ + "schemaVersion": 1, + "artifacts": [ + { + "name": "git", + "digest": "sha256:<64 lowercase hex>", + "size": 17961114, + "path": "packages/git/<64 lowercase hex>.aospkg" + } + ] +} +``` + +Use it when you need raw URLs, such as to mirror packages or to configure a +hosted VM: resolve `path` against the manifest URL and pass `digest` along. +Registry software is distributed only as `.aospkg` files from this location, not +as npm packages. See [Publishing Software](/agentos/docs/custom-software/publishing). + +## Default software + +Every VM installs a default bundle first: `coreutils` (which provides `sh`), +`sed`, `grep`, `gawk`, `findutils`, `diffutils`, `tar`, and `gzip`. The bundle +ships with the library and the hosted runtime, so it needs no download. Pass +`defaultSoftware: false` to `AgentOs.create()`, or set `"defaultSoftware": false` +in a hosted VM's `config`, for a bare VM that has only the software you list. ## Install while running Install a package into a running VM from an HTTPS URL, with an optional exact -`sha256:<64 lowercase hex>` digest. The library also accepts a trusted local -path. +`sha256:<64 lowercase hex>` digest. The library also accepts a registry package +name and a trusted local path. @@ -33,8 +93,8 @@ import { createAgentOsClient } from "@rivet-dev/agentos"; const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" }); const vm = client.agentOS.getOrCreate(["my-vm"]); -// Registry software is published as digest-addressed .aospkg files next to a -// manifest. Use a release version, or `latest`. +// Hosted install takes a URL and digest. Look the package up in a release +// manifest; use a release version, or `latest`. const base = "https://releases.rivet.dev/agent-os/latest/software/"; const { artifacts } = await (await fetch(`${base}manifest.json`)).json(); const ripgrep = artifacts.find((artifact: { name: string }) => artifact.name === "ripgrep"); @@ -82,14 +142,16 @@ import { createAgentOsClient } from "@rivet-dev/agentos"; const client = createAgentOsClient({ endpoint: "https://api.rivet.dev" }); +// Hosted config takes a URL and digest. Look the package up in a release +// manifest; use a release version, or `latest`. +const base = "https://releases.rivet.dev/agent-os/latest/software/"; +const { artifacts } = await (await fetch(`${base}manifest.json`)).json(); +const git = artifacts.find((artifact: { name: string }) => artifact.name === "git"); + const vm = client.agentOS.getOrCreate(["my-vm"], { createWithInput: { config: { - software: [ - { - url: "https://releases.rivet.dev/agent-os/latest/software/packages/git/.aospkg", - }, - ], + software: [{ url: new URL(git.path, base).href, digest: git.digest }], }, }, }); @@ -99,10 +161,31 @@ const vm = client.agentOS.getOrCreate(["my-vm"], { -Hosted VMs take package URLs in their `software` config. The library takes -`{ packagePath }` references to packed `.aospkg` files, which is what the -`@agentos-software/*` packages in the agentOS repository export, and -`defaultSoftware: false` for a bare VM with only the software you list. +The library's `software` option accepts trusted local `{ packagePath }` files, +registry packages by name (`{ registry: "git" }`), and `{ url, digest }` +artifacts. Registry and URL entries are downloaded and verified on the host +before `AgentOs.create()` returns, and they appear in `software.installed()`. + +Hosted VMs take `{ url, digest }` sources in their `software` config, and +download and verify them when the VM starts. The hosted client does not resolve +registry names yet, so look the package up in the +[release manifest](#release-manifest) as shown above. + +## Custom and local packages + +A package you build yourself, or any other `.aospkg` file, installs the same way +as a registry package. See +[Software Package Definition](/agentos/docs/custom-software/definition) and +[Building Software](/agentos/docs/custom-software/building-wasm) for how to +build one. + + + +The library reads trusted local paths, both in `software` at creation and with +`software.install({ type: "path", path })` while running. Hosted VMs cannot read +files from your machine, so upload the `.aospkg` to an HTTPS location you +control and pass its URL and `sha256:` digest, at creation or with +`v1.software.install`. ## Verification and caching @@ -118,5 +201,5 @@ download. Hosted workers also warm popular packages at startup; see ## Embedded API The embedding process is trusted, so `software.install` accepts local package -paths as well as URLs. Read more in the +paths as well as registry names and URLs. Read more in the [embedded API quickstart](/agentos/docs/quickstart-embedded). diff --git a/vendor/agentos/examples/embedded/config-reference.ts b/vendor/agentos/examples/embedded/config-reference.ts index 0ee1bbc6..89333993 100644 --- a/vendor/agentos/examples/embedded/config-reference.ts +++ b/vendor/agentos/examples/embedded/config-reference.ts @@ -19,8 +19,12 @@ const vm = await AgentOs.create({ // Kernel permission policy (see /agentos/docs/permissions) and runtime caps. permissions: { network: "allow" }, limits: { jsRuntime: { v8HeapLimitMb: 128 } }, - // Install a packed .aospkg from a trusted local path at boot. - software: [{ packagePath: "/path/to/tool.aospkg" }], + // Install a packed .aospkg from a trusted local path, and a registry package + // by name, at boot. + software: [{ packagePath: "/path/to/tool.aospkg" }, { registry: "git" }], + // Where registry packages resolve. Defaults to releases.rivet.dev at this + // client's release; point `url` at a mirror or pin `version`. + softwareRegistry: { url: "https://releases.rivet.dev/agent-os/" }, // Also install the default software bundle (sh + coreutils). Defaults to true; // set false for a bare VM with only the software you list. defaultSoftware: true, diff --git a/vendor/agentos/examples/embedded/host-functions-javascript.ts b/vendor/agentos/examples/embedded/host-functions-javascript.ts index 71cbe9e4..8c38bb64 100644 --- a/vendor/agentos/examples/embedded/host-functions-javascript.ts +++ b/vendor/agentos/examples/embedded/host-functions-javascript.ts @@ -31,6 +31,18 @@ try { { output: { capture: "all" } }, ); console.log(result.outcome === "succeeded" ? result.stdout : result.error); + + // Every guest Node process gets the same globals, including scripts started + // with process.spawn(), from the shell, or by another guest process. + await vm.writeFile( + "/app/report.mjs", + `const forecast = await weather.forecast({ city: "Tokyo" }); +console.log(forecast);`, + ); + const report = await vm.process.exec("node /app/report.mjs", { + output: { capture: "all" }, + }); + console.log(report.outcome === "succeeded" ? report.stdout : report.error); } finally { await vm.dispose(); } diff --git a/vendor/agentos/examples/embedded/package.json b/vendor/agentos/examples/embedded/package.json index 9d95fd0c..13e16bf2 100644 --- a/vendor/agentos/examples/embedded/package.json +++ b/vendor/agentos/examples/embedded/package.json @@ -12,7 +12,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/embedded/quickstart-configure.ts b/vendor/agentos/examples/embedded/quickstart-configure.ts new file mode 100644 index 00000000..a119e6ee --- /dev/null +++ b/vendor/agentos/examples/embedded/quickstart-configure.ts @@ -0,0 +1,43 @@ +import { resolve } from "node:path"; +import { AgentOs } from "@rivet-dev/agentos-core"; + +const vm = await AgentOs.create({ + // Store the root filesystem in SQLite so files survive VM recreation. + database: { type: "sqlite_file", path: resolve("agentos.sqlite") }, + rootFilesystem: { type: "native", plugin: { id: "chunked_sqlite", config: {} } }, + + // Attach a host directory (read-only) and an S3 bucket. + mounts: [ + { + path: "/mnt/code", + plugin: { id: "host_dir", config: { hostPath: "/path/to/repo" } }, + readOnly: true, + }, + { + path: "/mnt/data", + plugin: { id: "chunked_s3", config: { bucket: "my-bucket", region: "us-east-1" } }, + }, + ], + + // Environment variables for guest processes. + environment: { NODE_ENV: "production" }, + + // Deny network access except to one host. + permissions: { + network: { + default: "deny", + rules: [ + { + mode: "allow", + operations: ["*"], + patterns: ["dns://api.example.com", "tcp://api.example.com:*"], + }, + ], + }, + }, + + // Cap processes and filesystem size. + limits: { resources: { maxProcesses: 64, maxFilesystemBytes: 256 * 1024 * 1024 } }, +}); + +await vm.dispose(); diff --git a/vendor/agentos/examples/embedded/quickstart.ts b/vendor/agentos/examples/embedded/quickstart.ts index bf1eaa56..1046ddc5 100644 --- a/vendor/agentos/examples/embedded/quickstart.ts +++ b/vendor/agentos/examples/embedded/quickstart.ts @@ -1,72 +1,26 @@ -// docs:start create import { AgentOs } from "@rivet-dev/agentos-core"; -// `AgentOs.create()` boots a VM inside this process and returns a handle to it. +// Boots a VM inside this process. It runs until dispose() or process exit. const vm = await AgentOs.create(); -// docs:end create try { - // docs:start bash + // Bash const result = await vm.process.exec("echo hello && ls /home/agentos", { output: { capture: "all" }, }); - console.log(result.stdout); - // docs:end bash - // docs:start filesystem + // Filesystem await vm.filesystem.writeFile("/home/agentos/hello.txt", "Hello, world!"); - const file = await vm.filesystem.readFile("/home/agentos/hello.txt"); - // docs:end filesystem console.log(new TextDecoder().decode(file)); - // docs:start dev-server - await vm.filesystem.writeFile( - "/home/agentos/server.js", - `require("node:http") - .createServer((req, res) => res.end("hello")) - .listen(3000);`, - ); - - await vm.process.spawn("node", ["/home/agentos/server.js"]); - - // The listener stays inside the VM. Send it a request from the host. - const response = await vm.network.httpRequest({ port: 3000, path: "/" }); - console.log(new TextDecoder().decode(response.body)); - // docs:end dev-server - - // docs:start languages + // JavaScript await vm.javascript.execute("console.log(1 + 2)"); - await vm.typescript.execute("const n: number = 3; console.log(n)"); + // Python const answer = await vm.python.evaluate("21 * 2"); - // docs:end languages console.log(answer.outcome === "succeeded" ? answer.value : answer.error); - - // docs:start cron - vm.cron.schedule({ - id: "cleanup", - schedule: "0 * * * *", - action: { type: "exec", command: "rm", args: ["-rf", "/tmp/cache"] }, - }); - // docs:end cron - - // docs:start software - // Registry packages are published next to a manifest with each release. - const base = "https://releases.rivet.dev/agent-os/latest/software/"; - const manifest = (await (await fetch(`${base}manifest.json`)).json()) as { - artifacts: { name: string; digest: string; path: string }[]; - }; - const ripgrep = manifest.artifacts.find((artifact) => artifact.name === "ripgrep"); - if (!ripgrep) throw new Error("ripgrep is not in the manifest"); - - await vm.software.install({ - type: "url", - url: new URL(ripgrep.path, base).href, - expectedDigest: ripgrep.digest, - }); - // docs:end software } finally { await vm.dispose(); } diff --git a/vendor/agentos/examples/embedded/software-install.ts b/vendor/agentos/examples/embedded/software-install.ts index d17349b2..43a42261 100644 --- a/vendor/agentos/examples/embedded/software-install.ts +++ b/vendor/agentos/examples/embedded/software-install.ts @@ -1,23 +1,14 @@ import { AgentOs } from "@rivet-dev/agentos-core"; -// Registry software is published as digest-addressed .aospkg files next to a -// manifest. Use a release version, or `latest`. -const base = "https://releases.rivet.dev/agent-os/latest/software/"; -const manifest = (await (await fetch(`${base}manifest.json`)).json()) as { - artifacts: { name: string; digest: string; path: string }[]; -}; -const ripgrep = manifest.artifacts.find((artifact) => artifact.name === "ripgrep"); -if (!ripgrep) throw new Error("ripgrep is not in the manifest"); - const vm = await AgentOs.create(); try { - // Install a package while the VM is running. The bytes are verified against - // the digest before the package is projected into /opt/agentos. + // Install a registry package while the VM is running. The bytes are verified + // against the published digest before the package is projected into + // /opt/agentos. const installed = await vm.software.install({ - type: "url", - url: new URL(ripgrep.path, base).href, - expectedDigest: ripgrep.digest, + type: "registry", + name: "ripgrep", }); console.log(installed.packageName, installed.version, installed.commands); diff --git a/vendor/agentos/examples/embedded/software-local.ts b/vendor/agentos/examples/embedded/software-local.ts new file mode 100644 index 00000000..46cd8a98 --- /dev/null +++ b/vendor/agentos/examples/embedded/software-local.ts @@ -0,0 +1,26 @@ +import { resolve } from "node:path"; +import { AgentOs } from "@rivet-dev/agentos-core"; + +// A trusted .aospkg file on the host, such as one you built with +// agentos-toolchain or downloaded from the registry. +const packagePath = resolve(process.argv[2] ?? "dist/package.aospkg"); + +// Install it when the VM is created. +const vm = await AgentOs.create({ software: [{ packagePath }] }); +try { + console.log(await vm.software.list()); +} finally { + await vm.dispose(); +} + +// Or install it into a running VM. +const running = await AgentOs.create(); +try { + const installed = await running.software.install({ + type: "path", + path: packagePath, + }); + console.log(installed.packageName, installed.version, installed.commands); +} finally { + await running.dispose(); +} diff --git a/vendor/agentos/examples/embedded/software.ts b/vendor/agentos/examples/embedded/software.ts index 39412307..0eb98b3e 100644 --- a/vendor/agentos/examples/embedded/software.ts +++ b/vendor/agentos/examples/embedded/software.ts @@ -1,7 +1,11 @@ -import git from "@agentos-software/git"; import { AgentOs } from "@rivet-dev/agentos-core"; -const vm = await AgentOs.create({ software: [git] }); +// The default bundle (sh, coreutils, and the standard CLI tools) is installed +// first, then the packages listed here. Registry packages resolve from this +// client's release and are verified against their published digest. +const vm = await AgentOs.create({ + software: [{ registry: "git" }], +}); try { const result = await vm.process.exec("git --version", { diff --git a/vendor/agentos/examples/js-networking/src/index.ts b/vendor/agentos/examples/js-networking/src/index.ts index cb4be484..b1ea5f1e 100644 --- a/vendor/agentos/examples/js-networking/src/index.ts +++ b/vendor/agentos/examples/js-networking/src/index.ts @@ -7,7 +7,9 @@ * 1. With network "allow", the guest starts a loopback HTTP server inside the * VM and fetches it - the request and response stay entirely within the * kernel socket table (hermetic, no real host network). - * 2. With an explicit network deny policy, the same fetch is blocked. + * 2. With network "deny", the same VM-local fetch still works, because + * listeners and loopback never leave the VM, but external egress is + * blocked. * 3. Host loopback is separate from VM loopback: even with network "allow", * a guest can reach a host loopback service only when the host port is in * loopbackExemptPorts. @@ -69,25 +71,34 @@ try { } // docs:end vm-network -// 2. Network denied explicitly. Supplying a partial policy denies omitted -// scopes too, so name the runtime capabilities needed to launch the program. +// 2. Network denied. A scalar deny blocks traffic that crosses the VM +// boundary, so the VM-local server still works while external egress fails. +const EGRESS_GUEST = ` +try { + await fetch("http://example.com/"); + console.log("unexpected: external fetch succeeded"); +} catch (error) { + console.log("external fetch:", error.cause?.code || error.code || error.name); +} +`; const denied = await AgentOs.create({ - permissions: { - fs: "allow", - network: "deny", - childProcess: "allow", - process: "allow", - env: "allow", - }, + permissions: { network: "deny" }, }); try { - const result = await denied.javascript.execute(GUEST, { + const local = await denied.javascript.execute(GUEST, { + output: { capture: "all" }, + }); + console.log("[network denied] VM-local exitCode:", local.exitCode); + console.log( + "[network denied] VM-local stdout:", + JSON.stringify(local.stdout?.trim()), + ); + const external = await denied.javascript.execute(EGRESS_GUEST, { output: { capture: "all" }, }); - console.log("[network denied] exitCode:", result.exitCode); console.log( - "[network denied] stderr:", - JSON.stringify(result.stderr?.trim().split("\n")[0]), + "[network denied] egress stdout:", + JSON.stringify(external.stdout?.trim()), ); } finally { await denied.dispose(); diff --git a/vendor/agentos/examples/quickstart/bash/package.json b/vendor/agentos/examples/quickstart/bash/package.json index a7c85504..be70b749 100644 --- a/vendor/agentos/examples/quickstart/bash/package.json +++ b/vendor/agentos/examples/quickstart/bash/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/cron/package.json b/vendor/agentos/examples/quickstart/cron/package.json index 24051970..0d35d805 100644 --- a/vendor/agentos/examples/quickstart/cron/package.json +++ b/vendor/agentos/examples/quickstart/cron/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/filesystem/package.json b/vendor/agentos/examples/quickstart/filesystem/package.json index 98a6aee4..ffb41823 100644 --- a/vendor/agentos/examples/quickstart/filesystem/package.json +++ b/vendor/agentos/examples/quickstart/filesystem/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/git/README.md b/vendor/agentos/examples/quickstart/git/README.md index 20e5e646..6676e2bf 100644 --- a/vendor/agentos/examples/quickstart/git/README.md +++ b/vendor/agentos/examples/quickstart/git/README.md @@ -9,7 +9,7 @@ Run real `git` inside a VM: initialize a repo, branch, commit, and clone it — ## How it works -The VM is created with the `@agentos-software/git` package mounted as software and filesystem, child-process, and env permissions enabled. From there it drives ordinary git commands through `vm.process.exec`, mixing in `vm.filesystem.writeFile`/`vm.filesystem.readFile` to stage files and inspect results. It commits on a `feature` branch so that `git clone` resolves HEAD to `feature`, then reads the clone's `.git/HEAD` and the feature file to confirm the branch carried over. +The VM is created with filesystem, child-process, and env permissions enabled, and installs `git` from the agentOS software registry with `software: [{ registry: "git" }]`, which resolves the package from the release manifest and verifies its digest. From there it drives ordinary git commands through `vm.process.exec`, mixing in `vm.filesystem.writeFile`/`vm.filesystem.readFile` to stage files and inspect results. It commits on a `feature` branch so that `git clone` resolves HEAD to `feature`, then reads the clone's `.git/HEAD` and the feature file to confirm the branch carried over. ## Run it diff --git a/vendor/agentos/examples/quickstart/git/index.ts b/vendor/agentos/examples/quickstart/git/index.ts index 67e96903..dfd4e3f1 100644 --- a/vendor/agentos/examples/quickstart/git/index.ts +++ b/vendor/agentos/examples/quickstart/git/index.ts @@ -2,7 +2,6 @@ import { createRequire } from "node:module"; import { dirname, resolve } from "node:path"; -import git from "@agentos-software/git"; import { AgentOs } from "@rivet-dev/agentos-core"; type ExecResult = { @@ -45,9 +44,11 @@ function parseHeadRef(content: string): string { return branch; } +// Install git from the agentOS software registry. The package is resolved from +// this client's release manifest and its bytes are verified before install. const vm = await AgentOs.create({ permissions: GIT_QUICKSTART_PERMISSIONS, - software: [git], + software: [{ registry: "git" }], }); async function run(command: string): Promise { @@ -64,6 +65,8 @@ async function run(command: string): Promise { }; } +await run('git config --global user.name "agentOS"'); +await run('git config --global user.email "agentos@example.com"'); await run("git init /tmp/origin"); await vm.filesystem.writeFile("/tmp/origin/README.md", "# demo repo\n"); await run("git -C /tmp/origin add README.md"); diff --git a/vendor/agentos/examples/quickstart/git/package.json b/vendor/agentos/examples/quickstart/git/package.json index 808b44aa..58a1cbc8 100644 --- a/vendor/agentos/examples/quickstart/git/package.json +++ b/vendor/agentos/examples/quickstart/git/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/hello-world/package.json b/vendor/agentos/examples/quickstart/hello-world/package.json index f1497bb2..ea9a3fc7 100644 --- a/vendor/agentos/examples/quickstart/hello-world/package.json +++ b/vendor/agentos/examples/quickstart/hello-world/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/network/package.json b/vendor/agentos/examples/quickstart/network/package.json index d54eb8c5..2f7358da 100644 --- a/vendor/agentos/examples/quickstart/network/package.json +++ b/vendor/agentos/examples/quickstart/network/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/nodejs/package.json b/vendor/agentos/examples/quickstart/nodejs/package.json index f29d71fc..7aa90c0b 100644 --- a/vendor/agentos/examples/quickstart/nodejs/package.json +++ b/vendor/agentos/examples/quickstart/nodejs/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/package.json b/vendor/agentos/examples/quickstart/package.json index 52df74f3..aeb4992a 100644 --- a/vendor/agentos/examples/quickstart/package.json +++ b/vendor/agentos/examples/quickstart/package.json @@ -27,7 +27,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/processes/package.json b/vendor/agentos/examples/quickstart/processes/package.json index ad904a60..009099aa 100644 --- a/vendor/agentos/examples/quickstart/processes/package.json +++ b/vendor/agentos/examples/quickstart/processes/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/s3-filesystem/package.json b/vendor/agentos/examples/quickstart/s3-filesystem/package.json index fa24bb47..15ff6945 100644 --- a/vendor/agentos/examples/quickstart/s3-filesystem/package.json +++ b/vendor/agentos/examples/quickstart/s3-filesystem/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": { diff --git a/vendor/agentos/examples/quickstart/sandbox/package.json b/vendor/agentos/examples/quickstart/sandbox/package.json index fd0c5998..c6bf49d0 100644 --- a/vendor/agentos/examples/quickstart/sandbox/package.json +++ b/vendor/agentos/examples/quickstart/sandbox/package.json @@ -13,7 +13,6 @@ "sandbox-agent": "^0.4.2", "dockerode": "^4.0.9", "get-port": "^7.1.0", - "@agentos-software/git": "workspace:*", "zod": "^4.1.11" }, "devDependencies": {