Skip to main content

forge_primitives/
command.rs

1//! `Command` - the UI → agent channel envelope.
2//!
3//! One variant per fire-and-forget action the UI can ask the agent
4//! to perform. Direct-return accessors (config_dir, settings_documents,
5//! etc.) live on a separate sync surface, not in `Command`.
6
7use crate::ids::{SessionId, ToolUseId};
8use crate::image::ImageAttachment;
9use crate::{PermissionMode, PermissionOutcome, QuestionOutcome};
10
11/// UI → agent channel envelope. Each variant maps to one inherent
12/// method on `forge_agent::ForgeSdkBridge`. Named `AgentCommand`
13/// to disambiguate from the higher-level
14/// `forge_workspace::protocol::Command` (UI → workspace) - the two
15/// envelopes are deliberately different shapes with overlapping
16/// names, and disambiguating the agent-side enum makes which one
17/// is meant obvious at every call site.
18#[derive(Debug, Clone, PartialEq)]
19pub enum AgentCommand {
20    // --- Session lifecycle ---
21    NewSession {
22        /// The id the child runs under, passed as `--session-id`. `None`
23        /// leaves the choice to the CLI. Never combined with a resume:
24        /// the CLI refuses both flags together, and `--session-id` is
25        /// create-only, so it is refused outright when a transcript of
26        /// that id already exists.
27        session_id: Option<String>,
28        cwd: String,
29        launch_settings: serde_json::Value,
30    },
31    ResumeSession {
32        session_id: SessionId,
33        /// Working directory for the spawned `claude` subprocess.
34        /// `claude --resume <id>` indexes sessions by the project key
35        /// derived from this directory; an empty value makes the
36        /// subprocess inherit forge's `$PWD` which usually does not
37        /// match the resumed session's project, causing "No
38        /// conversation found with session ID …" even when the
39        /// `.jsonl` exists. Source from the catalog when picking a
40        /// session by id.
41        cwd: String,
42        launch_settings: serde_json::Value,
43    },
44    /// Resume `session_id`; if the resume fails at the transport level
45    /// (e.g. the underlying `.jsonl` is missing, locked, or otherwise
46    /// unreadable by the `claude` subprocess), automatically retry as
47    /// `NewSession { cwd, … }`. Used by every project-rooted entry
48    /// path (`forge`, `forge <project>`, Projects-pane project-header
49    /// click) so a stale or cross-account catalog entry can't strand
50    /// the user with no recoverable session.
51    ResumeOrNewSession {
52        session_id: SessionId,
53        cwd: String,
54        launch_settings: serde_json::Value,
55    },
56
57    // --- Conversation ---
58    Prompt {
59        session_id: SessionId,
60        text: String,
61        /// The prompt's own id, stamped on the frame. The CLI emits this
62        /// prompt's `command_lifecycle` frames only under a stamped id, and a
63        /// view keys its row to those frames by it. Minted by whoever
64        /// dispatches the prompt.
65        uuid: String,
66    },
67    PromptWithImages {
68        session_id: SessionId,
69        text: String,
70        images: Vec<ImageAttachment>,
71        /// As on [`Self::Prompt`].
72        uuid: String,
73    },
74    Cancel {
75        session_id: SessionId,
76    },
77    /// Drop one prompt still sitting in the CLI's queue, by the uuid it was
78    /// sent under. Answered by [`crate::Message`]-side lifecycle state: a
79    /// prompt the CLI already took cannot be reached this way.
80    CancelQueuedPrompt {
81        session_id: SessionId,
82        uuid: String,
83    },
84
85    // --- Controls ---
86    SetMode {
87        session_id: SessionId,
88        mode: PermissionMode,
89    },
90    SetModel {
91        session_id: SessionId,
92        model: String,
93    },
94
95    // --- Snapshots requested by UI ---
96    GetContextUsage {
97        session_id: SessionId,
98    },
99    GetMcpSnapshot {
100        session_id: SessionId,
101    },
102
103    // --- Callback responses ---
104    PermissionResponse {
105        session_id: SessionId,
106        tool_call_id: ToolUseId,
107        outcome: PermissionOutcome,
108    },
109    QuestionResponse {
110        session_id: SessionId,
111        tool_call_id: ToolUseId,
112        outcome: QuestionOutcome,
113    },
114}