Spaces:
Sleeping
Sleeping
Download api/agent.py from RoxieRoller/H-script-AI: direct link, hf CLI and curl.
- Browser
- Download file 6.71 kB
-
https://huggingface.co/spaces/RoxieRoller/H-script-AI/resolve/main/api/agent.py
- Command line
-
hf download hf://spaces/RoxieRoller/H-script-AI/api/agent.py
-
curl -L -o agent.py https://huggingface.co/spaces/RoxieRoller/H-script-AI/resolve/main/api/agent.py
6.71 kB
| """ | |
| POST /ai/agent | |
| Agentic multi-turn AI with tool calling. | |
| Agent can: run code, explain, fix, read editor content. | |
| Fixes are SUGGESTED only β user manually accepts. | |
| """ | |
| import os, httpx | |
| from fastapi import APIRouter | |
| from pydantic import BaseModel | |
| from core.gemini_client import ask_gemini, HSCRIPT_SYSTEM_PROMPT | |
| router = APIRouter() | |
| BACKEND_URL = os.getenv("BACKEND_URL", "http://localhost:5000") | |
| # ββ Tool definitions for Gemini ββββββββββββββββββββββββββββ | |
| TOOLS = [ | |
| { | |
| "name": "run_code", | |
| "description": "Execute H-Script code and return the output and any errors", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "code": {"type": "string", "description": "The H-Script code to run"} | |
| }, | |
| "required": ["code"] | |
| } | |
| }, | |
| { | |
| "name": "explain_code", | |
| "description": "Explain what a piece of H-Script code does", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "code": {"type": "string", "description": "The H-Script code to explain"} | |
| }, | |
| "required": ["code"] | |
| } | |
| }, | |
| { | |
| "name": "suggest_fix", | |
| "description": "Suggest a fix for broken H-Script code given an error message", | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "code": {"type": "string", "description": "The broken H-Script code"}, | |
| "error": {"type": "string", "description": "The error message"} | |
| }, | |
| "required": ["code", "error"] | |
| } | |
| }, | |
| ] | |
| # ββ Tool execution βββββββββββββββββββββββββββββββββββββββββ | |
| async def execute_tool(name: str, args: dict) -> dict: | |
| if name == "run_code": | |
| try: | |
| async with httpx.AsyncClient(timeout=10) as client: | |
| r = await client.post(f"{BACKEND_URL}/api/run", json={"code": args["code"]}) | |
| return r.json() | |
| except Exception as e: | |
| return {"output": [], "errors": [str(e)]} | |
| elif name == "explain_code": | |
| explanation = await ask_gemini( | |
| f"Explain this H-Script code in simple Hinglish:\n```\n{args['code']}\n```" | |
| ) | |
| return {"explanation": explanation} | |
| elif name == "suggest_fix": | |
| fix = await ask_gemini( | |
| f"Fix this H-Script code.\nCode:\n```\n{args['code']}\n```\nError: {args['error']}\n" | |
| "Return ONLY the fixed code in a code block, then EXPLANATION: [what you fixed]" | |
| ) | |
| return {"suggestion": fix} | |
| return {"error": f"Unknown tool: {name}"} | |
| # ββ Request / Response models ββββββββββββββββββββββββββββββ | |
| class Message(BaseModel): | |
| role: str # 'user' | 'assistant' | |
| content: str | |
| class AgentRequest(BaseModel): | |
| message: str | |
| code: str | None = None # current editor content | |
| history: list[Message] = [] | |
| class AgentResponse(BaseModel): | |
| reply: str | |
| action: str | None = None # 'fix' | 'explain' | 'run' | None | |
| result: dict | None = None # tool result if any | |
| history: list[Message] # updated conversation history | |
| # ββ Agent endpoint βββββββββββββββββββββββββββββββββββββββββ | |
| async def agent_chat(body: AgentRequest): | |
| # Build conversation context | |
| history_text = "" | |
| for msg in body.history[-10:]: # last 10 messages for context | |
| role = "User" if msg.role == "user" else "Assistant" | |
| history_text += f"{role}: {msg.content}\n" | |
| code_context = "" | |
| if body.code: | |
| code_context = f"\nCurrent editor code:\n```\n{body.code}\n```\n" | |
| # Available tools description | |
| tools_desc = """ | |
| You have access to these tools (call them when needed): | |
| - run_code(code) β execute H-Script and see output | |
| - explain_code(code) β explain code | |
| - suggest_fix(code, error) β suggest a fix (user will manually accept) | |
| To call a tool, write: TOOL_CALL: tool_name(arg1="value1", arg2="value2") | |
| """ | |
| prompt = f"""{HSCRIPT_SYSTEM_PROMPT} | |
| {tools_desc} | |
| {code_context} | |
| Conversation so far: | |
| {history_text} | |
| User: {body.message} | |
| Think step by step. If you need to run code or use a tool, do it. | |
| Then give your final response to the user. | |
| """ | |
| raw_reply = "" | |
| tool_used = None | |
| tool_result = None | |
| action = None | |
| try: | |
| # First pass β ask Gemini | |
| raw_reply = await ask_gemini(prompt) | |
| # Check if Gemini wants to use a tool | |
| if "TOOL_CALL:" in raw_reply: | |
| import re | |
| match = re.search(r'TOOL_CALL:\s*(\w+)\(([^)]*)\)', raw_reply) | |
| if match: | |
| tool_name = match.group(1) | |
| args_str = match.group(2) | |
| # Parse simple key="value" args | |
| args = {} | |
| for m in re.finditer(r'(\w+)\s*=\s*"([^"]*)"', args_str): | |
| args[m.group(1)] = m.group(2) | |
| # Also handle code blocks in args (multiline) | |
| if not args and body.code: | |
| if tool_name in ("run_code", "explain_code"): | |
| args = {"code": body.code} | |
| elif tool_name == "suggest_fix": | |
| args = {"code": body.code, "error": ""} | |
| tool_result = await execute_tool(tool_name, args) | |
| tool_used = tool_name | |
| # Map tool name to action | |
| action = {"run_code": "run", "explain_code": "explain", "suggest_fix": "fix"}.get(tool_name) | |
| # Second pass β Gemini reflects on tool result | |
| reflect_prompt = f"""{HSCRIPT_SYSTEM_PROMPT} | |
| User asked: {body.message} | |
| {code_context} | |
| You used tool '{tool_name}' and got this result: | |
| {tool_result} | |
| Now give a helpful, friendly final response to the user based on this result. | |
| If it's a fix suggestion, present it clearly and say "You can accept or reject this fix." | |
| """ | |
| raw_reply = await ask_gemini(reflect_prompt) | |
| except Exception as e: | |
| raw_reply = f"Oops bhai, kuch toh gadbad ho gayi π ({str(e)})" | |
| # Update history | |
| updated_history = list(body.history) + [ | |
| Message(role="user", content=body.message), | |
| Message(role="assistant", content=raw_reply), | |
| ] | |
| return AgentResponse( | |
| reply=raw_reply, | |
| action=action, | |
| result=tool_result, | |
| history=updated_history, | |
| ) | |