sofhiaazzhr Claude Opus 4.7 commited on
Commit
4abb099
·
1 Parent(s): 0cb4e6d

[KM-628] Analytics tool registry

Browse files

Real registry of the 8 analyze_* family tools (src/tools/registry.py), built on
the canonical ToolSpec (KM-627) and the prompt-style DESCRIPTION constants
(KM-625). Replaces the analytics slice of the agent team's stub registry.

- Pattern A: each tool takes data="${t<id>}" placeholder (no self-fetch).
- input_schema.required mirrors each compute fn's no-default params; descriptive
relaxes column_ids to optional (compute treats None = all columns).
- output_kind per tool; analyze_comparison = stats.

The 4 data-access tools + default_registry() composition land with KM-465 #4.
Verified: registry builds (8 tools), ruff + mypy strict clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Files changed (1) hide show
  1. src/tools/registry.py +167 -0
src/tools/registry.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Analytics tool registry
2
+
3
+ The real registry of the `analyze_*` family, built on the canonical `ToolSpec`
4
+ (src/tools/contracts.py) and the prompt-style `DESCRIPTION` constants the Planner
5
+ reads to choose a tool (KM-625). This replaces the agent team's local stub in
6
+ `src/agents/planner/registry.py` for the analytics slice.
7
+
8
+ Conventions (decided with the agent team, KM-465):
9
+ - **Pattern A** — `analyze_*` tools do NOT self-fetch by `source_id`. Each takes a
10
+ `data` argument that is a `"${t<id>}"` placeholder pointing at an upstream
11
+ `query_structured` table output, resolved to a DataFrame at execution time.
12
+ Column arguments reference the aliases that upstream query produced.
13
+ - `input_schema` is the lightweight JSON-schema-ish dict the planner validator
14
+ consumes: `required` (arg names with no default) + `properties` (allowed args).
15
+ `required` mirrors each compute function's no-default parameters; value-typing of
16
+ placeholder args is deferred to execution time.
17
+ - `output_kind` is the `ToolOutput.kind` each tool returns: stats (labelled-metric
18
+ dict) | table (rows×cols) | series (ordered periods).
19
+
20
+ The four data-access tools (query_structured / retrieve_documents / list_sources /
21
+ describe_source) are registered separately once their wrappers land (KM-465 #4);
22
+ `default_registry()` composes both slices.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ from src.tools.analytics import (
28
+ aggregation,
29
+ comparison,
30
+ decomposition,
31
+ descriptive,
32
+ quality,
33
+ relationship,
34
+ segmentation,
35
+ temporal,
36
+ )
37
+ from src.tools.contracts import ToolRegistry, ToolSpec
38
+
39
+ ANALYTICS_TOOLS: list[ToolSpec] = [
40
+ ToolSpec(
41
+ name="analyze_descriptive",
42
+ category="analytics.descriptive",
43
+ input_schema={
44
+ "required": ["data"],
45
+ "properties": {
46
+ "data": {"type": "string"},
47
+ "column_ids": {"type": "array"},
48
+ "metrics": {"type": "array"},
49
+ },
50
+ },
51
+ output_kind="stats",
52
+ description=descriptive.DESCRIPTION,
53
+ ),
54
+ ToolSpec(
55
+ name="analyze_aggregate",
56
+ category="analytics.aggregation",
57
+ input_schema={
58
+ "required": ["data", "aggregations"],
59
+ "properties": {
60
+ "data": {"type": "string"},
61
+ "aggregations": {"type": "object"},
62
+ "group_by": {"type": "array"},
63
+ },
64
+ },
65
+ output_kind="table",
66
+ description=aggregation.DESCRIPTION,
67
+ ),
68
+ ToolSpec(
69
+ name="analyze_comparison",
70
+ category="analytics.comparison",
71
+ input_schema={
72
+ "required": ["data", "dimension", "value_column", "group_a", "group_b"],
73
+ "properties": {
74
+ "data": {"type": "string"},
75
+ "dimension": {"type": "string"},
76
+ "value_column": {"type": "string"},
77
+ "group_a": {},
78
+ "group_b": {},
79
+ "agg": {"type": "string"},
80
+ },
81
+ },
82
+ output_kind="stats",
83
+ description=comparison.DESCRIPTION,
84
+ ),
85
+ ToolSpec(
86
+ name="analyze_contribution",
87
+ category="analytics.decomposition",
88
+ input_schema={
89
+ "required": ["data", "dimension", "value_column"],
90
+ "properties": {
91
+ "data": {"type": "string"},
92
+ "dimension": {"type": "string"},
93
+ "value_column": {"type": "string"},
94
+ "agg": {"type": "string"},
95
+ "top_n": {"type": "integer"},
96
+ },
97
+ },
98
+ output_kind="table",
99
+ description=decomposition.DESCRIPTION,
100
+ ),
101
+ ToolSpec(
102
+ name="analyze_profile",
103
+ category="analytics.quality",
104
+ input_schema={
105
+ "required": ["data"],
106
+ "properties": {
107
+ "data": {"type": "string"},
108
+ "column_ids": {"type": "array"},
109
+ },
110
+ },
111
+ output_kind="stats",
112
+ description=quality.DESCRIPTION,
113
+ ),
114
+ ToolSpec(
115
+ name="analyze_correlation",
116
+ category="analytics.relationship",
117
+ input_schema={
118
+ "required": ["data"],
119
+ "properties": {
120
+ "data": {"type": "string"},
121
+ "column_ids": {"type": "array"},
122
+ "method": {"type": "string"},
123
+ },
124
+ },
125
+ output_kind="stats",
126
+ description=relationship.DESCRIPTION,
127
+ ),
128
+ ToolSpec(
129
+ name="analyze_segment",
130
+ category="analytics.segmentation",
131
+ input_schema={
132
+ "required": ["data", "column", "bins"],
133
+ "properties": {
134
+ "data": {"type": "string"},
135
+ "column": {"type": "string"},
136
+ "bins": {},
137
+ "method": {"type": "string"},
138
+ "labels": {"type": "array"},
139
+ "value_column": {"type": "string"},
140
+ "agg": {"type": "string"},
141
+ },
142
+ },
143
+ output_kind="table",
144
+ description=segmentation.DESCRIPTION,
145
+ ),
146
+ ToolSpec(
147
+ name="analyze_trend",
148
+ category="analytics.timeseries",
149
+ input_schema={
150
+ "required": ["data", "date_column", "value_column"],
151
+ "properties": {
152
+ "data": {"type": "string"},
153
+ "date_column": {"type": "string"},
154
+ "value_column": {"type": "string"},
155
+ "freq": {"type": "string"},
156
+ "agg": {"type": "string"},
157
+ },
158
+ },
159
+ output_kind="series",
160
+ description=temporal.DESCRIPTION,
161
+ ),
162
+ ]
163
+
164
+
165
+ def analytics_registry() -> ToolRegistry:
166
+ """The analytics (`analyze_*`) slice of the tool registry (fresh instance)."""
167
+ return ToolRegistry(tools=list(ANALYTICS_TOOLS))