| """Tool / command catalog API endpoints. |
| |
| Exposes the agent's user-invocable slash-command catalog so the Golang backend |
| can cache it and the frontend can render its "/" command menu WITHOUT calling the |
| AI agent for every list (Golang GETs + caches `list_tools`). |
| |
| Scope confirmed: the catalog is the UNIFIED set of |
| everything the user can invoke via `/` — |
| spanning what the team internally splits into skills + analytics tools + |
| data-access tools. Naming : verb-first, kebab-case, `/` prefix. |
| |
| Each command maps 1:1 to a real internal tool/intent `name` (the dispatch key); |
| the granular data-access tools (check_data, check_knowledge, retrieve_data, |
| retrieve_knowledge) are listed separately. |
| NOTE: the merged `check` intent still exists for natural-language routing — it is |
| NOT a slash command; slash invocation bypasses the router to the tool directly. |
| Deferred analytics tools (comparison/contribution/profile/segment) are NOT |
| exposed (not wired to the Planner). |
| |
| Stateless and deterministic — safe for the Golang backend to cache. |
| """ |
|
|
| from typing import Literal |
|
|
| from fastapi import APIRouter |
| from pydantic import BaseModel |
|
|
| from src.middlewares.logging import get_logger, log_execution |
|
|
| logger = get_logger("tools_api") |
|
|
| router = APIRouter(prefix="/api/v1", tags=["Tools"]) |
|
|
| CommandType = Literal["skill", "analytics", "data_access"] |
|
|
|
|
| class CommandResponse(BaseModel): |
| command: str |
| name: str |
| type: CommandType |
| description: str |
|
|
|
|
| class ListToolsResponse(BaseModel): |
| count: int |
| tools: list[CommandResponse] |
|
|
|
|
| |
| |
| |
| _COMMAND_CATALOG: list[CommandResponse] = [ |
| CommandResponse( |
| command="/help", |
| name="help", |
| type="skill", |
| description="Show what the assistant can do and guide your next step.", |
| ), |
| CommandResponse( |
| command="/problem-statement", |
| name="problem_statement", |
| type="skill", |
| description="Define and validate your analysis goal (objective + metric) " |
| "before exploring data.", |
| ), |
| CommandResponse( |
| command="/analyze-descriptive", |
| name="analyze_descriptive", |
| type="analytics", |
| description="Summary statistics for selected columns (count, mean, min, max, …).", |
| ), |
| CommandResponse( |
| command="/analyze-aggregate", |
| name="analyze_aggregate", |
| type="analytics", |
| description="Group and aggregate values (sum, count, average) by dimension.", |
| ), |
| CommandResponse( |
| command="/analyze-correlation", |
| name="analyze_correlation", |
| type="analytics", |
| description="Correlation strength between numeric columns.", |
| ), |
| CommandResponse( |
| command="/analyze-trend", |
| name="analyze_trend", |
| type="analytics", |
| description="Trend of a value over time at a chosen frequency.", |
| ), |
| CommandResponse( |
| command="/check-data", |
| name="check_data", |
| type="data_access", |
| description="Inventory of the available structured data sources.", |
| ), |
| CommandResponse( |
| command="/check-knowledge", |
| name="check_knowledge", |
| type="data_access", |
| description="Inventory of the available knowledge / uploaded documents.", |
| ), |
| CommandResponse( |
| command="/retrieve-data", |
| name="retrieve_data", |
| type="data_access", |
| description="Pull rows from a structured source for analysis.", |
| ), |
| CommandResponse( |
| command="/retrieve-knowledge", |
| name="retrieve_knowledge", |
| type="data_access", |
| description="Retrieve relevant passages from your uploaded documents.", |
| ), |
| ] |
|
|
|
|
| @router.get("/tools", response_model=ListToolsResponse) |
| @log_execution(logger) |
| async def list_tools() -> ListToolsResponse: |
| """List the user-invocable slash-command catalog (skills + tools). |
| |
| Static per deployment — safe for the Golang backend to cache. |
| """ |
| return ListToolsResponse(count=len(_COMMAND_CATALOG), tools=_COMMAND_CATALOG) |
|
|