Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 73 additions & 22 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clap::{Parser, Subcommand};
use crate::client::CovalClient;
use crate::commands;
use crate::config::Config;
use crate::output::OutputFormat;
use crate::output::{OutputContext, OutputFormat};

#[derive(Parser)]
#[command(name = "coval")]
Expand All @@ -21,6 +21,9 @@ pub struct Cli {

#[arg(long, global = true, env = "COVAL_API_URL")]
pub api_url: Option<String>,

#[arg(long, global = true)]
pub agent: bool,
}

#[derive(Subcommand)]
Expand Down Expand Up @@ -100,18 +103,68 @@ pub enum Commands {
},
}

pub async fn run(cli: Cli) -> anyhow::Result<()> {
impl Commands {
pub fn resource(&self) -> &'static str {
match self {
Self::Login(_) | Self::Whoami => "auth",
Self::Config { .. } => "config",
Self::Agents { .. } => "agents",
Self::Conversations { .. } => "conversations",
Self::Runs { .. } => "runs",
Self::Simulations { .. } => "simulations",
Self::TestSets { .. } => "test-sets",
Self::TestCases { .. } => "test-cases",
Self::Personas { .. } => "personas",
Self::Metrics { .. } => "metrics",
Self::Mutations { .. } => "mutations",
Self::ApiKeys { .. } => "api-keys",
Self::RunTemplates { .. } => "run-templates",
Self::ScheduledRuns { .. } => "scheduled-runs",
Self::Dashboards { command } => match command {
commands::dashboards::DashboardCommands::Widgets { .. } => "widgets",
_ => "dashboards",
},
Self::ReviewAnnotations { .. } => "review-annotations",
Self::ReviewProjects { .. } => "review-projects",
}
}

pub fn operation(&self) -> &'static str {
match self {
Self::Login(_) => "login",
Self::Whoami => "whoami",
Self::Config { command } => command.operation(),
Self::Agents { command } => command.operation(),
Self::Conversations { command } => command.operation(),
Self::Runs { command } => command.operation(),
Self::Simulations { command } => command.operation(),
Self::TestSets { command } => command.operation(),
Self::TestCases { command } => command.operation(),
Self::Personas { command } => command.operation(),
Self::Metrics { command } => command.operation(),
Self::Mutations { command } => command.operation(),
Self::ApiKeys { command } => command.operation(),
Self::RunTemplates { command } => command.operation(),
Self::ScheduledRuns { command } => command.operation(),
Self::Dashboards { command } => command.operation(),
Self::ReviewAnnotations { command } => command.operation(),
Self::ReviewProjects { command } => command.operation(),
}
}
}

pub async fn run(cli: Cli, ctx: &OutputContext) -> anyhow::Result<()> {
let config = Config::load().unwrap_or_default();
let api_key = cli.api_key.or(config.api_key);
let api_url = cli.api_url.or(config.api_url);

match cli.command {
Commands::Login(args) => commands::auth::login(args).await,
Commands::Login(args) => commands::auth::login(args, ctx).await,
Commands::Whoami => {
commands::auth::whoami(api_key.as_ref());
commands::auth::whoami(api_key.as_ref(), ctx);
Ok(())
}
Commands::Config { command } => commands::config::execute(command),
Commands::Config { command } => commands::config::execute(command, ctx),
_ => {
let api_key = api_key.ok_or_else(|| {
anyhow::anyhow!(
Expand All @@ -122,49 +175,47 @@ pub async fn run(cli: Cli) -> anyhow::Result<()> {

match cli.command {
Commands::Agents { command } => {
commands::agents::execute(command, &client, cli.format).await
commands::agents::execute(command, &client, ctx).await
}
Commands::Conversations { command } => {
commands::conversations::execute(command, &client, cli.format).await
}
Commands::Runs { command } => {
commands::runs::execute(command, &client, cli.format).await
commands::conversations::execute(command, &client, ctx).await
}
Commands::Runs { command } => commands::runs::execute(command, &client, ctx).await,
Commands::Simulations { command } => {
commands::simulations::execute(command, &client, cli.format).await
commands::simulations::execute(command, &client, ctx).await
}
Commands::TestSets { command } => {
commands::test_sets::execute(command, &client, cli.format).await
commands::test_sets::execute(command, &client, ctx).await
}
Commands::TestCases { command } => {
commands::test_cases::execute(command, &client, cli.format).await
commands::test_cases::execute(command, &client, ctx).await
}
Commands::Personas { command } => {
commands::personas::execute(command, &client, cli.format).await
commands::personas::execute(command, &client, ctx).await
}
Commands::Metrics { command } => {
commands::metrics::execute(command, &client, cli.format).await
commands::metrics::execute(command, &client, ctx).await
}
Commands::Mutations { command } => {
commands::mutations::execute(command, &client, cli.format).await
commands::mutations::execute(command, &client, ctx).await
}
Commands::ApiKeys { command } => {
commands::api_keys::execute(command, &client, cli.format).await
commands::api_keys::execute(command, &client, ctx).await
}
Commands::RunTemplates { command } => {
commands::run_templates::execute(command, &client, cli.format).await
commands::run_templates::execute(command, &client, ctx).await
}
Commands::ScheduledRuns { command } => {
commands::scheduled_runs::execute(command, &client, cli.format).await
commands::scheduled_runs::execute(command, &client, ctx).await
}
Commands::Dashboards { command } => {
commands::dashboards::execute(command, &client, cli.format).await
commands::dashboards::execute(command, &client, ctx).await
}
Commands::ReviewAnnotations { command } => {
commands::review_annotations::execute(command, &client, cli.format).await
commands::review_annotations::execute(command, &client, ctx).await
}
Commands::ReviewProjects { command } => {
commands::review_projects::execute(command, &client, cli.format).await
commands::review_projects::execute(command, &client, ctx).await
}
_ => unreachable!(),
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/models/conversation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub struct GetConversationResponse {
pub conversation: Conversation,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub struct ConversationAudioUrlResponse {
pub audio_url: String,
pub conversation_id: String,
Expand Down
2 changes: 1 addition & 1 deletion src/client/models/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub struct GetSimulationResponse {
pub simulation: Simulation,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub struct AudioUrlResponse {
pub audio_url: String,
pub simulation_id: String,
Expand Down
27 changes: 20 additions & 7 deletions src/commands/agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clap::{Args, Subcommand};

use crate::client::models::{AgentType, CreateAgentRequest, ListParams, UpdateAgentRequest};
use crate::client::CovalClient;
use crate::output::{print_list, print_one, print_success, OutputFormat};
use crate::output::{emit_list, emit_one, emit_success, OutputContext};

#[derive(Subcommand)]
pub enum AgentCommands {
Expand All @@ -14,6 +14,18 @@ pub enum AgentCommands {
Delete(DeleteArgs),
}

impl AgentCommands {
pub fn operation(&self) -> &'static str {
match self {
Self::List(_) => "list",
Self::Get(_) => "get",
Self::Create(_) => "create",
Self::Update(_) => "update",
Self::Delete(_) => "delete",
}
}
}

#[derive(Args)]
pub struct ListArgs {
#[arg(long)]
Expand Down Expand Up @@ -87,7 +99,8 @@ pub struct DeleteArgs {
agent_id: String,
}

pub async fn execute(cmd: AgentCommands, client: &CovalClient, format: OutputFormat) -> Result<()> {
pub async fn execute(cmd: AgentCommands, client: &CovalClient, ctx: &OutputContext) -> Result<()> {
let operation = cmd.operation();
match cmd {
AgentCommands::List(args) => {
let params = ListParams {
Expand All @@ -97,11 +110,11 @@ pub async fn execute(cmd: AgentCommands, client: &CovalClient, format: OutputFor
..Default::default()
};
let response = client.agents().list(params).await?;
print_list(&response.agents, format);
emit_list(ctx, "agents", operation, &response.agents);
}
AgentCommands::Get(args) => {
let agent = client.agents().get(&args.agent_id).await?;
print_one(&agent, format);
emit_one(ctx, "agents", operation, &agent);
}
AgentCommands::Create(args) => {
let metadata = args
Expand All @@ -121,7 +134,7 @@ pub async fn execute(cmd: AgentCommands, client: &CovalClient, format: OutputFor
test_set_ids: args.test_set_ids,
};
let agent = client.agents().create(req).await?;
print_one(&agent, format);
emit_one(ctx, "agents", operation, &agent);
}
AgentCommands::Update(args) => {
let metadata = args
Expand All @@ -141,11 +154,11 @@ pub async fn execute(cmd: AgentCommands, client: &CovalClient, format: OutputFor
test_set_ids: args.test_set_ids,
};
let agent = client.agents().update(&args.agent_id, req).await?;
print_one(&agent, format);
emit_one(ctx, "agents", operation, &agent);
}
AgentCommands::Delete(args) => {
client.agents().delete(&args.agent_id).await?;
print_success("Agent deleted.");
emit_success(ctx, "agents", operation, "Agent deleted.");
}
}
Ok(())
Expand Down
49 changes: 37 additions & 12 deletions src/commands/api_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::client::models::{
UpdateApiKeyRequest,
};
use crate::client::CovalClient;
use crate::output::{print_list, print_one, print_success, OutputFormat};
use crate::output::{
emit_list, emit_one, emit_one_with_warnings, emit_success, AgentWarning, OutputContext,
};

#[derive(Subcommand)]
pub enum ApiKeyCommands {
Expand All @@ -16,6 +18,17 @@ pub enum ApiKeyCommands {
Delete(DeleteArgs),
}

impl ApiKeyCommands {
pub fn operation(&self) -> &'static str {
match self {
Self::List(_) => "list",
Self::Create(_) => "create",
Self::Update(_) => "update",
Self::Delete(_) => "delete",
}
}
}

#[derive(Args)]
pub struct ListArgs {
#[arg(long)]
Expand Down Expand Up @@ -58,11 +71,8 @@ pub struct DeleteArgs {
api_key_id: String,
}

pub async fn execute(
cmd: ApiKeyCommands,
client: &CovalClient,
format: OutputFormat,
) -> Result<()> {
pub async fn execute(cmd: ApiKeyCommands, client: &CovalClient, ctx: &OutputContext) -> Result<()> {
let operation = cmd.operation();
match cmd {
ApiKeyCommands::List(args) => {
let params = ListParams {
Expand All @@ -75,7 +85,7 @@ pub async fn execute(
.api_keys()
.list(params, args.status, args.environment)
.await?;
print_list(&response.api_keys, format);
emit_list(ctx, "api-keys", operation, &response.api_keys);
}
ApiKeyCommands::Create(args) => {
let req = CreateApiKeyRequest {
Expand All @@ -87,22 +97,37 @@ pub async fn execute(
};
let api_key = client.api_keys().create(req).await?;
if !api_key.key.is_empty() && !api_key.key.contains("***") {
eprintln!("WARNING: Store this key now. It will not be shown again.");
eprintln!("Key: {}", api_key.key);
if ctx.agent {
emit_one_with_warnings(
ctx,
"api-keys",
operation,
&api_key,
vec![AgentWarning::new(
"store_api_key",
"Store this key now. It will not be shown again.",
)],
);
} else {
eprintln!("WARNING: Store this key now. It will not be shown again.");
eprintln!("Key: {}", api_key.key);
emit_one(ctx, "api-keys", operation, &api_key);
}
} else {
emit_one(ctx, "api-keys", operation, &api_key);
}
print_one(&api_key, format);
}
ApiKeyCommands::Update(args) => {
let req = UpdateApiKeyRequest {
status: args.status,
reason: args.reason,
};
let api_key = client.api_keys().update(&args.api_key_id, req).await?;
print_one(&api_key, format);
emit_one(ctx, "api-keys", operation, &api_key);
}
ApiKeyCommands::Delete(args) => {
client.api_keys().delete(&args.api_key_id).await?;
print_success("API key deleted.");
emit_success(ctx, "api-keys", operation, "API key deleted.");
}
}
Ok(())
Expand Down
Loading
Loading