ishaq101's picture
/feat ds tools (#22)
e201ae4
Raw History Blame
7.18 kB
"""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 (
ab_test,
aggregation,
anomaly,
cluster,
data_quality,
descriptive,
forecast,
importance,
merge,
pareto,
relationship,
segmentation,
temporal,
visualization,
)
from src.tools.contracts import ToolRegistry, ToolSpec
from src.tools.spec_builder import spec_from_model
# Active this round — the analytics (+ render_chart, SPINE_V2_PLAN §4.1) tools
# the Planner may select.
ACTIVE_ANALYTICS_TOOLS: list[ToolSpec] = [
spec_from_model(
name="analyze_descriptive",
category="analytics.descriptive",
output_kind="stats",
description=descriptive.DESCRIPTION,
input_model=descriptive.DescriptiveInput,
phase="P1",
),
spec_from_model(
name="analyze_aggregate",
category="analytics.aggregation",
output_kind="table",
description=aggregation.DESCRIPTION,
input_model=aggregation.AggregateInput,
phase="P1",
),
spec_from_model(
name="analyze_correlation",
category="analytics.relationship",
output_kind="stats",
description=relationship.DESCRIPTION,
input_model=relationship.CorrelationInput,
phase="P1",
),
spec_from_model(
name="analyze_trend",
category="analytics.timeseries",
output_kind="series",
description=temporal.DESCRIPTION,
input_model=temporal.TrendInput,
phase="P1",
),
spec_from_model(
name="analyze_merge",
category="analytics.combine",
output_kind="table",
description=merge.DESCRIPTION,
input_model=merge.MergeInput,
phase="P1",
),
spec_from_model(
name="render_chart",
category="analytics.visualization",
output_kind="chart",
description=visualization.DESCRIPTION,
input_model=visualization.RenderChartInput,
phase="P1",
),
# --- Activated 2026-09-17 (A15): the 8 new/renamed tools, moved from DEFERRED to
# ACTIVE. All-active + grouping (A17) decision — grouping keeps the planner accurate
# at 18 tools. NOTE: their planner few-shots (examples.py, A18 — Rifqi) land in sync.
# Renamed from analyze_comparison (A11): absorbs the significance test (Welch t-test).
spec_from_model(
name="analyze_ab_test",
category="analytics.comparison",
output_kind="stats",
description=ab_test.DESCRIPTION,
input_model=ab_test.AbTestInput,
phase="P1",
),
# Renamed from analyze_contribution (A12): reframed to Pareto 80/20 + auto-chart.
# Spec derived from its pydantic InputModel via spec_builder.
spec_from_model(
name="analyze_pareto",
category="analytics.pareto",
output_kind="table",
description=pareto.DESCRIPTION,
input_model=pareto.ParetoInput,
phase="P1",
),
# Renamed from analyze_profile (A14): activate + missing-rate bar chart.
# Spec derived from its pydantic InputModel via spec_builder.
spec_from_model(
name="analyze_data_quality",
category="analytics.quality",
output_kind="stats",
description=data_quality.DESCRIPTION,
input_model=data_quality.DataQualityInput,
phase="P1",
),
# Activated + renamed from analyze_segment (A13): + bar chart, spec from InputModel.
spec_from_model(
name="analyze_segmentation",
category="analytics.segmentation",
output_kind="table",
description=segmentation.DESCRIPTION,
input_model=segmentation.SegmentationInput,
phase="P1",
),
# First ML tool (§0.9). Spec derived from its pydantic InputModel via
# spec_builder, not hand-written. DEFERRED until the demo scenario locks P1 and
# its planner few-shot lands (examples.py) — see the ACTIVE/DEFERRED note above.
spec_from_model(
name="analyze_forecast",
category="analytics.timeseries",
output_kind="series",
description=forecast.DESCRIPTION,
input_model=forecast.ForecastInput,
phase="P1",
),
# Second ML tool (§0.9). Same spec_builder + DEFERRED pattern as analyze_forecast.
spec_from_model(
name="analyze_anomaly",
category="analytics.anomaly",
output_kind="stats",
description=anomaly.DESCRIPTION,
input_model=anomaly.AnomalyInput,
phase="P1",
),
# A8 + A10 (Rifqi wrote the tool files; Sofhia registers per the ownership split).
spec_from_model(
name="analyze_importance",
category="analytics.relationship",
output_kind="stats",
description=importance.DESCRIPTION,
input_model=importance.ImportanceInput,
phase="P1",
),
spec_from_model(
name="analyze_cluster",
category="analytics.clustering",
output_kind="stats",
description=cluster.DESCRIPTION,
input_model=cluster.ClusterInput,
phase="P1",
),
]
# All analytical tools are ACTIVE this round (A15, 2026-09-17) — nothing deferred.
# The mechanism is kept so a future tool can still ship dark (move a spec here).
DEFERRED_ANALYTICS_TOOLS: list[ToolSpec] = []
# 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))