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]

Reply via email to