Spaces:
Sleeping
Sleeping
| """ | |
| agents/clarification_agent.py | |
| ------------------------------- | |
| Clarification Agent for AutoDevAgent. | |
| Checks whether a user task is clear enough to generate correct code | |
| and tests. If the task is ambiguous, incomplete, or contradictory it | |
| returns a concise question asking the user to clarify. | |
| Design: | |
| - Uses the fast model (8B) β it's a lightweight classification + Q-gen task. | |
| - Returns {"clear": True} or {"clear": False, "question": "..."} | |
| - Runs in app.py BEFORE the LangGraph pipeline starts, so the | |
| pipeline never wastes tokens on an unclear task. | |
| - Only asks for clarification when genuinely needed β simple, well-formed | |
| tasks ("write a function to reverse a string") always pass through. | |
| Usage: | |
| from agents.clarification_agent import ClarificationAgent | |
| agent = ClarificationAgent() | |
| result = agent.check("Write a Python function") | |
| if not result["clear"]: | |
| print(result["question"]) | |
| """ | |
| import logging | |
| from typing import Any | |
| from langchain_groq import ChatGroq | |
| from langchain_core.messages import SystemMessage, HumanMessage | |
| from config import settings | |
| logger = logging.getLogger(__name__) | |
| CLARIFICATION_SYSTEM = """ | |
| You are a requirements analyst for a code generation assistant that writes | |
| Python and SQL code. Your job is to decide if a user's task description is | |
| clear enough to generate correct, testable code β without guessing. | |
| A task is CLEAR if: | |
| - The programming language or goal is inferable (Python function, SQL query, etc.) | |
| - The inputs and expected outputs can be reasonably inferred | |
| - There is enough detail to write a correct implementation | |
| A task is UNCLEAR if: | |
| - It is too vague to know what to implement (e.g. "make something cool") | |
| - Key information is missing that would change the implementation significantly | |
| (e.g. "sort the data" β what data? what format? ascending or descending?) | |
| - It is contradictory or impossible to implement as stated | |
| - It is a single word or fragment with no actionable meaning | |
| Rules: | |
| - Be LENIENT β most standard programming tasks are clear enough. Do not ask | |
| for clarification on well-known patterns (reverse a string, fibonacci, etc.). | |
| - If UNCLEAR, ask ONE short, specific question (max 20 words) that would give | |
| enough info to proceed. Do not ask multiple questions. | |
| - Never ask for clarification on things the agent can reasonably assume | |
| (e.g. don't ask "should I use a function or a class?" for a simple task). | |
| Respond with ONLY valid JSON β no explanation, no markdown: | |
| {"clear": true} | |
| or | |
| {"clear": false, "question": "Your single clarifying question here."} | |
| """.strip() | |
| class ClarificationAgent: | |
| """ | |
| Checks if a task description is clear enough to generate code. | |
| Returns a dict: | |
| {"clear": True} | |
| {"clear": False, "question": "..."} | |
| """ | |
| def __init__(self) -> None: | |
| self._llm = ChatGroq( | |
| api_key=settings.groq_api_key, | |
| model=settings.groq_model_fast, # 8B β lightweight task | |
| temperature=0.0, | |
| max_tokens=120, | |
| request_timeout=settings.groq_request_timeout, | |
| ) | |
| def check(self, task: str) -> dict[str, Any]: | |
| """ | |
| Check if the task is clear enough to proceed. | |
| Args: | |
| task: The user's raw task description. | |
| Returns: | |
| {"clear": True} β task is actionable, proceed | |
| {"clear": False, "question": str} β needs clarification | |
| """ | |
| if not task or not task.strip(): | |
| return {"clear": False, "question": "Please describe what you'd like me to build."} | |
| try: | |
| response = self._llm.invoke([ | |
| SystemMessage(content=CLARIFICATION_SYSTEM), | |
| HumanMessage(content=f"Task: {task.strip()}"), | |
| ]) | |
| raw = response.content.strip() | |
| # Parse JSON response | |
| import json, re | |
| # Strip markdown fences if model wrapped it | |
| raw = re.sub(r'^```[a-z]*\n?', '', raw).rstrip('`').strip() | |
| result = json.loads(raw) | |
| if result.get("clear") is True: | |
| logger.info("ClarificationAgent: task is clear β proceeding") | |
| return {"clear": True} | |
| else: | |
| question = result.get("question", "Could you provide more details about the expected inputs and outputs?") | |
| logger.info("ClarificationAgent: task needs clarification β %s", question) | |
| return {"clear": False, "question": question} | |
| except Exception as e: | |
| # On any failure, let the pipeline proceed β don't block on a clarification error | |
| logger.warning("ClarificationAgent failed (%s) β proceeding anyway", e) | |
| return {"clear": True} | |