File size: 5,934 Bytes
0721bb4
 
 
 
 
 
17e31c6
 
 
 
0e02a0f
 
 
 
 
 
 
 
 
0721bb4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e02a0f
17e31c6
 
 
 
 
 
0e02a0f
 
 
 
 
 
 
0721bb4
 
 
 
 
 
 
17e31c6
 
 
 
 
 
 
0e02a0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0721bb4
 
 
3bacc1d
0721bb4
 
 
 
 
3bacc1d
 
 
0721bb4
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
"""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-07-09): the FE slash-command catalog is now just `/help`. `/report` was
removed — report generation is button-only (the Generate button in the Report panel);
typing `/report` no longer creates a report (the router sends it to `check`), so
surfacing it as a slash command would mislead. 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-07-09: the only FE-callable slash skill is now /help. The rest below are
# COMMENTED OUT — NOT deleted — on purpose:
#   - /report is retired as a slash command: report generation is button-only (Generate
#     button in the Report panel). Typing /report no longer generates a report (the router
#     routes it to `check`), so exposing it here would misdirect users. The report HTTP
#     endpoint (POST /api/v1/tools/report in report.py) stays — the Generate button calls it.
#   - /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.",
    # ),
]


@router.get("/tools/list", 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.

    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)