ralph_workflow/agents/providers/
validation.rs1use super::detection::strip_model_flag_prefix;
6use super::types::OpenCodeProviderType;
7
8#[must_use]
12pub fn validate_model_flag(model_flag: &str) -> Vec<String> {
13 let mut warnings = Vec::new();
14
15 let model = strip_model_flag_prefix(model_flag);
16 if model.is_empty() {
17 return warnings;
18 }
19
20 if !model.contains('/') {
22 warnings.push(format!(
23 "Model '{model}' has no provider prefix. Expected format: 'provider/model' (e.g., 'opencode/glm-4.7-free')"
24 ));
25 return warnings;
26 }
27
28 let provider_type = OpenCodeProviderType::from_model_flag(model);
29
30 if provider_type == OpenCodeProviderType::OpenCodeZen && model.to_lowercase().contains("zai") {
32 warnings.push(
33 "Model flag uses 'opencode/' prefix but contains 'zai'. \
34 For Z.AI Direct access, use 'zai/' prefix instead."
35 .to_string(),
36 );
37 }
38
39 if provider_type.requires_cloud() {
41 warnings.push(format!(
42 "{} provider requires cloud configuration. {}",
43 provider_type.name(),
44 provider_type.auth_command()
45 ));
46 }
47
48 if provider_type == OpenCodeProviderType::Custom {
50 let prefix = model.split('/').next().unwrap_or("");
51 warnings.push(format!(
52 "Unknown provider prefix '{prefix}'. This may work if OpenCode supports it. \
53 Run 'ralph --list-providers' to see known providers."
54 ));
55 }
56
57 if provider_type.is_local() {
59 warnings.push(format!(
60 "{} is a local provider. {}",
61 provider_type.name(),
62 provider_type.auth_command()
63 ));
64 }
65
66 warnings
67}
68
69#[must_use]
71pub fn auth_failure_advice(model_flag: Option<&str>) -> String {
72 match model_flag {
73 Some(flag) => {
74 let model = strip_model_flag_prefix(flag);
75 let prefix = model.split('/').next().unwrap_or("").to_lowercase();
76 if matches!(prefix.as_str(), "zai" | "zhipuai") {
77 return "Authentication failed for Z.AI provider. Run: opencode auth login -> select 'Z.AI' or 'Z.AI Coding Plan'".to_string();
78 }
79 let provider = OpenCodeProviderType::from_model_flag(flag);
80 format!(
81 "Authentication failed for {} provider. Run: {}",
82 provider.name(),
83 provider.auth_command()
84 )
85 }
86 None => "Check API key or run 'opencode auth login' to authenticate.".to_string(),
87 }
88}