use std::fmt::Write as _;
use crate::language::Language;
use crate::solver::BlueprintComposition;
pub use super::blueprint_data::{CAPABILITIES, RECIPES};
#[derive(Clone, Copy)]
pub struct Capability {
pub slug: &'static str,
pub label: &'static str,
pub keywords: &'static [&'static str],
}
#[derive(Clone, Copy)]
pub struct RecipeProgram {
pub language_slug: &'static str,
pub libraries: &'static [&'static str],
pub run_command: &'static str,
pub execution: BlueprintExecution,
pub code: &'static str,
}
#[derive(Clone, Copy)]
pub enum BlueprintExecution {
ExternalLibrariesAndNetwork,
ReviewDataAssumptions,
LocalSourceAnalysis,
}
#[derive(Clone, Copy)]
pub struct BlueprintRecipe {
pub slug: &'static str,
pub label: &'static str,
pub required_capabilities: &'static [&'static str],
pub programs: &'static [RecipeProgram],
}
impl BlueprintRecipe {
fn program_for(&self, language_slug: &str) -> Option<&'static RecipeProgram> {
self.programs
.iter()
.find(|program| program.language_slug == language_slug)
}
}
pub struct Blueprint {
pub recipe: &'static BlueprintRecipe,
pub program: &'static RecipeProgram,
pub capabilities: Vec<&'static Capability>,
}
#[must_use]
pub fn detect_capabilities(normalized: &str) -> Vec<&'static Capability> {
CAPABILITIES
.iter()
.filter(|capability| {
capability
.keywords
.iter()
.any(|keyword| contains_keyword(normalized, keyword))
})
.collect()
}
#[must_use]
pub fn select_blueprint(normalized: &str, language_slug: &str) -> Option<Blueprint> {
let detected = detect_capabilities(normalized);
let detected_slugs: Vec<&str> = detected.iter().map(|capability| capability.slug).collect();
let recipe = RECIPES.iter().find(|recipe| {
recipe
.required_capabilities
.iter()
.all(|required| detected_slugs.contains(required))
&& recipe.program_for(language_slug).is_some()
})?;
let program = recipe.program_for(language_slug)?;
Some(Blueprint {
recipe,
program,
capabilities: detected,
})
}
fn contains_keyword(normalized: &str, keyword: &str) -> bool {
if crate::coding::contains_cjk(keyword) {
return normalized.contains(keyword);
}
if keyword.contains(' ') {
return normalized.contains(keyword);
}
normalized
.split(|character: char| !character.is_alphanumeric())
.any(|token| token == keyword || (keyword.len() >= 4 && token.starts_with(keyword)))
}
fn comment_marker(language_slug: &str) -> &'static str {
match language_slug {
"python" | "ruby" => "#",
_ => "//",
}
}
const REGION_OPEN: &str = "region:";
const REGION_CLOSE: &str = "endregion:";
fn region_directive<'line>(trimmed: &'line str, marker: &str) -> Option<(bool, &'line str)> {
let rest = trimmed.strip_prefix(marker)?.trim_start();
if let Some(slug) = rest.strip_prefix(REGION_CLOSE) {
return Some((false, slug.trim()));
}
let slug = rest.strip_prefix(REGION_OPEN)?;
Some((true, slug.trim()))
}
#[must_use]
pub fn compose_program(blueprint: &Blueprint, strategy: BlueprintComposition) -> String {
let language_slug = blueprint.program.language_slug;
let marker = comment_marker(language_slug);
let compose = strategy == BlueprintComposition::Composed;
let requested = |slug: &str| blueprint.capabilities.iter().any(|c| c.slug == slug);
let mut kept: Vec<&str> = Vec::new();
let mut skipping = false;
for line in blueprint.program.code.lines() {
let trimmed = line.trim_start();
if let Some((is_open, slug)) = region_directive(trimmed, marker) {
skipping = is_open && compose && !requested(slug);
continue;
}
if !skipping {
kept.push(line);
}
}
if compose && !wants_comments(blueprint) {
strip_comment_lines(&kept, language_slug)
} else {
collapse_blank_runs(&kept)
}
}
fn strip_comment_lines(lines: &[&str], language_slug: &str) -> String {
let marker = comment_marker(language_slug);
let mut kept: Vec<&str> = Vec::new();
let mut in_docstring = false;
for &line in lines {
let trimmed = line.trim_start();
if language_slug == "python" {
if in_docstring {
if trimmed.contains("\"\"\"") {
in_docstring = false;
}
continue;
}
if let Some(rest) = trimmed.strip_prefix("\"\"\"") {
if !rest.contains("\"\"\"") {
in_docstring = true;
}
continue;
}
}
if trimmed.starts_with(marker) {
continue;
}
kept.push(line);
}
collapse_blank_runs(&kept)
}
fn collapse_blank_runs(lines: &[&str]) -> String {
let mut out = String::new();
let mut pending_blank = false;
let mut wrote_any = false;
for line in lines {
if line.trim().is_empty() {
if wrote_any {
pending_blank = true;
}
continue;
}
if pending_blank {
out.push('\n');
pending_blank = false;
}
out.push_str(line);
out.push('\n');
wrote_any = true;
}
if out.ends_with('\n') {
out.pop();
}
out
}
#[must_use]
pub fn wants_comments(blueprint: &Blueprint) -> bool {
blueprint
.capabilities
.iter()
.any(|capability| capability.slug == "comments")
}
#[must_use]
pub fn blueprint_intro(language_name: &str, recipe_label: &str, language: Language) -> String {
match language {
Language::Russian => format!(
"Вот программа на языке {language_name}, которая решает составную задачу \
({recipe_label}). Я разбил ваш запрос на следующие подзадачи:"
),
Language::Hindi => format!(
"यहाँ {language_name} में एक प्रोग्राम है जो इस संयुक्त कार्य को हल करता है \
({recipe_label})। मैंने आपके अनुरोध को इन उप-कार्यों में विभाजित किया है:"
),
Language::Chinese => format!(
"这是一个解决该复合任务的 {language_name} 程序({recipe_label})。\
我已将您的请求分解为以下子任务:"
),
_ => format!(
"Here is a {language_name} program for the requested composite task \
({recipe_label}). I decomposed your request into these sub-tasks:"
),
}
}
#[must_use]
pub fn capability_label(capability: &Capability, language: Language) -> &'static str {
match (capability.slug, language) {
("http_request", Language::Russian) => "Выполнить HTTP-запрос",
("http_request", Language::Hindi) => "HTTP अनुरोध करें",
("http_request", Language::Chinese) => "发起 HTTP 请求",
("json_parse", Language::Russian) => "Разобрать JSON-ответ",
("json_parse", Language::Hindi) => "JSON प्रतिक्रिया पार्स करें",
("json_parse", Language::Chinese) => "解析 JSON 响应",
("statistics", Language::Russian) => "Вычислить статистику (среднее, медиана)",
("statistics", Language::Hindi) => "सांख्यिकी (औसत, माध्यिका) की गणना करें",
("statistics", Language::Chinese) => "计算统计量(平均值、中位数)",
("output_results", Language::Russian) => "Вывести результаты",
("output_results", Language::Hindi) => "परिणाम आउटपुट करें",
("output_results", Language::Chinese) => "输出结果",
("error_handling", Language::Russian) => "Обработать ошибки",
("error_handling", Language::Hindi) => "त्रुटियाँ संभालें",
("error_handling", Language::Chinese) => "处理错误",
("comments", Language::Russian) => "Снабдить код комментариями",
("comments", Language::Hindi) => "कोड में टिप्पणियाँ जोड़ें",
("comments", Language::Chinese) => "为代码添加注释",
("web_research", Language::Russian) => "Найти актуальные исходные данные",
("web_research", Language::Hindi) => "वर्तमान स्रोत डेटा खोजें",
("web_research", Language::Chinese) => "检索当前来源数据",
("city_costs", Language::Russian) => "Сравнить стоимость жизни по городам",
("city_costs", Language::Hindi) => "शहरों की जीवन-यापन लागत की तुलना करें",
("city_costs", Language::Chinese) => "比较城市生活成本",
("budget_rule", Language::Russian) => "Применить правило бюджета 50/30/20",
("budget_rule", Language::Hindi) => "50/30/20 बजट नियम लागू करें",
("budget_rule", Language::Chinese) => "应用 50/30/20 预算规则",
("compound_savings", Language::Russian) => "Рассчитать накопления со сложным процентом",
("compound_savings", Language::Hindi) => "चक्रवृद्धि बचत का अनुमान लगाएँ",
("compound_savings", Language::Chinese) => "预测复利储蓄",
("markdown_report", Language::Russian) => "Экспортировать Markdown-отчёт со сравнением",
("markdown_report", Language::Hindi) => "Markdown तुलना रिपोर्ट निर्यात करें",
("markdown_report", Language::Chinese) => "导出 Markdown 比较报告",
_ => capability.label,
}
}
#[must_use]
pub const fn libraries_heading(language: Language) -> &'static str {
match language {
Language::Russian => "Необходимые библиотеки:",
Language::Hindi => "आवश्यक लाइब्रेरियाँ:",
Language::Chinese => "所需的库:",
_ => "Required libraries:",
}
}
#[must_use]
pub fn blueprint_execution_report(
run_command: &str,
execution: BlueprintExecution,
language: Language,
) -> String {
match (execution, language) {
(BlueprintExecution::LocalSourceAnalysis, _) => format!(
"Execution status: not run — this source-metrics blueprint uses only the Rust \
standard library, but the answer renderer did not compile it in place. The \
code is provided for review. Run it yourself from a Cargo project: \
`{run_command}`."
),
(BlueprintExecution::ReviewDataAssumptions, Language::Russian) => format!(
"Статус выполнения: не запускалось — этот отчёт не выполнялся в офлайн-песочнице, \
а встроенные допущения о данных нужно проверить перед использованием. Код приведён \
для проверки. Запустить самостоятельно: `{run_command}`."
),
(BlueprintExecution::ReviewDataAssumptions, Language::Hindi) => format!(
"निष्पादन स्थिति: नहीं चलाया गया — यह रिपोर्ट ऑफ़लाइन सैंडबॉक्स में नहीं चली, \
और embedded data assumptions को उपयोग से पहले जाँचना चाहिए। कोड समीक्षा के लिए \
दिया गया है। स्वयं चलाएँ: `{run_command}`।"
),
(BlueprintExecution::ReviewDataAssumptions, Language::Chinese) => format!(
"执行状态:未运行 —— 该报告未在离线沙箱中执行,内置数据假设应先核对再使用。\
代码仅供审阅。自行运行:`{run_command}`。"
),
(BlueprintExecution::ReviewDataAssumptions, _) => format!(
"Execution status: not run — this report blueprint was not executed in the \
offline sandbox, and the embedded data assumptions should be reviewed \
before use. The code is provided for review. Run it yourself: \
`{run_command}`."
),
(_, Language::Russian) => format!(
"Статус выполнения: не запускалось — программе нужны внешние библиотеки и \
доступ к сети, поэтому офлайн-песочница её не выполняет. Код приведён для \
проверки. Запустить самостоятельно: `{run_command}`."
),
(_, Language::Hindi) => format!(
"निष्पादन स्थिति: नहीं चलाया गया — प्रोग्राम को बाहरी लाइब्रेरियों और नेटवर्क पहुँच \
की आवश्यकता है, इसलिए ऑफ़लाइन सैंडबॉक्स इसे नहीं चलाता। कोड समीक्षा के लिए दिया \
गया है। स्वयं चलाएँ: `{run_command}`।"
),
(_, Language::Chinese) => format!(
"执行状态:未运行 —— 该程序需要外部库和网络访问,因此离线沙箱不会执行它。\
代码仅供审阅。自行运行:`{run_command}`。"
),
_ => format!(
"Execution status: not run — this program needs external libraries and network \
access, so the offline sandbox does not execute it. The code is provided for \
review. Run it yourself: `{run_command}`."
),
}
}
#[must_use]
pub fn recipe_summary(recipe: &BlueprintRecipe, language: Language) -> &'static str {
match (recipe.slug, language) {
("http_json_stats", Language::Russian) => {
"загрузить JSON по HTTP и вывести среднее и медиану его чисел"
}
("http_json_stats", Language::Hindi) => {
"HTTP के माध्यम से JSON प्राप्त करें और उसकी संख्याओं का औसत और माध्यिका दिखाएँ"
}
("http_json_stats", Language::Chinese) => {
"通过 HTTP 获取 JSON 并报告其中数字的平均值和中位数"
}
("personal_budget_report", Language::Russian) => {
"собрать бюджетный калькулятор 50/30/20 с городскими расходами, источниками и Markdown-отчётом"
}
("personal_budget_report", Language::Hindi) => {
"स्रोतों सहित 50/30/20 शहर बजट कैलकुलेटर और Markdown रिपोर्ट बनाएँ"
}
("personal_budget_report", Language::Chinese) => {
"生成带来源的 50/30/20 城市预算计算器和 Markdown 报告"
}
("crypto_portfolio_tracker", Language::Russian) => {
"смоделировать криптопортфель с оповещениями и Markdown-панелью"
}
("crypto_portfolio_tracker", Language::Hindi) => {
"alerts और Markdown dashboard वाला crypto portfolio tracker simulate करें"
}
("crypto_portfolio_tracker", Language::Chinese) => {
"模拟带提醒和 Markdown 仪表盘的加密投资组合追踪器"
}
_ => recipe.label,
}
}
fn recipe_addendum(recipe: &BlueprintRecipe, _language: Language) -> Option<&'static str> {
(recipe.slug == "self_source_metrics_report").then_some(
"Response self-analysis:\n\
- Reasoning text metrics: functions=0, loops=0, conditionals=0, comments=0, \
complexity_score=1.\n\
- Comparison: the generated Rust code is more complex than the reasoning text \
because it contains executable parsing, loops, conditionals, helper functions, \
and JSON rendering logic.",
)
}
#[must_use]
const fn how_to_run_heading(language: Language) -> &'static str {
match language {
Language::Russian => "Как запустить самостоятельно:",
Language::Hindi => "इसे स्वयं कैसे चलाएँ:",
Language::Chinese => "如何自行运行:",
_ => "How to run it yourself:",
}
}
#[must_use]
pub fn render(blueprint: &Blueprint, language: Language, strategy: BlueprintComposition) -> String {
let catalog_language = crate::coding::program_language_by_slug(blueprint.program.language_slug);
let language_name =
catalog_language.map_or(blueprint.program.language_slug, |language| language.name);
let code_fence = catalog_language.map_or(blueprint.program.language_slug, |l| l.code_fence);
let summary = recipe_summary(blueprint.recipe, language);
let mut body = blueprint_intro(language_name, summary, language);
body.push_str("\n\n");
for (index, capability) in blueprint.capabilities.iter().enumerate() {
writeln!(
body,
"{}. {}",
index + 1,
capability_label(capability, language)
)
.expect("string write is infallible");
}
let program_code = compose_program(blueprint, strategy);
write!(
body,
"\n```{code_fence}\n{program_code}\n```\n\n{}\n",
libraries_heading(language)
)
.expect("string write is infallible");
for library in blueprint.program.libraries {
writeln!(body, "- {library}").expect("string write is infallible");
}
write!(
body,
"\n{}\n\n{}",
how_to_run_heading(language),
blueprint_execution_report(
blueprint.program.run_command,
blueprint.program.execution,
language
)
)
.expect("string write is infallible");
if let Some(addendum) = recipe_addendum(blueprint.recipe, language) {
write!(body, "\n\n{addendum}").expect("string write is infallible");
}
body
}