get_metric
Retrieve metric data with grouping, ordering, and filtering. Returns ranked rows and parameterized SQL, resolving multi-table joins automatically.
Instructions
Use this when you have a metric name + want ranked/sliced rows (top-N, most/highest/lowest). Returns rows + parameterised SQL. Compiler chains multi-hop joins automatically (anchor order_item + group_by user.email + order_by total_items_sold desc → order_item → order → user). Pass order_by= for deterministic ranking; without it, limit is non-deterministic (envelope flags missing_order_by_with_limit). Use list_metrics instead when you don't know the metric name.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The metric name to compute (e.g. `total_revenue`). Call `list_metrics` to enumerate every declared metric with its anchor entity, aggregation, and time-bucketing capabilities. | |
| group_by | No | Tuple of `entity.column` references to slice by (e.g. `('product_category.name',)`). Each entity must be reachable from the metric's anchor via a chain of one or more canonical joins. Multi-hop chains (e.g. `order_item → order → user`) resolve automatically; if 2+ paths exist, the call refuses with `ambiguous_path` and the agent disambiguates via the `via` arg. Empty tuple = no slicing. | |
| filters | No | Tuple of `(column, op, value)` predicates. Column is `entity.column` form. Ops: eq, ne, lt, lte, gt, gte, in, not_in, is_null, not_null. Values bind as parameters — never inlined into SQL. | |
| time_grain | No | One of the metric's declared time_grains (day, week, month, quarter, year). Defaults null = no time bucketing. | |
| time_dimension | No | Disambiguates time-dimension inheritance when a metric carries no local `time_dimension` and 2+ timestamp columns are reachable via canonical joins. Pass `<entity>.<column>` form chosen from the `ambiguous_time_dimension` error's candidate list (also visible in the error message). Silently ignored when the metric has its own declared `time_dimension` — that always wins. Defaults null (no disambiguation). | |
| limit | No | Max rows returned. Defaults 1000, valid range 1-10000. Out-of-range values refuse with a typed `malformed_name` envelope (not a transport error). The compiler always emits LIMIT regardless of group_by complexity. | |
| via | No | Canonical-join names the chain MUST traverse, used to disambiguate `ambiguous_path` (multiple paths between anchor and a group_by entity) or `ambiguous_join` (parallel canonical joins on a single hop). Pass one or more join names returned by `list_joins` or by the prior error's `candidate_paths` / `candidate_join_names`. Each name must appear on a valid chain; otherwise the call refuses with `unknown_via_join`. Defaults to empty (no constraint) — only set when an ambiguity error tells you to. | |
| order_by | No | ORDER BY clauses applied to the result. Each entry's `column` must be EITHER the metric's `name` (the measure aggregate's SELECT alias) OR one of the `group_by` columns in `entity.column` form. Anything else refuses with `unknown_order_by_column`. `direction` is `asc` (default) or `desc`. Pass this when you want deterministic ranking (e.g. "top 5 users by total_items_sold" → `order_by=[{column:'total_items_sold', direction:'desc'}]`). The compiler auto-appends a tie-breaking secondary key (first group_by column ASC) so equal measure values produce identical row order across runs. Empty tuple + non-empty `group_by` defaults to ASC on every group column so the LIMIT N slice stays deterministic without the caller having to construct one; override by passing any explicit clause. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| status | Yes | ||
| data | No | ||
| error | No | ||
| confidence | No | ||
| provenance | No | ||
| follow_up_hints | No | ||
| degradation_reason | No | ||
| charter_version | No | 1.2 |