Skip to main content

steer_tools/tools/
dispatch_agent.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5use crate::ToolSpec;
6use crate::error::{ToolExecutionError, WorkspaceOpError};
7use crate::result::AgentResult;
8
9pub const DISPATCH_AGENT_TOOL_NAME: &str = "dispatch_agent";
10
11pub struct DispatchAgentToolSpec;
12
13impl ToolSpec for DispatchAgentToolSpec {
14    type Params = DispatchAgentParams;
15    type Result = AgentResult;
16    type Error = DispatchAgentError;
17
18    const NAME: &'static str = DISPATCH_AGENT_TOOL_NAME;
19    const DISPLAY_NAME: &'static str = "Dispatch Agent";
20
21    fn execution_error(error: Self::Error) -> ToolExecutionError {
22        ToolExecutionError::DispatchAgent(error)
23    }
24}
25
26#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
27#[serde(tag = "location", rename_all = "snake_case")]
28pub enum WorkspaceTarget {
29    /// Run the sub-agent in the caller's current workspace.
30    Current,
31    /// Create a fresh workspace (jj workspace or git worktree) and run there.
32    /// The resulting path may differ from the caller's current directory.
33    New { name: String },
34}
35
36#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
37#[serde(tag = "session", rename_all = "snake_case")]
38pub enum DispatchAgentTarget {
39    /// Start a new child session.
40    New {
41        workspace: WorkspaceTarget,
42        #[serde(default)]
43        agent: Option<String>,
44    },
45    /// Continue an existing child session by id.
46    Resume { session_id: String },
47}
48
49#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
50pub struct DispatchAgentParams {
51    /// Instructions for the sub-agent.
52    /// Do not prepend synthetic path headers like `Repo: ...` or `CWD: ...`.
53    /// The sub-agent receives its working-directory context automatically.
54    pub prompt: String,
55    /// Session/workspace target for the sub-agent call.
56    pub target: DispatchAgentTarget,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Error)]
60#[serde(tag = "code", content = "details", rename_all = "snake_case")]
61pub enum DispatchAgentError {
62    #[error("{0}")]
63    Workspace(WorkspaceOpError),
64
65    #[error("workspace unavailable: {message}")]
66    WorkspaceUnavailable { message: String },
67
68    #[error("sub-agent failed: {message}")]
69    SpawnFailed { message: String },
70
71    #[error("failed to load session {session_id}: {message}")]
72    SessionLoadFailed { session_id: String, message: String },
73
74    #[error("session {session_id} is missing a SessionCreated event")]
75    MissingSessionCreatedEvent { session_id: String },
76
77    #[error("session {session_id} is not a child of current session {parent_session_id}")]
78    InvalidParentSession {
79        session_id: String,
80        parent_session_id: String,
81    },
82
83    #[error("failed to open workspace for session {session_id}: {message}")]
84    WorkspaceOpenFailed { session_id: String, message: String },
85}