Skip to main content

substrate_core/
cloud_dispatch_port.rs

1//! CloudDispatchPort — submit remote cloud-agent tasks and harvest PR results.
2//!
3//! Core defines the port contract and value types; `cloud-*` adapter crates
4//! implement it against Cursor Cloud Agents, Kilo gateway-backed dispatch, etc.
5
6use async_trait::async_trait;
7use serde::{Deserialize, Serialize};
8
9use crate::error::Result;
10
11/// Opaque handle returned by [`CloudDispatchPort::submit_task`].
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct CloudTaskHandle {
14    /// Adapter-local task identifier (stable for poll/harvest).
15    pub id: String,
16}
17
18/// Observed lifecycle state of a cloud-dispatched task.
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20pub enum CloudTaskStatus {
21    /// Task accepted but not yet executing.
22    Queued,
23    /// Remote agent is actively working.
24    Running,
25    /// Task completed successfully; [`CloudDispatchPort::harvest`] may be called.
26    Succeeded,
27    /// Task failed; optional adapter message for diagnostics.
28    Failed {
29        /// Human-readable failure reason when available.
30        message: Option<String>,
31    },
32}
33
34/// Normalized harvest payload after a successful cloud run.
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36pub struct CloudResult {
37    /// Pull-request URL when the adapter opened one.
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub pr_url: Option<String>,
40    /// Branch containing the agent's work.
41    pub branch: String,
42    /// Short summary of changes (commit message, agent reply, or diff stat).
43    pub diff_summary: String,
44}
45
46/// Outbound port for harness-agnostic cloud agent dispatch.
47///
48/// Lifecycle: [`submit_task`](CloudDispatchPort::submit_task) enqueues work and
49/// returns a handle; [`poll_status`](CloudDispatchPort::poll_status) observes
50/// progress; [`harvest`](CloudDispatchPort::harvest) collects the PR outcome
51/// once status is [`CloudTaskStatus::Succeeded`].
52#[async_trait]
53pub trait CloudDispatchPort: Send + Sync {
54    /// Submit a remote task against `repo` on base ref `branch` with `prompt`.
55    async fn submit_task(&self, repo: &str, branch: &str, prompt: &str) -> Result<CloudTaskHandle>;
56
57    /// Poll the current status for `handle`.
58    async fn poll_status(&self, handle: &CloudTaskHandle) -> Result<CloudTaskStatus>;
59
60    /// Harvest the normalized result for a succeeded task.
61    async fn harvest(&self, handle: &CloudTaskHandle) -> Result<CloudResult>;
62}