release: 0.46.2 — friendlier hint on missing-table errors for remote tables (#219)
## Summary
`agnes query "DESCRIBE unit_economics"` (where `unit_economics` is `query_mode='remote'`) previously returned DuckDB's nearest-name suggestion (`Did you mean "order_economics"`?), sending users down the wrong path. Now appends a friendly hint about remote tables.
Reproduced from a real analyst session — colleague spent ~30s diagnosing what was actually "this is a remote table, not materialized locally".
## Test plan
- [x] New test: `_query_local("DESCRIBE unit_economics", ...)` against an empty local DuckDB triggers the new hint, original DuckDB error still echoed.
- [x] Negative test: a syntax-error query does NOT trigger the hint (regex only matches "Table with name X does not exist").
- [x] `pytest tests/test_cli_query*.py` clean.
<!-- devin-review-badge-begin -->
---
<a href="https://app.devin.ai/review/keboola/agnes-the-ai-analyst/pull/219" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
This commit is contained in:
parent
378ee40459
commit
50d10443d1
4 changed files with 71 additions and 1 deletions
|
|
@ -10,6 +10,12 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.46.2] — 2026-05-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- `agnes query` against a `query_mode='remote'` table previously surfaced DuckDB's misleading "did you mean <similar materialized table>" suggestion. Now appends a friendlier hint pointing users to `agnes catalog`, `agnes schema <id>`, and `agnes query --remote`. Reproduces from a real analyst session where `DESCRIBE unit_economics` (a remote table) sent the user down a 30-second wrong path.
|
||||
|
||||
## [0.46.1] — 2026-05-07
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
|
@ -78,6 +79,26 @@ def _query_local(sql: str, fmt: str, limit: int):
|
|||
_output(columns, result, fmt)
|
||||
except Exception as e:
|
||||
typer.echo(f"Query error: {e}", err=True)
|
||||
# DuckDB's "Did you mean <similar materialized view>" suggestion is
|
||||
# misleading when the unresolvable identifier is actually a
|
||||
# `query_mode='remote'` table — those have no local view by design.
|
||||
# Append a friendly hint pointing the user at `agnes catalog`,
|
||||
# `agnes schema`, and `agnes query --remote`. We don't verify against
|
||||
# the remote registry here (this command is offline-friendly), so the
|
||||
# hint is conditional ("might be") — safe even when the name was just
|
||||
# a typo.
|
||||
m = re.search(r"Table with name ([A-Za-z_][A-Za-z0-9_]*) does not exist", str(e))
|
||||
if m:
|
||||
typer.echo("", err=True)
|
||||
typer.echo(
|
||||
f"Note: `{m.group(1)}` might be a `query_mode='remote'` table. Local "
|
||||
"DuckDB only holds views for `local` and `materialized` tables — "
|
||||
"`remote` ones live on BigQuery and are not synced.\n"
|
||||
" - List all registered tables: agnes catalog\n"
|
||||
" - Inspect column schema: agnes schema <name>\n"
|
||||
" - Run a query against BigQuery: agnes query --remote \"<SQL>\"",
|
||||
err=True,
|
||||
)
|
||||
raise typer.Exit(1)
|
||||
finally:
|
||||
conn.close()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "agnes-the-ai-analyst"
|
||||
version = "0.46.1"
|
||||
version = "0.46.2"
|
||||
description = "Agnes — AI Data Analyst platform for AI analytical systems"
|
||||
requires-python = ">=3.11,<3.14"
|
||||
license = "MIT"
|
||||
|
|
|
|||
|
|
@ -150,3 +150,46 @@ class TestLocalQuery:
|
|||
result = runner.invoke(app, ["query", "SELECT * FROM nonexistent_table_xyz"])
|
||||
assert result.exit_code == 1
|
||||
assert "Query error" in result.output
|
||||
|
||||
def test_local_query_missing_table_hints_remote(self, tmp_config):
|
||||
"""Querying a table absent from local DuckDB surfaces a hint about
|
||||
`query_mode='remote'` tables alongside the original DuckDB error.
|
||||
|
||||
Reproduces the analyst-session UX gap where DuckDB's nearest-name
|
||||
("Did you mean <other_table>") suggestion sent the user down the
|
||||
wrong path — they thought the table didn't exist or they typo'd,
|
||||
when in fact it's a remote table that intentionally has no local
|
||||
view.
|
||||
"""
|
||||
import duckdb
|
||||
db_dir = tmp_config / "local" / "user" / "duckdb"
|
||||
db_dir.mkdir(parents=True)
|
||||
duckdb.connect(str(db_dir / "analytics.duckdb")).close()
|
||||
|
||||
result = runner.invoke(app, ["query", "DESCRIBE unit_economics"])
|
||||
assert result.exit_code == 1
|
||||
# Original DuckDB diagnostic must remain visible (don't break logging).
|
||||
assert "Query error" in result.output
|
||||
assert "Table with name unit_economics does not exist" in result.output
|
||||
# New hint fires.
|
||||
assert "query_mode='remote'" in result.output
|
||||
assert "agnes catalog" in result.output
|
||||
assert "agnes schema" in result.output
|
||||
assert "agnes query --remote" in result.output
|
||||
|
||||
def test_local_query_syntax_error_does_not_show_remote_hint(self, tmp_config):
|
||||
"""A non-missing-table failure (e.g. raw syntax error) must NOT
|
||||
trigger the new remote-mode hint — the regex only matches DuckDB's
|
||||
`Table with name X does not exist` shape.
|
||||
"""
|
||||
import duckdb
|
||||
db_dir = tmp_config / "local" / "user" / "duckdb"
|
||||
db_dir.mkdir(parents=True)
|
||||
duckdb.connect(str(db_dir / "analytics.duckdb")).close()
|
||||
|
||||
# Trailing FROM with no relation -> ParserException, not CatalogException.
|
||||
result = runner.invoke(app, ["query", "SELECT * FROM"])
|
||||
assert result.exit_code == 1
|
||||
assert "Query error" in result.output
|
||||
assert "query_mode='remote'" not in result.output
|
||||
assert "agnes query --remote" not in result.output
|
||||
|
|
|
|||
Loading…
Reference in a new issue