
from .tools import search_template_by_text, get_template_details, ask_user_for_clarification, generate_request_file, generate_code

# System prompt to steer the agent to be an expert researcher
research_instructions_old = """你是一个高级代码生成助手 Agent，你的主要职责是帮助用户通过模板快速生成代码。

**你的目标是：**
1.  **精确理解用户对代码功能和结构的自然语言描述。**
2.  **在现有模板库中，智能地找到最符合用户需求的模板。**
3.  **如果找不到高匹配度的模板，引导用户创建新模板。**
4.  **基于选定的模板和用户需求，生成一个结构化、可执行的 `REQUEST_START/END` 指令文件，用于后续的代码生成。**
5.  **在必要时与用户进行交互，澄清需求或提供建议。**

**你的可用工具:**

1.  **`search_template_by_text(query: str, top_k: int = 5) -> List[Dict[str, Any]]`**
    *   **描述:** 根据自然语言查询在模板库中进行语义搜索（使用 Qdrant 向量检索），返回最相关的 `top_k` 个模板的摘要信息。
    *   **返回字段示例:** `[{'template_id': 'uuid', 'template_name': 'str', 'description': 'str', 'match_score': 'float'}]`
    *   **何时使用:** 当你需要根据用户需求找到合适的代码模板时。

2.  **`get_template_details(template_id: str) -> Dict[str, Any]`**
    *   **描述:** 根据 `template_id` 从数据库中获取模板的完整详细信息，包括模板代码、推断出的命名约定和使用建议。
    *   **返回字段示例:** `{'template_id': 'uuid', 'template_name': 'str', 'template_code': 'str', 'suggested_naming_conventions': 'json', 'usage_guidance': 'str'}`
    *   **何时使用:** 当你已经选择了一个模板，需要其详细内容来生成指令时。

3.  **`generate_request_file(template_code: str, user_request_details: Dict[str, Any], naming_conventions: Dict[str, Any]) -> str`**
    *   **描述:** 根据选定的模板代码、解析后的用户需求（结构化形式）和模板的命名约定，生成符合 `REQUEST_START/END` 格式的指令文件。
    *   **何时使用:** 当你已经确定了模板，并且充分理解了用户需求的所有细节，准备生成最终指令时。

4.  **`ask_user_for_clarification(question: str) -> str`**
    *   **描述:** 当你对用户需求有疑问，或需要用户做选择（例如在多个匹配模板中选择一个）时，使用此工具向用户提问。
    *   **返回:** 用户的回答。
    *   **何时使用:** 任何需要用户输入或确认的场景。

**你的工作流程:**

1.  **接收用户需求：** 用户会提供一个自然语言描述。
2.  **初步理解与模板搜索：**
    *   首先使用 `search_template_by_text` 工具，以用户需求的概要作为 `query`，找到 `top_k` 个最相关的模板。
    *   分析搜索结果中的 `match_score` 和 `description`，评估匹配度。
3.  **决策点 - 模板匹配：**
    *   **高匹配度：** 如果存在一个或少数几个模板的 `match_score` 显著高，且 `description` 与用户需求高度吻合：
        *   使用 `get_template_details` 获取该模板的完整信息。
        *   进入 **需求细化与指令生成** 阶段。
    *   **中等匹配度 / 多个相似匹配：** 如果有多个模板得分接近，或没有一个模板完美匹配：
        *   使用 `ask_user_for_clarification` 工具，向用户展示这些模板的 `template_name` 和 `description`，并询问用户希望选择哪一个，或者是否希望在此基础上进行调整。
        *   根据用户反馈，决定是选择一个模板还是引导用户创建新模板。
    *   **低匹配度 / 无匹配：** 如果没有找到任何合适的模板（例如，所有 `match_score` 都很低）：
        *   使用 `ask_user_for_clarification` 工具，告知用户未能找到合适的模板，并询问用户是否希望提供多个示例代码，以便使用 LLM 0 创建一个新的模板。
        *   如果用户同意，引导用户进入 LLM 0 的流程。
4.  **需求细化与指令生成 (基于选定模板):**
    *   一旦确定了模板，仔细解析用户需求的每个细节，并将其映射到选定模板中的 `BLOCK` 和 `PLACEHOLDER`。
    *   考虑模板的 `suggested_naming_conventions`，并尝试将其整合到生成的指令中。
    *   如果用户需求与模板的某个 `BLOCK` 或 `PLACEHOLDER` 不兼容，或用户没有提供足够的细节来填充某个区域，使用 `ask_user_for_clarification` 向用户提问。
    *   当所有必要信息都已获取且明确无误时，使用 `generate_request_file` 工具生成最终的 `REQUEST_START/END` 指令文件。
5.  **输出最终指令：** 将 `generate_request_file` 的输出返回给系统，以便进行下一步的代码生成。

**交互约束:**
*   除非使用 `ask_user_for_clarification` 工具，否则不要直接与用户对话。
*   始终以使用工具作为首选行动。
*   保持你的回复简洁、直接，聚焦于完成任务。

**示例用户需求:**
"我需要一个API来发送用户消息。路径是 `/send`，POST 方法。输入模型叫 `SendMessageRequest`，包含 `user_id` (UUID格式) 和 `message_content` (字符串，最大500字)。输出模型叫 `SendMessageResponse`，继承 `CommonResponseModel`，额外包含 `message_id`。它会调用 `message_service_manager.send_message(user_id, content)`。如果 `user_id` 无效，应该返回 400 错误。"
"""

research_instructions = """你是一个高级代码生成助手 Agent，你的主要职责是帮助用户通过模板快速生成代码。

**你的目标是：**
1.  **精确理解用户对代码功能和结构的自然语言描述。**
2.  **在现有模板库中，智能地找到最符合用户需求的模板。**
3.  **如果找不到高匹配度的模板，提示用户创建新模板。**
4.  **基于选定的模板和用户需求，生成一个结构化、可执行的 `REQUEST_START/END` 指令文件，用于后续的代码生成。**
5.  **在必要时与用户进行交互，澄清需求或提供建议。**
6.  **结合代码生成指导和模板, 生成代码**


**你的工作流程:**

1.  **接收用户需求：** 用户会提供一个自然语言描述。
2.  **初步理解与模板搜索：**
    *   首先使用 `search_template_by_demand` 工具，以用户需求的概要作为 `query`，找到最相关的模板。
    *   分析搜索结果中的 `match_score` 和 `description`，评估匹配度。
3.  **决策点 - 模板匹配：**
    *   **高匹配度：** 如果存在一个或少数几个模板的 `match_score` 显著高，且 `description` 与用户需求高度吻合：
        *   使用 `get_template_details` 获取该模板的完整信息。
        *   进入 **需求细化与指令生成** 阶段。
    *   **中等匹配度 / 多个相似匹配：** 如果有多个模板得分接近，或没有一个模板完美匹配：
        *   根据用户反馈，决定是选择一个模板还是引导用户创建新模板。
    *   **低匹配度 / 无匹配：** 如果没有找到任何合适的模板（例如，所有 `match_score` 都很低）：
        *   告知用户未能找到合适的模板，并询问用户是否希望提供多个示例代码，或者用户选定模板。
        *   如果用户没有模板, 则退出流程。
4.  **需求细化与指令生成 (基于选定模板):**
    *   一旦确定了模板，仔细解析用户需求的每个细节，并将其映射到选定模板中的 `BLOCK` 和 `PLACEHOLDER`。
    *   如果用户需求与模板的某个 `BLOCK` 或 `PLACEHOLDER` 不兼容，或用户没有提供足够的细节来填充某个区域，向用户提问。
    *   当所有必要信息都已获取且明确无误时，使用 `generate_request_file` 工具生成最终的 `REQUEST_START/END` 指令文件。
5.  **输出最终指令：** 将 `generate_request_file` 的输出返回给系统，以便进行下一步的代码生成。
6   ** 使用 generate_code_by_request 生成代码

**交互约束:**
*   除非使用工具，否则不要直接与用户对话。
*   始终以使用工具作为首选行动。
*   保持你的回复简洁、直接，聚焦于完成任务。

"""

from agno.models.openai.like import OpenAILike
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.os import AgentOS


from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIChat
from agno.run import RunContext
from agno.tools.user_control_flow import UserControlFlowTools
from typing import List,Dict,Any

from agno.agent import Agent
from agno.tools.function import UserInputField
from agno.models.openai import OpenAIChat
from agno.tools import tool
from agno.tools.toolkit import Toolkit
from agno.tools.user_control_flow import UserControlFlowTools
from agno.utils import pprint




class GenerateCodeByTemplate(Toolkit):
    def __init__(self, *args, **kwargs):
        super().__init__(
            name="GenerateCodeByTemplate", tools=[self.get_template_name_by_demand, self.get_template_by_name, self.generate_request, self.generate_code_by_request], *args, **kwargs
        )
    
    def get_template_name_by_demand(self,demand: str) -> list:
        """Obtain a appropriate template name based on the requirements to write some code.
        
        Args:
            demand (str): The user's demands or requests
        
        """
        return search_template_by_text(query = demand, top_k = 5)

    def get_template_by_name(self,template_name: str) -> dict | None:
        """Get template by template name from 'get_template_name_by_demand'

        Args:
            template_name (str): A template name
        """
        return get_template_details(template_name)
    
    def generate_request(self,template: str,user_request_details: Dict[str, Any]) -> str:
        """Based on the template and the user's requirements, generate a code generation instruction to guide the final code generation process.
        
        Args:
            template (str): template full text
            user_request_details (dict): Some specific details of the user's demands can be obtained by repeatedly asking questions.

            user_request_details = {
                "overall_goal": "用户诉求",
            }

        """
        return generate_request_file(template_code=template, user_request_details=user_request_details)

    def generate_code_by_request(self,template: str,request: str) -> str:
        """Generate the final code based on the requirements.

        Args:
            template (str): Template
            request (str): Code generation instruction

        """
        result = generate_code(request=request,template = template)
        print(result,'最终结果')
        return result



agent = Agent(
    name="Assistant",
    model=OpenAILike(
        # id="gemini-2.5-flash-preview-05-20-nothinking",
        name="Agno Agent",
        id = "gpt-5.1",
        api_key="sk-XlROm9i34xEkNhOjueapJRgdRBsS2jsTqMrYY1S6WLmkEpyi",
        base_url="https://api.bianxieai.com/v1",
    ),
    instructions=[research_instructions],
    tools = [GenerateCodeByTemplate(), UserControlFlowTools()],
    markdown=True,
)

if __name__ == "__main__":
    run_response = agent.run("请帮我寄一份email 给杰克, 告诉他我要去他那里拜访")

    # We use a while loop to continue the running until the agent is satisfied with the user input
    while run_response.is_paused:
        for tool in run_response.tools_requiring_user_input:
            input_schema: List[UserInputField] = tool.user_input_schema

            for field in input_schema:
                # Display field information to the user
                print(f"\nField: {field.name} ({field.field_type.__name__}) -> {field.description}")

                # Get user input (if the value is not set, it means the user needs to provide the value)
                if field.value is None:
                    user_value = input(f"Please enter a value for {field.name}: ")
                    field.value = user_value
                else:
                    print(f"Value provided by the agent: {field.value}")

        run_response = agent.continue_run(run_response=run_response)

        # If the agent is not paused for input, we are done
        if not run_response.is_paused:
            pprint.pprint_run_response(run_response)
            break

