| """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 (2026-06-24, KM-674): the FE slash-command catalog is now just the two | |
| FE-callable skills — `/help` and `/report`. Naming: verb-first, kebab-case, `/` | |
| prefix; each command maps 1:1 to a real internal tool/intent `name` (the dispatch | |
| key). | |
| The analytics + data-access tools (analyze_*, check_*, retrieve_*) and the retired | |
| `/problem-statement` skill are kept COMMENTED in the catalog below, NOT deleted — | |
| they still exist and run via the router/Planner, and check_data/check_knowledge are | |
| served by Golang; they are simply not surfaced in the FE slash menu for now. Slash | |
| invocation bypasses the router to the tool directly, so re-exposing one is a matter | |
| of un-commenting its entry. | |
| 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 # FE-facing slash command, e.g. "/analyze-descriptive" | |
| name: str # internal handler/tool name, e.g. "analyze_descriptive" | |
| type: CommandType | |
| description: str | |
| class ListToolsResponse(BaseModel): | |
| count: int | |
| tools: list[CommandResponse] | |
| # Single source of truth for the FE slash-command catalog. Order = display order. | |
| # Keep `command` in Harry's convention (verb-first, kebab-case, `/`); `name` is the | |
| # internal route/tool name used by the orchestrator. | |
| # | |
| # 2026-06-24 (KM-674 batch): the FE-callable skills are ONLY /help + /report. The rest | |
| # below are COMMENTED OUT — NOT deleted — on purpose: | |
| # - /problem-statement is retired (objective + business_questions now live in the | |
| # New-Analysis form, not a slash skill). | |
| # - check_data / check_knowledge stay available but are served by Golang, not exposed | |
| # in the FE slash menu. | |
| # - the analytics + data-access tools still exist and run via the router/Planner; they | |
| # are simply not surfaced as FE slash commands here. | |
| # Re-enable any line if the FE slash menu is later widened back out. | |
| _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="/report", | |
| name="report", | |
| type="skill", | |
| description="Generate a versioned analysis report (background, EDA, " | |
| "key findings, insights).", | |
| ), | |
| # 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.", | |
| # ), | |
| ] | |
| async def list_tools() -> ListToolsResponse: | |
| """List the user-invocable slash-command catalog (skills + tools). | |
| Static per deployment — safe for the Golang backend to cache. | |
| pr/5 Phase 2: moved from `GET /api/v1/tools` to `GET /api/v1/tools/list` so the | |
| skills group is `/tools/list` · `/tools/help` · `/tools/report`. | |
| """ | |
| return ListToolsResponse(count=len(_COMMAND_CATALOG), tools=_COMMAND_CATALOG) | |