use std::path::PathBuf;
use anyhow::{Context as _, Result, anyhow};
use crate::vision::VisionApiConfig;
use super::QuestionSource;
#[derive(Clone, Debug, clap::Parser)]
pub struct PipelineArgs {
#[arg(long)]
pub image: PathBuf,
#[command(flatten)]
pub questions: QuestionSource,
#[arg(long)]
pub vision_url: String,
#[arg(long, default_value = "qwen3-vl-8b")]
pub vision_model: String,
#[arg(long)]
pub vision_api_key: Option<String>,
#[arg(long)]
pub vision_prompt: Option<String>,
#[arg(long, default_value = "opencode")]
pub acp_binary: PathBuf,
#[arg(long = "acp-arg")]
pub acp_args: Vec<String>,
#[arg(long)]
pub model: Option<String>,
#[arg(long)]
pub effort: Option<String>,
#[arg(long)]
pub system_prompt: Option<String>,
#[arg(long)]
pub json: bool,
#[arg(long, default_value = "screenshot")]
pub name: String,
}
pub fn run_pipeline(args: PipelineArgs) -> Result<()> {
let question = args.questions.resolve().map_err(|e| anyhow!(e))?;
let vision_config = VisionApiConfig {
url: args.vision_url,
model: args.vision_model,
api_key: args.vision_api_key,
};
let vision_prompt = args
.vision_prompt
.unwrap_or_else(|| crate::DEFAULT_VISION_PROMPT.to_string());
let system_prompt = match args.system_prompt.clone() {
Some(prompt) => Some(prompt),
None => args
.questions
.resolve_system_prompt()
.map_err(|e| anyhow!(e))?,
};
let rubric_options = crate::RubricOptions {
model: args.model,
effort: args.effort.map(Into::into),
system_prompt,
};
let acp_args = if args.acp_args.is_empty() {
vec!["acp".to_string()]
} else {
args.acp_args
};
let rubric_config = crate::RubricRunConfig {
codex_acp_binary: args.acp_binary,
acp_args,
extra_env: Vec::new(),
cwd: None,
};
let verdict = crate::evaluate_image_rubric_pipeline(
&args.image,
&question,
&vision_config,
&vision_prompt,
&rubric_options,
&rubric_config,
)
.with_context(|| format!("pipeline for {} failed", args.image.display()))?;
if args.json {
println!("{}", serde_json::to_string(&verdict)?);
return Ok(());
}
crate::assert_verdict(&args.name, verdict)
.map(|()| println!("visual rubric passed"))
.map_err(|error| anyhow::anyhow!(error))
}