Skip to main content

agent_infra_cli/
execution_cli.rs

1//! `infra execution` — durable run and event operations.
2
3use agent_infra_sdk::InfraClient;
4use agent_infra_sdk::execution_contract::{
5    AppendExecutionEventRequest, CreateExecutionRunRequest, GetExecutionEventsRequest,
6    GetExecutionRunRequest, ListExecutionRunsRequest, UpdateExecutionRunRequest,
7};
8use anyhow::Result;
9use clap::{Args, Subcommand, ValueEnum};
10
11use crate::{CommandOutput, JsonInput};
12
13#[derive(Debug, Subcommand)]
14pub enum ExecutionCommand {
15    /// Create a run from a CreateExecutionRunRequest JSON document.
16    Create {
17        #[command(flatten)]
18        input: JsonInput,
19    },
20    /// Update a run from an UpdateExecutionRunRequest JSON document.
21    Update {
22        #[command(flatten)]
23        input: JsonInput,
24    },
25    /// Get one run by ID or idempotency key.
26    Get {
27        #[arg(long, conflicts_with = "idempotency_key")]
28        run_id: Option<String>,
29        #[arg(long, conflicts_with = "run_id")]
30        idempotency_key: Option<String>,
31    },
32    /// List runs by status, session, or limit.
33    List(ExecutionListArgs),
34    /// Cancel a queued or running run.
35    Cancel { run_id: String },
36    /// Append an execution event from an AppendExecutionEventRequest JSON document.
37    Event {
38        run_id: String,
39        #[command(flatten)]
40        input: JsonInput,
41    },
42    /// List execution events for a session.
43    Events {
44        session_id: String,
45        #[arg(long, value_parser = clap::value_parser!(u64).range(1..=1000))]
46        limit: Option<u64>,
47    },
48}
49
50#[derive(Debug, Args)]
51pub struct ExecutionListArgs {
52    #[arg(long, value_enum)]
53    status: Option<CliExecutionStatus>,
54    #[arg(long)]
55    session_id: Option<String>,
56    #[arg(long, value_parser = clap::value_parser!(u64).range(1..=1000))]
57    limit: Option<u64>,
58}
59
60#[derive(Clone, Copy, Debug, ValueEnum)]
61enum CliExecutionStatus {
62    Queued,
63    Running,
64    Completed,
65    Failed,
66    Canceled,
67}
68
69impl From<CliExecutionStatus> for agent_infra_sdk::execution_contract::ExecutionRunStatus {
70    fn from(value: CliExecutionStatus) -> Self {
71        match value {
72            CliExecutionStatus::Queued => Self::Queued,
73            CliExecutionStatus::Running => Self::Running,
74            CliExecutionStatus::Completed => Self::Completed,
75            CliExecutionStatus::Failed => Self::Failed,
76            CliExecutionStatus::Canceled => Self::Canceled,
77        }
78    }
79}
80
81pub(crate) async fn execute(
82    client: &InfraClient,
83    command: ExecutionCommand,
84) -> Result<CommandOutput> {
85    let execution = client.execution();
86    match command {
87        ExecutionCommand::Create { input } => {
88            let request: CreateExecutionRunRequest = input.read()?;
89            CommandOutput::json(execution.create_run(&request).await?)
90        }
91        ExecutionCommand::Update { input } => {
92            let request: UpdateExecutionRunRequest = input.read()?;
93            CommandOutput::json(execution.update_run(&request).await?)
94        }
95        ExecutionCommand::Get {
96            run_id,
97            idempotency_key,
98        } => {
99            let request = GetExecutionRunRequest {
100                run_id,
101                idempotency_key,
102            };
103            CommandOutput::json(execution.get_run(&request).await?)
104        }
105        ExecutionCommand::List(args) => {
106            let request = ListExecutionRunsRequest {
107                status: args.status.map(Into::into),
108                session_id: args.session_id,
109                limit: args.limit.map(|limit| limit as usize),
110            };
111            CommandOutput::json(execution.runs(&request).await?)
112        }
113        ExecutionCommand::Cancel { run_id } => {
114            CommandOutput::json(execution.cancel_run(&run_id).await?)
115        }
116        ExecutionCommand::Event { run_id, input } => {
117            let request: AppendExecutionEventRequest = input.read()?;
118            CommandOutput::json(execution.append_event(&run_id, &request).await?)
119        }
120        ExecutionCommand::Events { session_id, limit } => {
121            let request = GetExecutionEventsRequest {
122                session_id,
123                limit: limit.map(|limit| limit as usize),
124            };
125            CommandOutput::json(execution.events(&request).await?)
126        }
127    }
128}