<?xml version="1.0" encoding="UTF-8"?>
<odoo noupdate="1">
    <!--
        Default AI agents + tools seeded on first install.

        These are the *sensible defaults* the user asked for: every platform
        pillar (course planning, weekly materials, exam generation, exercise
        generation, LMS tutor, grading) gets a pre-configured LangGraph
        agent so the system works out of the box. Admins edit the system
        prompts, models, temperatures and tool bindings from
        /admin/ai/prompts → Agents tab.
    -->

    <!-- ============================== TOOLS ============================== -->

    <!-- Retrieval -->
    <record id="ai_tool_resources_search" model="encoach.ai.tool">
        <field name="key">resources.search</field>
        <field name="name">Search resources</field>
        <field name="category">retrieval</field>
        <field name="description">Semantic search over the LMS resource library. Returns resource ids, titles and snippets. Use this BEFORE generating content so the agent reuses existing, approved materials instead of hallucinating.</field>
        <field name="schema_json">{"type":"object","properties":{"query":{"type":"string","description":"Natural language search query"},"skill":{"type":"string","enum":["reading","writing","listening","speaking","grammar","vocabulary"]},"cefr_level":{"type":"string","enum":["pre_a1","a1","a2","b1","b2","c1","c2"]},"limit":{"type":"integer","default":5,"minimum":1,"maximum":20}},"required":["query"]}</field>
        <field name="sequence">10</field>
    </record>

    <record id="ai_tool_rubric_fetch" model="encoach.ai.tool">
        <field name="key">rubric.fetch</field>
        <field name="name">Fetch rubric</field>
        <field name="category">reference</field>
        <field name="description">Return the grading rubric and criterion descriptors for a given rubric id or skill. Always call before grading so the LLM uses the approved rubric, not its own defaults.</field>
        <field name="schema_json">{"type":"object","properties":{"rubric_id":{"type":"integer"},"skill":{"type":"string","enum":["reading","writing","listening","speaking"]}}}</field>
        <field name="sequence">20</field>
    </record>

    <record id="ai_tool_outcomes_fetch" model="encoach.ai.tool">
        <field name="key">outcomes.fetch</field>
        <field name="name">Fetch course outcomes</field>
        <field name="category">reference</field>
        <field name="description">Return the registered learning outcomes for a course or CEFR level. Use it when generating course plans to stay aligned with the programme specification.</field>
        <field name="schema_json">{"type":"object","properties":{"course_id":{"type":"integer"},"cefr_level":{"type":"string","enum":["pre_a1","a1","a2","b1","b2","c1","c2"]}}}</field>
        <field name="sequence">30</field>
    </record>

    <record id="ai_tool_student_profile" model="encoach.ai.tool">
        <field name="key">student.profile</field>
        <field name="name">Get student gap profile</field>
        <field name="category">reference</field>
        <field name="description">Return the student's CEFR band, strengths and gaps so content can be personalised. Required input for personalised exercise generation and tutor follow-ups.</field>
        <field name="schema_json">{"type":"object","properties":{"student_id":{"type":"integer"}},"required":["student_id"]}</field>
        <field name="sequence">40</field>
    </record>

    <!-- Quality gates -->
    <record id="ai_tool_quality_cefr" model="encoach.ai.tool">
        <field name="key">quality.cefr_check</field>
        <field name="name">CEFR readability check</field>
        <field name="category">quality</field>
        <field name="description">Check whether a text reads at the target CEFR level using Flesch-Kincaid. Returns ok=false with specific issues when the passage is too easy or too hard for the requested band.</field>
        <field name="schema_json">{"type":"object","properties":{"text":{"type":"string"},"target_cefr":{"type":"string","enum":["a1","a2","b1","b2","c1","c2"]}},"required":["text","target_cefr"]}</field>
        <field name="sequence">50</field>
    </record>

    <record id="ai_tool_quality_ai" model="encoach.ai.tool">
        <field name="key">quality.ai_detect</field>
        <field name="name">AI-content detection</field>
        <field name="category">quality</field>
        <field name="description">Probability the text was written by an AI (via GPTZero). Used during submission review — not usually during generation.</field>
        <field name="schema_json">{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}</field>
        <field name="sequence">60</field>
    </record>

    <record id="ai_tool_quality_gate" model="encoach.ai.tool">
        <field name="key">quality.content_gate</field>
        <field name="name">Unified content gate</field>
        <field name="category">quality</field>
        <field name="description">Run the project's combined content-source gate (CEFR + toxicity + length checks). Returns ok=false with the first failing rule.</field>
        <field name="schema_json">{"type":"object","properties":{"text":{"type":"string"},"cefr_level":{"type":"string"}},"required":["text"]}</field>
        <field name="sequence">70</field>
    </record>

    <!-- Persistence -->
    <record id="ai_tool_course_plan_save" model="encoach.ai.tool">
        <field name="key">course_plan.save</field>
        <field name="name">Save course plan</field>
        <field name="category">persistence</field>
        <field name="mutates" eval="True"/>
        <field name="description">Persist an AI-generated course plan header and its weekly rows. Only call once you're confident the JSON is valid and has been reviewed.</field>
        <field name="schema_json">{"type":"object","properties":{"plan_vals":{"type":"object"},"weeks":{"type":"array","items":{"type":"object"}}},"required":["plan_vals"]}</field>
        <field name="sequence">80</field>
    </record>

    <record id="ai_tool_course_plan_save_materials" model="encoach.ai.tool">
        <field name="key">course_plan.save_materials</field>
        <field name="name">Save weekly teaching materials</field>
        <field name="category">persistence</field>
        <field name="mutates" eval="True"/>
        <field name="description">Persist the generated per-week teaching materials against an existing course plan and week.</field>
        <field name="schema_json">{"type":"object","properties":{"plan_id":{"type":"integer"},"week_id":{"type":"integer"},"materials":{"type":"array","items":{"type":"object"}}},"required":["plan_id","week_id","materials"]}</field>
        <field name="sequence">90</field>
    </record>

    <!-- Media generation -->
    <record id="ai_tool_media_audio" model="encoach.ai.tool">
        <field name="key">media.synthesize_audio</field>
        <field name="name">Synthesize narration audio</field>
        <field name="category">media</field>
        <field name="mutates" eval="True"/>
        <field name="description">Render an MP3 narration of a material's text using AWS Polly (default) or ElevenLabs. Used for listening_script and speaking_prompt materials. Returns the media id, status and a /web/content URL when ready.</field>
        <field name="schema_json">{"type":"object","properties":{"material_id":{"type":"integer"},"voice":{"type":"string"},"language":{"type":"string","default":"en-GB"},"gender":{"type":"string","enum":["female","male"]},"provider":{"type":"string","enum":["polly","elevenlabs"]}},"required":["material_id"]}</field>
        <field name="sequence">120</field>
    </record>

    <record id="ai_tool_media_image" model="encoach.ai.tool">
        <field name="key">media.generate_image</field>
        <field name="name">Generate illustration (DALL-E)</field>
        <field name="category">media</field>
        <field name="mutates" eval="True"/>
        <field name="description">Generate a single PNG illustration with OpenAI DALL-E 3 for a course-plan material. Used for reading hero images and vocabulary flashcards. Honours the per-plan image budget (encoach_ai_course.image_budget_per_plan).</field>
        <field name="schema_json">{"type":"object","properties":{"material_id":{"type":"integer"},"prompt":{"type":"string"},"size":{"type":"string","enum":["1024x1024","1024x1792","1792x1024"]},"style":{"type":"string","enum":["natural","vivid"]},"quality":{"type":"string","enum":["standard","hd"]}},"required":["material_id"]}</field>
        <field name="sequence">130</field>
    </record>

    <record id="ai_tool_media_video" model="encoach.ai.tool">
        <field name="key">media.compose_video</field>
        <field name="name">Compose slideshow video (ffmpeg)</field>
        <field name="category">media</field>
        <field name="mutates" eval="True"/>
        <field name="description">Combine an existing audio narration with a still image into an MP4 (1280x720) using a local ffmpeg subprocess. Auto-creates audio and/or image first if the material lacks them. Falls back gracefully when ffmpeg is missing on the server.</field>
        <field name="schema_json">{"type":"object","properties":{"material_id":{"type":"integer"}},"required":["material_id"]}</field>
        <field name="sequence">140</field>
    </record>

    <!-- Scoring -->
    <record id="ai_tool_scoring_writing" model="encoach.ai.tool">
        <field name="key">scoring.grade_writing</field>
        <field name="name">Grade writing response</field>
        <field name="category">scoring</field>
        <field name="description">Grade a writing response against a rubric using the platform's standard writing examiner prompt.</field>
        <field name="schema_json">{"type":"object","properties":{"rubric":{"type":"string"},"task":{"type":"string"},"response":{"type":"string"}},"required":["rubric","response"]}</field>
        <field name="sequence">100</field>
    </record>

    <record id="ai_tool_scoring_speaking" model="encoach.ai.tool">
        <field name="key">scoring.grade_speaking</field>
        <field name="name">Grade speaking transcript</field>
        <field name="category">scoring</field>
        <field name="description">Grade a speaking transcript against a rubric using the platform's standard speaking examiner prompt.</field>
        <field name="schema_json">{"type":"object","properties":{"rubric":{"type":"string"},"transcript":{"type":"string"}},"required":["rubric","transcript"]}</field>
        <field name="sequence">110</field>
    </record>

    <!-- ============================== AGENTS ============================== -->

    <!-- 1. Course planner -->
    <record id="ai_agent_course_planner" model="encoach.ai.agent">
        <field name="key">course_planner</field>
        <field name="name">Course Planner</field>
        <field name="description">Generates a full course plan (description, objectives, per-skill outcomes, grammar scope, assessment weights, week-by-week delivery) from a short brief. Used by the Smart Wizard and /api/ai/course-plan.</field>
        <field name="model">gpt-4o</field>
        <field name="fallback_model">gpt-4o-mini</field>
        <field name="temperature">0.4</field>
        <field name="max_tokens">4096</field>
        <field name="response_format">json</field>
        <field name="graph_type">plan_review_revise</field>
        <field name="max_revisions">1</field>
        <field name="quality_checks">quality.cefr_check</field>
        <field name="sequence">10</field>
        <field name="system_prompt">You are an expert English language curriculum designer. You produce structured, institution-grade course outlines suitable for a general foundation English programme.

Rules:
- Output MUST be a single valid JSON object matching the schema the user supplies.
- Use CEFR can-do statements when writing outcomes; cite the CEFR level in objectives.
- Distribute the weeks so grammar and skills build cumulatively, not randomly.
- Keep outcome codes short and stable (RLO1, WLO1, LLO1, SLO1, GLO1, VLO1) and reuse them in weeks[*].items[*].outcome_codes.
- Never wrap the JSON in prose, markdown, or code fences.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_outcomes_fetch'),
            ref('ai_tool_resources_search'),
            ref('ai_tool_quality_cefr'),
            ref('ai_tool_course_plan_save'),
        ])]"/>
    </record>

    <!-- 2. Week materials -->
    <record id="ai_agent_course_week_materials" model="encoach.ai.agent">
        <field name="key">course_week_materials</field>
        <field name="name">Week Teaching Materials</field>
        <field name="description">Given a course plan and a week number, produces classroom-ready materials (reading passage, listening script, speaking prompt, writing prompt, grammar mini-lesson, vocabulary list) aligned to the registered outcomes.</field>
        <field name="model">gpt-4o</field>
        <field name="fallback_model">gpt-4o-mini</field>
        <field name="temperature">0.6</field>
        <field name="max_tokens">6000</field>
        <field name="response_format">json</field>
        <field name="graph_type">plan_review_revise</field>
        <field name="max_revisions">1</field>
        <field name="quality_checks">quality.cefr_check</field>
        <field name="sequence">20</field>
        <field name="system_prompt">You are an expert EFL teacher creating ready-to-use classroom materials.

Rules:
- Every material MUST target only the outcome codes supplied for that week.
- Keep reading passages within the CEFR band's word-count window (A1~80, A2~150, B1~250, B2~400, C1~600, C2~800 words).
- Listening scripts must be natural dialogue/monologue, 3-4 minutes, with 4-6 comprehension questions.
- Speaking prompts include useful-language chunks the learner can recycle.
- Grammar lesson: one clear rule + 3 examples + 5 practice items with answer keys.
- Vocabulary: 8-12 entries with part of speech, CEFR-appropriate definition, and an example sentence in context.
- Output valid JSON only; no prose or markdown around it.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_outcomes_fetch'),
            ref('ai_tool_resources_search'),
            ref('ai_tool_quality_cefr'),
            ref('ai_tool_course_plan_save_materials'),
            ref('ai_tool_media_audio'),
            ref('ai_tool_media_image'),
        ])]"/>
    </record>

    <!-- 3. Exam generator -->
    <record id="ai_agent_exam_generator" model="encoach.ai.agent">
        <field name="key">exam_generator</field>
        <field name="name">Exam Generator</field>
        <field name="description">Generates exam questions (MCQ, short answer, cloze, speaking prompts, writing tasks) matching a structure and blueprint.</field>
        <field name="model">gpt-4o</field>
        <field name="fallback_model">gpt-4o-mini</field>
        <field name="temperature">0.5</field>
        <field name="max_tokens">6000</field>
        <field name="response_format">json</field>
        <field name="graph_type">plan_review_revise</field>
        <field name="max_revisions">1</field>
        <field name="quality_checks">quality.cefr_check</field>
        <field name="sequence">30</field>
        <field name="system_prompt">You are a senior EFL / IELTS examiner generating authentic, validly constructed exam questions.

Rules:
- Follow the exam structure blueprint exactly: same number of sections, same question types, same scoring weights.
- Every MCQ has exactly one correct answer and three plausible distractors; avoid "all of the above".
- Reading/listening stems reference only content present in the accompanying passage/transcript.
- Never produce content outside the requested CEFR band.
- Output is a single JSON object; no explanations around it.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_resources_search'),
            ref('ai_tool_outcomes_fetch'),
            ref('ai_tool_rubric_fetch'),
            ref('ai_tool_quality_cefr'),
        ])]"/>
    </record>

    <!-- 4. Personalised exercise generator -->
    <record id="ai_agent_exercise_generator" model="encoach.ai.agent">
        <field name="key">exercise_generator</field>
        <field name="name">Personalised Exercise Generator</field>
        <field name="description">Produces targeted practice items (gap-fill, reordering, short response) using a learner's gap profile to focus on their weakest outcomes.</field>
        <field name="model">gpt-4o-mini</field>
        <field name="fallback_model">gpt-4o</field>
        <field name="temperature">0.7</field>
        <field name="max_tokens">3000</field>
        <field name="response_format">json</field>
        <field name="graph_type">react</field>
        <field name="max_revisions">0</field>
        <field name="quality_checks"></field>
        <field name="sequence">40</field>
        <field name="system_prompt">You are a remedial English tutor generating short, focused practice items for one learner.

Workflow:
1. Call `student.profile` with the student_id you are given. Read their CEFR band and gap_json.
2. Optionally call `resources.search` to find an anchor text at the right level.
3. Then produce 6-10 practice items that target the biggest gaps. Prefer item types the learner has been scoring low on.
4. Each item has: prompt, correct_answer, distractors (for MCQ), brief rationale, target_outcome_code.
5. Output a JSON object {"items": [...]}.

Never fabricate gap data — if student.profile fails, ask for a student_id in your final message and emit an empty items list.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_student_profile'),
            ref('ai_tool_resources_search'),
            ref('ai_tool_outcomes_fetch'),
            ref('ai_tool_quality_cefr'),
        ])]"/>
    </record>

    <!-- 5. LMS tutor / study assistant -->
    <record id="ai_agent_lms_tutor" model="encoach.ai.agent">
        <field name="key">lms_tutor</field>
        <field name="name">LMS Tutor</field>
        <field name="description">Chat assistant students talk to from inside a lesson. Can look up their profile, search the library, fetch outcomes, and answer questions about their course.</field>
        <field name="model">gpt-4o-mini</field>
        <field name="fallback_model">gpt-4o</field>
        <field name="temperature">0.6</field>
        <field name="max_tokens">1500</field>
        <field name="response_format">text</field>
        <field name="graph_type">react</field>
        <field name="max_revisions">0</field>
        <field name="quality_checks"></field>
        <field name="sequence">50</field>
        <field name="system_prompt">You are a friendly, encouraging English tutor inside the EnCoach LMS. You speak to learners directly.

Principles:
- Adapt vocabulary and sentence length to the learner's CEFR level.
- When the learner asks about their progress, call `student.profile` first.
- When they ask about a topic, prefer searching `resources.search` for approved materials before inventing examples.
- Be concrete: give one example, one practice question, one next step.
- Never invent scores or progress data; if a tool fails, tell the learner you'll flag the issue to their teacher.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_resources_search'),
            ref('ai_tool_student_profile'),
            ref('ai_tool_outcomes_fetch'),
        ])]"/>
    </record>

    <!-- 6. Writing grader -->
    <record id="ai_agent_writing_grader" model="encoach.ai.agent">
        <field name="key">writing_grader</field>
        <field name="name">Writing Grader</field>
        <field name="description">Grades a writing submission against its rubric and produces band scores, feedback, and targeted suggestions.</field>
        <field name="model">gpt-4o</field>
        <field name="fallback_model">gpt-4o-mini</field>
        <field name="temperature">0.2</field>
        <field name="max_tokens">1800</field>
        <field name="response_format">json</field>
        <field name="graph_type">simple</field>
        <field name="max_revisions">0</field>
        <field name="quality_checks"></field>
        <field name="sequence">60</field>
        <field name="system_prompt">You are a calibrated IELTS / EFL writing examiner.

Rules:
- Score every criterion in the rubric exactly once.
- Use only band values the rubric advertises (0-9 for IELTS, 0-100 or A1-C2 for other rubrics — follow what the user sends).
- Feedback must quote one line of evidence from the student's text before each judgement.
- Suggestions must be specific ("replace X with Y") not generic ("improve grammar").
- Output JSON: {"scores": {"criterion_code": number}, "overall_band": number, "feedback": string, "suggestions": [string]}.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_rubric_fetch'),
            ref('ai_tool_scoring_writing'),
        ])]"/>
    </record>

    <!-- 7. Speaking evaluator -->
    <record id="ai_agent_speaking_grader" model="encoach.ai.agent">
        <field name="key">speaking_grader</field>
        <field name="name">Speaking Evaluator</field>
        <field name="description">Grades a speaking transcript against its rubric and produces band scores, feedback on fluency / pronunciation, and next-step drills.</field>
        <field name="model">gpt-4o</field>
        <field name="fallback_model">gpt-4o-mini</field>
        <field name="temperature">0.2</field>
        <field name="max_tokens">1800</field>
        <field name="response_format">json</field>
        <field name="graph_type">simple</field>
        <field name="max_revisions">0</field>
        <field name="quality_checks"></field>
        <field name="sequence">70</field>
        <field name="system_prompt">You are a calibrated IELTS Speaking examiner judging a transcript.

Rules:
- Only score what the transcript supports; pronunciation judgements must be flagged as indirect.
- Quote a line of the transcript before each criterion judgement.
- Suggestions prescribe one concrete drill (e.g. "practice minimal pairs /iː/ vs /ɪ/ for 2 weeks").
- Output JSON: {"scores": {"criterion_code": number}, "overall_band": number, "feedback": string, "suggestions": [string]}.</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_rubric_fetch'),
            ref('ai_tool_scoring_speaking'),
        ])]"/>
    </record>

    <!-- 8. Course media director -->
    <record id="ai_agent_course_media_director" model="encoach.ai.agent">
        <field name="key">course_media_director</field>
        <field name="name">Course Media Director</field>
        <field name="description">Given a generated week of teaching materials, decides which media (audio narration, illustrations, slideshow video) each material needs and orchestrates their generation through the media tools.</field>
        <field name="model">gpt-4o-mini</field>
        <field name="fallback_model">gpt-4o</field>
        <field name="temperature">0.3</field>
        <field name="max_tokens">2000</field>
        <field name="response_format">text</field>
        <field name="graph_type">react</field>
        <field name="max_revisions">0</field>
        <field name="quality_checks"></field>
        <field name="sequence">80</field>
        <field name="system_prompt">You are the multimedia director for an English language course. Given the materials of one week, you decide what media each material needs, then call the matching tools.

Default policy:
- listening_script -> media.synthesize_audio (mandatory) + media.generate_image (optional, scene illustration) + media.compose_video (optional, slideshow)
- speaking_prompt  -> media.synthesize_audio for the model answer (optional)
- reading_text     -> media.generate_image for a hero illustration (optional)
- vocabulary_list  -> media.generate_image for the first 1-3 terms (use vocab term in the prompt)
- writing_prompt / grammar_lesson -> usually no media

Rules:
- Always check if a material already has ready media of a given kind before regenerating; if so, skip.
- Stop after issuing the planned tool calls; never invent material ids.
- When done, emit a short text summary listing what was generated (media_id, status, error if any).</field>
        <field name="tool_ids" eval="[(6, 0, [
            ref('ai_tool_media_audio'),
            ref('ai_tool_media_image'),
            ref('ai_tool_media_video'),
        ])]"/>
    </record>

    <!-- Default per-plan image budget. Adjust in System Parameters. -->
    <record id="ai_default_image_budget" model="ir.config_parameter">
        <field name="key">encoach_ai_course.image_budget_per_plan</field>
        <field name="value">60</field>
    </record>

    <!-- Feature flag: pipelines consult this before routing through AgentRuntime.
         Default "True" so the defaults-ship-working contract holds. -->
    <record id="ai_default_use_langgraph" model="ir.config_parameter">
        <field name="key">encoach_ai.use_langgraph_runtime</field>
        <field name="value">True</field>
    </record>
</odoo>
