Architecture¶
datasight is a FastAPI web server with a Svelte 5 + TypeScript + Tailwind
frontend (built with Vite, served as static assets by FastAPI). The LLM agent
loop, tool execution, and SSE streaming are implemented in plain Python, with
a pluggable LLMClient abstraction that supports Anthropic, GitHub Models,
and Ollama — see Choosing an LLM for
guidance on picking a provider.
System overview¶
flowchart TB
subgraph ui ["Web UI (FastAPI + SSE)"]
WEB[FastAPI server]
HTML[Svelte frontend]
end
subgraph agent ["LLM Agent Loop"]
LLM[LLMClient]
ANTH[Anthropic API]
GH[GitHub Models]
OLL[Ollama local]
SQL[run_sql tool]
VIZ[visualize_data tool]
LLM -.-> ANTH
LLM -.-> GH
LLM -.-> OLL
SQL --> RUNNER[SqlRunner]
VIZ --> CHART[Interactive<br>ChartGenerator]
end
subgraph db ["Database"]
DUCK[DuckDB<br>local file]
SQLITE[SQLite<br>local file]
PG[PostgreSQL<br>remote server]
FLIGHT[Flight SQL<br>remote server]
end
HTML <-->|SSE stream| WEB
WEB --> LLM
LLM --> SQL
LLM --> VIZ
RUNNER --> DUCK
RUNNER --> SQLITE
RUNNER --> PG
RUNNER --> FLIGHT
style WEB fill:#15a8a8,stroke:#023d60
style HTML fill:#15a8a8,stroke:#023d60
style LLM fill:#023d60,stroke:#023d60
style ANTH fill:#023d60,stroke:#023d60
style GH fill:#023d60,stroke:#023d60
style OLL fill:#023d60,stroke:#023d60
style SQL fill:#023d60,stroke:#023d60
style VIZ fill:#023d60,stroke:#023d60
style RUNNER fill:#bf1363,stroke:#023d60
style CHART fill:#bf1363,stroke:#023d60
style DUCK fill:#fe5d26,stroke:#023d60
style SQLITE fill:#fe5d26,stroke:#023d60
style PG fill:#fe5d26,stroke:#023d60
style FLIGHT fill:#fe5d26,stroke:#023d60
style ui fill:#f0fafa,stroke:#15a8a8
style agent fill:#f0f0fa,stroke:#023d60
style db fill:#fff5f0,stroke:#fe5d26
Request flow¶
sequenceDiagram
participant U as User
participant W as FastAPI
participant L as LLM (via LLMClient)
participant D as Database
U->>W: POST /api/chat (SSE)
activate W
loop Until LLM stops calling tools
W->>L: send messages + tools
activate L
L-->>W: tool_use (run_sql / visualize_data)
deactivate L
W->>D: Execute SQL
activate D
D-->>W: DataFrame
deactivate D
W-->>U: SSE: tool_result (table / chart)
end
W->>L: final turn
activate L
L-->>W: text response
deactivate L
W-->>U: SSE: token stream
W-->>U: SSE: done
deactivate W
Modules¶
datasight.cli- Click CLI entry point. See the CLI reference for the full command tree.
datasight.agent- Shared agent loop and tool execution. Used by both the web UI and the
headless
askCLI. Containsrun_agent_loop(),execute_tool(), and Plotly spec resolution helpers. datasight.settings- Typed settings loaded from
.env/ environment variables (LLM provider, database connection, feature flags). datasight.config- Configuration helpers — loads schema descriptions, example queries, and creates SQL runners from settings.
datasight.schema- Database introspection. Discovers tables, columns, and row counts using
multiple strategies (DuckDB
SHOW TABLES,INFORMATION_SCHEMA, SQLitePRAGMA table_info). datasight.llm- LLM client abstraction with implementations for Anthropic, GitHub Models, and Ollama. Converts between provider-specific message and tool formats.
datasight.prompts- System prompt assembly — stitches schema, descriptions, example queries, and tool guidance into the LLM context.
datasight.chart- Interactive Plotly chart generator with chart-type switching buttons.
datasight.runner- SQL execution backends —
DuckDBRunnerandSQLiteRunnerfor local files,PostgresRunnerfor PostgreSQL servers, andFlightSqlRunnerfor remote databases via Arrow gRPC. datasight.sql_validation- SQL parsing and safety checks with
sqlglot— rejects non-SELECT statements and flags dialect issues before execution. datasight.query_log- Append-only JSON log of every executed query, surfaced by
datasight log. datasight.cost- Token accounting and cost estimation per LLM call and per session.
datasight.verify- Query verification engine used by
datasight verifyto replay example queries across models and compare results. datasight.data_profile,datasight.integrity,datasight.distribution,datasight.validation,datasight.audit_report- Data-quality commands — profiling, integrity checks, distribution statistics, validation rules, and the combined audit report.
datasight.explore- Ad-hoc file exploration for the
inspectcommand (CSV / Parquet without a project). datasight.generate- LLM-assisted project scaffolding (
datasight generate) — produces schema descriptions and example queries from raw data files. datasight.export- Converts a conversation session into a self-contained HTML page with inline CSS, Plotly charts, and syntax-highlighted SQL.
datasight.web.app- FastAPI application with SSE streaming, tool execution, and REST API endpoints for schema, query browsing, dashboards, and saved reports.
datasight.demo,datasight.demo_dsgrid_tempo,datasight.demo_time_validation- Demo-project generators — download EIA generation data, NREL TEMPO EV charging projections, and a synthetic time-validation dataset, respectively.
Schema context injection¶
The AI receives database context at startup, which is included in every system prompt:
flowchart LR
A[Auto-discovered schema<br>tables, columns, types, rows] --> D[System prompt]
B[schema_description.md<br>domain context] --> D
C[queries.yaml<br>few-shot examples] --> D
D --> E[LLM]
style A fill:#2e7ebb,stroke:#1a5c8a
style B fill:#8a7d55,stroke:#6b6040
style C fill:#8a7d55,stroke:#6b6040
style D fill:#15a8a8,stroke:#023d60
style E fill:#fe5d26,stroke:#c44a1e
The schema is introspected once at startup. The description and example queries are loaded from disk and formatted into the prompt. Together, they give the AI enough context to write accurate SQL without needing to explore the database itself.
Timeouts and retries¶
Query timeouts¶
All SQL runners enforce a configurable timeout on query execution
(default: 120 seconds). The timeout wraps the asyncio.to_thread call
with asyncio.wait_for, so it applies at the async layer regardless of the
database backend.
When a query times out, the runner raises QueryTimeoutError (a subclass
of QueryError). The agent loop catches this and returns a descriptive
error message to the LLM so it can retry with a simpler query.
The default is set by DEFAULT_QUERY_TIMEOUT in datasight.runner. Each
runner accepts a query_timeout parameter in its constructor to override
the default.
LLM timeouts¶
Both the Anthropic and OpenAI-compatible LLM clients pass a timeout to their
underlying SDK clients (default: 120 seconds, set by
DEFAULT_LLM_TIMEOUT in datasight.llm). This prevents indefinite hangs
when an API endpoint is unresponsive.
LLM retries¶
Transient LLM failures are retried automatically with exponential backoff:
- Max attempts: 3 (set by
DEFAULT_MAX_RETRIES) - Base delay: 1 second, doubled each retry (1s, 2s, 4s)
- Anthropic: retries on
APIConnectionErrorandRateLimitError(429). OtherAPIStatusErrorresponses (auth failures, validation errors) fail immediately. - OpenAI-compatible: retries on errors whose message contains
connection,timeout,rate,429,502,503, or504. All other errors fail immediately.
Client disconnect detection¶
The SSE chat generator checks request.is_disconnected() before each LLM
call and before each tool execution. When the user clicks Stop in the
web UI, the frontend aborts the fetch request, and the backend detects the
disconnect and stops processing — avoiding wasted LLM API calls and
database queries.
Web UI¶
The frontend is built with Svelte 5 + TypeScript + Tailwind CSS and uses
Vite as the build tool. Source lives in frontend/ and is compiled to static
assets served by FastAPI. Generated assets under src/datasight/web/static/
and src/datasight/web/templates/index.html are ignored by git; run
bash scripts/build-frontend.sh after a clean checkout or before packaging to
create them. It features:
- Sidebar with a table browser (expandable columns) and example queries that filter by selected table
- SSE streaming for real-time token-by-token responses
- Inline tool results — data tables and interactive Plotly charts rendered directly in the chat
- Markdown rendering with syntax-highlighted SQL code blocks