Skip to main content

AgentOs

Struct AgentOs 

Source
pub struct AgentOs { /* private fields */ }
Expand description

The high-level client. Cheaply cloneable via Arc.

Implementations§

Source§

impl AgentOs

Source

pub async fn create(options: AgentOsConfig) -> Result<AgentOs, ClientError>

The sole public VM entry point. Processes software, spawns/authenticates the sidecar, creates the VM, waits for ready (10s), configures it, takes a lease, and constructs the cron manager (default crate::config::TimerScheduleDriver).

Dispose the VM (= TS dispose). Teardown order:

  1. cron dispose
  2. close all sessions (swallow errors)
  3. kill all shells + snapshot pending exits
  4. kill all ACP terminals
  5. drain tracked shell-exit tasks (two-phase, bounded by crate::SHELL_DISPOSE_TIMEOUT_MS)
  6. unregister the sidecar event listener
  7. release the lease (or tear down the transport)

Idempotent (guarded by disposed). Dynamically link a software package into the RUNNING VM (parity with the TS client’s linkSoftware). Forwarded to the sidecar, which owns the /opt/agentos projection and appends the package to its live staging dir, so the package’s commands appear under /opt/agentos/bin (on $PATH) immediately with no reboot. Errors if a command name is already linked.

Source

pub async fn shutdown(&self) -> Result<(), ClientError>

Source

pub fn sidecar(&self) -> Arc<AgentOsSidecar>

The (possibly shared) sidecar handle backing this VM. Public for parity with TS AgentOs.sidecar (e.g. describe() reports active_vm_count across VMs sharing a pool).

Source

pub fn provided_commands(&self) -> Vec<(String, Vec<String>)>

The commands each configured package ships, keyed by the package’s manifest name (matching [SoftwareInfoDto::package] on the actor-plugin side). Read from each package dir the same way the sidecar’s command_targets does (package.json bin, else the bin/ dir). An agent package (no shipped commands) contributes an empty list.

WORKAROUND: agent-os owns command provisioning (it forwards each package dir), so it can read the host dirs here. The authoritative resolved set — deduping when two packages provide the same command, priority order, and executability — is owned by secure-exec’s projection. This re-derives a slice of that. TODO: replace with a secure-exec API that reports discovered commands per package instead of us re-reading dirs.

Source§

impl AgentOs

Source

pub fn schedule_cron( &self, options: CronJobOptions, ) -> Result<CronJobHandle, ClientError>

Schedule a cron job. SYNC. Validates the schedule (errors InvalidSchedule / PastSchedule). id defaults to a UUID; overlap defaults to allow.

Mirrors TS AgentOs.scheduleCron / CronManager.schedule: validation happens up front, the driver is asked to arm the timer (this.driver.schedule({ id, schedule, callback })), and the job is registered. The driver owns all timing: it parses the schedule, fires the callback, reschedules cron after each fire, and is cancelled on CronJobHandle::cancel / CronManager::dispose. The returned CronJobHandle cancels the job.

Source

pub fn list_cron_jobs(&self) -> Vec<CronJobInfo>

Snapshot all cron jobs. Mirrors TS CronManager.list.

Source

pub fn cancel_cron_job(&self, id: &str)

Cancel a cron job. No-op if unknown; never errors. Mirrors TS CronManager.cancel.

Source

pub fn cron_events(&self) -> Receiver<CronEvent>

Subscribe to cron events. The TS API returns no unsubscribe; dropping the receiver is the equivalent. Each run emits Fire then Complete|Error. Mirrors TS AgentOs.onCronEvent.

Source§

impl AgentOs

Source

pub async fn read_file(&self, path: &str) -> Result<Vec<u8>>

Read a file’s raw bytes (no decode).

Source

pub async fn write_file( &self, path: &str, content: impl Into<FileContent>, ) -> Result<()>

Write a file. Writable-path guard; does NOT auto-create parents; Text -> UTF-8.

Source

pub async fn write_files( &self, entries: Vec<BatchWriteEntry>, ) -> Vec<BatchWriteResult>

Batch write. Sequential; never rejects (per-entry error); auto-creates parent dirs.

Source

pub async fn read_files(&self, paths: Vec<String>) -> Vec<BatchReadResult>

Batch read. Sequential; never rejects; content None on failure.

Source

pub async fn mkdir(&self, path: &str, options: MkdirOptions) -> Result<()>

Make a directory. Recursive -> writable guard + mkdirp; non-recursive -> safe guard + single level. The guard asymmetry is load-bearing.

Source

pub async fn readdir(&self, path: &str) -> Result<Vec<String>>

List basenames (may include ./..).

Source

pub async fn read_dir_with_types( &self, path: &str, ) -> Result<Vec<VirtualDirEntry>>

Typed directory listing: each child reported with its resolved type. secure-exec’s native READ_DIR returns basenames only (entries: list<str>), so the type of each entry is derived with a per-child lstat (a symlink is reported as such, lstat-style, not followed). Goes through the kernel, so mounts are listed correctly. ./.. are filtered.

Source

pub async fn readdir_recursive( &self, path: &str, options: ReaddirRecursiveOptions, ) -> Result<Vec<DirEntry>>

Recursive BFS listing; symlinks recorded but NOT descended; a stat failure aborts the call.

Source

pub async fn stat(&self, path: &str) -> Result<VirtualStat>

Stat (follows symlinks).

Source

pub async fn exists(&self, path: &str) -> Result<bool>

Existence check. Safe-path guard still errors; missing path -> false.

Source

pub async fn snapshot_root_filesystem(&self) -> Result<RootSnapshotExport>

Export the root filesystem snapshot. Octal-string mode + utf8/base64 content verbatim.

Source

pub fn mount_fs( &self, path: &str, driver: Arc<dyn VirtualFileSystem>, options: MountFsOptions, ) -> Result<(), ClientError>

Mount an in-process VirtualFileSystem driver. SYNC. Safe-path guard. The driver is a live trait object and cannot cross an RPC boundary, so it is registered (together with the read_only flag, mirroring TS kernel.mountFs({ readOnly })) in the in-process mount table keyed by its normalized guest path.

Source

pub fn unmount_fs(&self, path: &str) -> Result<(), ClientError>

Unmount a previously mounted path. SYNC.

Source

pub async fn move_path(&self, from: &str, to: &str) -> Result<()>

Move a path. lstat(from) no-follow; symlink/non-dir -> rename; real dir -> recursive copy (preserve mode/uid/gid/symlinks) + recursive delete. (TS move.)

Source

pub async fn delete(&self, path: &str, options: DeleteOptions) -> Result<()>

Delete a path. lstat to discriminate; recursive manually recurses children then remove_dir; non-recursive dir -> remove_dir (ENOTEMPTY if non-empty).

Source§

impl AgentOs

Source

pub async fn fetch( &self, port: u16, request: Request<Bytes>, ) -> Result<Response<Bytes>>

Fetch from a guest server listening on port inside the VM.

path is derived from the request URI’s pathname+search; the host is ignored. The body is only sent for methods other than GET/HEAD. The response body is base64-decoded.

Source§

impl AgentOs

Source

pub async fn exec( &self, command: &str, options: ExecOptions, ) -> Result<ExecResult>

Run a command to completion. The wire Execute request starts the process and returns a process id immediately; stdout/stderr are accumulated and the call resolves once the matching ProcessExited event arrives. This mirrors the TS pass-through to kernel.exec semantically: the result is the full captured stdout/stderr plus exit code.

Source

pub async fn exec_argv( &self, command: &str, args: &[String], options: ExecOptions, ) -> Result<ExecResult>

Run a command to completion from an already-structured (command, args) argv, bypassing the exec command-line parser. Each args element is sent verbatim as a distinct argv element — no whitespace re-splitting, no shell metacharacter detection, and no routing through sh -c. Callers that already hold a structured argv (for example the cron Exec action) must use this so the structured-argv contract is preserved end to end.

Source

pub fn spawn( &self, command: &str, args: Vec<String>, options: SpawnOptions, ) -> Result<SpawnHandle>

Spawn a process. SYNC; returns { pid } only. Installs stdout/stderr fan-out over broadcast channels and wires exit via a background event-pump task. The user-facing pid is the SDK-allocated map key (the wire process_id is held inside the [ProcessEntry]).

Source

pub fn write_process_stdin( &self, pid: u32, data: StdinInput, ) -> Result<(), ClientError>

Write to a spawned process’s stdin. SYNC. Errors with ProcessNotFound.

Source

pub fn close_process_stdin(&self, pid: u32) -> Result<(), ClientError>

Close a spawned process’s stdin. SYNC. Errors with ProcessNotFound.

Source

pub fn on_process_stdout(&self, pid: u32) -> Result<ByteStream, ClientError>

Subscribe to a spawned process’s stdout. No replay; multi-subscriber. Errors if unknown.

Source

pub fn on_process_stderr(&self, pid: u32) -> Result<ByteStream, ClientError>

Subscribe to a spawned process’s stderr. No replay; multi-subscriber. Errors if unknown.

Source

pub fn on_process_exit( &self, pid: u32, handler: impl FnOnce(i32) + Send + 'static, ) -> Result<Subscription, ClientError>

Register a once-only exit handler. If the process has already exited, the handler fires immediately and synchronously and a no-op unsubscribe is returned (the watch already holds Some(code)). Otherwise the handler fires once when the exit code lands. The exit code is i32, never null.

Source

pub async fn wait_process(&self, pid: u32) -> Result<i32, ClientError>

Await a spawned process’s exit code. Unknown-pid lookup errors (synchronously in TS; here the lookup error is returned before any awaiting begins).

Source

pub fn list_processes(&self) -> Vec<SpawnedProcessInfo>

List SDK-spawned processes only. running = exit_code.is_none().

Source

pub async fn all_processes(&self) -> Result<Vec<ProcessInfo>>

List ALL kernel processes (native sidecar process snapshot).

The kernel snapshot keys processes by their raw kernel pid. SDK-spawned root processes carry a synthetic display pid (the spawn return value); this remaps each snapshot entry’s pid/ppid/pgid/sid back to that display pid via the per-process kernel_pid watch, so a caller can correlate spawn() with all_processes()/process_tree(). Results are sorted ascending by display pid (TS snapshotProcesses .sort((l,r) => l.pid - r.pid)).

Source

pub async fn process_tree(&self) -> Result<Vec<ProcessTreeNode>>

Build the process forest from all_processes, linked by ppid.

Source

pub fn get_process(&self, pid: u32) -> Result<SpawnedProcessInfo, ClientError>

Get a single SDK-spawned process’s info. Errors (not None) when not found.

Source

pub fn stop_process(&self, pid: u32) -> Result<(), ClientError>

SIGTERM a spawned process. No-op if already exited; errors if unknown.

Source

pub fn kill_process(&self, pid: u32) -> Result<(), ClientError>

SIGKILL a spawned process. No-op if already exited; errors if unknown.

Source§

impl AgentOs

Source

pub fn list_sessions(&self) -> Vec<SessionInfo>

List in-memory sessions.

Source

pub fn list_agents(&self) -> Vec<AgentRegistryEntry>

List available agents (host FS). Unions package agent ids + the built-in AGENT_CONFIGS keys; installed is determined by reading the adapter package.json (host FS, try/catch).

PARITY GAP: the agent-config registry (AGENT_CONFIGS, package agent configs, software roots, adapter package.json resolution) does not exist in the client scaffold and lives in shared modules this task may not edit. Returns an empty list until that infrastructure is added. See todosLeft.

Source

pub async fn create_session( &self, agent_type: &str, options: CreateSessionOptions, ) -> Result<SessionId>

Create an ACP session. Resolves the agent config, merges env (user wins), creates the session via the sidecar (runtime: java_script, protocol v1, default client caps), and hydrates state. Agent OS owns dynamic tool-reference instructions and forwards them as additional instructions; the sidecar owns final base-prompt assembly and agent-specific injection. On hydration failure the session is removed and the error rethrown. Returns the session id only.

Source

pub async fn resume_session( &self, session_id: &str, agent_type: &str, options: ResumeSessionOptions, ) -> Result<ResumeSessionResult>

Resume a session that exists in durable storage but is not live in this VM (e.g. after a Rivet actor slept and woke with a fresh VM). Thin forwarder: resolves the agent config + adapter entrypoint exactly as create_session does, then forwards a single AcpResumeSessionRequest to the sidecar, which owns the resume state machine (native session/load when supported, else session/new + transcript-continuation preamble). The returned session_id is the live id in this VM (equal to session_id for native loads, freshly assigned for the fallback); the caller remaps external -> live. The new live session is registered + hydrated locally so subsequent prompts route to it.

Resume depends on a durable root; on a non-durable (default in-memory) root there is no surviving store and the fallback tier always runs.

Source

pub async fn destroy_session(&self, session_id: &str) -> Result<()>

Destroy a session. Best-effort cancel_session then internal close.

Source

pub async fn prompt(&self, session_id: &str, text: &str) -> Result<PromptResult>

Prompt a session. Subscribes to live session/update events, accumulates agent_message_chunk text, sends session/prompt, and unsubscribes by dropping the receiver. The response may itself be an error.

Source

pub async fn cancel_session(&self, session_id: &str) -> Result<JsonRpcResponse>

Cancel a session. If prompt requests are pending, resolves locally + background session/cancel and returns a synthetic { via: "prompt-fallback" }; else real session/cancel.

Source

pub fn close_session(&self, session_id: &str) -> Result<(), ClientError>

Close a session. SYNC fire-and-forget. Errors only if unknown across sessions / closed-ids / in-flight closes. Aborts pending, rejects pending permissions, records the closed id (bounded 2048). Mirrors closeSession, whose known-check spans _sessions, _closedSessionIds, and _sessionClosePromises.

Source

pub async fn respond_permission( &self, session_id: &str, permission_id: &str, reply: PermissionReply, ) -> Result<JsonRpcResponse>

Respond to a permission request. If a pending reply slot exists, resolves it and returns a synthetic { via: "sidecar-request" }; else the legacy request/permission RPC. Mirrors respondPermission.

Source

pub async fn set_session_mode( &self, session_id: &str, mode_id: &str, ) -> Result<JsonRpcResponse>

Set the session mode (session/set_mode). Updates cached current_mode_id on success.

Source

pub fn get_session_modes(&self, session_id: &str) -> Option<SessionModeState>

Get cached session mode state.

Source

pub async fn set_session_model( &self, session_id: &str, model: &str, ) -> Result<JsonRpcResponse>

Set the session model. Uses set_config_option with category model; readonly -> error response.

Source

pub async fn set_session_thought_level( &self, session_id: &str, level: &str, ) -> Result<JsonRpcResponse>

Set the session thought level. Same as model with category thought_level.

Source

pub fn get_session_config_options( &self, session_id: &str, ) -> Vec<SessionConfigOption>

Get cached config options (shallow copy).

Source

pub fn get_session_capabilities( &self, session_id: &str, ) -> Option<AgentCapabilities>

Get cached capabilities. Mirrors getSessionCapabilities: returns null (None) when the stored capabilities object has no keys (Object.keys(caps).length === 0).

Source

pub fn get_session_agent_info(&self, session_id: &str) -> Option<AgentInfo>

Get cached agent info.

Source

pub async fn raw_session_send( &self, session_id: &str, method: &str, params: Option<Value>, ) -> Result<JsonRpcResponse>

Raw passthrough to send_session_request (which already re-hydrates + applies set_mode / set_config_option cache updates). Mirrors rawSessionSend.

Source

pub async fn raw_send( &self, session_id: &str, method: &str, params: Option<Value>, ) -> Result<JsonRpcResponse>

Thin alias for raw_session_send.

Source

pub fn on_session_event( &self, session_id: &str, ) -> Result<SessionEventSubscription, ClientError>

Subscribe to live session/update events. Only events emitted after subscription are delivered.

Source

pub fn on_permission_request( &self, session_id: &str, ) -> Result<PermissionRequestSubscription, ClientError>

Subscribe to permission requests raised by the session’s guest agent. Requests originate from the sidecar permission_request callback (the sidecar normalizes both the legacy request/permission and ACP session/request_permission method names before invoking the host). With no subscribers a request auto-rejects; subscribers reply via the carried PermissionResponder or AgentOs::respond_permission, bounded by the crate::PERMISSION_TIMEOUT_MS timeout.

Source

pub fn on_agent_exit( &self, session_id: &str, ) -> Result<AgentExitSubscription, ClientError>

Subscribe to unexpected adapter process exits (crashes) for a session, including the sidecar’s bounded auto-restart outcome. Only events emitted after subscription are delivered; only restart == "restarted" leaves the session usable. Mirrors the TS onAgentExit option.

Source§

impl AgentOs

Source

pub async fn create_sidecar( sidecar_id: Option<String>, ) -> Result<Arc<AgentOsSidecar>, ClientError>

Create an explicit sidecar handle. sidecar_id defaults to agentos-sidecar-<uuid>.

Parity with TypeScript createAgentOsSidecarInternal: the explicit handle carries an Explicit placement whose sidecar_id echoes the resolved id and has no shared pool.

Source

pub async fn get_shared_sidecar( pool: Option<String>, sidecar_binary_path: Option<String>, ) -> Result<Arc<AgentOsSidecar>, ClientError>

Get (or create) a pooled shared sidecar. Pool defaults to "default". Uses the process-global cache.

Parity with TypeScript getSharedAgentOsSidecarInternal: return the cached sidecar for the pool when it exists and is not disposed; otherwise build a fresh handle (agentos-shared-sidecar:<pool>, Shared placement) and cache it. Because the cache is a process-global concurrent map rather than a synchronously-checked Map, the insert is done atomically with entry/insert so two racing callers converge on a single live handle.

Source§

impl AgentOs

Source

pub fn open_shell(&self, options: OpenShellOptions) -> Result<ShellHandle>

Open a PTY-backed shell. SYNC. Returns a synthetic shell-N id (NOT a pid).

The shell id and its registry entry are allocated synchronously (matching the TS sync contract); the actual guest-process spawn, output fan-out, and exit-task registration happen on a background task because the wire spawn is async. The exit task is tracked in the pending-shell-exit set so dispose can drain it (two-phase teardown).

Stdout is fanned into the shell’s data broadcast (on_shell_data); stderr is fanned into a SEPARATE stderr broadcast (on_shell_stderr + the OpenShellOptions::on_stderr callback), matching the TS real-process routing where stderr never reaches the data stream.

Source

pub async fn connect_terminal( &self, options: ConnectTerminalOptions, ) -> Result<u32>

Connect a terminal bound to host stdio. Returns a PID. NOT tracked in the shells map; cannot be addressed by other shell methods. Killed during dispose via the ACP-terminal registry.

Mirrors the TS connectTerminal, which routes its onData/onStderr callbacks through openShell. The Rust port opens a shell, wires the caller’s on_data to the shell’s data stream and on_stderr to the shell’s stderr stream, then returns the shell’s pid. Host stdin binding, terminal raw-mode, and SIGWINCH/resize forwarding are host-process concerns that have no native wire op and are intentionally not bound here.

Source

pub fn write_shell( &self, shell_id: &str, data: StdinInput, ) -> Result<(), ClientError>

Write to a shell. SYNC fire-and-forget. Errors with ClientError::ShellNotFound.

Source

pub async fn write_shell_awaited( &self, shell_id: &str, data: StdinInput, ) -> Result<(), ClientError>

Write to a shell and AWAIT the wire write. Same routing as Self::write_shell, but the caller observes wire failures instead of a fire-and-forget warn — used by the actor plugin’s writeShell action so a failed write rejects the action.

Source

pub fn on_shell_data(&self, shell_id: &str) -> Result<ByteStream, ClientError>

Subscribe to a shell’s stdout data. SYNC register; multi-handler; dropping the returned stream is the unsubscribe. Carries stdout ONLY (stderr is on on_shell_stderr). Errors with ClientError::ShellNotFound.

Source

pub fn on_shell_stderr(&self, shell_id: &str) -> Result<ByteStream, ClientError>

Subscribe to a shell’s stderr. SYNC register; multi-handler; dropping the returned stream is the unsubscribe. This is the dedicated stderr channel backing the TS onStderr option; stderr is never fanned into on_shell_data. Errors with ClientError::ShellNotFound.

Source

pub fn resize_shell( &self, shell_id: &str, cols: u16, rows: u16, ) -> Result<(), ClientError>

Resize a shell’s PTY winsize. SYNC fire-and-forget, mirroring the TS ShellHandle.resize (which dispatches resizePty in the background after the spawn lands). Errors with ClientError::ShellNotFound.

Source

pub async fn wait_shell(&self, shell_id: &str) -> Result<i32, ClientError>

Wait for a shell to exit and return its process exit code (TS waitShell). Resolves immediately for a shell that already exited within the bounded retention window. Errors with ClientError::ShellNotFound for an unknown id.

Source

pub fn close_shell(&self, shell_id: &str) -> Result<(), ClientError>

Close a shell. SYNC. kill() + immediate map delete; the exit task is still drained by dispose. Errors with ClientError::ShellNotFound.

Trait Implementations§

Source§

impl Clone for AgentOs

Source§

fn clone(&self) -> AgentOs

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more