Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- run: cargo build --release -p agentos-native-sidecar
- run: cargo build --release -p agentos-native-baseline
- run: cargo build --release --target wasm32-wasip1 -p agentos-native-baseline
- run: make -C registry/native commands
- run: make -C toolchain commands
- run: node packages/runtime-core/scripts/copy-wasm-commands.mjs --require
- run: pnpm --dir packages/runtime-core build
- run: pnpm --dir packages/runtime-benchmarks bench:check
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
with:
targets: wasm32-wasip1
- run: pnpm install --frozen-lockfile
- run: make -C registry/native commands
- run: make -C toolchain commands
- run: node packages/runtime-core/scripts/copy-wasm-commands.mjs --require
- run: cargo check --workspace
- run: cargo clippy --workspace --all-targets -- -D warnings
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- run: pnpm install --frozen-lockfile
- run: |
if grep -qE '^[[:space:]]*-[[:space:]]*website[[:space:]]*$' pnpm-workspace.yaml; then
npx turbo build --filter='!@agentos/website'
npx turbo build --filter='!@rivet-dev/agentos-website'
else
npx turbo build
fi
Expand All @@ -42,6 +42,7 @@ jobs:
- run: node scripts/check-agentos-client-protocol-compat.mjs
- run: node --test scripts/verify-fixed-versions.test.mjs
- run: node scripts/verify-fixed-versions.mjs
- run: pnpm check-layout
- run: cargo fmt --check
- run: pnpm check-types
- run: pnpm lint
Expand All @@ -63,10 +64,10 @@ jobs:
targets: wasm32-wasip1
- uses: Swatinem/rust-cache@v2
with:
workspaces: registry/native -> registry/native/target
key: wasm-commands-${{ hashFiles('registry/native/Cargo.lock') }}
workspaces: toolchain -> toolchain/target
key: wasm-commands-${{ hashFiles('toolchain/Cargo.lock') }}
- run: pnpm install --frozen-lockfile --filter '@rivet-dev/agentos-runtime-core...'
- run: make -C registry/native commands
- run: make -C toolchain commands
- run: node packages/runtime-core/scripts/copy-wasm-commands.mjs --require
- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -107,7 +108,7 @@ jobs:
- run: node packages/runtime-core/scripts/copy-wasm-commands.mjs --require
- run: |
if grep -qE '^[[:space:]]*-[[:space:]]*website[[:space:]]*$' pnpm-workspace.yaml; then
npx turbo build --filter='!@agentos/website'
npx turbo build --filter='!@rivet-dev/agentos-website'
else
npx turbo build
fi
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ jobs:
targets: wasm32-wasip1
- uses: Swatinem/rust-cache@v2
with:
workspaces: registry/native -> registry/native/target
key: wasm-commands-${{ hashFiles('registry/native/Cargo.lock') }}
workspaces: toolchain -> toolchain/target
key: wasm-commands-${{ hashFiles('toolchain/Cargo.lock') }}
- run: pnpm install --frozen-lockfile --filter '@rivet-dev/agentos-runtime-core...'
- run: make -C registry/native commands
- run: make -C toolchain commands
- run: node packages/runtime-core/scripts/copy-wasm-commands.mjs --require
- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -112,7 +112,7 @@ jobs:
key: ${{ runner.os }}-${{ matrix.target }}-rusty-v8-${{ hashFiles('Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-rusty-v8-
- run: pnpm install --frozen-lockfile --filter='!@agentos/website'
- run: pnpm install --frozen-lockfile --filter='!@rivet-dev/agentos-website'
- name: Set up Linux GNU sysroot
run: scripts/ci/setup-linux-gnu-sysroot.sh
- name: Build sidecar binaries
Expand Down Expand Up @@ -183,7 +183,7 @@ jobs:
key: ${{ runner.os }}-${{ matrix.target }}-rusty-v8-${{ hashFiles('Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-rusty-v8-
- run: pnpm install --frozen-lockfile --filter='!@agentos/website'
- run: pnpm install --frozen-lockfile --filter='!@rivet-dev/agentos-website'
- name: Set up Linux GNU sysroot
run: scripts/ci/setup-linux-gnu-sysroot.sh
- name: Build plugin cdylib
Expand Down Expand Up @@ -281,7 +281,7 @@ jobs:
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
registry-url: https://registry.npmjs.org
- run: pnpm install --frozen-lockfile --filter='!@agentos/website'
- run: pnpm install --frozen-lockfile --filter='!@rivet-dev/agentos-website'
- uses: actions/download-artifact@v4
with:
name: wasm-commands
Expand Down Expand Up @@ -460,7 +460,7 @@ jobs:
key: ${{ runner.os }}-x86_64-unknown-linux-gnu-rusty-v8-${{ hashFiles('Cargo.lock') }}
restore-keys: |
${{ runner.os }}-x86_64-unknown-linux-gnu-rusty-v8-
- run: pnpm install --frozen-lockfile --filter='!@agentos/website'
- run: pnpm install --frozen-lockfile --filter='!@rivet-dev/agentos-website'
- name: Bump Cargo versions
run: |
pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \
Expand Down
15 changes: 15 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ the guest — over inventing a softer fallback that hides the failure.

- `scripts/publish` is the source of truth for npm/crates discovery, version
rewriting, npm publish, crates publish, release assets, and R2 upload.
- npm package scopes are load-bearing for version rewriting, so every package
must use the scope that matches how it publishes:
- `@rivet-dev/agentos-*` — core/internal packages, incl. private tooling and
test-only helpers (e.g. `@rivet-dev/agentos-test-harness`). The version
bumper pins these `workspace:*` deps to the build version without hitting
npm, so private/unpublished packages are safe here.
- `@agentos-software/*` — independently-versioned software packages. The
bumper resolves these `workspace:*` deps to their published npm `latest`,
so a package under this scope MUST be published to npm or the publish fails.
- The bare `@agentos/*` scope is NOT ours — we do not own that npm org, so no
package may use it (not even private, never-published ones). Everything
internal, including tooling, test helpers, and the website, lives under
`@rivet-dev/agentos-*`. Beyond the ownership problem, the bumper treats an
unrecognized scope as an independently-versioned software package and runs
`npm view` on it, which hard-fails for anything unpublished.
- Publishable npm packages and Rust crates are AgentOS-owned. Compatibility
`@secure-exec/*`, `secure-exec`, and `secure-exec-*` artifacts are emitted
from the generated mirror.
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
resolver = "2"
exclude = ["software"]
members = [
"crates/agentos-protocol",
"crates/agentos-sidecar-core",
Expand Down
6 changes: 3 additions & 3 deletions crates/client/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn wasm_command_mounts() -> Vec<MountConfig> {
/// Locate the materialized coreutils package under the in-repo registry build.
pub fn coreutils_package_dir() -> Option<PathBuf> {
let registry_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../registry/software/coreutils/dist/package");
.join("../../software/coreutils/dist/package");
if registry_dir.join("agentos-package.json").is_file() {
return std::fs::canonicalize(registry_dir).ok();
}
Expand All @@ -175,7 +175,7 @@ pub fn coreutils_wasm_dir() -> Option<PathBuf> {
}

let legacy_registry_dir =
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../registry/software/coreutils/wasm");
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../software/coreutils/wasm");
if legacy_registry_dir.is_dir() {
return std::fs::canonicalize(legacy_registry_dir).ok();
}
Expand Down Expand Up @@ -244,6 +244,6 @@ pub async fn require_wasm_commands(os: &AgentOs, test_name: &str) -> bool {
eprintln!("skipping {message}");
false
} else {
panic!("{message}; run the registry/native command build or set AGENT_OS_CLIENT_ALLOW_E2E_SKIPS=1 for local skip-only runs");
panic!("{message}; run the toolchain command build or set AGENT_OS_CLIENT_ALLOW_E2E_SKIPS=1 for local skip-only runs");
}
}
2 changes: 1 addition & 1 deletion crates/client/tests/packages_aospkg_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod common;
fn coreutils_aospkg() -> Option<PathBuf> {
for path in [
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../registry/software/coreutils/dist/package.aospkg"),
.join("../../software/coreutils/dist/package.aospkg"),
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../node_modules/@agentos-software/coreutils/dist/package.aospkg"),
] {
Expand Down
6 changes: 3 additions & 3 deletions crates/client/tests/pi_session_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! - `AGENT_OS_PI_MODULE_CWD` env (a workspace with a built/installed `@agentos-software/pi`), else
//! - the repo root, but only when the in-repo adapter is built
//! (`node_modules/@agentos-software/pi/dist/adapter.js`). Build it with `pnpm --dir packages/core
//! build && pnpm --dir registry/agent/pi build` (core first for types).
//! build && pnpm --dir software/pi build` (core first for types).
//!
//! Background: a real agent SDK exercises module-loading patterns (tsc `__exportStar` CJS barrels,
//! deep pnpm symlink graphs, `__dirname` package self-location) that mock ACP adapters never touch.
Expand Down Expand Up @@ -55,11 +55,11 @@ fn pi_module_cwd() -> Option<String> {

fn pi_package_path() -> Option<PathBuf> {
// Prefer the packed .aospkg — the artifact the registry actually ships.
let aospkg = repo_root().join("registry/agent/pi/dist/package.aospkg");
let aospkg = repo_root().join("software/pi/dist/package.aospkg");
if aospkg.is_file() {
return std::fs::canonicalize(aospkg).ok();
}
let dir = repo_root().join("registry/agent/pi/dist/package");
let dir = repo_root().join("software/pi/dist/package");
if dir.join("agentos-package.json").is_file() {
std::fs::canonicalize(dir).ok()
} else {
Expand Down
4 changes: 2 additions & 2 deletions crates/client/tests/shell_pty_packages_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn coreutils_package_path() -> Option<PathBuf> {
// Prefer the packed .aospkg — the artifact registry packages actually ship.
for aospkg in [
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../registry/software/coreutils/dist/package.aospkg"),
.join("../../software/coreutils/dist/package.aospkg"),
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../node_modules/@agentos-software/coreutils/dist/package.aospkg"),
] {
Expand All @@ -27,7 +27,7 @@ fn coreutils_package_path() -> Option<PathBuf> {
}
for dir in [
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../registry/software/coreutils/dist/package"),
.join("../../software/coreutils/dist/package"),
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../node_modules/@agentos-software/coreutils/dist/package"),
] {
Expand Down
2 changes: 1 addition & 1 deletion crates/execution/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ ESM loader hooks (`loader.mjs`) and CJS `Module._load` patches (`runner.mjs`) ar
- Node-facing `readdir` results must filter `.`/`..`.
- Async methods should dispatch under `fs.promises.*`.
- `fs.promises` methods that need real concurrency must use dedicated async bridge globals in `packages/build-tools/bridge-src/`; wrapping `fs.*Sync` inside `async` functions still serializes `Promise.all(...)` behind the first sidecar response.
- When adding WASI guest imports in `registry/native/crates/wasi-ext`, mirror the required module/object in `crates/execution/src/node_import_cache.rs`'s inline `NODE_WASM_RUNNER_SOURCE`; missing modules fail at `WebAssembly.instantiate()` before guest `main()` runs.
- When adding WASI guest imports in `toolchain/crates/wasi-ext`, mirror the required module/object in `crates/execution/src/node_import_cache.rs`'s inline `NODE_WASM_RUNNER_SOURCE`; missing modules fail at `WebAssembly.instantiate()` before guest `main()` runs.
- Keep the embedded WASI shim in `crates/execution/src/wasm.rs` aligned with the patched wasi-libc surface used by the C command suite; overrides like `fcntl(F_SETFL)` now depend on `fd_fdstat_set_flags`, and missing imports fail at instantiation time before the guest command can do real work.
- The shared-V8 WASM runner now resolves its own module loads plus internal guest `fs.openSync` / `fs.readSync` / `fs.writeSync` / `fs.closeSync` traffic inside `crates/execution/src/wasm.rs`; if the embedded runner gains more internal file syscalls, extend that internal sync-RPC handling there instead of surfacing those requests to callers or reintroducing a host-Node runtime path.
- fd-based APIs (`open`, `read`, `write`, `close`, `fstat`) plus `createReadStream`/`createWriteStream` should ride the same bridge.
Expand Down
54 changes: 47 additions & 7 deletions crates/execution/assets/runners/wasi-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
const __agentOSWasiOpenDirectory = 2;
const __agentOSWasiOpenExclusive = 4;
const __agentOSWasiOpenTruncate = 8;
const __agentOSWasiFdflagsAppend = 1;
const __agentOSWasiRightFdRead = 1n << 1n;
const __agentOSWasiRightFdWrite = 1n << 6n;
const __agentOSWasiDefaultRightsBase = 0xffffffffffffffffn;
Expand Down Expand Up @@ -396,6 +397,14 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
}
}

_hasReadRights(rights) {
try {
return (BigInt(rights) & __agentOSWasiRightFdRead) !== 0n;
} catch {
return true;
}
}

_writeUint32(ptr, value) {
try {
this._memoryView().setUint32(Number(ptr) >>> 0, Number(value) >>> 0, true);
Expand Down Expand Up @@ -779,6 +788,9 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
}

_mapFsError(error) {
__agentOSWasiDebug(
`fs error code=${String(error?.code ?? "")} message=${String(error?.message ?? error)}`,
);
switch (error?.code) {
case "EACCES":
case "EPERM":
Expand Down Expand Up @@ -827,6 +839,7 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
refCount: 1,
open: true,
readOnly: entry.readOnly === true,
append: entry.append === true,
};
}

Expand Down Expand Up @@ -1380,19 +1393,28 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written));
}
}
const position = handle.append
? this._measureWasiPhase("appendFstat", () =>
Number(__agentOSFs().fstatSync(handle.targetFd).size ?? 0)
)
: null;
const written = this._measureWasiPhase("writeSync", () =>
__agentOSFs().writeSync(
handle.targetFd,
bytes,
0,
bytes.length,
null,
position,
)
);
return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written));
}
if (handle?.kind === "guest-file" && typeof handle.targetFd === "number") {
const position = handle.append ? null : (handle.position ?? 0);
const position = handle.append
? this._measureWasiPhase("appendFstat", () =>
Number(__agentOSFs().fstatSync(handle.targetFd).size ?? 0)
)
: (handle.position ?? 0);
const written = this._measureWasiPhase("writeSync", () =>
__agentOSFs().writeSync(
handle.targetFd,
Expand Down Expand Up @@ -1469,7 +1491,11 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
}
if (entry.kind === "file") {
this._clearStatCache();
const position = typeof entry.offset === "number" ? entry.offset : null;
const position = entry.append
? this._measureWasiPhase("appendFstat", () =>
Number(__agentOSFs().fstatSync(entry.realFd).size ?? 0)
)
: (typeof entry.offset === "number" ? entry.offset : null);
const written = this._measureWasiPhase("writeSync", () =>
__agentOSFs().writeSync(
entry.realFd,
Expand All @@ -1479,7 +1505,11 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
position,
)
);
if (typeof entry.offset === "number") {
if (entry.append) {
entry.offset = this._measureWasiPhase("appendFstat", () =>
Number(__agentOSFs().fstatSync(entry.realFd).size ?? 0)
);
} else if (typeof entry.offset === "number") {
entry.offset += written;
}
return this._measureWasiPhase("writeResultPtr", () => this._writeUint32(nwrittenPtr, written));
Expand Down Expand Up @@ -2206,8 +2236,12 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
this._clearStatCache();
}
const fsConstants = __agentOSFs().constants ?? {};
const requestedFdFlags = Number(_fdflags) >>> 0;
const append = (requestedFdFlags & __agentOSWasiFdflagsAppend) !== 0;
let openFlags = requestedWriteAccess
? fsConstants.O_RDWR ?? 2
? (this._hasReadRights(requestedRightsBase)
? fsConstants.O_RDWR ?? 2
: fsConstants.O_WRONLY ?? 1)
: fsConstants.O_RDONLY ?? 0;
if ((requestedFlags & __agentOSWasiOpenCreate) !== 0) {
openFlags |= fsConstants.O_CREAT ?? 64;
Expand All @@ -2218,6 +2252,9 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
if ((requestedFlags & __agentOSWasiOpenTruncate) !== 0) {
openFlags |= fsConstants.O_TRUNC ?? 512;
}
if (append) {
openFlags |= fsConstants.O_APPEND ?? 1024;
}
if (openDirectory) {
openFlags |= fsConstants.O_DIRECTORY ?? 0;
}
Expand All @@ -2235,10 +2272,13 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule =
hostPath: fsPath,
readOnly: resolved.readOnly === true,
realFd,
offset: 0,
offset: append
? Number(__agentOSFs().fstatSync(realFd).size ?? 0)
: 0,
append,
rightsBase: requestedRightsBase & allowedRightsInheriting,
rightsInheriting: requestedRightsInheriting & allowedRightsInheriting,
fdFlags: (Number(_fdflags) >>> 0) & 0xffff,
fdFlags: requestedFdFlags & 0xffff,
});
});
return this._measureWasiPhase("writeOpenedFd", () => this._writeUint32(openedFdPtr, openedFd));
Expand Down
Loading
Loading