Skip to main content

Agent

Trait Agent 

Source
pub trait Agent: Send + Sync {
    // Required methods
    fn launch_command(&self, session: &Session) -> String;
    fn environment(&self, session: &Session) -> Vec<(String, String)>;
    fn initial_prompt(&self, session: &Session) -> String;

    // Provided methods
    fn system_prompt(&self) -> Option<String> { ... }
    fn detect_activity<'life0, 'life1, 'async_trait>(
        &'life0 self,
        session: &'life1 Session,
    ) -> Pin<Box<dyn Future<Output = Result<ActivityState>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn cost_estimate<'life0, 'life1, 'async_trait>(
        &'life0 self,
        session: &'life1 Session,
    ) -> Pin<Box<dyn Future<Output = Result<Option<CostEstimate>>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
}
Expand description

A specific AI coding tool (Claude Code, Codex, Aider, Cursor, …).

Mostly a metadata provider (launch command, env, prompt), plus one async hook — detect_activity — which the lifecycle loop polls to learn what the underlying agent process is currently doing. The TS reference does this by tailing a JSONL log file the agent writes; Slice 1 Phase C’s stub just returns Ready so the polling loop has something to drive.

Required Methods§

Source

fn launch_command(&self, session: &Session) -> String

Single shell string the runtime will run inside its execution context.

Source

fn environment(&self, session: &Session) -> Vec<(String, String)>

Source

fn initial_prompt(&self, session: &Session) -> String

First prompt to deliver after the process is up.

Provided Methods§

Source

fn system_prompt(&self) -> Option<String>

System rules / workflow guidance that must be prepended to the user prompt by the caller.

Agents that support a dedicated system-prompt CLI flag (e.g. Claude Code’s --append-system-prompt) inject rules at launch time via launch_command and return None here. Agents without such a flag (e.g. Cursor) return Some(rules) so callers composing a richer prompt via build_prompt can prepend them before delivery.

Default: None — no system prompt to inject separately.

Source

fn detect_activity<'life0, 'life1, 'async_trait>( &'life0 self, session: &'life1 Session, ) -> Pin<Box<dyn Future<Output = Result<ActivityState>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Inspect whatever evidence this agent leaves behind (log files, terminal scrollback, pid probes, …) and report its current activity state. Called once per lifecycle tick.

The default impl consults {workspace}/.ao/activity.jsonl via activity_log::detect_activity_from_log and surfaces:

  • Exited when the last entry is terminal (no staleness downgrade — exit is a one-way signal).
  • WaitingInput / Blocked when the last entry is actionable and fresh (within ACTIVITY_INPUT_STALENESS_SECS).

Falls back to Ready when there’s no workspace, no log, or the log only carries noisy signals (Active / Ready / Idle / stale actionable). Plugins with richer native detection (JSONL tailing, git-index mtime, …) override this entirely.

Source

fn cost_estimate<'life0, 'life1, 'async_trait>( &'life0 self, session: &'life1 Session, ) -> Pin<Box<dyn Future<Output = Result<Option<CostEstimate>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Poll current aggregated token usage / cost from the agent’s logs.

Called by the lifecycle loop when a session’s status changes (not every tick). The default impl consults {workspace}/.ao/usage.jsonl via cost_log::parse_usage_jsonl and returns the aggregate when entries exist. Returns None when cost tracking is unavailable — either because there’s no workspace, the file is missing, or it aggregates to zero tokens. Plugins with native cost sources (e.g. agent-claude-code reading ~/.claude/projects/**) override this.

Implementors§