This is an automated email from the ASF dual-hosted git repository.

EnxDev pushed a commit to branch test/chatbot-local
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 4e8145f14be0b4723ea9c7a3a5ce059b3e417766
Author: Enzo Martellucci <[email protected]>
AuthorDate: Wed May 27 16:26:45 2026 +0200

    fix(extensions): match /sqllab path without trailing slash in derivePageType
    
    Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
 CHATBOT_SIP.md                                 | 585 +++++++++++++++++++++++++
 superset-frontend/src/core/navigation/index.ts |   2 +-
 2 files changed, 586 insertions(+), 1 deletion(-)

diff --git a/CHATBOT_SIP.md b/CHATBOT_SIP.md
new file mode 100644
index 00000000000..2da7db22861
--- /dev/null
+++ b/CHATBOT_SIP.md
@@ -0,0 +1,585 @@
+Chatbot extensions
+Author: Enzo Martellucci
+Team: Preset
+Status: Draft | Under Review | Completed
+Day: May, 2026
+
+1. Introduction
+   This document defines the extension point that allows an external chatbot 
to be embedded into the Superset UI.
+   1.1 Motivation
+   The goal is to let any community-built chatbot plug into Superset through 
the standard extension system using the same well-defined APIs already 
established for SQL Lab and the dashboard, without the chatbot reaching into 
Superset's internal Redux store or source modules.
+   1.2 Items Not Included
+   These are explicitly out of scope for this SIP and are either deferred to
+   another SIP or left to the extension implementation:
+
+- Frontend tool execution / agentic UI manipulation (the agent changing a
+  chart's config, a dashboard's layout, or the SQL editor's contents live on
+  screen) is out of scope and deferred to the _[SIP] Proposal for
+  integrating Superset client actions for AI agent applications_ (Justin Park).
+  This SIP defines how the chatbot is _mounted and given context_; that SIP
+  defines how the chatbot \*acts on the UI”.
+- The chatbot UI itself is out of scope. This SIP defines the host
+  contract; the look, feel, conversation model, streaming, and persistence are
+  entirely the extension's responsibility.
+- The MCP/LLM backend (server, model communication, tool selection) is out
+  of scope.
+
+2. Functional requirements
+   Registration & rendering
+   Extensions must be able to register a chatbot provider
+   Only one chatbot should be visible/active at a time (Singleton)
+   The chatbot should be visible across all supported application surfaces
+   Extensions must be able to render a fully custom chatbot UI
+   Content sharing APIs/hooks
+   The chatbot must receive contextual information about the current page:
+   Page type: `home`, `dashboard`, `chart`, `sqllab`, `dataset`
+   The current dashboard/chart data, the saved chart, the dashboard filters and
+   the dashboard-ui-control state
+   The chatbot must be notified when the page context changes (navigation 
entity change, title change) without polling.
+   The page context the chatbot receives must be host-derived and aligned with 
the current user's backend-authorized application view: the host computes it 
and exposes only what the current user is already authorized to see. The 
chatbot must not read the host's Redux store or other internal state to 
assemble context (the chatbot must not depend on internal frontend structure to 
assemble the context).
+   The chatbot must support conversation state/history (owned by the 
extension, never the host) 3) Administration
+   An admin can enable/disable the chatbot and when more than one chatbot 
extension is installed, choose which one is active
+
+2.1 Non-functional requirements
+Context sharing must respect Superset permission and security boundaries. The 
host must not expose entities, metadata, or datasource-derived context the 
current user is not authorized to access.
+Namespace APIs must remain decoupled from frontend implementation details and 
internal state-management architecture.
+The architecture must minimize impact on existing frontend performance. In 
particular, exposing page context must not force unnecessary host view 
re-renders.
+Context change notifications must not require polling.
+Third-party chatbot failures must not break the main application (fault 
isolation at the mount boundary).
+The integration system must remain extensible for future AI capabilities and 
additional application surfaces.
+The architecture should avoid hard dependency on any specific LLM vendor.
+The system must support incremental adoption and migration from existing 
integrations. 3. Proposed Extension Point
+3.1 Summary
+One extension point is proposed.
+Extension Point
+Contribution Area ID
+Registration API
+Cardinality
+Chatbot bubble
+`superset.chatbot`
+`views.registerView()`
+Exclusive (singleton)
+
+3.2 The Chatbot Bubble
+Contribution area: `superset.chatbot`
+The host renders a fixed mount point at the bottom-right corner of the 
Superset application shell. A chatbot extension registers a single React 
component into this slot, and the host renders it persistently across all 
routes (dashboard, SQL Lab, explore, datasets, etc.).
+New contribution scope — manifest schema change required the static 
contribution schema in `@apache-superset/core` is currently SQL-Lab-only: 
`ViewContributions` only accepts a `sqllab` scope keyed by `SqlLabLocation`.
+There is no app-shell-level scope, so `superset.chatbot` cannot be declared in 
`extension.json` today.
+
+This SIP therefore requires extending the manifest contribution schema to add 
an app-root scope (e.g. `app` / `appShell`) that can carry the 
`superset.chatbot` location.
+This is a schema change, not just a runtime `registerView()` call: both the
+static manifest declaration and the runtime registration must understand the 
new
+scope.
+The extension owns the bubble's collapsed appearance (the icon), its expanded 
appearance (the conversation panel), all animations, all open/close state, and 
all internal chatbot behavior.
+
+Singleton / exclusive behavior
+Unlike most contribution areas (which accept multiple contributions and render 
them as a list or stack), `superset.chatbot` is exclusive; only one chatbot 
extension can be active at a time.
+Two floating bubbles in the same corner would be confusing, and the 
conversation model is fundamentally singular.
+If no chatbot extension is installed, the corner stays empty and no bubble 
appears.
+If exactly one chatbot extension is installed, its component is mounted 
automatically.
+If multiple chatbot extensions are installed, the host resolves the conflict 
via a configurable policy (see Section 4, open questions).
+Note that the existing `registerView` / `getViews(location)` registry already 
supports "multiple contributions registered at a location, host chooses what to 
render".
+
+Singleton behavior is therefore a host-side selection policy at the 
`superset.chatbot` location, not a new registration primitive: the host 
enumerates the candidates registered at `superset.chatbot` and picks one 
according to the admin setting (see §2, Administration).
+
+`getViews` does not expose providers — by design there is a concrete 
limitation in the public API as it exists today. `getViews(location)` returns 
`View[] | undefined` — i.e. only the view descriptors (`id`, `name`, 
`description`).
+It does not return the `provider` functions that `registerView` was given.
+
+This is important to state precisely, because it is not an oversight to "fix" 
by widening `getViews`:
+
+- A `provider` is a function that constructs and returns a React element — 
calling it _renders_ the view. The view descriptor (`id`/`name`/`description`) 
is inert metadata; the provider is executable rendering logic.
+- `getViews` is a **public, extension-facing** API. If it returned providers, 
any extension could obtain and invoke another extension's provider directly — 
rendering a view outside the host's mount point, lifecycle, and fault-isolation 
boundary.
+  Keeping `getViews` descriptor-only is a deliberate boundary: the public 
surface lets extensions _
+  discover what is registered, but only the **host** can \_render_ what is 
registered (via the registration/mount path).
+- Consequence for the singleton picker: with the public API alone, the host 
can enumerate the registered chatbots but cannot obtain the provider needed to 
render the selected one. The picker described here therefore cannot be built on 
`getViews` as-is — and `getViews` should **not** be changed to expose 
providers, because that would dissolve the boundary above.
+
+Proposed solution: this SIP requires a **host-internal** resolution mechanism 
for exclusive locations — one that the host can use to obtain a provider, 
without that capability becoming part of the public extension-facing contract.
+
+const candidates = getViews('superset.chatbot');
+
+const selectedId =
+adminSettings.activeChatbotId ??
+candidates?.[0]?.id;
+
+const provider = getViewProvider(
+'superset.chatbot',
+selectedId,
+);
+
+return provider?.();
+
+`getViews()` remains a descriptor-only public API.
+The host uses an internal provider-resolution mechanism to obtain the 
renderable provider for the selected chatbot.
+
+Two acceptable forms:
+
+- (preferred) Add an internal host-only registry accessor that returns the
+  `provider` for a registered view id at a given location
+  `getViewProvider(location, id)`. `getViews` stays unchanged as the public, 
descriptor-only enumeration API; the provider accessor is host-internal and not 
part of the extension-facing contract.
+  The host renders the chatbot via `getViewProvider('superset.chatbot', 
selectedId)`.
+
+- (alternative) Treat `superset.chatbot` as a first-class exclusive 
contribution area in core with a dedicated `getActiveChatbot()` resolver that 
applies the
+  admin policy internally and returns a single renderable provider.
+
+The preferred form is the smaller change and keeps the public `getViews` 
semantics intact — `getViews` stays descriptor-only, and the 
provider-resolution capability lives entirely host-internal, preserving the 
boundary described above.
+Either way, this is a required core change and must be tracked as such in the 
Migration Plan (§6 P1); the SIP cannot rely on `getViews` alone.
+
+Positioning and lifecycle (host responsibilities)
+The host provides:
+Provide the APIs for the interactions
+Provide the context
+Mounting at the app root level, so the bubble persists across route changes.
+Eager loading of the chatbot bundle as part of the app shell startup, so the 
bubble is available immediately rather than appearing late.
+Disposable cleanup when the extension is deactivated, uninstalled, or replaced.
+Fixed positioning at the bottom-right corner of the viewport (24px margin from 
the edges).
+A managed z-index above dashboard content and the standard toast layer, below 
modal dialogs.
+Component contract (extension responsibilities)
+The registered component is the entire chatbot UI. It is responsible for:
+The collapsed bubble state (icon, optional notification badge, hover/focus 
states).
+The expanded panel state (header, conversation, composer, side panels).
+All open/close transitions, keyboard shortcuts (e.g., Cmd+K to open), and 
accessibility (focus trap, ARIA labels, screen reader support).
+All conversation state, message history, streaming, and persistence.
+All LLM communication and tool execution.
+Responsive behavior on narrow viewports (typically transitioning to a 
full-screen overlay below ~768px).
+The host does not inject styling or behavior into the registered component 
beyond what the standard namespaces provide.
+Registration example
+
+import { views } from '@apache-superset/core';
+import { ChatbotApp } from './ChatbotApp';
+
+export function activate(context: ExtensionContext) {
+const disposable = views.registerView(
+{
+id: 'superset.copilot',
+name: 'Superset Copilot',
+icon: 'Bubble',
+},
+'superset.chatbot',
+() => <ChatbotApp />,
+);
+
+context.subscriptions.push(disposable);
+}
+
+The extension registers a single renderable provider into the
+`superset.chatbot` contribution area.
+
+The host resolves exactly one active chatbot provider and mounts it
+at the application-shell level.
+
+The chatbot needs an icon:
+It identifies the chatbot in the admin "Default chatbot" picker (see §4) and 
in any contribution manifest listing, and it is the natural identity for the 
collapsed bubble.
+The current `View` interface in `@apache-superset/core` is `{ id, name, 
description? }` and has no `icon` field, so
+this SIP **proposes adding an `icon` field to the `View` descriptor**.
+The registration example above must be updated to pass one once the form below 
is decided.
+
+The remaining open concern is who owns the icon and whether it is mutable:
+
+- (a) Static descriptor icon. `icon` is a fixed field on the `View` 
descriptor, set once at `registerView()` time and never changed.
+  The host uses it for the admin picker / manifest listing.
+  The collapsed bubble shown in the corner is still rendered by the extension 
component itself (see Component contract), so a static descriptor icon and a 
richer extension-rendered bubble can coexist:
+  The descriptor icon identifies metadata, the bubble is a live UI.
+- (b) Runtime-updatable icon.
+  The chatbot owner can change its icon after registration — e.g. to reflect a 
notification/unread badge, a loading or "thinking" state, or dynamic rebranding.
+  This requires more than a descriptor field: either a mutable handle returned 
from `registerView()` (e.g.
+  `handle.setIcon(...)`) or a small chatbot-scoped API to update it.
+  It also raises the question of where that icon is consumed — the admin 
picker would show a point-in-time value, while the bubble already updates 
freely because the extension renders it.
+
+Recommendation: (a) for the descriptor `icon` — keep the registry field static 
and simple, since its only consumers are identity surfaces (picker, manifest) 
that do not need live updates.
+Dynamic icon states (notification badge, thinking
+indicator) belong to the collapsed bubble, which the extension component 
already owns and re-renders on its own; they do not need to flow through the 
host
+descriptor.
+If a concrete need emerges for the host to reflect a live chatbot icon outside 
the bubble, option (b) can be revisited in a follow-up rather than expanding 
`registerView` now.
+
+State APIs the chatbot uses
+The chatbot does not receive a dedicated host-managed state namespace.
+It reads host state through the same public namespaces available to any other 
extension:
+The table below distinguishes namespaces that **exist today** in 
`@apache-superset/core` from those this SIP **must add** as new work.
+
+Namespace
+Status
+Purpose for the chatbot
+sqlLab
+Exists today
+SQL Lab-specific APIs and state (`getCurrentTab()` and `onDidChange*` events)
+authentication
+Exists today
+Current user Auth/session CSRF token for same-session requests the chatbot 
uses the user's existing browser session; no separate token is issued or sent
+commands
+Exists today
+Host actions utilities
+dashboard
+NEW (added by this SIP)
+Dashboard-specific APIs and state (current dashboard, filters, 
dashboard-ui-control state)
+explore
+NEW (added by this SIP)
+Chart/explore-specific APIs and state (saved chart, current chart data)
+
+dataset
+NEW (added by this SIP)
+Dataset-specific APIs and state (current dataset); provides context for the 
`dataset` page type
+
+navigation
+NEW (added by this SIP)
+Route/page surface, including the `onDidChangePage` change event
+
+Namespaces this SIP must add — required core work, only `sqlLab`, 
`authentication`, `commands`, `menus` and `editors` currently exist in 
`@apache-superset/core` (`superset-frontend/packages/superset-core/src/`).
+
+There is no `dashboard`, `explore`, `dataset`, or `navigation` namespace 
today, and no
+`navigation.onDidChangePage` event, these do not exist yet — this SIP is what 
introduces them.
+Each new namespace must follow the established `sqlLab` shape: a
+state getter plus an `Event<T>` change subscription. Concretely, this SIP 
requires
+adding:
+
+- `dashboard` namespace — `dashboard.getCurrentDashboard()` plus change events 
for
+  the dashboard entity, its filters, and its UI-control state.
+- `explore` namespace — `explore.getCurrentChart()` (saved chart + current 
chart
+  data) plus a change event.
+- `navigation` namespace — a current-page getter (`pageType` + focused entity) 
and
+  the `navigation.onDidChangePage` event used for the without-polling 
notification
+  in §2.
+
+Page context
+Per-surface namespaces
+The chatbot does not interact directly with the host application's internal 
state management implementation.
+Instead, each application surface exposes a dedicated namespace that provides 
a stable, host-managed API for that surface.
+These namespaces expose curated API types rather than internal implementation 
details such as Redux slices or component-local state.
+The purpose of the namespace layer is to:
+provide a stable extension contract
+normalize surface-specific context
+avoid coupling extensions to host implementation details
+preserve compatibility across future frontend architecture changes
+For example, the host may evolve from Redux-based state management to another 
implementation in the future without requiring chatbot extensions to change, as 
long as the namespace contract remains stable.
+Each namespace exposes normalized semantic context aligned with the current 
user's backend-authorized application view
+
+Permission enforcement itself remains a backend concern — the namespace 
surfaces data that backend APIs have already scoped to the current user; it is 
not a security boundary of its own.
+
+Namespace composition model
+
+This SIP intentionally does not introduce a single aggregate context namespace.
+Instead:
+each surface exposes its own namespace
+chatbot extensions compose those already-safe pieces into a higher-level 
PageContext
+
+For example:
+
+const pageContext = {
+pageType: navigation.getPageType(),
+
+dashboard: dashboard.getCurrentDashboard(),
+
+sqlLab: sqlLab.getCurrentTab(),
+
+chart: explore.getCurrentChart(),
+
+dataset: dataset.getCurrentDataset(),
+};
+
+The extension-side adapter assembles normalized semantic context fragments.
+It does not derive or permission-filter entities itself.
+
+Namespace API shape
+Each namespace follows the established sqlLab API shape:
+synchronous state getter(s)
+Event<T>-style change subscriptions
+
+This allows chatbot extensions to react to page-context changes without 
polling.
+
+Example:
+
+const dashboardContext = dashboard.getCurrentDashboard();
+
+const disposable = dashboard.onDidChangeDashboard(nextDashboard => {
+chatbot.updateContext(nextDashboard);
+});
+
+The new namespaces follow the sqlLab namespace shape, but not necessarily its 
implementation model.
+
+Existing sqlLab namespace behavior
+The existing sqlLab namespace (superset-frontend/src/core/sqlLab/index.ts) 
already follows this general API shape today.
+
+Internally, the current implementation is a lightweight wrapper around Redux 
state (store.getState()), but that implementation detail is not part of the 
extension contract and should not be relied upon by extensions.
+
+This SIP extends the namespace-based model to additional application surfaces 
(dashboard, explore, dataset, navigation), standardizing semantic context 
normalization and a stable extension contract.
+
+Where permission enforcement happens
+Permission enforcement is a backend concern, and this is the normal Superset 
data flow: every frontend surface receives its state from backend APIs that 
already scope data to the current user's permissions. Frontend application 
state reflects backend-authorized API responses.
+
+`sqlLab` follows the standard Superset authorization model: backend APIs scope 
SQL Lab data to the current user's permissions before that data enters frontend 
application state (for example through `DatabaseFilter` applied in 
`DatabaseDAO.find_all()`).
+
+The `sqlLab` namespace therefore exposes a stable extension-facing API over 
already-authorized application state rather than enforcing authorization itself.
+
+The new namespaces follow the same principle: a namespace getter surfaces data 
from backend APIs that scope it to the current user — it is not itself a 
security boundary.
+
+Namespace normalization requirements
+
+Each namespace getter must:
+normalize application state into stable semantic extension-facing APIs
+expose context aligned with backend authorization semantics
+avoid exposing raw Redux structures or internal frontend implementation details
+provide a stable abstraction layer independent of frontend state-management 
implementation details
+
+For example, a native implementation such as:
+// ❌ Avoid exposing internal host state directly
+
+dashboard.getCurrentDashboard() {
+return store.getState().dashboard;
+}
+
+would incorrectly expose internal dashboard state directly to extensions and 
would tightly couple extensions to the host implementation.
+Instead, namespaces must expose normalized semantic context objects.
+
+// ✅ Expose a stable semantic contract
+dashboard.getCurrentDashboard() {
+return {
+id: dashboard.id,
+title: dashboard.title,
+filters: dashboard.filters,
+charts: dashboard.visibleCharts,
+uiState: dashboard.uiState,
+};
+}
+
+Per-surface context contracts
+Each namespace defines the semantic context contract exposed to extensions for 
that application surface.
+Namespaces:
+normalize frontend/application state into stable extension-facing APIs
+expose only context relevant to that surface
+avoid exposing unrelated implementation details or internal Redux structures
+preserve the permission semantics already enforced by the backend APIs serving 
that surface
+The namespace layer is therefore:
+an abstraction boundary
+a semantic normalization layer
+a stable extension contract
+It is not the primary authorization boundary; authorization remains enforced 
by backend APIs and Superset access-control mechanisms.
+dashboard
+dashboard.getCurrentDashboard() exposes:
+dashboard identity
+visible dashboard charts
+dashboard filter state
+dashboard UI-control state
+semantic dashboard context relevant to chatbot integrations
+The namespace should avoid exposing:
+unrelated internal dashboard rendering structures
+Redux-specific implementation details
+internal entity graphs not intended as extension contracts
+The dashboard context must remain aligned with the backend permission 
semantics of the dashboard APIs serving that surface.
+explore
+explore.getCurrentChart() exposes:
+current chart identity
+saved chart metadata
+transient chart-editing context
+semantic chart state relevant to the active Explore session
+The namespace should avoid exposing:
+unrelated chart entities
+unrelated datasource metadata
+frontend implementation-specific state structures
+
+dataset
+dataset.getCurrentDataset() exposes:
+dataset identity
+dataset metadata
+semantic dataset context relevant to the active page
+The namespace must remain aligned with backend-enforced dataset visibility and 
column-access semantics.
+navigation
+navigation exposes lightweight routing and surface context:
+page type
+focused entity identity
+page-change events
+It should not embed full entity payloads already exposed through other 
namespaces.
+
+Namespace compatibility
+Namespace contracts are part of the public Superset extension API surface and 
follow the normal compatibility guarantees of @apache-superset/core.
+Breaking changes to namespace contracts require standard deprecation and 
migration paths rather than silent behavioral changes.
+Extensions should depend only on the documented namespace contracts and not on 
internal frontend implementation details.
+
+Reusing existing permission logic
+The backend scoping required above (notably the dashboard-context endpoint) 
must reuse the host's existing permission checks — the same ChartFilter / 
datasource-access and can_access logic already used by the API layer — rather 
than reimplementing parallel filtering logic. This ensures the context the 
chatbot receives cannot drift from the backend authorization model.
+
+4. Design decision
+   Host-derived context vs. chatbot-assembled context
+   Multiple approaches were evaluated for how chatbot extensions receive page 
context.
+   Option 1 — chatbot-assembled context
+   The host exposes low-level primitives, routing information, and 
surface-specific state.
+   Each chatbot extension independently derives:
+   the current pageType
+   the focused entity
+   dashboard/chart/dataset context
+   its own higher-level context object
+   Option 2 — host-derived context (chosen)
+   The host computes normalized, permission-safe per-surface context through 
stable extension namespaces.
+   The chatbot consumes and composes those already-safe fragments into its own 
application-specific context.
+   This SIP chooses Option 2.
+   The primary reason is that context derivation, semantic normalization, and 
extension-facing context contracts should remain host-owned concerns rather 
than extension responsibilities.
+   Under Option 1, each chatbot extension independently derives semantic 
context from low-level frontend state and routing information.
+   While much of that state already originates from permission-checked backend 
APIs, the meaning and visibility semantics of that state vary by surface and 
are tightly coupled to internal frontend implementation details.
+   This creates several problems:
+   extensions become coupled to Redux structure and frontend internals
+   semantic context derivation becomes inconsistent across chatbot 
implementations
+   frontend architecture changes become breaking changes for extensions
+   permission-aware normalization logic becomes duplicated across extensions
+   Option 2 establishes a host-owned semantic normalization layer through 
stable extension namespaces.
+
+The host computes and normalizes the exposed context — sourced from 
permission-scoped backend APIs before it reaches the extension, providing a 
stable semantic contract across application surfaces. Permission enforcement 
stays on the backend (where it already lives); the namespace layer provides 
normalization and a stable contract, not a security boundary.
+
+Option 2 also provides:
+stable, typed extension-facing contracts
+semantic per-surface APIs
+decoupling from frontend implementation details
+compatibility with future frontend architecture changes
+For example, the host may evolve away from Redux-based state management in the 
future without requiring chatbot extensions to change, as long as the namespace 
contracts remain stable.
+
+Alternative evaluated: route-only / backend-derived context
+A third approach was also evaluated.
+Under this model:
+the frontend exposes only routing information (URL + route params)
+the chatbot backend or MCP server reconstructs context independently
+all entity resolution happens server-side through APIs
+This approach was rejected because it loses synchronization with unsaved 
frontend state and transient UI context.
+For example:
+unsaved chart edits in Explore
+dashboard filter changes not yet persisted
+temporary UI-control state
+selected charts/tabs
+local SQL editor changes
+draft configuration changes
+are all part of the user's active working context but may not yet exist in 
persisted backend state or be representable through the URL alone.
+A route-only model would therefore cause the chatbot context to drift from 
what the user is actively seeing and editing in the frontend.
+The chosen namespace-based model allows the chatbot to remain synchronized 
with live frontend state while still preserving stable, host-managed extension 
APIs.
+
+Current namespace behavior
+The existing sqlLab namespace already follows the general model introduced by 
this SIP:
+backend APIs enforce authorization and visibility
+frontend state reflects the user's authorized application state
+the namespace layer exposes stable semantic extension-facing APIs over that 
state
+This SIP extends that model to additional application surfaces such as:
+dashboard
+explore
+dataset
+navigation
+The new namespaces introduced by this SIP are intended to provide:
+stable semantic extension contracts
+normalized page-context APIs
+decoupling from frontend implementation details
+compatibility across future frontend architecture changes
+Some application surfaces may require dedicated context-oriented APIs to 
expose semantic chatbot context cleanly and consistently.
+For example, dashboard chatbot context requires a stable representation of:
+dashboard entities
+dashboard filter state
+dashboard UI-control state
+active chart context
+rather than direct exposure of internal frontend state structures.
+The namespace layer therefore acts as:
+a semantic normalization layer
+a stable extension abstraction boundary
+the public context-sharing API for chatbot extensions
+Extensions consume namespace APIs rather than internal host state or frontend 
implementation details.
+
+Tradeoffs accepted by this design
+The cost of Option 2 is accepted intentionally.
+The host must:
+build and maintain the context derivation layer
+expose new namespaces as additional application surfaces become extension-aware
+evolve namespace contracts over time
+Chatbot extensions are intentionally limited to the context exposed by those 
namespaces.
+If additional context is required, the namespace contract must evolve 
explicitly rather than allowing extensions to depend on arbitrary host state 
directly.
+That restriction is deliberate because it preserves:
+stable extension contracts
+implementation independence
+centralized semantic normalization
+consistent semantic context contracts aligned with backend authorization 
semantics
+
+Extension-owned conversation state
+All conversation state, message history, tool-call state, streaming buffers, 
and persistence remain entirely owned by the chatbot extension.
+They are never reflected in:
+the host Redux store
+host-managed frontend state
+shared application reducers
+host persistence layers
+The host owns page-context exposure only.
+The chatbot owns all conversational runtime state.
+
+Design considerations
+The bubble must not occlude critical dashboard content. The host guarantees a 
safe zone in the corner, but the extension is responsible for not extending the 
expanded panel in a way that covers important UI on smaller viewports.
+The host does not animate the bubble or panel — animation is the extension's 
responsibility, so each chatbot can have its own brand identity.
+The chatbot extension is initialized as part of the application shell 
lifecycle so the bubble is available consistently across routes and can be 
invoked immediately by the user. Since extensions are delivered through Module 
Federation, chatbot implementations should still be mindful of remote bundle 
size and avoid expensive synchronous initialization work during activation or 
first render.
+If the chatbot extension fails to load (Module Federation fetch error, runtime 
exception during activation), the host logs the error, shows a notification and 
leaves the corner empty rather than displaying a broken placeholder.
+
+5. Open Questions
+
+Per-page visibility. Should the chatbot extension declare which pages it's 
relevant for (e.g., "only show on dashboard and SQL Lab")?
+Two options:
+Extension hides itself via navigation.onDidChangePage events.
+Extension declares page scopes in extension.json and the host enforces them.
+The first is simpler and keeps the host policy-free; the second is more 
discoverable.
+
+Generalizing the slot. Should superset.chatbot be a chatbot-specific area, or 
should it generalize to something like app.floating-action that could accept 
multiple stacked widgets (chatbot, tour guide, notification widget)?
+My recommendation is to keep it chatbot-specific for now. If other 
floating-widget use cases emerge, introduce a separate contribution area rather 
than overloading this one.
+
+6. Related Documents
+   Contribution types
+   Client actions
+
+7. Migration Plan
+   Base branch chat-prototype
+
+Required core changes
+The following are net-new additions to `@apache-superset/core` and the host 
that
+this SIP depends on; they do not exist today and must land for the chatbot
+extension point to be implementable:
+
+- New `dashboard` namespace — current-dashboard getter plus change events for 
the
+  dashboard entity, its filters, and its UI-control state. Serves the 
`dashboard`
+  page type.
+
+- New `explore` namespace — current-chart getter (saved chart + chart data) 
plus a
+  change event. Serves the `chart` page type (Explore view).
+- New `dataset` namespace — current-dataset getter plus a change event. Serves 
the
+  `dataset` page type.
+
+- New `navigation` namespace — current-page getter and the `onDidChangePage` 
event.
+- Semantic normalization and stable extension-facing contracts for the new
+  `dashboard`, `explore`, `dataset`, and `navigation` namespaces.
+
+  The namespace layer must expose curated semantic context APIs over
+  backend-authorized application state while avoiding direct exposure of
+  Redux structures or other frontend implementation details.
+
+  This work also includes the permission-scoped dashboard-context backend
+  endpoint required to align dashboard chatbot context with existing
+  Superset authorization semantics (§2.1).
+
+- New app-root contribution scope in the manifest schema (`ViewContributions`) 
so
+  `superset.chatbot` can be declared in `extension.json` (currently 
SQL-Lab-only).
+- Host-side exclusive-location resolution — an internal provider accessor (e.g.
+  `getViewProvider(location, id)`) or a dedicated `getActiveChatbot()` 
resolver, so
+  the host can render the selected singleton; `getViews` returns descriptors 
only.
+- Admin setting for singleton conflict resolution (the "Default chatbot" 
picker,
+  §4 option (c)).
+- New `icon` field on the `View` descriptor interface (§3.2) — required for the
+  admin picker and manifest listing.
+  Open decision before implementation: whether the field is static (set at 
`registerView()`) or runtime-updatable by the chatbot owner; this SIP 
recommends static.
+
+8. Phases
+   The required core changes above are sequenced into the following phases. 
Tickets
+   must reference these phase numbers (P1–P4) — there is no other phase 
numbering for
+   this SIP.
+
+- P1 — Mount point & registration. The `superset.chatbot` contribution area, 
the
+  app-root contribution scope in `ViewContributions`, host-side 
exclusive-location
+  resolution (`getViewProvider` / `getActiveChatbot`), eager mount at the app
+  shell, fault isolation at the mount boundary, and the extension
+  lifecycle/teardown contract — the deactivate/uninstall/replace **signal** 
and the
+  `Disposable` cleanup drives.
+  Open item in P1: whether teardown needs an
+  async-aware hook (e.g. `deactivate(): Promise<void>`) in addition to the
+  synchronous `Disposable`, since `Disposable.dispose()` is not awaited.
+- P2 — Admin & singleton selection. The `icon` field on `View`, the "Default
+  chatbot" admin setting, and admin enable/disable behavior (§2, §4).
+- P3 — Context namespaces. The new `dashboard`, `explore`, `dataset`, and
+  `navigation` namespaces (semantic normalization + stable contract), plus the
+  permission-scoped dashboard-context endpoint that closes the §2.1 gap on the
+  backend. This is the critical path for page-context tickets.
+
+- P4 — Navigation/client-action commands. Out of this SIP's scope — owned by 
the
+  client-actions SIP (Justin Park).
diff --git a/superset-frontend/src/core/navigation/index.ts 
b/superset-frontend/src/core/navigation/index.ts
index 96e87754f9e..01859ba6fed 100644
--- a/superset-frontend/src/core/navigation/index.ts
+++ b/superset-frontend/src/core/navigation/index.ts
@@ -36,7 +36,7 @@ function derivePageType(pathname: string): PageType {
   if (pathname.startsWith('/explore/')) return 'explore';
   if (pathname.startsWith('/superset/explore/')) return 'explore';
   if (pathname.startsWith('/chart/add')) return 'explore';
-  if (pathname.startsWith('/sqllab/')) return 'sqllab';
+  if (pathname === '/sqllab' || pathname.startsWith('/sqllab/')) return 
'sqllab';
   if (pathname.startsWith('/dataset/')) return 'dataset';
   if (pathname.startsWith('/superset/welcome/')) return 'home';
   return 'other';


Reply via email to