use super::*;
pub(super) fn resolve_output_schema_for_task(
task: &SubagentTask,
config: &SubagentRunConfig,
) -> Option<Value> {
let identity = task.identity.as_deref()?;
let schema_ref = config
.profiles
.get(identity)
.and_then(|profile| profile.output_schema.as_ref())
.cloned()
.or_else(|| {
output_schema::default_phase_for_identity(identity)
.map(SubagentOutputSchemaRef::Builtin)
})?;
output_schema::schema_for_ref(&schema_ref)
}
pub(super) fn validate_schema_bound_output(
schema: &Value,
output_text: &str,
) -> Result<Value, Vec<SchemaValidationError>> {
let trimmed = output_text.trim();
let instance = serde_json::from_str::<Value>(trimmed).map_err(|error| {
vec![SchemaValidationError {
instance_path: String::new(),
schema_path: String::new(),
message: format!("output must be one JSON object: {error}"),
}]
})?;
if !instance.is_object() {
return Err(vec![SchemaValidationError {
instance_path: String::new(),
schema_path: String::new(),
message: "output must be one JSON object".to_string(),
}]);
}
output_schema::validate_instance(schema, &instance)?;
Ok(instance)
}
pub(super) fn schema_validation_feedback_prompt(
attempt: u64,
max_retries: u64,
errors: &[SchemaValidationError],
) -> String {
json!({
"schema_validation_error": true,
"attempt": attempt,
"max_retries": max_retries,
"errors": redact_schema_validation_errors(errors),
"instruction": "Return only a JSON object matching the required output_schema. Do not include markdown or prose."
})
.to_string()
}
pub(super) fn schema_validation_exhausted_error(errors: &[SchemaValidationError]) -> String {
json!({
"schema_validation_error": true,
"exhausted": true,
"errors": redact_schema_validation_errors(errors),
"instruction": "Subagent did not return JSON matching the required output_schema before retry exhaustion."
})
.to_string()
}
fn redact_schema_validation_errors(errors: &[SchemaValidationError]) -> Vec<SchemaValidationError> {
errors
.iter()
.map(|error| SchemaValidationError {
instance_path: redact_sensitive_text(&error.instance_path),
schema_path: redact_sensitive_text(&error.schema_path),
message: redact_sensitive_text(&error.message),
})
.collect()
}