udi-yac 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -63
- package/dist/{ce-entry-BN36qTNy.js → ce-entry-2FSWiz2q.js} +20397 -19941
- package/dist/index.d.ts +1610 -0
- package/dist/{rolldown-runtime-CWhphoD1.js → rolldown-runtime-DArdT4gl.js} +2 -2
- package/dist/udi-yac.css +1 -1
- package/dist/udi-yac.js +30462 -25773
- package/package.json +23 -23
- package/dist/favicon.svg +0 -22
- package/dist/icons.svg +0 -24
- package/dist/src/app/ErrorBoundary.d.ts +0 -19
- package/dist/src/app/UDIChat.d.ts +0 -3
- package/dist/src/app/UDIChatConfig.d.ts +0 -104
- package/dist/src/app/UDIChatContext.d.ts +0 -57
- package/dist/src/app/snapshotRegistry.d.ts +0 -19
- package/dist/src/app/snapshotRegistry.test.d.ts +0 -1
- package/dist/src/app/validateConfig.d.ts +0 -2
- package/dist/src/app/validateConfig.test.d.ts +0 -1
- package/dist/src/components/FieldTooltipContent.d.ts +0 -12
- package/dist/src/components/MarkdownText.d.ts +0 -6
- package/dist/src/components/ui/accordion.d.ts +0 -13
- package/dist/src/components/ui/badge.d.ts +0 -7
- package/dist/src/components/ui/button.d.ts +0 -9
- package/dist/src/components/ui/card.d.ts +0 -11
- package/dist/src/components/ui/checkbox.d.ts +0 -3
- package/dist/src/components/ui/dialog.d.ts +0 -17
- package/dist/src/components/ui/dropdown-menu.d.ts +0 -29
- package/dist/src/components/ui/input.d.ts +0 -3
- package/dist/src/components/ui/label.d.ts +0 -3
- package/dist/src/components/ui/popover.d.ts +0 -9
- package/dist/src/components/ui/scroll-area.d.ts +0 -8
- package/dist/src/components/ui/select.d.ts +0 -15
- package/dist/src/components/ui/separator.d.ts +0 -3
- package/dist/src/components/ui/slider.d.ts +0 -4
- package/dist/src/components/ui/switch.d.ts +0 -5
- package/dist/src/components/ui/tabs.d.ts +0 -10
- package/dist/src/components/ui/textarea.d.ts +0 -3
- package/dist/src/components/ui/tooltip.d.ts +0 -6
- package/dist/src/features/chat/api/completions.d.ts +0 -27
- package/dist/src/features/chat/components/ApiKeyInput.d.ts +0 -5
- package/dist/src/features/chat/components/BrushFilterWidgets.d.ts +0 -8
- package/dist/src/features/chat/components/ChatHeaderBar.d.ts +0 -20
- package/dist/src/features/chat/components/ChatInput.d.ts +0 -7
- package/dist/src/features/chat/components/ChatPanel.d.ts +0 -18
- package/dist/src/features/chat/components/ClosedVisualizationsPanel.d.ts +0 -6
- package/dist/src/features/chat/components/ConversationList.d.ts +0 -1
- package/dist/src/features/chat/components/DebugToggleSection.d.ts +0 -13
- package/dist/src/features/chat/components/InlineExamplePrompts.d.ts +0 -13
- package/dist/src/features/chat/components/MemoryBankButton.d.ts +0 -6
- package/dist/src/features/chat/components/MessageBubble.d.ts +0 -8
- package/dist/src/features/chat/components/MessageList.d.ts +0 -7
- package/dist/src/features/chat/components/SessionStatusDialog.d.ts +0 -13
- package/dist/src/features/chat/hooks/useApiKey.d.ts +0 -24
- package/dist/src/features/chat/hooks/useChatApi.d.ts +0 -26
- package/dist/src/features/chat/hooks/useDebugExports.d.ts +0 -11
- package/dist/src/features/chat/hooks/useExamplePrompts.d.ts +0 -7
- package/dist/src/features/chat/hooks/useMessageListScroll.d.ts +0 -20
- package/dist/src/features/chat/hooks/useResetHandlers.d.ts +0 -8
- package/dist/src/features/chat/index.d.ts +0 -9
- package/dist/src/features/chat/stores/conversationStore.d.ts +0 -34
- package/dist/src/features/chat/stores/conversationStore.test.d.ts +0 -1
- package/dist/src/features/dashboard/components/DashboardCard.d.ts +0 -9
- package/dist/src/features/dashboard/components/DashboardGrid.d.ts +0 -6
- package/dist/src/features/dashboard/components/DashboardPanel.d.ts +0 -1
- package/dist/src/features/dashboard/components/DataCounts.d.ts +0 -1
- package/dist/src/features/dashboard/components/DownloadButton.d.ts +0 -1
- package/dist/src/features/dashboard/components/FilterToolbar.d.ts +0 -1
- package/dist/src/features/dashboard/components/GridSettingsButton.d.ts +0 -1
- package/dist/src/features/dashboard/components/ScrollAffordances.d.ts +0 -15
- package/dist/src/features/dashboard/components/SessionImportExportButton.d.ts +0 -1
- package/dist/src/features/dashboard/components/VizTweakComponent.d.ts +0 -8
- package/dist/src/features/dashboard/components/VizTweakComponent.types.d.ts +0 -29
- package/dist/src/features/dashboard/components/WelcomeSplash.d.ts +0 -1
- package/dist/src/features/dashboard/hooks/useBrushFilters.d.ts +0 -45
- package/dist/src/features/dashboard/hooks/useBrushFilters.test.d.ts +0 -1
- package/dist/src/features/dashboard/hooks/useLayoutPersistence.d.ts +0 -1
- package/dist/src/features/dashboard/index.d.ts +0 -11
- package/dist/src/features/dashboard/stores/dashboardStore.d.ts +0 -110
- package/dist/src/features/dashboard/stores/dashboardStore.test.d.ts +0 -1
- package/dist/src/features/dashboard/stores/dataFiltersStore.d.ts +0 -34
- package/dist/src/features/dashboard/stores/dataFiltersStore.test.d.ts +0 -1
- package/dist/src/features/dashboard/stores/memoryBankStore.d.ts +0 -8
- package/dist/src/features/dashboard/stores/memoryBankStore.test.d.ts +0 -1
- package/dist/src/features/dashboard/types.d.ts +0 -50
- package/dist/src/features/dashboard/utils/dashboardSerialization.d.ts +0 -49
- package/dist/src/features/dashboard/utils/dashboardSerialization.test.d.ts +0 -1
- package/dist/src/features/dashboard/utils/gridDefaults.d.ts +0 -17
- package/dist/src/features/dashboard/utils/gridPacking.d.ts +0 -56
- package/dist/src/features/dashboard/utils/gridPacking.test.d.ts +0 -1
- package/dist/src/features/dashboard/utils/initialCardSize.d.ts +0 -27
- package/dist/src/features/dashboard/utils/relevantTableMapping.d.ts +0 -21
- package/dist/src/features/dashboard/utils/relevantTableMapping.test.d.ts +0 -1
- package/dist/src/features/dashboard/utils/tweakability.d.ts +0 -37
- package/dist/src/features/data-package/components/DataOverviewPanel.d.ts +0 -10
- package/dist/src/features/data-package/components/DataOverviewPanel.test.d.ts +0 -1
- package/dist/src/features/data-package/components/EntityOverview.d.ts +0 -10
- package/dist/src/features/data-package/index.d.ts +0 -8
- package/dist/src/features/data-package/stores/dataPackageStore.d.ts +0 -39
- package/dist/src/features/data-package/stores/dataPackageStore.test.d.ts +0 -1
- package/dist/src/features/data-package/utils/entityOverview.d.ts +0 -136
- package/dist/src/features/data-package/utils/entityOverview.test.d.ts +0 -1
- package/dist/src/features/data-package/utils/joinDataPath.d.ts +0 -7
- package/dist/src/features/data-package/utils/joinDataPath.test.d.ts +0 -1
- package/dist/src/features/data-package/utils/structuredTextParser.d.ts +0 -14
- package/dist/src/features/data-package/utils/structuredTextParser.test.d.ts +0 -1
- package/dist/src/features/tool-calls/components/ClarifyVariable.d.ts +0 -6
- package/dist/src/features/tool-calls/components/FieldListChip.d.ts +0 -13
- package/dist/src/features/tool-calls/components/FilterComponent.d.ts +0 -9
- package/dist/src/features/tool-calls/components/FreeTextExplain.d.ts +0 -2
- package/dist/src/features/tool-calls/components/IntervalFilterComponent.d.ts +0 -16
- package/dist/src/features/tool-calls/components/PointFilterComponent.d.ts +0 -14
- package/dist/src/features/tool-calls/components/PointFilterComponent.test.d.ts +0 -1
- package/dist/src/features/tool-calls/components/RebuffNotice.d.ts +0 -5
- package/dist/src/features/tool-calls/components/ToolCallRenderer.d.ts +0 -11
- package/dist/src/features/tool-calls/components/VisualizationCard.d.ts +0 -10
- package/dist/src/features/tool-calls/index.d.ts +0 -8
- package/dist/src/features/tool-calls/types.d.ts +0 -60
- package/dist/src/index.d.ts +0 -6
- package/dist/src/lib/chatRoot.d.ts +0 -7
- package/dist/src/lib/utils.d.ts +0 -8
- package/dist/src/stores/globalStore.d.ts +0 -16
- package/dist/src/stores/globalStore.test.d.ts +0 -1
- package/dist/src/test/setup.d.ts +0 -0
- package/dist/src/types/dataPackage.d.ts +0 -50
- package/dist/src/types/messages.d.ts +0 -24
- package/dist/src/types/usage.d.ts +0 -18
- package/dist/src/utils/entityIcons.d.ts +0 -10
- package/dist/src/utils/highlightMatch.d.ts +0 -7
- package/dist/src/utils/httpError.d.ts +0 -11
- package/dist/src/utils/httpError.test.d.ts +0 -1
- package/dist/src/utils/specMutations.d.ts +0 -101
- package/dist/src/utils/specMutations.test.d.ts +0 -1
package/README.md
CHANGED
|
@@ -18,20 +18,26 @@ pnpm test:watch # vitest in watch mode
|
|
|
18
18
|
|
|
19
19
|
### Standalone app config (env vars)
|
|
20
20
|
|
|
21
|
-
The standalone `App.tsx` reads these Vite env vars
|
|
21
|
+
The standalone `App.tsx` reads these Vite env vars. Copy `.env.example` to `.env.local` to override locally — all are optional.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
| -------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
25
|
-
| `VITE_UDI_API_BASE_URL` | `http://localhost:8007` | UDIAgent FastAPI server URL |
|
|
26
|
-
| `VITE_UDI_DATA_PACKAGE` | (unset → inline HuBMAP API package from `src/data/hubmapRemote.ts`) | Optional path/URL to a `datapackage_udi.json`. Overrides the inline default when set. |
|
|
27
|
-
| `VITE_UDI_REQUIRE_API_KEY` | `true` | Set to `false` to skip the in-app OpenAI key prompt |
|
|
28
|
-
| `VITE_UDI_MODEL` | (unset) | Optional LLM model override |
|
|
23
|
+
Each is described once in [`src/app/envVars.ts`](src/app/envVars.ts); this table, `.env.example`, and `src/env.d.ts` are generated from it by `node scripts/gen-chat-env-docs.mjs`, and CI fails if they drift.
|
|
29
24
|
|
|
30
|
-
|
|
25
|
+
<!-- BEGIN generated: env vars (scripts/gen-chat-env-docs.mjs) -->
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
| Variable | Default | Description |
|
|
28
|
+
| -------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
29
|
+
| `VITE_UDI_API_BASE_URL` | `http://localhost:8007` | UDIAgent FastAPI server URL. May also be a same-origin path (e.g. `/api/yac`) when the chat sits behind the host app’s reverse proxy. |
|
|
30
|
+
| `VITE_UDI_DATA_PACKAGE` | `/data/hubmap/datapackage.json` | Path or URL to a `datapackage.json`. Defaults to the bundled HuBMAP snapshot synced from `sample-data/`. Ignored when `VITE_UDI_REMOTE_PACKAGE` is set. |
|
|
31
|
+
| `VITE_UDI_REMOTE_PACKAGE` | — | Name of a server-side data package (configured on the agent via `UDI_QUERY_BACKENDS`). When set, no CSVs load in the browser: metadata comes from `/v1/yac/metadata` and queries go to `/v1/yac/query`. Takes precedence over `VITE_UDI_DATA_PACKAGE`. |
|
|
32
|
+
| `VITE_UDI_REQUIRE_API_KEY` | `true` | Prompt the user for an OpenAI key in the UI. Defaults to `true`, but `.env.example` ships `false` because local dev runs against an agent that has its own `OPENAI_API_KEY`. |
|
|
33
|
+
| `VITE_UDI_MODEL` | — | LLM model override. Sent **only when the user supplies their own OpenAI key** — the agent honors a requested model only alongside an `X-OpenAI-Key`, so whoever pays for the tokens picks the model. Otherwise the agent’s `GPT_MODEL_NAME` applies. |
|
|
34
|
+
| `VITE_UDI_READ_ONLY` | `false` | Start in read-only mode: the chat pane and the dashboard’s top bar (counts, grid settings, session import/export, downloads) are hidden, as is every editing control on the cards, while brushing, filters and the table toggle stay. `true` leaves an Explore Data button over the dashboard that opens the chat; `locked` removes it. With the chat hidden there is nothing to build a dashboard from, so pair this with `VITE_UDI_INITIAL_SESSION`. |
|
|
35
|
+
| `VITE_UDI_INITIAL_SESSION` | — | Path or URL to a session export — the JSON written by the dashboard’s `Session → Export session` action. Fetched at startup and used to seed the dashboard and the conversation behind it. Anything under `public/` is served from the site root, so `public/demo-session.json` is `/demo-session.json`. A malformed file fails loudly through the ErrorBoundary; a missing one only logs, and the dashboard starts empty. |
|
|
36
|
+
| `VITE_BASE` | `/` | Public base path for the built SPA (read in `vite.config.ts`, build-time only). The library build always uses `./`. |
|
|
37
|
+
|
|
38
|
+
<!-- END generated: env vars -->
|
|
39
|
+
|
|
40
|
+
To switch between bundled data packages and server-side (remote) mode, use `node scripts/set-chat-data-source.mjs <package> [--remote]` rather than editing `.env.local` by hand — the repo-root README and `dev/duckdb/README.md` cover the full flow.
|
|
35
41
|
|
|
36
42
|
> **Note on `build` vs `build:lib`**: `pnpm build` produces a deployable standalone SPA — this is the default so CI/deploy pipelines behave as expected. To build the publishable library bundle (the `UDIChat` React component), use `pnpm build:lib`, which invokes `vite build --mode lib` and emits both JS and `.d.ts` files under `dist/`.
|
|
37
43
|
|
|
@@ -44,14 +50,28 @@ VITE_UDI_DATA_PACKAGE=/data/hubmap_2025-05-05/datapackage_udi.json
|
|
|
44
50
|
- **Arquero** for client-side data loading and domain computation
|
|
45
51
|
- **Vite** for dev server and library builds
|
|
46
52
|
|
|
53
|
+
### Agent version pairing
|
|
54
|
+
|
|
55
|
+
`udi-yac` and `udiagent` share a private contract beyond the HTTP shape: the
|
|
56
|
+
agent sends a chart's title and summary **tokenized** (`{enc:x}`, `{ent:entity3}`,
|
|
57
|
+
`{col:entity2_field}`, …) and this package resolves them against the spec, the
|
|
58
|
+
template's bindings and the data package's display labels. The vocabulary grows
|
|
59
|
+
as templates need new wording, so **run an agent no newer than your `udi-yac`**.
|
|
60
|
+
|
|
61
|
+
A newer client against an older agent is always fine. The other way round, a
|
|
62
|
+
token this version does not know makes the wording fall back to a title derived
|
|
63
|
+
from the spec — readable, just less specific. Builds from before that fallback
|
|
64
|
+
landed print the unknown token instead, so an old enough `udi-yac` shows
|
|
65
|
+
`{col:entity2_field}` in a card title where a current one degrades cleanly.
|
|
66
|
+
|
|
47
67
|
## Architecture
|
|
48
68
|
|
|
49
69
|
### Dual Build Modes
|
|
50
70
|
|
|
51
71
|
The project builds as both a **library** and a **standalone app**:
|
|
52
72
|
|
|
53
|
-
- **Library** (`pnpm build`): Exports the `UDIChat`
|
|
54
|
-
- **Standalone** (`pnpm build
|
|
73
|
+
- **Library** (`pnpm build:lib`): Exports the `UDIChat` / `UDIDashboard` components and the `UDIChatConfig` type. Consumers provide React and render `<UDIChat>` with configuration props.
|
|
74
|
+
- **Standalone** (`pnpm build`): Builds `App.tsx` as a full SPA with dev defaults.
|
|
55
75
|
|
|
56
76
|
### Library Usage
|
|
57
77
|
|
|
@@ -75,32 +95,136 @@ Embedding in another app? Two things worth knowing up front:
|
|
|
75
95
|
|
|
76
96
|
- **`apiBaseUrl` accepts a same-origin path** (`/api/yac`), so agent traffic can go
|
|
77
97
|
through your own reverse proxy and let your server attach auth — no CORS, no token in
|
|
78
|
-
the browser. `authToken`
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
the browser. Leave `authToken` unset and the chat sends no `Authorization` header at
|
|
99
|
+
all, so there is nothing for the proxy to strip. This is the only workable shape when
|
|
100
|
+
your portal keeps its identity-provider token server-side; forward the body, the
|
|
101
|
+
`X-Conversation-Id` and `X-OpenAI-Key` request headers, and the `X-Usage-*` response
|
|
102
|
+
headers.
|
|
103
|
+
- **Every style is scoped.** Design tokens and element resets are confined to the root
|
|
104
|
+
element's `udi-yac` class, and every Tailwind utility we emit carries a `udi:` prefix
|
|
105
|
+
(`udi:flex`), so nothing collides with your own Tailwind build whichever stylesheet
|
|
106
|
+
loads last. The sheet ships no preflight, so it cannot reset your typography or box
|
|
107
|
+
model. Dark mode follows a `.dark` class on any ancestor (the usual shadcn convention).
|
|
108
|
+
- **The bundle is server-safe.** `import 'udi-yac'` evaluates without a DOM, so a route
|
|
109
|
+
file that imports it does not break SSR. Rendering `<UDIChat>` still requires a
|
|
110
|
+
browser — mount it client-side.
|
|
111
|
+
- **`react` and `react-dom` are the only runtime dependencies.** Everything else,
|
|
112
|
+
`udi-toolkit` included, is bundled into the published file. Types are bundled too:
|
|
113
|
+
import `UDIPalette` from `udi-yac`, not from `udi-toolkit`.
|
|
82
114
|
|
|
83
115
|
### Config Props
|
|
84
116
|
|
|
85
|
-
| Prop
|
|
86
|
-
|
|
|
87
|
-
| `apiBaseUrl`
|
|
88
|
-
| `remotePackage`
|
|
89
|
-
| `dataPackagePath`
|
|
90
|
-
| `dataPackage`
|
|
91
|
-
| `dataFieldDomains`
|
|
92
|
-
| `fetchOptions`
|
|
93
|
-
| `authToken`
|
|
94
|
-
| `requireApiKey`
|
|
95
|
-
| `model`
|
|
96
|
-
| `downloadActions`
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
117
|
+
| Prop | Type | Description |
|
|
118
|
+
| --------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
119
|
+
| `apiBaseUrl` | `string` | Base URL for the UDIAgent API. Absolute (`https://agent.example.org`) or a same-origin path (`/api/yac`). |
|
|
120
|
+
| `remotePackage` | `string?` | Server-side data package name. Schema/domains come from `GET /v1/yac/metadata` and queries from `POST /v1/yac/query`; no CSVs load in the browser and cross-filtering becomes commit-on-mouse-up. Takes precedence over both data-package props. |
|
|
121
|
+
| `dataPackagePath` | `string?` | URL/path to `datapackage_udi.json`. Ignored when `dataPackage` is provided. |
|
|
122
|
+
| `dataPackage` | `DataPackage?` | Provide a data package object directly instead of fetching from a URL. Takes precedence over `dataPackagePath`. |
|
|
123
|
+
| `dataFieldDomains` | `DataFieldDomain[]?` | Pre-computed field domains. Skips CSV loading for domain computation when provided with `dataPackage`. |
|
|
124
|
+
| `fetchOptions` | `RequestInit?` | Custom fetch options (headers, credentials, etc.) forwarded to all data-loading fetch calls. |
|
|
125
|
+
| `authToken` | `string?` | JWT bearer token for API auth. Omit it when a backend proxy attaches the header instead; no `Authorization` header is then sent. |
|
|
126
|
+
| `requireApiKey` | `boolean?` | Show API key input before chatting |
|
|
127
|
+
| `model` | `string?` | LLM model name override |
|
|
128
|
+
| `downloadActions` | `DownloadAction[]?` | Extra items appended to the Download Data dropdown. See [Custom download actions](#custom-download-actions). |
|
|
129
|
+
| `downloadButtonLabel` | `string?` | Override the Download dropdown's trigger label. Defaults to `Download Data`. |
|
|
130
|
+
| `entityIcons` | `EntityIconMap?` | Icon overrides for entity count chips. See [Custom entity icons](#custom-entity-icons). |
|
|
131
|
+
| `mascot` | `ReactNode \| null?` | Replace or hide the welcome mascot. See [Custom mascot](#custom-mascot). |
|
|
132
|
+
| `splashMessages` | `readonly string[]?` | Override or hide the randomised prompt above the mascot. See [Custom splash messages](#custom-splash-messages). |
|
|
133
|
+
| `onEvent` | `TrackerFn?` | Analytics callback invoked on key user actions. See [Analytics events](#analytics-events). |
|
|
134
|
+
| `palette` | `UDIPalette?` | Default color palette for every chart and table. See [Custom color palette](#custom-color-palette). |
|
|
135
|
+
| `readOnly` | `boolean \| 'locked'?` | Start with the chat collapsed to a rail and every editing control hidden. `'locked'` removes the way back out. See [Read-only dashboard embed](#read-only-dashboard-embed). |
|
|
136
|
+
| `initialSession` | `unknown?` | A session export to seed the dashboard and conversation with. See [Read-only dashboard embed](#read-only-dashboard-embed). |
|
|
137
|
+
| `filters` | `UDIFilter[]?` | Filters set by the embedding page. See [Filters from the host page](#filters-from-the-host-page). |
|
|
138
|
+
| `onFiltersChange` | `(filters) => void` | Called with every filter in place whenever one changes. See [Filters from the host page](#filters-from-the-host-page). |
|
|
139
|
+
| `className` | `string?` | CSS class for the root element |
|
|
140
|
+
| `style` | `CSSProperties?` | Inline styles for the root element |
|
|
141
|
+
|
|
142
|
+
### Read-only dashboard embed
|
|
143
|
+
|
|
144
|
+
To drop UDI into a host app as a **dashboard** rather than a chat, use `UDIDashboard` (or
|
|
145
|
+
`UDIChat` with `readOnly`). The chat pane, the dashboard's top bar and every editing control
|
|
146
|
+
disappear, leaving the dashboard the full width and height.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { UDIDashboard } from 'udi-yac';
|
|
150
|
+
import 'udi-yac/style.css';
|
|
151
|
+
|
|
152
|
+
<div className="h-screen">
|
|
153
|
+
<UDIDashboard
|
|
154
|
+
apiBaseUrl="/api/yac"
|
|
155
|
+
dataPackagePath="./data/hubmap/datapackage.json"
|
|
156
|
+
initialSession={savedSession}
|
|
157
|
+
/>
|
|
158
|
+
</div>;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Read-only is the starting mode, not a lock.** A floating "Explore Data" button at the dashboard's
|
|
162
|
+
bottom right leaves read-only, at which point the full chat and every editing control appear. The
|
|
163
|
+
chat opens fresh: the conversation `initialSession` carried is hidden, though the model still has
|
|
164
|
+
it as context for the charts on the dashboard. If your users must not be able to chat at all,
|
|
165
|
+
pass `readOnly="locked"` to `UDIChat` instead: the button is dropped, leaving no way out.
|
|
166
|
+
|
|
167
|
+
| Removed in read-only | Kept in read-only |
|
|
168
|
+
| -------------------------------------------------------------------------- | --------------------------------------- |
|
|
169
|
+
| The chat pane and the data overview | Brushing and cross-filtering |
|
|
170
|
+
| Card drag, resize, rename, close, field tweak | The filter chips, including clearing |
|
|
171
|
+
| The top bar: counts, grid settings, session import / export, Download Data | The chart / table toggle and all-fields |
|
|
172
|
+
| The Filters section, while nothing is filtered | The info tooltips |
|
|
173
|
+
|
|
174
|
+
Layout changes are not written to `localStorage` while read-only, since there are none to make.
|
|
175
|
+
|
|
176
|
+
#### Seeding the dashboard
|
|
177
|
+
|
|
178
|
+
With the chat hidden there is nothing to build a dashboard from, so a read-only embed almost
|
|
179
|
+
always wants `initialSession`. It takes the JSON that the dashboard's **Session → Export session**
|
|
180
|
+
action writes — build a dashboard in the app, export it, and ship that file with your host:
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import savedSession from './my-dashboard.json';
|
|
184
|
+
|
|
185
|
+
<UDIDashboard
|
|
186
|
+
apiBaseUrl="/api/yac"
|
|
187
|
+
dataPackagePath="/data/datapackage.json"
|
|
188
|
+
initialSession={savedSession}
|
|
189
|
+
/>;
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The prop is typed `unknown` so `JSON.parse(text)` can go straight in; it is validated against the
|
|
193
|
+
`SessionExport` shape and a malformed payload throws a descriptive error rather than leaving a
|
|
194
|
+
silently empty dashboard. It is applied once, after the data package finishes loading. `readOnly`
|
|
195
|
+
and `initialSession` are independent — seeding a normal, chat-enabled session works too.
|
|
196
|
+
|
|
197
|
+
To try the same thing in the standalone app without writing any code, point the two env vars at
|
|
198
|
+
an exported session — `VITE_UDI_READ_ONLY=locked` and `VITE_UDI_INITIAL_SESSION=/demo-session.json`
|
|
199
|
+
in `.env.local`, with the file dropped in `public/` (served from the site root). The app fetches it
|
|
200
|
+
at startup and hands it to `initialSession`.
|
|
201
|
+
|
|
202
|
+
### Filters from the host page
|
|
203
|
+
|
|
204
|
+
A host page can set filters and follow the ones in place, so controls outside the chat can drive it
|
|
205
|
+
and read the results it is narrowing to:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
const [filters, setFilters] = useState<UDIFilter[]>([
|
|
209
|
+
{ id: 'cohort', dataSourceKey: 'donors', type: 'point', selection: { sex: ['Female'] } },
|
|
210
|
+
]);
|
|
211
|
+
|
|
212
|
+
<UDIDashboard {...config} filters={filters} onFiltersChange={(all) => console.log(all)} />;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- **`filters`** entries are keyed by `id`. Each shows as a chip in the Filters bar and filters every
|
|
216
|
+
chart, like a filter asked for in the chat; the user can adjust, clear or remove it there. An
|
|
217
|
+
entry is applied again only when that entry changes, so re-rendering with the same array never
|
|
218
|
+
undoes the user's edits. Dropping an entry deletes its filter. Filters are applied once the data
|
|
219
|
+
package has loaded, and survive a conversation reset.
|
|
220
|
+
- **`onFiltersChange`** receives every filter in place — chat, chart and host filters, each tagged
|
|
221
|
+
with its `origin` (`'chat' | 'chart' | 'host'`). A filter whose values are empty (`[]`) has been
|
|
222
|
+
cleared: its chip stays, reading "All", and it drops nothing. Removed filters are left out.
|
|
223
|
+
Entries whose `origin` is `'chat'` or `'chart'` are ignored when passed back in `filters`, so the
|
|
224
|
+
callback's output can be fed straight back.
|
|
225
|
+
|
|
226
|
+
A `point` filter's `selection` maps each field to the values to keep; an `interval` filter's maps
|
|
227
|
+
each field to `[min, max]`.
|
|
104
228
|
|
|
105
229
|
### Data Source Configuration
|
|
106
230
|
|
|
@@ -227,7 +351,18 @@ See [`src/data/hubmapRemote.ts`](src/data/hubmapRemote.ts) for the canonical inl
|
|
|
227
351
|
|
|
228
352
|
- **Interval filters**: range sliders for numeric fields
|
|
229
353
|
- **Point filters**: checkbox selection for categorical fields
|
|
230
|
-
- **
|
|
354
|
+
- **Filters bar**: a chip per filter; each opens a popover with that filter's controls, **Clear
|
|
355
|
+
all** (keep the filter, filter nothing — the chip reads "All") and **Remove filter** (drop the
|
|
356
|
+
chip and collapse the filter's chat item; expanding that item brings it back cleared). **Reset**
|
|
357
|
+
clears every filter.
|
|
358
|
+
- **Multi-select on charts**: hold a key over a chart and click bars, their axis labels, or its legend entries:
|
|
359
|
+
- **Shift** picks a range: every category from the first click to the last, in axis or legend order.
|
|
360
|
+
- **Ctrl** (**⌘** on macOS) toggles each click on its own.
|
|
361
|
+
|
|
362
|
+
Nothing is applied (or queried) until the key is released or the pointer leaves the chart, when the picks become one filter.
|
|
363
|
+
Picks are limited to the bars drawn; to add one the chart's own filter hides, clear the
|
|
364
|
+
filter first.
|
|
365
|
+
|
|
231
366
|
- **Cross-entity filtering**: filters propagate across related entities via foreign keys
|
|
232
367
|
- **Null value filtering** toggle
|
|
233
368
|
|
|
@@ -298,8 +433,7 @@ Consumer entries are merged on top of the built-in icons (`donors`, `samples`, `
|
|
|
298
433
|
Pass `palette` on `UDIChatConfig` to set the default colors used by every chart and table (dashboard cards, chat-message previews, and the memory bank). A spec-level per-encoding `range` still overrides the palette.
|
|
299
434
|
|
|
300
435
|
```tsx
|
|
301
|
-
import { UDIChat } from 'udi-yac';
|
|
302
|
-
import type { UDIPalette } from 'udi-toolkit/react';
|
|
436
|
+
import { UDIChat, type UDIPalette } from 'udi-yac';
|
|
303
437
|
import { interpolateViridis } from 'd3-scale-chromatic';
|
|
304
438
|
|
|
305
439
|
const palette: UDIPalette = {
|
|
@@ -317,6 +451,20 @@ const palette: UDIPalette = {
|
|
|
317
451
|
|
|
318
452
|
The `category`/`ordinal` fields accept a color array or a Vega scheme name. The `ramp` accepts a scheme name, a color array, or an interpolator function. Note: in the **table** renderer, function and array ramps are honored, while a bare scheme-name ramp falls back to the default (scheme names apply fully to Vega charts).
|
|
319
453
|
|
|
454
|
+
#### Chart chrome follows your theme automatically
|
|
455
|
+
|
|
456
|
+
Everything above colors the _data_. The surrounding chrome — plot background, axis lines, gridlines, tick labels, table text — is derived from the design tokens in effect on the chat root (`--foreground`, `--muted-foreground`, `--border`), and re-read whenever a `dark` class is toggled on any ancestor. So charts and tables follow light/dark mode, and follow your own token overrides, with no configuration.
|
|
457
|
+
|
|
458
|
+
Supply any of these to take over a channel; each one you set wins, and the rest stay theme-derived:
|
|
459
|
+
|
|
460
|
+
| Field | Controls |
|
|
461
|
+
| ------------ | ------------------------------------------------------------- |
|
|
462
|
+
| `background` | Plot and table background. `'transparent'` inherits the card. |
|
|
463
|
+
| `axis` | Axis domain lines and ticks. |
|
|
464
|
+
| `grid` | Gridlines, the plot frame, and table rules. |
|
|
465
|
+
| `text` | Tick labels, axis and legend titles, table text. |
|
|
466
|
+
| `mutedText` | Empty cells and truncation notices. |
|
|
467
|
+
|
|
320
468
|
### Custom mascot
|
|
321
469
|
|
|
322
470
|
The empty-dashboard welcome splash renders a YAC mascot by default. Consumers can replace it or hide it via the `mascot` prop on `UDIChatConfig`:
|
|
@@ -392,25 +540,27 @@ Event names are stable, snake_case strings. **Properties carry metadata only —
|
|
|
392
540
|
|
|
393
541
|
**Correlation ids.** Every event carries a `sessionId` (minted once per `UDIChat` mount) so all events from one chat instance can be stitched together and two tabs can be told apart. A subset of events — the ones bound to a single send↔response round trip — also carries a shared `turnId`, making it trivial to match a `message_sent` to the `response_received`, `rebuff_received`, or `request_failed` it produced. A retry after entering an API key reuses the original `turnId` so the retry's response still pairs back to the originating send.
|
|
394
542
|
|
|
395
|
-
| Event
|
|
396
|
-
|
|
|
397
|
-
| `message_sent`
|
|
398
|
-
| `response_received`
|
|
399
|
-
| `rebuff_received`
|
|
400
|
-
| `request_failed`
|
|
401
|
-
| `api_key_set`
|
|
402
|
-
| `api_key_cleared`
|
|
403
|
-
| `conversation_reset`
|
|
404
|
-
| `
|
|
405
|
-
| `
|
|
406
|
-
| `
|
|
407
|
-
| `
|
|
408
|
-
| `
|
|
409
|
-
| `
|
|
410
|
-
| `
|
|
411
|
-
| `
|
|
412
|
-
| `
|
|
413
|
-
| `
|
|
543
|
+
| Event | Fired when | Properties |
|
|
544
|
+
| ---------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
545
|
+
| `message_sent` | User submits a message through the chat input | `turnId: string`<br>`charCount: number` — length of the text, not the text itself<br>`conversationLength: number` — messages already in the conversation when this one was added<br>`hasUserApiKey: boolean` — whether the request will carry the user's key |
|
|
546
|
+
| `response_received` | Server completes a `/v1/yac/completions` call (including rebuffs) | `turnId: string` — matches the originating `message_sent`<br>`durationMs: number`<br>`toolCallNames: string[]` — e.g. `["RenderVisualization", "FreeTextExplain"]`<br>`toolCallCount: number`<br>`hadUserKey: boolean`<br>`hasRebuff: boolean` |
|
|
547
|
+
| `rebuff_received` | The response contains a `Rebuff` tool_call | `turnId: string`<br>`reason?: string` — machine-readable discriminator; `"budget_exceeded"` for quota rebuffs, absent for ordinary rebuffs<br>`hadUserKey: boolean` |
|
|
548
|
+
| `request_failed` | `/v1/yac/completions` throws (network error, HTTP !ok) | `turnId: string`<br>`durationMs: number`<br>`hadUserKey: boolean` |
|
|
549
|
+
| `api_key_set` | User submits a key through the `ApiKeyInput` | `inResponseToQuota: boolean` — true if a budget-exceeded rebuff had triggered the prompt (distinguishes first-time entry from quota-recovery entry) |
|
|
550
|
+
| `api_key_cleared` | User clears their stored key via the header icon | _(none)_ |
|
|
551
|
+
| `conversation_reset` | User clicks the Reset button (clears messages, pinned viz, filters, memory bank) | `conversationLength: number` — message count at the moment of reset |
|
|
552
|
+
| `read_only_exited` | User leaves read-only mode with the Explore Data button | _(none)_ |
|
|
553
|
+
| `visualization_pinned` | A new visualization is auto-pinned from an assistant response | `hasTitle: boolean`<br>`toolCallIndex: number` — position within the assistant message's tool_calls |
|
|
554
|
+
| `visualization_closed` | User clicks the × on a pinned visualization card | `hasTitle: boolean` |
|
|
555
|
+
| `download_raw_data` | User clicks "Download Raw Data" in the Download Data dropdown | `sources: number` — count of sources contributing rows<br>`rowsTotal: number` |
|
|
556
|
+
| `download_manifest` | User clicks "Download Manifest" | `idsTotal: number` — count of `hubmap_id` values in the exported manifest |
|
|
557
|
+
| `download_<slug>` | User clicks a custom `downloadActions` entry | `label: string` — the original menu label |
|
|
558
|
+
| `filter_range_changed` | User commits a new range on a quantitative (interval) filter slider, including the reset button | `entity: string`<br>`field: string`<br>`isReset: boolean` — true when triggered by the reset button<br>`isFullRange: boolean` — true when the new range covers the full domain |
|
|
559
|
+
| `filter_selection_changed` | User toggles a checkbox or clicks "Clear all" on a categorical (point) filter | `entity: string`<br>`field: string`<br>`action: 'toggle' \| 'clear_all'`<br>`checked?: boolean` — present only when `action === 'toggle'`<br>`selectionCount: number` — count of selected values after the change (no values themselves) |
|
|
560
|
+
| `filter_entity_changed` | User changes the target entity on a tweakable filter card | `filterType: 'interval' \| 'point'`<br>`entity: string` — the newly selected entity<br>`field: string` — the field carried over to the new entity (may be empty) |
|
|
561
|
+
| `filter_field_changed` | User changes the target field on a tweakable filter card | `filterType: 'interval' \| 'point'`<br>`entity: string`<br>`field: string` — the newly selected field |
|
|
562
|
+
| `visualization_tweaked` | User changes the field a `VizTweakComponent` dropdown controls | `encoding: string` — the channel, or the template parameter for a re-bind<br>`kind: 'field' \| 'dimension' \| 'measure' \| 'binding'` — `binding` means the agent re-instantiated the template; the rest are local spec rewrites |
|
|
563
|
+
| `visualization_tweak_failed` | The agent refused a template re-bind (invalid binding, unknown template, transport failure) | `encoding: string`<br>`kind: 'binding'` |
|
|
414
564
|
|
|
415
565
|
Every row in the table above also includes `sessionId: string`; it's omitted from the per-event cells to keep the table scannable.
|
|
416
566
|
|
|
@@ -418,7 +568,7 @@ Every row in the table above also includes `sessionId: string`; it's omitted fro
|
|
|
418
568
|
|
|
419
569
|
**Properties you will _not_ see.** By design, the following never cross the tracker boundary: raw message text, tool_call `arguments`, OpenAI API keys, data rows, filter values. Only counts, booleans, tool-call names, ids, and short slug strings are emitted.
|
|
420
570
|
|
|
421
|
-
### Debug Mode (type
|
|
571
|
+
### Debug Mode (type `//admin` in chat)
|
|
422
572
|
|
|
423
573
|
- System prompts toggle (show/hide system messages)
|
|
424
574
|
- Conversation sidebar drawer (load saved session JSON files)
|
|
@@ -474,7 +624,10 @@ src/
|
|
|
474
624
|
DashboardPanel.tsx # Dashboard layout (counts, filters, viz grid)
|
|
475
625
|
DashboardCard.tsx # Single pinned viz (chart, toolbar, tweak, spec)
|
|
476
626
|
DataCounts.tsx # Per-entity row counts (total + filtered)
|
|
477
|
-
FilterToolbar.tsx #
|
|
627
|
+
FilterToolbar.tsx # Filter chips, each a popover of its controls
|
|
628
|
+
FilterControls.tsx # Filter widget by type + collapsible chat item
|
|
629
|
+
IntervalFilterComponent.tsx # Range slider
|
|
630
|
+
PointFilterComponent.tsx # Checkbox list
|
|
478
631
|
DownloadButton.tsx # CSV/manifest download dropdown
|
|
479
632
|
VizTweakComponent.tsx # Field encoding swap dropdowns
|
|
480
633
|
VizTweakComponent.types.ts # TweakableParam, LayerLike, MappingLike
|
|
@@ -502,9 +655,7 @@ src/
|
|
|
502
655
|
components/
|
|
503
656
|
ToolCallRenderer.tsx # Dispatches tool calls to renderers
|
|
504
657
|
VisualizationCard.tsx # UDIVis preview (chat) / pinned badge
|
|
505
|
-
FilterComponent.tsx #
|
|
506
|
-
IntervalFilterComponent.tsx
|
|
507
|
-
PointFilterComponent.tsx
|
|
658
|
+
FilterComponent.tsx # A FilterData tool call's chat item
|
|
508
659
|
FreeTextExplain.tsx # Markdown explanation with structured text
|
|
509
660
|
RebuffNotice.tsx # Rejection with suggestion buttons
|
|
510
661
|
ClarifyVariable.tsx # Field disambiguation UI
|