bsovran opened a new issue, #42806: URL: https://github.com/apache/superset/issues/42806
*Please make sure you are familiar with the SIP process documented* [here](https://github.com/apache/superset/issues/5602). ## [SIP] Proposal for an opt-in AI assistant for natural-language data questions ### Motivation Answering a question about a Superset chart today means leaving the chart. A user looking at a number that seems wrong has to work out which dataset feeds it, open SQL Lab, reconstruct the chart's filters and time grain by hand, and only then ask their actual question. The context is all on screen and none of it is available to them in a form they can query. Several deployments have built assistants to close this gap, and they converge on the same shape: a side panel that knows what the user is looking at, can run read-only SQL, and shows its work. They also converge on the same problems, which is what makes this worth standardising rather than leaving to plugins: 1. **Grounding.** An assistant that cannot see the active dashboard filters answers a different question than the one asked, and does so confidently. Getting this right needs access to Redux state that only first-party code has. 2. **Permissions.** An assistant that queries on the user's behalf must not become a way to read past that user's grants. This belongs in core, next to the existing security model, not in a plugin that has to re-derive it. 3. **Prompt drift.** A prompt that starts generic accumulates one deployment's table names, hostnames and business metrics. Without a structural check this is invisible until the assistant confidently emits another warehouse's SQL dialect. 4. **Vendor lock-in.** Superset should not name a model vendor. Deployments run private gateways, self-hosted models and different providers, and that has to be configuration rather than a fork. The goal is a seam other people can build on, with the security and grounding parts solved once — not a particular model or vendor in core. ### Proposed Change A side panel, off by default behind the `AI_ASSISTANT` feature flag, registered through the existing `registerChat` extension point in `@apache-superset/core`. When enabled, a user on a dashboard, chart or SQL Lab tab can ask a question and get an answer grounded in that page. Five layers, each replaceable by configuration: **Provider seam** (`AI_LLM_PROVIDER_CLASS`) — the only place an API shape, base URL, credential or model identifier may appear. Core never names a vendor: callers request a capability tier (`default`, `fast`, `reasoning`) and the provider maps it to a model. Two providers ship behind optional extras (OpenAI-compatible, Anthropic); a private gateway is a `base_url` change. **Agent runtime** (`AI_AGENT_RUNTIME_CLASS`) — the default is a tool-use loop that alternates model and tool calls until the model stops. It streams answer text as the model produces it and emits each completed step as a structured record. Swapping in a different agent engine is a config change. **Tools** — built on the existing `superset/mcp_service` command and DAO layers rather than a parallel implementation. Each agent profile declares an allowlist, and a policy chain enforces invariants independently of the prompt: generated SQL is parsed with `SQLScript.has_mutation()` and refused if it writes. Deployments can attach their own MCP servers (`AI_AGENT_MCP_SERVERS`) without patching core. **Prompt assembly** — a system prompt is a list of typed sections, each carrying its layer and its author. Assembly *fails* rather than ships when a core-sourced section contains an absolute URL, a schema-qualified table, or a reference to a tool that does not exist. This is the structural answer to problem 3 above; convention alone does not hold. **Storage** — threads, messages and feedback in the metadata database. The assistant message row is written *before* inference starts, so a client that reconnects has something to attach to, and a run that fails still leaves a readable transcript rather than an empty bubble. Two execution modes. Inline (default) runs the turn inside the streaming request — simple, no extra infrastructure. Worker mode (`AI_ASSISTANT_EXECUTION_MODE = "worker"`) runs it on Celery and publishes to a Redis-backed event bus, which decouples the run from any reader so a client can reconnect to one already in progress; the stream endpoint becomes a pure subscriber. On the UI: reasoning and each tool call stream in as they happen, expandable per step to show the arguments, the exact SQL and the rows returned. The page context the assistant was given is shown alongside, because an answer that looks wrong is usually an answer about a different slice of data than the reader assumed. **Security.** The API is `@protect()`-ed on a `BaseSupersetApi` subclass, so Flask-AppBuilder authorization runs. `AIAssistant` is added to `ALPHA_ONLY_VIEW_MENUS`, keeping it out of Gamma and therefore Public. Ownership is enforced again in the command and DAO layers, so a thread UUID is never on its own a capability. Tools run as the requesting user — in worker mode via `override_user` — so a question cannot read past that user's grants. Tool output is framed as untrusted data in the prompt, never instruction. ### New or Changed Public Interfaces **REST — a new `/api/v1/ai` resource, 12 routes:** | Route | Method | Purpose | |---|---|---| | `/agent/` | GET | Agent profiles the user may select | | `/model/` | GET | Configured model identifiers | | `/thread/` | POST, GET | Create / list conversations | | `/thread/<uuid>` | GET, PUT, DELETE | Read / rename / delete | | `/thread/<uuid>/message` | POST | Submit a turn (returns `202` + `run_id`) | | `/thread/<uuid>/stream` | GET | SSE frames for a run | | `/thread/<uuid>/cancel` | POST | Cooperative stop | | `/feedback` | POST | Rate an answer | | `/suggested-prompts` | POST | Opening suggestions (opt-in) | **Models:** three new tables — `ai_chat_threads`, `ai_chat_messages`, `ai_chat_feedback`. No existing table changes. **Config:** 34 new `AI_*` keys, all with defaults; nothing is required unless the flag is on. Notable extension points: `AI_LLM_PROVIDER_CLASS`, `AI_AGENT_RUNTIME_CLASS`, `AI_AGENT_PROFILES`, `AI_AGENT_TOOL_POLICIES`, `AI_KNOWLEDGE_PROVIDERS`, `AI_TELEMETRY`, `AI_SYSTEM_PROMPT_MUTATOR`, `AI_AGENT_MCP_SERVERS`. **Frontend:** a new `src/features/ai` feature registering itself as a chat provider. No existing component changes; the panel does not render when the flag is off, nor in `?standalone=` or `/embedded/` renders. **Observability:** `AI_TELEMETRY` takes a list of sinks, so Braintrust, LangSmith or an OSS alternative can be attached without core knowing about any of them. Content redaction is on by default. ### New dependencies All optional extras — **none added to base requirements**. A deployment with the flag off installs nothing new. | Extra | Package | License | Notes | |---|---|---|---| | `ai-openai` | `openai>=1.60.0,<2` | Apache-2.0 | Actively maintained; also serves any OpenAI-compatible gateway | | `ai-anthropic` | `anthropic>=0.40.0,<1` | MIT | Actively maintained | | `ai-mcp` | `mcp>=1.24.0,<2` | MIT | Only for attaching external MCP servers | Both SDKs are imported inside the functions that need them, never at module scope, so a deployment without the extra still starts every Superset process. Worker mode additionally needs Celery and Redis, both of which Superset already supports. Inline mode needs neither. ### Migration Plan and Compatibility One additive migration creating three tables. No existing table is altered, no data is backfilled, and `downgrade()` drops the three tables — verified reversible, and verified as part of a fresh install from an empty database. Fully backward compatible. With `AI_ASSISTANT` off — the default — no route is registered, no panel renders, no dependency is required, and the only footprint is three empty tables. There are no stored URLs to update. `AI_ASSISTANT_MESSAGE_RETENTION_DAYS` provides pruning for deployments that do not want to keep transcripts indefinitely. ### Rejected Alternatives **A plugin or extension rather than core.** Tried first, and it fails on the two things that matter most. Grounding needs Redux state that only first-party code can read, and permission enforcement would have to be re-derived outside the security model — exactly where it should not live. The extension points here are the compromise: the seams are in core, the model and the vendor are not. **Naming a model or vendor in core.** Rejected outright. Deployments run private gateways and self-hosted models, and a default vendor in core is a default a deployment cannot change without forking. **Free-text prompt constants.** What most implementations do, and it drifts: deployment specifics accumulate in layers documented as generic, and stale tool names get patched by string replacement against another module's constant. Typed sections that fail assembly turn both into errors at import time. **Trusting the prompt for read-only enforcement.** Rejected. "Only write SELECT statements" is an instruction, and instructions are not a security boundary — particularly when tool output can carry text an attacker authored. SQL is parsed and refused independently of what the model was told. **Worker execution as the default.** Rejected for the initial version. It is required for reconnection, but it makes Celery and Redis mandatory for a feature many will want to try with neither. Inline is the default; worker is one config key away. **Always-on data catalogue in the prompt.** Rejected. Every turn would pay for every domain whether or not the question touches it, and the prompt grows without bound as a deployment documents more of its warehouse. A compact index in the prompt with bodies behind a tool keeps it bounded. --- Ref: https://github.com/apache/superset/pull/42805 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
