jiq 3.21.0

Interactive JSON query tool with real-time output
Documentation
//! Prompt template generation
//!
//! Builds prose prompts for AI requests based on query context.
//! Generates different prompts for error troubleshooting vs success optimization.

use super::context::QueryContext;

/// Build a prompt based on query context
///
/// Dispatches to either error troubleshooting or success optimization prompt
/// based on the `is_success` field in the context.
pub fn build_prompt(context: &QueryContext) -> String {
    if context.is_success {
        build_success_prompt(context)
    } else {
        build_error_prompt(context)
    }
}

/// Build a prompt for error troubleshooting
///
/// Creates a prose prompt that includes the query, error message,
/// JSON sample, and structure information to help the AI provide
/// relevant assistance.
pub fn build_error_prompt(context: &QueryContext) -> String {
    let mut prompt = String::new();

    prompt.push_str("You are a jq query assistant helping troubleshoot errors.\n");

    prompt.push_str("## Current Query\n");
    prompt.push_str(&format!("```\n{}\n```\n", context.query));
    prompt.push_str(&format!("Cursor position: {}\n\n", context.cursor_pos));

    if let Some(ref error) = context.error {
        prompt.push_str("## Error\n");
        prompt.push_str(&format!("```\n{}\n```\n\n", error));
    }

    if let Some(ref schema) = context.input_schema {
        prompt.push_str("## Input JSON Schema\n");
        prompt.push_str(&format!("```json\n{}\n```\n\n", schema));
    }

    if let Some(ref base_query) = context.base_query {
        prompt.push_str("## Last Working Query\n");
        prompt.push_str(&format!("```\n{}\n```\n\n", base_query));

        if let Some(ref result) = context.base_query_result {
            prompt.push_str("## Last Working Query Output\n");
            prompt.push_str(&format!("```json\n{}\n```\n\n", result));
        }
    }

    prompt.push_str("## Response Format\n");
    prompt.push_str(
        "Return ONLY a raw JSON object (no markdown, no code fences) with this EXACT structure:\n",
    );
    prompt.push_str(r#"{"suggestions": [{"type": "fix", "query": "jq_query", "details": "1 line description"}]}"#);
    prompt.push_str("\n\n");
    prompt.push_str("- type: \"fix\" for error corrections, \"optimize\" for improvements, \"next\" for next steps\n");
    prompt.push_str("- query: valid jq syntax, single line\n");
    prompt.push_str("- details: brief 1-sentence explanation\n");
    prompt.push_str("- Provide 3-5 suggestions\n");
    prompt.push_str("- IMPORTANT: Return raw JSON only, do NOT wrap in ```json code fences\n\n");

    prompt.push_str("## Natural Language in Query\n");
    prompt.push_str("The query may contain natural language. Two patterns:\n\n");
    prompt.push_str("### Pattern A: `<jq_query> <natural_language>`\n");
    prompt.push_str("User has a partial jq query followed by natural language.\n");
    prompt.push_str("The natural language could be:\n");
    prompt.push_str("- Debugging: 'why no results', 'why empty'\n");
    prompt.push_str("- Extending: 'how to filter by age', 'add sorting'\n");
    prompt.push_str("- Understanding: 'what does this do'\n");
    prompt.push_str("- Alternatives: 'is there a better way'\n");
    prompt.push_str("- Next steps: 'now get their names too'\n\n");
    prompt.push_str("You must:\n");
    prompt.push_str("1. IDENTIFY the jq query portion (valid jq syntax before natural language)\n");
    prompt.push_str("2. UNDERSTAND what the user is asking about that query\n");
    prompt.push_str("3. RESPOND appropriately (debug, extend, explain, or suggest alternatives)\n");
    prompt.push_str(
        "CRITICAL: Do NOT suggest 'remove trailing text'. ADDRESS the user's intent!\n\n",
    );
    prompt.push_str("### Pattern B: `<natural_language>` only\n");
    prompt.push_str(
        "Entire query is natural language. Interpret intent and provide [Next] suggestions.\n\n",
    );

    prompt
}

/// Build a prompt for successful query optimization
///
/// Creates a prose prompt that includes the query, output sample,
/// and structure information to help the AI suggest optimizations.
pub fn build_success_prompt(context: &QueryContext) -> String {
    let mut prompt = String::new();

    prompt.push_str("You are a jq query assistant helping optimize queries.\n");

    prompt.push_str("## Current Query\n");
    prompt.push_str(&format!("```\n{}\n```\n", context.query));
    prompt.push_str(&format!("Cursor position: {}\n\n", context.cursor_pos));

    if let Some(ref schema) = context.input_schema {
        prompt.push_str("## Input JSON Schema\n");
        prompt.push_str(&format!("```json\n{}\n```\n\n", schema));
    }

    if let Some(ref output_sample) = context.output_sample {
        prompt.push_str("## Current Query Output\n");
        prompt.push_str(&format!("```json\n{}\n```\n\n", output_sample));
    } else if context.is_empty_result {
        prompt.push_str("## Current Query Output\n");
        prompt
            .push_str("The current query output is empty or consists entirely of null values.\n\n");
    }

    if context.is_empty_result
        && let Some(ref base_query) = context.base_query
    {
        prompt.push_str("## Last Non-Empty Query\n");
        prompt.push_str(&format!("```\n{}\n```\n\n", base_query));

        if let Some(ref result) = context.base_query_result {
            prompt.push_str("## Last Non-Empty Query Output (displayed in results)\n");
            prompt.push_str(&format!("```json\n{}\n```\n\n", result));
        }
    }

    prompt.push_str("## Response Format\n");
    prompt.push_str(
        "Return ONLY a raw JSON object (no markdown, no code fences) with this EXACT structure:\n",
    );
    prompt.push_str(r#"{"suggestions": [{"type": "optimize", "query": "jq_query", "details": "1 line description"}]}"#);
    prompt.push_str("\n\n");
    prompt.push_str(
        "- type: \"optimize\" for improvements, \"next\" for next steps or related queries\n",
    );
    prompt.push_str("- query: valid jq syntax, single line\n");
    prompt.push_str("- details: brief 1-sentence explanation\n");
    prompt.push_str("- Provide 3-5 suggestions\n");
    prompt.push_str(
        "- If the query is already optimal, provide \"next\" suggestions for related operations\n",
    );
    prompt.push_str("- IMPORTANT: Return raw JSON only, do NOT wrap in ```json code fences\n\n");

    prompt.push_str("## Natural Language in Query\n");
    prompt.push_str("The query may contain natural language. Two patterns:\n\n");
    prompt.push_str("### Pattern A: `<jq_query> <natural_language>`\n");
    prompt.push_str("User has a partial jq query followed by natural language.\n");
    prompt.push_str("The natural language could be:\n");
    prompt.push_str("- Debugging: 'why no results', 'why empty'\n");
    prompt.push_str("- Extending: 'how to filter by age', 'add sorting'\n");
    prompt.push_str("- Understanding: 'what does this do'\n");
    prompt.push_str("- Alternatives: 'is there a better way'\n");
    prompt.push_str("- Next steps: 'now get their names too'\n\n");
    prompt.push_str("You must:\n");
    prompt.push_str("1. IDENTIFY the jq query portion (valid jq syntax before natural language)\n");
    prompt.push_str("2. UNDERSTAND what the user is asking about that query\n");
    prompt.push_str("3. RESPOND appropriately (debug, extend, explain, or suggest alternatives)\n");
    prompt.push_str(
        "CRITICAL: Do NOT suggest 'remove trailing text'. ADDRESS the user's intent!\n\n",
    );
    prompt.push_str("### Pattern B: `<natural_language>` only\n");
    prompt.push_str(
        "Entire query is natural language. Interpret intent and provide [Next] suggestions.\n\n",
    );

    prompt
}

#[cfg(test)]
#[path = "prompt_tests.rs"]
mod prompt_tests;