XTOOLS / app.py
1990two's picture
Upload 3 files
8f766ee verified
Raw History Blame Contribute Delete
1.6 kB
import importlib
from fastapi import FastAPI, HTTPException
from registry import TOOLS, BY_NAME
app = FastAPI(title="XTOOLS", description="90two tool server")
_registry_cache = {}
def _load(tool_name: str):
if tool_name not in _registry_cache:
mod = importlib.import_module(f"tools.{tool_name}")
_registry_cache[tool_name] = mod.run
return _registry_cache[tool_name]
def _validate(tool_name: str, params: dict) -> dict:
spec = BY_NAME[tool_name]
cleaned = {}
for p in spec["params"]:
name = p["name"]
if name in params:
cleaned[name] = params[name]
elif p["required"]:
raise HTTPException(status_code=422, detail=f"Missing required param: {name}")
else:
cleaned[name] = p["default"]
return cleaned
@app.get("/")
def health():
return {"status": "ok", "tool_count": len(TOOLS)}
@app.get("/registry")
def get_registry():
"""Full tool manifest -- name, category, auth type, and param schema for every tool."""
return {"tools": TOOLS}
@app.post("/tools/{tool_name}")
def call_tool(tool_name: str, params: dict = None):
if tool_name not in BY_NAME:
raise HTTPException(status_code=404, detail=f"Unknown tool: {tool_name}")
params = params or {}
cleaned = _validate(tool_name, params)
run_fn = _load(tool_name)
try:
return run_fn(cleaned)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"{type(e).__name__}: {e}")