Skip to main content

Module: database

A plug-and-play database inspector — a psql-like console pane where the user (or the agent) writes SQL and runs it against any connected database. It ships with a pluggable driver layer so you can connect to several providers, and exposes the dashboard's own local vector store as the built-in app connection.

Status: implemented — frontend in packages/core/src/modules/database/, backend in backend/modules/database/.

What it does

  • Connections — a named-connection store. The built-in app connection (the local vector store) is always present and read-only; you add your own connections for external databases. Connections persist in .data/connections.json.
  • SQL console — write SQL, run it with Run or Ctrl/Cmd+Enter, and get a results grid with column headers, a status line (N rows · M ms, truncation flag), and inline error output. Recent queries are kept in a history dropdown. A Read-only toggle restricts a run to a single SELECT/WITH/EXPLAIN statement.
  • Schema sidebar — an introspected tree of tables → columns (with types and PK markers). Click a table to drop a SELECT * FROM <table> LIMIT 100 into the editor.
  • No synthetic data — the pane only ever shows real rows returned from a real connection.

Providers & drivers

Each provider is a thin synchronous driver (backend/modules/database/drivers/) behind a uniform test / run_query / introspect contract. Routes run drivers via asyncio.to_thread so the (blocking) client libraries never stall the event loop. Client libraries are imported lazily, so a missing optional dependency yields a clear error rather than breaking boot.

ProviderDriverDependencyNotes
sqlitesqlite_driverstdlibBacks the built-in app connection and any .sqlite/.db file. Registers the app's cosine_similarity() SQL function.
postgrespostgres_driverpsycopg[binary]Connect to any Postgres; pgvector vector columns and bytea blobs are summarized in the grid.
duckdbduckdb_driverduckdbLocal analytical/columnar querying (file or in-memory).
mysqlmysql_driverpymysqlMySQL / MariaDB.

Result cells are coerced to JSON-safe values: binary blobs and long numeric arrays (embeddings, pgvector) are summarized (e.g. <1536 bytes>, [384 numbers]), and dates/decimals are stringified.

The built-in app vector store

The dashboard's own data lives in a local SQLite file at .data/vector_store.db. It uses a custom Python cosine_similarity(v1_bytes, v2_bytes) SQL function (registered via sqlite3.Connection.create_function) for semantic search:

SELECT id, collection, text, metadata,
cosine_similarity(embedding, :query_emb) AS score
FROM documents
WHERE collection = :collection
ORDER BY score DESC LIMIT :limit

Because it's just the app connection, you can run ordinary SQL against it in the console (SELECT id, collection FROM documents). Embeddings are generated by a tiered pipeline (active agent provider → dedicated embedding model probe → deterministic local hash fallback so it works offline) in embeddings.py. The same vector store backs agent-commons matchmaking — see network.

Contributions to the Layout Shell

  • Widget: database.console — the connection bar + schema sidebar + SQL console.
  • Command: database.open (Database: Open Console) — opens the console in the workspace center.
  • Settings: database.defaultConnection (default app) and database.rowLimit (default 1000), read live via useSetting() — see settings.

Backend REST API

Mounted under /api/database.

MethodPathDescription
GET/connectionsList connections (built-in + saved, secrets redacted) and available providers.
POST/connectionsCreate a connection.
PUT/connections/{id}Update a connection (built-in is read-only; omitted secrets are preserved).
DELETE/connections/{id}Delete a saved connection.
POST/connections/testProbe an unsaved connection (form still holds the password).
POST/connections/{id}/testProbe a stored connection (server-side credentials).
GET/connections/{id}/schemaIntrospected tables/columns.
POST/queryRun SQL against a connection. read_only rejects non-SELECT. Returns columns, rows, rowcount, elapsed_ms, truncated.
GET/statusApp vector store stats + active embedding provider/model.
POST/pullStream an Ollama all-minilm embedding-model download (NDJSON).
GET/collectionsApp vector store collection names.
GET/documentsList app vector store documents (paginated, filterable).
POST/documentsEmbed and upsert a document into the app vector store.
DELETE/documents/{id}Delete a document by id.
POST/searchSemantic similarity search in an app vector store collection.

Agent Tools

The widget registers these tools with the agent orchestrator:

Tool NameDescriptionParametersSide Effect
database.listConnectionsList connections the agent can query.noneNo
database.describeSchema (tables/columns) for a connection, so the agent writes correct SQL.connection_id (str, opt)No
database.queryRun a read-only SELECT against a connection.sql (str), connection_id (str, opt)No
database.executeRun a writing statement (INSERT/UPDATE/DELETE/DDL); permission-gated.sql (str), connection_id (str, opt)Yes
database.semanticSearchVector search a collection in the app vector store.collection (str), text (str), limit (int, opt)No

Agent Context

The console exposes the active connection and its schema via useAgentContext() so the agent can target the right database:

{
activeConnection: "app",
provider: "sqlite",
tables: [{ name: "documents", columns: ["id", "collection", "text", "embedding"] }]
}

Security

SQL execution is unsandboxed (consistent with the v1 trusted plugin posture). The agent's database.query tool is read-only; writes go through database.execute, which is side-effect gated. Connection credentials are stored as plaintext in the gitignored .data/connections.json; encryption is a tracked follow-up.

Browser vs Desktop

Identical in both layouts — the frontend talks to the local FastAPI server, which owns the driver connections and the SQLite vector store.