Skip to main content

WorkerFacade

Trait WorkerFacade 

Source
pub trait WorkerFacade: Send + Sync {
    // Required methods
    fn caller_project(&self, caller: &SessionSlot) -> Option<CallerProject>;
    fn spawn_worker<'life0, 'life1, 'async_trait>(
        &'life0 self,
        caller: &'life1 SessionSlot,
        label: String,
        charter: String,
        kick: Option<String>,
        resume_kick: Option<String>,
        interactive: bool,
        resume_session: bool,
        mcp_families: Option<Vec<String>>,
        cwd: Option<String>,
    ) -> Pin<Box<dyn Future<Output = Result<WorkerSpawnReply, WorkerSpawnError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn update_worker(
        &self,
        caller: &SessionSlot,
        label: &str,
        charter: Option<String>,
        kick: Option<String>,
        resume_kick: Option<String>,
        mcp_families: Option<Vec<String>>,
    ) -> Result<(), WorkerUpdateError>;
    fn despawn_worker<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        caller: &'life1 SessionSlot,
        label: &'life2 str,
        force: bool,
    ) -> Pin<Box<dyn Future<Output = Result<DespawnOutcome, WorkerDespawnError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn list_workers(&self, caller: &SessionSlot) -> Vec<WorkerStatus>;
    fn list_all_workers(&self) -> Vec<WorkerStatus>;
    fn capacity(&self, caller: &SessionSlot) -> Option<WorkerCapacity>;
    fn deliver_worker_prompt<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        caller: &'life1 SessionSlot,
        target_label: &'life2 str,
        wrapped: WrappedPrompt,
    ) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn deliver_worker_prompt_to_project<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
        &'life0 self,
        caller: &'life1 SessionSlot,
        org: &'life2 str,
        project: &'life3 str,
        target_label: &'life4 str,
        wrapped: WrappedPrompt,
    ) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait,
             'life4: 'async_trait;
    fn deliver_prompt_to_lead<'life0, 'life1, 'async_trait>(
        &'life0 self,
        caller: &'life1 SessionSlot,
        wrapped: WrappedPrompt,
    ) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerLeadDeliverError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
}
Expand description

The narrow workspace-state surface workers MCP Tool impls depend on.

spawn_worker is async because the production impl awaits a oneshot receiver wired into Command::SpawnWorker. The remaining methods are synchronous (one mutex acquire over in-memory state).

Required Methods§

Source

fn caller_project(&self, caller: &SessionSlot) -> Option<CallerProject>

Resolve the caller’s project key + lead/worker flag. Returns None when caller matches no known session.

Source

fn spawn_worker<'life0, 'life1, 'async_trait>( &'life0 self, caller: &'life1 SessionSlot, label: String, charter: String, kick: Option<String>, resume_kick: Option<String>, interactive: bool, resume_session: bool, mcp_families: Option<Vec<String>>, cwd: Option<String>, ) -> Pin<Box<dyn Future<Output = Result<WorkerSpawnReply, WorkerSpawnError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Dispatch a Command::SpawnWorker and await its synchronous reply. Gating (lead-only, non-empty label, non-empty charter) happens before dispatch. resume_kick is persisted rather than delivered now; it replaces the generic restart note when this worker resumes after a forge restart with a turn that was cut off. A worker that was idle when forge stopped resumes with nothing delivered. interactive keeps the built-in AskUserQuestion tool, which every other worker is denied. resume_session resumes the label’s most recent prior session instead of starting fresh. A label with none resolves to ResumeTarget::None, which starts a fresh session and says so in the reply’s SessionChoice; only a lookup that failed is an error.

cwd names the tree the worker should run in when it is not the project’s own - an absolute or ~-prefixed path, resolved to its repo root. None keeps the project’s path for a fresh spawn, and adopts the row’s recorded tree for a resume that states none.

Source

fn update_worker( &self, caller: &SessionSlot, label: &str, charter: Option<String>, kick: Option<String>, resume_kick: Option<String>, mcp_families: Option<Vec<String>>, ) -> Result<(), WorkerUpdateError>

Merge the supplied fields onto the stored dynamic-worker row for label in the caller’s project, leaving a None field at its stored value. Errors with NoSuchWorker when no row exists: update revises an existing worker, it never creates one. Takes effect on that worker’s next respawn, since a session’s system prompt and tool list are fixed when the session spawns. mcp_families follows the same contract: None leaves the stored selection alone, Some(names) replaces it - canonicalised by the tool - and Some(empty) resets it to every family.

Source

fn despawn_worker<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, caller: &'life1 SessionSlot, label: &'life2 str, force: bool, ) -> Pin<Box<dyn Future<Output = Result<DespawnOutcome, WorkerDespawnError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Dispatch a Command::DespawnWorker and await its result. Gating (lead-only, non-empty label) happens before dispatch. force removes a dirty worktree; without it a dirty worktree blocks the despawn (DespawnOutcome::Blocked).

Source

fn list_workers(&self, caller: &SessionSlot) -> Vec<WorkerStatus>

Snapshot of every worker in the caller’s project. Returns an empty Vec when the caller resolves to no project.

Source

fn list_all_workers(&self) -> Vec<WorkerStatus>

Snapshot of every project’s workers: the real workspace walks list_projects in config order, the mock sorts its project keys.

Source

fn capacity(&self, caller: &SessionSlot) -> Option<WorkerCapacity>

The caller’s project worker capacity: the cap the spawn path enforces (max_workers in the project’s [[orgs.projects]] entry, else DEFAULT_MAX_WORKERS_PER_PROJECT) paired with the live count. A plain data read - the same one the spawn path’s cap check performs. Returns None when the caller resolves to no project.

Source

fn deliver_worker_prompt<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, caller: &'life1 SessionSlot, target_label: &'life2 str, wrapped: WrappedPrompt, ) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Dispatch a worker-bound wrapped prompt. Delivered means the prompt was accepted - handed to the target’s session queue, held for its turn end, or parked for its connect - which is the whole claim the sender’s ack makes; anything that reached no session is an error. UnknownLabel when no live worker matches.

Source

fn deliver_worker_prompt_to_project<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, caller: &'life1 SessionSlot, org: &'life2 str, project: &'life3 str, target_label: &'life4 str, wrapped: WrappedPrompt, ) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerDeliverError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait,

Dispatch a worker-bound wrapped prompt to a project named by its (org, project) pair rather than the caller’s own. The caller lives in another project, so the target cannot be resolved from it. Mirrors deliver_worker_prompt otherwise: an unknown label is an error and a sleeping target is not auto-spawned.

Source

fn deliver_prompt_to_lead<'life0, 'life1, 'async_trait>( &'life0 self, caller: &'life1 SessionSlot, wrapped: WrappedPrompt, ) -> Pin<Box<dyn Future<Output = Result<WorkerTargetStatus, WorkerLeadDeliverError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Dispatch a wrapped prompt from a worker back to its lead. Caller MUST be a worker. The target lead is resolved from the caller’s WorkerEntry::spawned_by_session_id. Same wire-shape contract as deliver_worker_prompt: Delivered means the lead’s session accepted it, and one the session could not take is an error.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§