use anyhow::Result;
use boxlite::BoxliteError;
use clap::{Args, Subcommand, ValueEnum};
use serde_json::Value;
use std::path::PathBuf;
#[cfg(test)]
mod tests;
#[derive(Args, Debug)]
pub struct AgentArgs {
#[command(subcommand)]
pub command: AgentCommand,
}
#[derive(Subcommand, Debug)]
pub enum AgentCommand {
Create {
#[command(flatten)]
target: BoxTarget,
#[arg(long, value_name = "IMPLEMENTATION")]
agent: String,
#[command(flatten)]
options: AgentCreateOptions,
},
Close {
#[command(flatten)]
target: AgentTarget,
#[command(flatten)]
options: AgentControlOptions,
},
Send {
#[command(flatten)]
target: AgentTarget,
text: String,
#[command(flatten)]
options: AgentSendOptions,
},
Inspect {
#[command(flatten)]
target: ReadTarget,
#[command(flatten)]
options: AgentInspectOptions,
},
Events {
#[command(flatten)]
target: ReadTarget,
#[command(flatten)]
options: AgentEventsOptions,
},
Respond {
#[command(flatten)]
target: AgentTarget,
#[arg(long, value_name = "REQUEST")]
request: String,
#[arg(value_name = "JSON", value_parser = parse_json)]
response: Value,
#[command(flatten)]
options: AgentControlOptions,
},
Wait {
#[command(flatten)]
target: TurnTarget,
#[command(flatten)]
options: AgentWaitOptions,
},
Steer {
#[command(flatten)]
target: TurnTarget,
text: String,
#[command(flatten)]
options: AgentControlOptions,
},
Interrupt {
#[command(flatten)]
target: TurnTarget,
#[command(flatten)]
options: AgentControlOptions,
},
}
#[derive(Args, Debug)]
pub struct BoxTarget {
#[arg(value_name = "BOX")]
target: String,
}
#[derive(Args, Debug)]
pub struct AgentTarget {
#[command(flatten)]
sandbox: BoxTarget,
#[arg(long = "agent", value_name = "AGENT")]
agent_id: String,
}
#[derive(Args, Debug)]
pub struct TurnTarget {
#[command(flatten)]
agent: AgentTarget,
#[arg(long, value_name = "TURN")]
turn: String,
}
#[derive(Args, Debug)]
pub struct ReadTarget {
#[command(flatten)]
agent: AgentTarget,
#[arg(long, value_name = "TURN")]
turn: Option<String>,
}
#[derive(Args, Debug)]
pub struct AgentCreateOptions {
#[arg(long)]
cwd: Option<PathBuf>,
#[arg(long, value_name = "JSON", value_parser = parse_json)]
agent_config: Option<Value>,
#[command(flatten)]
control: AgentControlOptions,
}
#[derive(Clone, Debug, PartialEq, Eq, ValueEnum)]
pub enum SendMode {
Queue,
Reject,
}
#[derive(Args, Debug)]
pub struct AgentSendOptions {
#[arg(long, value_enum, default_value = "queue")]
mode: SendMode,
#[arg(long, value_name = "JSON", value_parser = parse_json)]
data: Option<Value>,
#[command(flatten)]
control: AgentControlOptions,
}
#[derive(Args, Debug)]
pub struct AgentControlOptions {
#[arg(long)]
idempotency_key: Option<String>,
}
#[derive(Args, Debug)]
pub struct AgentWaitOptions {
#[arg(long, value_name = "SECONDS")]
timeout_seconds: Option<u64>,
}
#[derive(Args, Debug)]
pub struct AgentEventsOptions {
#[arg(long, value_name = "CURSOR")]
after: Option<String>,
}
#[derive(Args, Debug)]
pub struct AgentInspectOptions {
#[arg(long, value_enum, conflicts_with = "turn")]
view: Option<AgentView>,
}
#[derive(Clone, Debug, PartialEq, Eq, ValueEnum)]
pub enum AgentView {
Config,
Capabilities,
Requests,
}
fn parse_json(input: &str) -> serde_json::Result<Value> {
serde_json::from_str(input)
}
pub fn execute(args: AgentArgs) -> Result<()> {
let operation = match args.command {
AgentCommand::Create { .. } => "agents.create",
AgentCommand::Close { .. } => "agent.close",
AgentCommand::Send { .. } => "agent.send",
AgentCommand::Respond { .. } => "agent.respond",
AgentCommand::Inspect { target, options } => match options.view {
Some(AgentView::Config) => "agent.config",
Some(AgentView::Capabilities) => "agent.capabilities",
Some(AgentView::Requests) => "agent.requests",
None if target.turn.is_some() => "turn.state",
None => "agent.state",
},
AgentCommand::Events { target, .. } if target.turn.is_some() => "turn.events",
AgentCommand::Events { .. } => "agent.events",
AgentCommand::Wait { .. } => "turn.wait",
AgentCommand::Steer { .. } => "turn.steer",
AgentCommand::Interrupt { .. } => "turn.interrupt",
};
Err(BoxliteError::Unsupported(format!("{operation} is not implemented")).into())
}