Skip to content

hotdata-framework: client gaps blocking agent use (error opacity, create_index, id-first, workspace default) #36

Description

@rohan-hotdata

Four gaps in hotdata-framework's HotdataClient, all surfaced while building the BM25 search tool (hotdata_langchain/search.py) and running it against production. Grouped because they all live in the same client surface.

Verified engine behaviour behind these: docs/engine-contract.md.

1. Errors discard the engine's message — highest impact

_execute_sql_once raises RuntimeError(e.reason or str(e)), which is the bare HTTP reason. The engine's actual message survives only in the underlying ApiException's body, further down the __cause__ chain.

What an agent sees vs. what the engine said:

agent sees : RuntimeError: Bad Request
engine said: Invalid function 'to_tsvector'. Did you mean 'to_char'?

This is not cosmetic. In a real agent run the model wrote Postgres full-text SQL, got Bad Request, and could not correct itself — the run aborted. The engine's own message is directly actionable and would very likely have been recovered from. Other observed examples that are similarly invisible today:

  • a database is required: set the X-Database-Id header or the database_id body field
  • No BM25 index found on column 'name' for <conn>.public.listings
  • must either specify a row count or at least one column

Fixing it here rather than per-consumer means hotdata-langchain, hotdata-ibis and hotdata-dlt-destination all benefit.

2. No create_index

There is no index API on HotdataClient at all, so the BM25 demo drops to raw hotdata.IndexesApi. Should cover both index types in one method — CreateIndexRequest already accepts bm25 and vector (fields: index_name, columns, index_type, metric, dimensions, embedding_provider_id, output_column, var_async) — rather than shipping a vector-only method and generalising later.

This blocks an agent provisioning its own searchable data: it can create a managed database and load into it, then cannot make it searchable.

3. resolve_managed_database falls back to name matching

It tries get_database(id), then scans list_databases() matching on db.name — which is a display label, not an identifier, and is not unique. Same bug class hotdata-dlt-destination removed entirely in its PR #59 ("address managed databases by id only, never by name").

Worse here than there, because names can arrive from an LLM: hotdata_load_managed_table(database="analytics", ...) could write into the wrong database on a collision. Latent rather than live — the test workspace has 8 databases with no duplicate labels.

4. from_env() picks a workspace silently

active = [w for w in workspaces if w.active]
chosen = active[0] if active else workspaces[0]

With HOTDATA_WORKSPACE unset there is no error and no warning. Given the tool set includes create_managed_database and load_managed_table, that is writes landing in a workspace nobody named. HotdataClient(api_key, workspace_id) already takes it explicitly; the ergonomic default is the problem.

Suggested order

(1) first — it is small and has demonstrated impact on agent behaviour. (2) unblocks self-provisioning. (3) and (4) are correctness/safety hardening and pair naturally with the id-first work in this repo.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai-native-layerPart of the AI-native query layer effort for LangChainbugSomething isn't workingrepo:frameworkImplementation lands in hotdata-framework / sdk-python

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions