use std::path::Path;
use anyhow::Result;
use serde_json::{Value, json};
use crate::component_qa_ops::{self, QaMode};
use crate::demo::runner_host::OperatorContext;
use crate::domains::{Domain, ProviderPack};
use crate::qa_setup_wizard;
use crate::setup_to_formspec;
pub fn is_qa_process_node(component_id: &str) -> bool {
component_id == "component-qa"
|| component_id == "ai.greentic.component-qa"
|| component_id.ends_with("/component-qa")
|| component_id.contains("qa.process")
}
pub fn handle_qa_process_node(
root: &Path,
node_config: &Value,
provider_pack: &ProviderPack,
provider_id: &str,
domain: Domain,
ctx: &OperatorContext,
interactive: bool,
) -> Result<Value> {
let mode_str = node_config
.get("mode")
.and_then(Value::as_str)
.unwrap_or("setup");
let mode = match mode_str {
"remove" => QaMode::Remove,
"upgrade" => QaMode::Upgrade,
"default" => QaMode::Default,
_ => QaMode::Setup,
};
let supplied_answers = node_config.get("answers").cloned();
let form_spec = setup_to_formspec::pack_to_form_spec(&provider_pack.path, provider_id);
let answers = if let Some(answers) = supplied_answers {
if let Some(ref spec) = form_spec {
qa_setup_wizard::validate_answers_against_form_spec(spec, &answers)?;
}
answers
} else if interactive {
let (answers, _spec) = qa_setup_wizard::run_qa_setup(
&provider_pack.path,
provider_id,
None,
true,
form_spec.clone(),
)?;
answers
} else {
json!({})
};
let providers_root = root
.join("state")
.join("runtime")
.join(&ctx.tenant)
.join("providers");
let current_config = crate::provider_config_envelope::read_provider_config_envelope(
&providers_root,
provider_id,
)?
.map(|envelope| envelope.config);
match component_qa_ops::apply_answers_via_component_qa(
root,
domain,
&ctx.tenant,
ctx.team.as_deref(),
provider_pack,
provider_id,
mode,
current_config.as_ref(),
&answers,
) {
Ok(Some(config)) => Ok(json!({
"status": "ok",
"config": config,
"mode": mode_str,
"provider": provider_id,
})),
Ok(None) => Ok(json!({
"status": "skip",
"reason": "provider does not support QA contract",
"provider": provider_id,
})),
Err(diag) => Ok(json!({
"status": "error",
"code": diag.code.as_str(),
"message": diag.message,
"provider": provider_id,
})),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detects_qa_process_node() {
assert!(is_qa_process_node("component-qa"));
assert!(is_qa_process_node("ai.greentic.component-qa"));
assert!(is_qa_process_node("root:component/component-qa"));
assert!(is_qa_process_node("qa.process.setup"));
assert!(!is_qa_process_node("component-llm-openai"));
assert!(!is_qa_process_node("messaging-telegram"));
}
}