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 {
47        session_id: String,
48    },
49}
50
51#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq)]
52pub struct DispatchAgentParams {
53    /// Instructions for the sub-agent.
54    /// Do not prepend synthetic path headers like `Repo: ...` or `CWD: ...`.
55    /// The sub-agent receives its working-directory context automatically.
56    pub prompt: String,
57    /// Session/workspace target for the sub-agent call.
58    pub target: DispatchAgentTarget,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Error)]
62#[serde(tag = "code", content = "details", rename_all = "snake_case")]
63pub enum DispatchAgentError {
64    #[error("{0}")]
65    Workspace(WorkspaceOpError),
66
67    #[error("workspace unavailable: {message}")]
68    WorkspaceUnavailable { message: String },
69
70    #[error("sub-agent failed: {message}")]
71    SpawnFailed { message: String },
72
73    #[error("failed to load session {session_id}: {message}")]
74    SessionLoadFailed { session_id: String, message: String },
75
76    #[error("session {session_id} is missing a SessionCreated event")]
77    MissingSessionCreatedEvent { session_id: String },
78
79    #[error("session {session_id} is not a child of current session {parent_session_id}")]
80    InvalidParentSession {
81        session_id: String,
82        parent_session_id: String,
83    },
84
85    #[error("failed to open workspace for session {session_id}: {message}")]
86    WorkspaceOpenFailed { session_id: String, message: String },
87}