Skip to content

Commit e957da1

Browse files
kulvirgitclaude
andcommitted
feat: add warehouse_explore tool for structured data exploration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8ccf349 commit e957da1

6 files changed

Lines changed: 157 additions & 0 deletions

File tree

packages/altimate-engine/src/altimate_engine/models.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,27 @@ class AltimateCoreIsSafeParams(BaseModel):
987987
sql: str
988988

989989

990+
# --- Warehouse Explore ---
991+
992+
993+
class WarehouseExploreParams(BaseModel):
994+
warehouse: str | None = None
995+
996+
997+
class WarehouseExploreTableInfo(BaseModel):
998+
schema_name: str = Field(alias="schema")
999+
name: str
1000+
columns: list[str]
1001+
1002+
model_config = {"populate_by_name": True}
1003+
1004+
1005+
class WarehouseExploreResult(BaseModel):
1006+
tables: list[WarehouseExploreTableInfo]
1007+
table_count: int
1008+
1009+
1010+
9901011
# --- JSON-RPC ---
9911012

9921013

packages/altimate-engine/src/altimate_engine/server.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
SqlRewriteRule,
6666
SqlTranslateParams,
6767
SqlTranslateResult,
68+
WarehouseExploreParams,
69+
WarehouseExploreTableInfo,
70+
WarehouseExploreResult,
6871
WarehouseInfo,
6972
WarehouseListResult,
7073
WarehouseTestParams,
@@ -212,6 +215,37 @@
212215
INTERNAL_ERROR = -32603
213216

214217

218+
# --- Warehouse helpers ---
219+
220+
221+
def _resolve_warehouse(warehouse_name: str | None):
222+
"""Resolve warehouse: explicit name > registered connections > dbt profiles."""
223+
if warehouse_name:
224+
return ConnectionRegistry.get(warehouse_name)
225+
# Try first registered connection
226+
connections = ConnectionRegistry.list()
227+
if connections:
228+
return ConnectionRegistry.get(connections[0]["name"])
229+
# Try dbt profiles
230+
dbt_conns = discover_dbt_connections()
231+
if dbt_conns:
232+
first_name = next(iter(dbt_conns))
233+
# Register it so ConnectionRegistry.get() works
234+
ConnectionRegistry.add(first_name, dbt_conns[first_name])
235+
return ConnectionRegistry.get(first_name)
236+
raise ValueError(
237+
"No warehouse connection found. Configure one or pass warehouse name."
238+
)
239+
240+
241+
def _parse_table_ref(table_name: str) -> tuple[str | None, str]:
242+
"""Parse 'schema.table' into (schema, table) or (None, table)."""
243+
parts = table_name.split(".", 1)
244+
if len(parts) == 2:
245+
return parts[0], parts[1]
246+
return None, parts[0]
247+
248+
215249
# Lazily-initialized singletons
216250
def _schema_context_to_dict(
217251
schema_context: dict[str, list] | None,
@@ -453,6 +487,28 @@ def dispatch(request: JsonRpcRequest) -> JsonRpcResponse:
453487
result = parse_manifest(DbtManifestParams(**params))
454488
elif method == "dbt.lineage":
455489
result = dbt_lineage(DbtLineageParams(**params))
490+
elif method == "warehouse.explore":
491+
p = WarehouseExploreParams(**params)
492+
connector = _resolve_warehouse(p.warehouse)
493+
connector.connect()
494+
try:
495+
tables_info = []
496+
for schema in connector.list_schemas():
497+
for tbl in connector.list_tables(schema):
498+
cols = connector.describe_table(schema, tbl["name"])
499+
col_names = [c["name"] for c in cols]
500+
tables_info.append(
501+
WarehouseExploreTableInfo(
502+
schema=schema,
503+
name=tbl["name"],
504+
columns=col_names,
505+
)
506+
)
507+
result = WarehouseExploreResult(
508+
tables=tables_info, table_count=len(tables_info)
509+
)
510+
finally:
511+
connector.close()
456512
elif method == "warehouse.list":
457513
warehouses = [WarehouseInfo(**w) for w in ConnectionRegistry.list()]
458514
result = WarehouseListResult(warehouses=warehouses)

packages/opencode/src/altimate/bridge/protocol.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,24 @@ export interface LocalTestResult {
951951
error?: string
952952
}
953953

954+
// --- Warehouse Explore ---
955+
956+
export interface WarehouseExploreParams {
957+
warehouse?: string
958+
}
959+
960+
export interface WarehouseExploreTableInfo {
961+
schema: string
962+
name: string
963+
columns: string[]
964+
}
965+
966+
export interface WarehouseExploreResult {
967+
tables: WarehouseExploreTableInfo[]
968+
table_count: number
969+
}
970+
971+
954972
// --- Method registry ---
955973

956974
export const BridgeMethods = {
@@ -975,6 +993,7 @@ export const BridgeMethods = {
975993
"warehouse.add": {} as { params: WarehouseAddParams; result: WarehouseAddResult },
976994
"warehouse.remove": {} as { params: WarehouseRemoveParams; result: WarehouseRemoveResult },
977995
"warehouse.discover": {} as { params: Record<string, never>; result: WarehouseDiscoverResult },
996+
"warehouse.explore": {} as { params: WarehouseExploreParams; result: WarehouseExploreResult },
978997
"finops.query_history": {} as { params: QueryHistoryParams; result: QueryHistoryResult },
979998
"finops.analyze_credits": {} as { params: CreditAnalysisParams; result: CreditAnalysisResult },
980999
"finops.expensive_queries": {} as { params: ExpensiveQueriesParams; result: ExpensiveQueriesResult },

packages/opencode/src/altimate/prompts/builder.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ You have full read/write access to the project. You can:
55
- Execute SQL against connected warehouses via `sql_execute`
66
- Validate SQL with AltimateCore via `sql_validate` (syntax, safety, lint, PII)
77
- Analyze SQL for anti-patterns and performance issues via `sql_analyze`
8+
- Explore warehouse schemas and tables via `warehouse_explore` (use FIRST)
89
- Inspect database schemas via `schema_inspect`
910
- Check column-level lineage via `lineage_check`
1011
- List and test warehouse connections via `warehouse_list` and `warehouse_test`
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import z from "zod"
2+
import { Tool } from "../../tool/tool"
3+
import { Bridge } from "../bridge/client"
4+
import type { WarehouseExploreResult } from "../bridge/protocol"
5+
6+
export const WarehouseExploreTool = Tool.define("warehouse_explore", {
7+
description:
8+
"List all schemas and table names in the connected warehouse. " +
9+
"Use this FIRST to see what tables exist. Then use schema_inspect " +
10+
"on specific tables to see their column types and details.",
11+
parameters: z.object({
12+
warehouse: z.string().optional().describe("Warehouse connection name (auto-detected if omitted)"),
13+
}),
14+
async execute(args, ctx) {
15+
try {
16+
const result = await Bridge.call("warehouse.explore", {
17+
warehouse: args.warehouse,
18+
})
19+
20+
return {
21+
title: `Warehouse: ${result.table_count} tables`,
22+
metadata: { tableCount: result.table_count },
23+
output: formatExploreResult(result),
24+
}
25+
} catch (e) {
26+
const msg = e instanceof Error ? e.message : String(e)
27+
return {
28+
title: "Warehouse: ERROR",
29+
metadata: { tableCount: 0 },
30+
output: `Failed to explore warehouse: ${msg}\n\nEnsure the Python bridge is running and a warehouse connection is configured.`,
31+
}
32+
}
33+
},
34+
})
35+
36+
function formatExploreResult(result: WarehouseExploreResult): string {
37+
if (result.table_count === 0) return "(no tables found)"
38+
39+
const lines: string[] = [`${result.table_count} tables found:`, ""]
40+
41+
// Group by schema
42+
const bySchema = new Map<string, typeof result.tables>()
43+
for (const table of result.tables) {
44+
const list = bySchema.get(table.schema) || []
45+
list.push(table)
46+
bySchema.set(table.schema, list)
47+
}
48+
49+
for (const [schema, tables] of bySchema) {
50+
lines.push(`### ${schema}`)
51+
for (const t of tables) {
52+
lines.push(`- ${t.name} (${t.columns.join(", ")})`)
53+
}
54+
lines.push("")
55+
}
56+
57+
return lines.join("\n")
58+
}

packages/opencode/src/tool/registry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { WarehouseTestTool } from "../altimate/tools/warehouse-test"
4444
import { WarehouseAddTool } from "../altimate/tools/warehouse-add"
4545
import { WarehouseRemoveTool } from "../altimate/tools/warehouse-remove"
4646
import { WarehouseDiscoverTool } from "../altimate/tools/warehouse-discover"
47+
import { WarehouseExploreTool } from "../altimate/tools/warehouse-explore"
4748
import { DbtRunTool } from "../altimate/tools/dbt-run"
4849
import { DbtManifestTool } from "../altimate/tools/dbt-manifest"
4950
import { DbtProfilesTool } from "../altimate/tools/dbt-profiles"
@@ -218,6 +219,7 @@ export namespace ToolRegistry {
218219
WarehouseAddTool,
219220
WarehouseRemoveTool,
220221
WarehouseDiscoverTool,
222+
WarehouseExploreTool,
221223
DbtRunTool,
222224
DbtManifestTool,
223225
DbtProfilesTool,

0 commit comments

Comments
 (0)