fn format_files_section_xml(files: &[String]) -> String {
if files.is_empty() {
"No specific files identified - you may modify any files needed to fix the issues."
.to_string()
} else {
format!("Files identified in issues:\n{}\n\nNOTE: If the issue references a file that is not listed here, you may still modify it.",
files.iter()
.map(|f| format!("- {f}"))
.collect::<Vec<_>>()
.join("\n"))
}
}
pub fn prompt_fix_xml_with_log(
context: &TemplateContext,
prompt_content: &str,
plan_content: &str,
issues_content: &str,
files_to_modify: &[String],
workspace: &dyn Workspace,
template_name: &str,
) -> RenderedTemplate {
let partials = get_shared_partials();
let template_content = context
.registry()
.get_template("fix_mode_xml")
.unwrap_or_else(|_| include_str!("../templates/fix_mode_xml.txt").to_string());
let variables = HashMap::from([
("PROMPT", prompt_content.to_string()),
("PLAN", plan_content.to_string()),
("ISSUES", issues_content.to_string()),
("FILES_TO_MODIFY", format_files_section_xml(files_to_modify)),
(
"FIX_RESULT_XML_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xml"),
),
(
"FIX_RESULT_XSD_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xsd"),
),
]);
match Template::new(&template_content).render_with_log(template_name, &variables, &partials) {
Ok(rendered) => rendered,
Err(err) => {
let unsubstituted = match &err {
crate::prompts::template_engine::TemplateError::MissingVariable(name) => {
vec![name.clone()]
}
_ => vec![],
};
let prompt_content = format!(
"FIX MODE\n\nFix the issues:\n\n{issues_content}\n\n\
Based on requirements:\n{prompt_content}\n\nPlan:\n{plan_content}\n\n\
Output format: <ralph-fix-result><ralph-summary>Summary</ralph-summary><ralph-fixes-applied>Changes made</ralph-fixes-applied></ralph-fix-result>\n"
);
RenderedTemplate {
content: prompt_content,
log: SubstitutionLog {
template_name: template_name.to_string(),
substituted: vec![
SubstitutionEntry {
name: "PROMPT".to_string(),
source: SubstitutionSource::Value,
},
SubstitutionEntry {
name: "PLAN".to_string(),
source: SubstitutionSource::Value,
},
SubstitutionEntry {
name: "ISSUES".to_string(),
source: SubstitutionSource::Value,
},
],
unsubstituted,
},
}
}
}
}
pub fn prompt_fix_xsd_retry_with_log(
context: &TemplateContext,
xsd_error: &str,
last_output: &str,
workspace: &dyn Workspace,
template_name: &str,
) -> RenderedTemplate {
write_fix_xsd_retry_files(workspace, last_output);
let schema_path = Path::new(".agent/tmp/fix_result.xsd");
let last_output_path = Path::new(".agent/tmp/last_output.xml");
let schema_exists = workspace.exists(schema_path);
let last_output_exists = workspace.exists(last_output_path);
let diagnostic_prefix = if !schema_exists || !last_output_exists {
let parts: Vec<String> =
std::iter::once("⚠️ WARNING: Required XSD retry files are missing:\n".to_string())
.chain(
if !schema_exists {
Some(format!(
" - Schema file: {} (workspace.root() = {})\n",
workspace.absolute_str(".agent/tmp/fix_result.xsd"),
workspace.root().display()
))
} else {
None
},
)
.chain(if !last_output_exists {
Some(format!(
" - Last output: {} (workspace.root() = {})\n",
workspace.absolute_str(".agent/tmp/last_output.xml"),
workspace.root().display()
))
} else {
None
})
.chain(std::iter::once(
"This likely indicates CWD != workspace.root() path mismatch.\n\n".to_string(),
))
.collect();
parts.concat()
} else {
String::new()
};
let build_manual_log = |template_name: &str, xsd_error: &str| {
if xsd_error.is_empty() {
SubstitutionLog {
template_name: template_name.to_string(),
substituted: Vec::new(),
unsubstituted: vec!["XSD_ERROR".to_string()],
}
} else {
SubstitutionLog {
template_name: template_name.to_string(),
substituted: vec![SubstitutionEntry {
name: "XSD_ERROR".to_string(),
source: SubstitutionSource::Value,
}],
unsubstituted: Vec::new(),
}
}
};
if !schema_exists && !last_output_exists {
let prompt_content = format!(
"{diagnostic_prefix}\
XSD VALIDATION FAILED - FIX XML ONLY\n\n\
**THIS IS A SUBMISSION-FIX-ONLY RETRY**\n\n\
Error: {xsd_error}\n\n\
The schema and previous output files could not be found.\n\n\
PRIMARY OBJECTIVE: Fix malformed XML structure - fix root parse errors FIRST.\n\n\
DO NOT DO:\n - Do NOT write any new code\n - Do NOT modify any source files\n - Do NOT run any commands\n - Do NOT do ANY fix/development work\n - Do NOT change the content/meaning of your response\n\n\
This is a PURE XML SYNTAX FIX. Your fix work is done. \
The only problem is that your XML output doesn't conform to the schema. \
Fix the XML structure, nothing else.\n\n\
Output format: <ralph-fix-result><ralph-status>all_issues_addressed|issues_remain|no_issues_found</ralph-status><ralph-summary>Summary</ralph-summary></ralph-fix-result>\n"
);
return RenderedTemplate {
content: prompt_content,
log: build_manual_log(template_name, xsd_error),
};
}
let partials = get_shared_partials();
let template_content = context
.registry()
.get_template("fix_mode_xsd_retry")
.unwrap_or_else(|_| include_str!("../templates/fix_mode_xsd_retry.txt").to_string());
let variables = HashMap::from([
("XSD_ERROR", xsd_error.to_string()),
(
"FIX_RESULT_XML_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xml"),
),
(
"FIX_RESULT_XSD_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xsd"),
),
(
"LAST_OUTPUT_XML_PATH",
workspace.absolute_str(".agent/tmp/last_output.xml"),
),
]);
let template = Template::new(&template_content);
template
.render_with_log(template_name, &variables, &partials)
.map(|mut rendered| {
if !diagnostic_prefix.is_empty() {
rendered.content = format!("{}\n{}", diagnostic_prefix, rendered.content);
}
rendered
})
.unwrap_or_else(|_| {
let prompt_content = format!(
"XSD VALIDATION FAILED - FIX XML ONLY\n\n\
**THIS IS A SUBMISSION-FIX-ONLY RETRY**\n\n\
Error: {xsd_error}\n\n\
REFERENCE ONLY: Read .agent/tmp/fix_result.xsd and .agent/tmp/last_output.xml.\n\
Do NOT redo fix/development work.\n\n\
PRIMARY OBJECTIVE: Fix malformed XML structure - fix root parse errors FIRST.\n\n\
DO NOT DO:\n\
- Do NOT write any new code\n\
- Do NOT modify any source files\n\
- Do NOT run any commands\n\
- Do NOT do ANY fix/development work\n\
- Do NOT change the content/meaning of your response\n\n\
This is a PURE XML SYNTAX FIX. Fix the XML structure to conform to the schema.\n\n\
Output format: <ralph-fix-result><ralph-status>all_issues_addressed|issues_remain|no_issues_found</ralph-status><ralph-summary>Summary</ralph-summary></ralph-fix-result>\n"
);
RenderedTemplate {
content: prompt_content,
log: build_manual_log(template_name, xsd_error),
}
})
}
pub fn prompt_fix_xml_with_context(
context: &TemplateContext,
prompt_content: &str,
plan_content: &str,
issues_content: &str,
files_to_modify: &[String],
workspace: &dyn Workspace,
) -> String {
let partials = get_shared_partials();
let template_content = context
.registry()
.get_template("fix_mode_xml")
.unwrap_or_else(|_| include_str!("../templates/fix_mode_xml.txt").to_string());
let variables = HashMap::from([
("PROMPT", prompt_content.to_string()),
("PLAN", plan_content.to_string()),
("ISSUES", issues_content.to_string()),
("FILES_TO_MODIFY", format_files_section_xml(files_to_modify)),
(
"FIX_RESULT_XML_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xml"),
),
(
"FIX_RESULT_XSD_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xsd"),
),
]);
Template::new(&template_content)
.render_with_partials(&variables, &partials)
.unwrap_or_else(|_| {
format!(
"FIX MODE\n\nFix the issues:\n\n{issues_content}\n\n\
Based on requirements:\n{prompt_content}\n\nPlan:\n{plan_content}\n\n\
Output format: <ralph-fix-result><ralph-summary>Summary</ralph-summary><ralph-fixes-applied>Changes made</ralph-fixes-applied></ralph-fix-result>\n"
)
})
}
pub fn prompt_fix_xsd_retry_with_context(
context: &TemplateContext,
_issues_content: &str,
xsd_error: &str,
last_output: &str,
workspace: &dyn Workspace,
) -> String {
write_fix_xsd_retry_files(workspace, last_output);
prompt_fix_xsd_retry_with_context_files(context, xsd_error, workspace)
}
pub fn prompt_fix_xsd_retry_with_context_files(
context: &TemplateContext,
xsd_error: &str,
workspace: &dyn Workspace,
) -> String {
let partials = get_shared_partials();
write_fix_xsd_retry_schema_files(workspace);
let schema_path = Path::new(".agent/tmp/fix_result.xsd");
let last_output_path = Path::new(".agent/tmp/last_output.xml");
let schema_exists = workspace.exists(schema_path);
let last_output_exists = workspace.exists(last_output_path);
let diagnostic_prefix = if !schema_exists || !last_output_exists {
let parts: Vec<String> =
std::iter::once("⚠️ WARNING: Required XSD retry files are missing:\n".to_string())
.chain(
if !schema_exists {
Some(format!(
" - Schema file: {} (workspace.root() = {})\n",
workspace.absolute_str(".agent/tmp/fix_result.xsd"),
workspace.root().display()
))
} else {
None
},
)
.chain(if !last_output_exists {
Some(format!(
" - Last output: {} (workspace.root() = {})\n",
workspace.absolute_str(".agent/tmp/last_output.xml"),
workspace.root().display()
))
} else {
None
})
.chain(std::iter::once(
"This likely indicates CWD != workspace.root() path mismatch.\n\n".to_string(),
))
.collect();
parts.concat()
} else {
String::new()
};
if !schema_exists && !last_output_exists {
return format!(
"{diagnostic_prefix}\
XSD VALIDATION FAILED - FIX XML ONLY\n\n\
**THIS IS A SUBMISSION-FIX-ONLY RETRY**\n\n\
Error: {xsd_error}\n\n\
The schema and previous output files could not be found.\n\n\
PRIMARY OBJECTIVE: Fix malformed XML structure - fix root parse errors FIRST.\n\n\
DO NOT DO:\n - Do NOT write any new code\n - Do NOT modify any source files\n - Do NOT run any commands\n - Do NOT do ANY fix/development work\n - Do NOT change the content/meaning of your response\n\n\
This is a PURE XML SYNTAX FIX. Your fix work is done. \
The only problem is that your XML output doesn't conform to the schema. \
Fix the XML structure, nothing else.\n\n\
Output format: <ralph-fix-result><ralph-status>all_issues_addressed|issues_remain|no_issues_found</ralph-status><ralph-summary>Summary</ralph-summary></ralph-fix-result>\n"
);
}
let template_content = context
.registry()
.get_template("fix_mode_xsd_retry")
.unwrap_or_else(|_| include_str!("../templates/fix_mode_xsd_retry.txt").to_string());
let variables = HashMap::from([
("XSD_ERROR", xsd_error.to_string()),
(
"FIX_RESULT_XML_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xml"),
),
(
"FIX_RESULT_XSD_PATH",
workspace.absolute_str(".agent/tmp/fix_result.xsd"),
),
(
"LAST_OUTPUT_XML_PATH",
workspace.absolute_str(".agent/tmp/last_output.xml"),
),
]);
let rendered_prompt = Template::new(&template_content)
.render_with_partials(&variables, &partials)
.unwrap_or_else(|_| {
format!(
"XSD VALIDATION FAILED - FIX XML ONLY\n\n\
**THIS IS A SUBMISSION-FIX-ONLY RETRY**\n\n\
Error: {xsd_error}\n\n\
REFERENCE ONLY: Read .agent/tmp/fix_result.xsd and .agent/tmp/last_output.xml.\n\
Do NOT redo fix/development work.\n\n\
PRIMARY OBJECTIVE: Fix malformed XML structure - fix root parse errors FIRST.\n\n\
DO NOT DO:\n\
- Do NOT write any new code\n\
- Do NOT modify any source files\n\
- Do NOT run any commands\n\
- Do NOT do ANY fix/development work\n\
- Do NOT change the content/meaning of your response\n\n\
This is a PURE XML SYNTAX FIX. Fix the XML structure to conform to the schema.\n\n\
Output format: <ralph-fix-result><ralph-status>all_issues_addressed|issues_remain|no_issues_found</ralph-status><ralph-summary>Summary</ralph-summary></ralph-fix-result>\n"
)
});
if diagnostic_prefix.is_empty() {
rendered_prompt
} else {
format!("{diagnostic_prefix}\n{rendered_prompt}")
}
}