File size: 5,397 Bytes
0721bb4
 
 
 
 
 
0e02a0f
 
 
 
 
 
 
 
 
 
 
0721bb4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e02a0f
 
 
 
 
 
 
 
 
 
0721bb4
 
 
 
 
 
 
 
0e02a0f
 
0721bb4
0e02a0f
 
0721bb4
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
"""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.",
    # ),
]


@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)