Spaces:
Paused
Paused
| """ | |
| Tool definitions (HF/OpenAI schema) and dispatcher for the VL agent. | |
| Three tools: | |
| - search_web: search the internet and return snippets | |
| - final_output: signal the agent loop to stop and return an answer | |
| - abort: signal the agent loop to stop and report a failure/reason | |
| """ | |
| import json | |
| import logging | |
| import os | |
| import urllib.error | |
| import urllib.parse | |
| import urllib.request | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| _BRAVE_WEB_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search" | |
| logger = logging.getLogger(__name__) | |
| if not logger.handlers: | |
| _handler = logging.StreamHandler() | |
| _handler.setFormatter(logging.Formatter("%(levelname)s %(name)s: %(message)s")) | |
| logger.addHandler(_handler) | |
| logger.setLevel(logging.INFO) | |
| logger.propagate = False | |
| # --------------------------------------------------------------------------- | |
| # Tool schemas (passed to InferenceClient.chat_completion(tools=...)) | |
| # --------------------------------------------------------------------------- | |
| AGENT_TOOLS = [ | |
| { | |
| "type": "function", | |
| "function": { | |
| "name": "search_web", | |
| "description": ( | |
| "Search the internet for up-to-date information. " | |
| "Use this when you need current facts, news, or data that you are " | |
| "not confident about from your training knowledge." | |
| ), | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "query": { | |
| "type": "string", | |
| "description": "The search query to look up on the web.", | |
| } | |
| }, | |
| "required": ["query"], | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": { | |
| "name": "final_output", | |
| "description": ( | |
| "Deliver the final answer to the user. " | |
| "Call this once you have gathered enough information and are ready " | |
| "to give a complete, accurate response. The 'answer' field will be " | |
| "shown directly to the user." | |
| ), | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "answer": { | |
| "type": "string", | |
| "description": "The complete final answer to present to the user.", | |
| } | |
| }, | |
| "required": ["answer"], | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": { | |
| "name": "abort", | |
| "description": ( | |
| "Abort the current task when it cannot be completed. " | |
| "Use this if the task is impossible, unsafe, or the user asked to stop." | |
| ), | |
| "parameters": { | |
| "type": "object", | |
| "properties": { | |
| "reason": { | |
| "type": "string", | |
| "description": "Explanation of why the task is being aborted.", | |
| } | |
| }, | |
| "required": [], | |
| }, | |
| }, | |
| }, | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # Tool implementations | |
| # --------------------------------------------------------------------------- | |
| def _brave_api_key() -> str | None: | |
| return os.environ.get("BRAVE_SEARCH_API_KEY") or os.environ.get("BRAVE_API_KEY") | |
| def _search_web(query: str, max_results: int = 5) -> str: | |
| """Run a Brave Web Search and return formatted snippets.""" | |
| count = max(1, min(max_results, 20)) | |
| logger.info("search_web input: query=%r max_results=%d", query, count) | |
| def _finish(out: str) -> str: | |
| logger.info("search_web output:\n%s", out) | |
| return out | |
| token = _brave_api_key() | |
| if not token: | |
| return _finish( | |
| "Search unavailable: set BRAVE_SEARCH_API_KEY or BRAVE_API_KEY " | |
| "in a .env file or the process environment." | |
| ) | |
| params = urllib.parse.urlencode({"q": query, "count": str(count)}) | |
| url = f"{_BRAVE_WEB_SEARCH_URL}?{params}" | |
| req = urllib.request.Request( | |
| url, | |
| headers={ | |
| "X-Subscription-Token": token, | |
| "Accept": "application/json", | |
| }, | |
| method="GET", | |
| ) | |
| try: | |
| with urllib.request.urlopen(req, timeout=30) as resp: | |
| payload = json.loads(resp.read().decode()) | |
| except urllib.error.HTTPError as exc: | |
| detail = exc.read().decode(errors="replace")[:800] | |
| return _finish(f"Brave Search API error ({exc.code}): {detail}") | |
| except urllib.error.URLError as exc: | |
| return _finish(f"Search request failed: {exc.reason or exc}") | |
| except json.JSONDecodeError as exc: | |
| return _finish(f"Search returned invalid JSON: {exc}") | |
| results = (payload.get("web") or {}).get("results") or [] | |
| if not results: | |
| return _finish("No results found for the given query.") | |
| blocks = [] | |
| for item in results[:count]: | |
| title = item.get("title") or "" | |
| body = item.get("description") or "" | |
| href = item.get("url") or "" | |
| blocks.append(f"**{title}**\n{body}\nSource: {href}") | |
| return _finish("\n\n---\n\n".join(blocks)) | |
| def _final_output(answer: str) -> str: | |
| """No-op implementation; the orchestrator reads 'answer' directly.""" | |
| return "Answer delivered." | |
| def _abort(reason: str = "") -> str: | |
| """No-op implementation; the orchestrator reads 'reason' directly.""" | |
| return f"Aborted: {reason}" if reason else "Task aborted." | |
| # --------------------------------------------------------------------------- | |
| # Dispatcher | |
| # --------------------------------------------------------------------------- | |
| def dispatch_tool(tool_name: str, arguments: dict | str) -> str: | |
| """ | |
| Call the named tool with the given arguments and return the result string. | |
| `arguments` may arrive as a JSON string (from the model) or already as a dict. | |
| """ | |
| if isinstance(arguments, str): | |
| try: | |
| arguments = json.loads(arguments) | |
| except json.JSONDecodeError: | |
| arguments = {} | |
| if tool_name == "search_web": | |
| query = arguments.get("query", "") | |
| if not query: | |
| msg = "Error: 'query' parameter is required for search_web." | |
| logger.info("search_web input: query=%r (missing)", query) | |
| logger.info("search_web output:\n%s", msg) | |
| return msg | |
| return _search_web(query) | |
| if tool_name == "final_output": | |
| answer = arguments.get("answer", "") | |
| return _final_output(answer) | |
| if tool_name == "abort": | |
| reason = arguments.get("reason", "") | |
| return _abort(reason) | |
| return f"Error: unknown tool '{tool_name}'." | |