File size: 7,879 Bytes
81e5fe7 0721bb4 81e5fe7 0721bb4 81e5fe7 49b0848 81e5fe7 5a60e93 81e5fe7 5a60e93 0721bb4 81e5fe7 0721bb4 49b0848 5a60e93 0721bb4 81e5fe7 0721bb4 81e5fe7 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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | """Analytics tool registry
The real registry of the `analyze_*` family, built on the canonical `ToolSpec`
(src/tools/contracts.py) and the prompt-style `DESCRIPTION` constants the Planner
reads to choose a tool (KM-625). This replaces the agent team's local stub in
`src/agents/planner/registry.py` for the analytics slice.
Conventions (decided with the agent team, KM-465):
- **Pattern A** — `analyze_*` tools do NOT self-fetch by `source_id`. Each takes a
`data` argument that is a `"${t<id>}"` placeholder pointing at an upstream
`retrieve_data` table output, resolved to a DataFrame at execution time.
Column arguments reference the aliases that upstream query produced.
- `input_schema` is the lightweight JSON-schema-ish dict the planner validator
consumes: `required` (arg names with no default) + `properties` (allowed args).
`required` mirrors each compute function's no-default parameters; value-typing of
placeholder args is deferred to execution time.
- `output_kind` is the `ToolOutput.kind` each tool returns: stats (labelled-metric
dict) | table (rows×cols) | series (ordered periods).
The four data-access tools (retrieve_data / retrieve_knowledge / check_data /
check_knowledge) are registered separately once their wrappers land (KM-465 #4);
`default_registry()` composes both slices.
"""
from __future__ import annotations
from src.tools.analytics import (
aggregation,
comparison,
decomposition,
descriptive,
merge,
quality,
relationship,
segmentation,
temporal,
visualization,
)
from src.tools.contracts import ToolRegistry, ToolSpec
# Active this round — the analytics (+ render_chart, SPINE_V2_PLAN §4.1) tools
# the Planner may select.
ACTIVE_ANALYTICS_TOOLS: list[ToolSpec] = [
ToolSpec(
name="analyze_descriptive",
category="analytics.descriptive",
input_schema={
"required": ["data", "column_ids"],
"properties": {
"data": {"type": "string"},
"column_ids": {"type": "array"},
"metrics": {"type": "array"},
},
},
output_kind="stats",
description=descriptive.DESCRIPTION,
),
ToolSpec(
name="analyze_aggregate",
category="analytics.aggregation",
input_schema={
"required": ["data", "aggregations"],
"properties": {
"data": {"type": "string"},
"aggregations": {"type": "object"},
"group_by": {"type": "array"},
},
},
output_kind="table",
description=aggregation.DESCRIPTION,
),
ToolSpec(
name="analyze_correlation",
category="analytics.relationship",
input_schema={
"required": ["data"],
"properties": {
"data": {"type": "string"},
"column_ids": {"type": "array"},
"method": {"type": "string"},
},
},
output_kind="stats",
description=relationship.DESCRIPTION,
),
ToolSpec(
name="analyze_trend",
category="analytics.timeseries",
input_schema={
"required": ["data", "date_column", "value_column"],
"properties": {
"data": {"type": "string"},
"date_column": {"type": "string"},
"value_column": {"type": "string"},
"freq": {"type": "string"},
"agg": {"type": "string"},
},
},
output_kind="series",
description=temporal.DESCRIPTION,
),
ToolSpec(
name="analyze_merge",
category="analytics.combine",
input_schema={
"required": ["data", "data_right", "on"],
"properties": {
"data": {"type": "string"},
"data_right": {"type": "string"},
"on": {"type": "array"},
"how": {"type": "string"},
"suffixes": {"type": "array"},
},
},
output_kind="table",
description=merge.DESCRIPTION,
),
ToolSpec(
name="render_chart",
category="analytics.visualization",
input_schema={
"required": ["data", "chart_type", "x", "y"],
"properties": {
"data": {"type": "string"},
"chart_type": {"type": "string"},
"x": {"type": "string"},
"y": {"type": "string"},
"series": {"type": "string"},
"title": {"type": "string"},
},
},
output_kind="chart",
description=visualization.DESCRIPTION,
),
]
# Deferred this round — specs kept intact for easy re-activation, NOT exposed to
# the Planner. The compute fns still exist (src/tools/analytics/*) and the invoker
# still maps them (src/tools/invoker.py); only registry exposure is withheld.
# To re-activate, move a spec back into ACTIVE_ANALYTICS_TOOLS. NOTE: a deferred
# tool re-activated here must also be re-added to the Planner few-shots
# (src/agents/planner/examples.py) — keep the two in sync.
DEFERRED_ANALYTICS_TOOLS: list[ToolSpec] = [
ToolSpec(
name="analyze_comparison",
category="analytics.comparison",
input_schema={
"required": ["data", "dimension", "value_column", "group_a", "group_b"],
"properties": {
"data": {"type": "string"},
"dimension": {"type": "string"},
"value_column": {"type": "string"},
"group_a": {},
"group_b": {},
"agg": {"type": "string"},
},
},
output_kind="stats",
description=comparison.DESCRIPTION,
),
ToolSpec(
name="analyze_contribution",
category="analytics.decomposition",
input_schema={
"required": ["data", "dimension", "value_column"],
"properties": {
"data": {"type": "string"},
"dimension": {"type": "string"},
"value_column": {"type": "string"},
"agg": {"type": "string"},
"top_n": {"type": "integer"},
},
},
output_kind="table",
description=decomposition.DESCRIPTION,
),
ToolSpec(
name="analyze_profile",
category="analytics.quality",
input_schema={
"required": ["data"],
"properties": {
"data": {"type": "string"},
"column_ids": {"type": "array"},
},
},
output_kind="stats",
description=quality.DESCRIPTION,
),
ToolSpec(
name="analyze_segment",
category="analytics.segmentation",
input_schema={
"required": ["data", "column", "bins"],
"properties": {
"data": {"type": "string"},
"column": {"type": "string"},
"bins": {},
"method": {"type": "string"},
"labels": {"type": "array"},
"value_column": {"type": "string"},
"agg": {"type": "string"},
},
},
output_kind="table",
description=segmentation.DESCRIPTION,
),
]
# Full set (active + deferred) — kept for callers that need every spec, e.g. tests
# or the invoker's name checks. The Planner-visible registry uses ACTIVE only.
ANALYTICS_TOOLS: list[ToolSpec] = [*ACTIVE_ANALYTICS_TOOLS, *DEFERRED_ANALYTICS_TOOLS]
def analytics_registry() -> ToolRegistry:
"""The analytics (`analyze_*`) slice of the tool registry (fresh instance).
Exposes only `ACTIVE_ANALYTICS_TOOLS`; deferred specs are withheld from the
Planner (see `DEFERRED_ANALYTICS_TOOLS`).
"""
return ToolRegistry(tools=list(ACTIVE_ANALYTICS_TOOLS))
|