ERP-DocIQ / backend /app /tools /__init__.py
kenmandal's picture
Deploy ERP-DocIQ: agentic OCR + IDP (MiniCPM-V 8B, Tesseract)
32b00ed verified
Raw
History Blame Contribute Delete
3.05 kB
"""Agent tool registry.
A deliberately small, trimmed tool set shared by the browser agent. Each tool has
a name, a JSON-schema parameter spec, and a handler bound at runtime. The schema
definitions are part of the cached prompt prefix, so keeping the set minimal is
itself a token optimization (the reference docs note unused tool defs cost tokens
on every call).
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Callable
@dataclass
class Tool:
name: str
description: str
parameters: dict # JSON-schema
handler: Callable[..., Any] | None = None
# Canonical browser tool definitions (the "contract" the agent reasons over).
BROWSER_TOOLS: list[Tool] = [
Tool(
name="navigate",
description="Go to a URL.",
parameters={"type": "object", "properties": {"url": {"type": "string"}},
"required": ["url"]},
),
Tool(
name="click",
description="Click an element by CSS selector or accessibility label.",
parameters={"type": "object", "properties": {"selector": {"type": "string"}},
"required": ["selector"]},
),
Tool(
name="fill",
description="Type text into a form field identified by selector.",
parameters={"type": "object", "properties": {
"selector": {"type": "string"}, "text": {"type": "string"}},
"required": ["selector", "text"]},
),
Tool(
name="extract",
description="Extract the structured data visible on the page as JSON.",
parameters={"type": "object", "properties": {}},
),
Tool(
name="screenshot",
description="Capture the current page for the audit trail.",
parameters={"type": "object", "properties": {}},
),
Tool(
name="done",
description="Finish the task; args.result is the final JSON payload.",
parameters={"type": "object", "properties": {"result": {}},
"required": ["result"]},
),
]
class ToolRegistry:
def __init__(self, tools: list[Tool]) -> None:
self._tools = {t.name: t for t in tools}
def names(self) -> list[str]:
return list(self._tools)
def get(self, name: str) -> Tool | None:
return self._tools.get(name)
def bind(self, name: str, handler: Callable[..., Any]) -> None:
if name in self._tools:
self._tools[name].handler = handler
def definitions(self) -> list[dict]:
return [
{"name": t.name, "description": t.description, "parameters": t.parameters}
for t in self._tools.values()
]
def call(self, name: str, args: dict) -> Any:
tool = self._tools.get(name)
if tool is None or tool.handler is None:
raise ValueError(f"unknown or unbound tool: {name}")
return tool.handler(**(args or {}))
def browser_registry() -> ToolRegistry:
return ToolRegistry([Tool(t.name, t.description, t.parameters) for t in BROWSER_TOOLS])