Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
2975f99
feat: add Librarian — AI-powered chat panel for SQL lineage Q&A
liliyaminibaeva Apr 14, 2026
1349521
chore: remove accidental non-code file
liliyaminibaeva Apr 14, 2026
0e2548a
fix: enable browser cache for embedding model and tighten prompt format
liliyaminibaeva Apr 14, 2026
225bb2e
feat: keep PDF row size and delete visible at narrow widths
liliyaminibaeva Apr 20, 2026
c4688a6
feat: move Librarian toggle from header to analysis toolbar
liliyaminibaeva Apr 20, 2026
cdae53e
feat: style schema identifiers in chat and tighten Librarian prompt
liliyaminibaeva Apr 20, 2026
7a3eb63
feat: add help popover to Librarian panel header
liliyaminibaeva Apr 20, 2026
a510ad1
feat: navigate to schema on clicking referenced assistant messages
liliyaminibaeva Apr 20, 2026
5db4819
feat: add schema search overlay to Schema view
liliyaminibaeva Apr 20, 2026
a5972ee
chore: verify Task 7 acceptance criteria for Librarian UI/LLM fixes
liliyaminibaeva Apr 20, 2026
2c2a93a
docs: add CHANGELOG entry for Librarian UI and prompt fixes
liliyaminibaeva Apr 20, 2026
15bb565
fix: address code review findings in Librarian tests
liliyaminibaeva Apr 20, 2026
e7e4b8a
fix: address code review findings
liliyaminibaeva Apr 20, 2026
8028e91
feat: Librarian UI improvements and multilingual embeddings
liliyaminibaeva Apr 23, 2026
511b6a7
docs: add Librarian user guide, test cases, and architecture notes
liliyaminibaeva Apr 23, 2026
e84f2ea
feat: reshape Librarian store to per-project buckets
liliyaminibaeva Apr 29, 2026
d4ec0dc
feat: sync activeProjectId from project store into Librarian store
liliyaminibaeva Apr 29, 2026
0e0fb9b
feat: migrate Librarian consumer components to per-project selectors
liliyaminibaeva Apr 29, 2026
ee41562
feat: scope Librarian chat hook to active project bucket
liliyaminibaeva Apr 29, 2026
49617b9
chore: verify Task 5 acceptance criteria for Librarian per-project is…
liliyaminibaeva Apr 29, 2026
bcd0639
docs: finalize Librarian per-project isolation rollout
liliyaminibaeva Apr 29, 2026
a160de0
fix: address code review findings
liliyaminibaeva Apr 29, 2026
b173f44
fix: address code review findings
liliyaminibaeva Apr 29, 2026
dc7eee8
feat: add lineage node-id resolver for chat-click highlight
liliyaminibaeva Apr 29, 2026
368a5b0
feat: extend NavigationTarget with highlightNodeIds and tablesToExpand
liliyaminibaeva Apr 29, 2026
1eed6d6
feat: route chat clicks to lineage tab with multi-reference highlight
liliyaminibaeva Apr 29, 2026
3095ad7
feat: consume highlightNodeIds in AnalysisView for chat-driven naviga…
liliyaminibaeva Apr 29, 2026
b533049
chore: verify Task 6 acceptance criteria for chat-click multi-highlight
liliyaminibaeva Apr 29, 2026
12d8ef8
docs: document chat-click lineage highlight behavior and limitation
liliyaminibaeva Apr 29, 2026
a92c1a1
fix: address code review findings
liliyaminibaeva Apr 29, 2026
bd58ac9
fix: address code review findings
liliyaminibaeva Apr 29, 2026
9e2e481
fix: address code review findings
liliyaminibaeva Apr 29, 2026
974b03c
fix: case-insensitive chat identifier matching, drive lineage search …
liliyaminibaeva Apr 30, 2026
4059f37
fix: stop auto-zooming on chat-click navigation
liliyaminibaeva Apr 30, 2026
a304d14
chore: migrate librarian to flat AnalyzeResult shape
liliyaminibaeva Apr 30, 2026
90a1d9b
feat(librarian): scope chat-click navigation to Summary + reveal pare…
liliyaminibaeva Apr 30, 2026
7871394
docs: consolidate Librarian CHANGELOG entry and refresh user guide
liliyaminibaeva May 4, 2026
d5b8585
style: apply prettier formatting to Librarian files
liliyaminibaeva May 4, 2026
390db0f
fix(librarian): correct column-owner mapping and surface embedding er…
melonamin May 11, 2026
b94d39c
fix: address code review findings
melonamin May 11, 2026
f1b755d
fix(librarian): address code review findings
melonamin May 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

#### Web App (app/) — Librarian (2026-05-04)

AI chat panel for asking questions about your data using SQL lineage and uploaded PDF documentation. Supports OpenAI, Anthropic, and custom OpenAI-compatible endpoints; multilingual embeddings (`Xenova/multilingual-e5-small`, 100+ languages); per-project state isolation (RAM-only) so chat, PDFs, and embedded chunks don't leak between projects.

Answers follow a structured **Summary / Data Lineage / Documentation** format. Schema identifiers are highlighted inline in assistant responses (case-insensitive, normalized to canonical schema casing). Clicking an assistant message reads the answer's Summary, highlights every referenced table and column in the Lineage view via the existing search pipeline (auto-enabling "show column edges" when a column is referenced), and gently pans + pulses on the source table containing the column.

Schema view gains a search control (table-name or column-name substring, Prev/Next cycling). Librarian toggle lives in the analysis toolbar next to Schema (⌘L / Ctrl+L); a help popover in the panel header describes the assistant and usage.

## [0.7.0] - 2026-04-23

### Added
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Features:
- Multi-file project support with schema DDL
- dbt/Jinja template preprocessing for dbt models
- Export to Mermaid, JSON, CSV, Excel, or HTML reports
- Librarian — AI chat panel that answers questions about your data based on lineage analysis and uploaded PDF docs
- All processing happens in your browser — your SQL never leaves your machine

### Command-Line Interface
Expand Down Expand Up @@ -114,6 +115,7 @@ See [CLI documentation](crates/flowscope-cli/README.md) for all options.
- Structured diagnostics with spans for precise highlighting
- Completion API for SQL authoring workflows
- TypeScript API and optional React visualization components
- Librarian AI chat panel for natural-language Q&A over SQL lineage and uploaded PDF documentation (OpenAI, Anthropic, or custom endpoints)

## Components

Expand Down Expand Up @@ -184,6 +186,7 @@ npm install @pondpilot/flowscope-react
## Documentation

- [docs/README.md](docs/README.md) — documentation map and reference index
- [docs/librarian.md](docs/librarian.md) — Librarian AI chat panel user guide
- [docs/guides/quickstart.md](docs/guides/quickstart.md) — TypeScript quickstart guide
- [docs/guides/schema-metadata.md](docs/guides/schema-metadata.md) — schema metadata setup
- [docs/dialect-coverage.md](docs/dialect-coverage.md) — dialect and statement coverage
Expand Down
31 changes: 31 additions & 0 deletions app/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ app/src/
│ ├── SchemaEditor.tsx # DDL schema editor
│ ├── ShareDialog.tsx # Project export/sharing
│ └── Workspace.tsx # Main two-panel layout
├── features/ # Feature modules (self-contained)
│ └── librarian/ # AI chat panel (Q&A over lineage + PDFs)
├── hooks/ # Custom React hooks
│ ├── useAnalysis.ts # SQL analysis workflow
│ ├── useFileNavigation.ts # Graph-to-editor navigation
Expand Down Expand Up @@ -74,6 +76,23 @@ The app now supports "Schema-Aware" analysis.
* Column validation
* Precise column lineage

### 5. Feature Modules

Self-contained feature folders under `app/src/features/` own all their code (components, hooks, services, workers, tests) and expose a public API via `index.ts`.

#### Librarian (`features/librarian/`)

AI-powered chat panel for SQL lineage Q&A.

- `components/` — panel, chat messages, input, PDF upload, AI settings dialog
- `services/` — AI client (OpenAI / Anthropic / custom), context builder, lineage formatter, PDF processor, vector search, embedding service
- `workers/` — embedding Web Worker (local Xenova/transformers model)
- `hooks/use-librarian-chat.ts` — chat orchestrator
- `hooks/use-sync-active-project.ts` — mirrors `activeProjectId` from `useProject()` into the Librarian store and prunes buckets for deleted projects
- `store.ts` — Zustand store. Per-project buckets (`byProject` keyed by `activeProjectId`) hold messages, PDF files, and embedded chunks; `isLoading` and `hasConfig` are global. Selector hooks `useLibrarianMessages` / `useLibrarianPdfFiles` / `useLibrarianPdfChunks` return the active project's slice. `addMessageToProject(projectId, ...)` writes to an explicit bucket so an in-flight LLM response is routed back to the originating project even if the user switches mid-flight.

State is Zustand (not React Context), UI is Radix + Tailwind. All AI calls hit the user's configured provider directly from the browser. See `docs/librarian.md` for the user guide.

## Data Flow

### Analysis Loop
Expand All @@ -87,12 +106,23 @@ The app now supports "Schema-Aware" analysis.
5. **Result**: The JSON result is dispatched to the Lineage Store.
6. **Rendering**: `AnalysisView` updates the Graph and Issues panel.

### Librarian Chat Flow

1. User types a question in the Librarian panel.
2. `use-librarian-chat.ts` gathers: current lineage (from `useLineageState`), active SQL file content, last 10 chat messages, and vector-search results over uploaded PDF chunks.
3. `context-builder.ts` assembles a structured prompt with labeled data sources (Data Lineage / SQL Code / Documentation / Conversation History).
4. `ai-service.ts` sends the prompt via `fetch()` to the configured provider (OpenAI / Anthropic / custom endpoint).
5. Response is stored in the chat and rendered with markdown + identifier highlighting.

PDF processing runs asynchronously: text extraction (pdfjs-dist) → 500-char chunking → embeddings (local `multilingual-e5-small` model in a Web Worker) → stored in the librarian store.

## UI Architecture

* **Layout**: `react-resizable-panels` provides the split-view.
* **Styling**: Tailwind CSS with `shadcn/ui` (Radix Primitives) pattern.
* **Icons**: Lucide React.
* **Editor**: `CodeMirror` (via `@pondpilot/flowscope-react`).
* **Librarian icon**: Custom SVG (`/public/polly-icon.svg`) for the toolbar, chat avatar, and empty state.

## Configuration

Expand All @@ -102,6 +132,7 @@ The app now supports "Schema-Aware" analysis.
* `Cmd/Ctrl + P`: Switch Project
* `Cmd/Ctrl + O`: Switch File
* `Cmd/Ctrl + D`: Switch Dialect
* `Cmd/Ctrl + L`: Toggle Librarian panel

## Future Improvements

Expand Down
13 changes: 11 additions & 2 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"typecheck": "tsc --noEmit",
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"test": "echo \"No tests defined for flowscope-app\""
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {
"@pondpilot/flowscope-core": "file:../packages/core",
Expand All @@ -21,19 +22,22 @@
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-tooltip": "^1.2.8",
"@xenova/transformers": "^2.17.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"fflate": "^0.8.2",
"file-saver": "^2.0.5",
"html-to-image": "^1.11.13",
"lucide-react": "^0.562.0",
"next-themes": "^0.4.6",
"pdfjs-dist": "4.8.69",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-resizable-panels": "^3.0.6",
Expand All @@ -43,15 +47,20 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/file-saver": "^2.0.7",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@vitejs/plugin-react": "^4.4.0",
"jsdom": "^26.1.0",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.0",
"typescript": "^5.9.0",
"vite": "^6.3.0",
"vite-plugin-top-level-await": "^1.6.0",
"vite-plugin-wasm": "^3.5.0"
"vite-plugin-wasm": "^3.5.0",
"vitest": "^3.2.4"
}
}
66 changes: 66 additions & 0 deletions app/public/polly-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 49 additions & 31 deletions app/src/components/AnalysisView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { usePersistedLineageState } from '@/hooks/usePersistedLineageState';
import { usePersistedMatrixState } from '@/hooks/usePersistedMatrixState';
import { usePersistedSchemaState } from '@/hooks/usePersistedSchemaState';
import { applyLineageNavigation } from '@/lib/lineage-navigation';
import { isValidTab, useNavigation } from '@/lib/navigation-context';
import { useViewStateStore, getNamespaceFilterStateWithDefaults } from '@/lib/view-state-store';
import { useProject } from '@/lib/project-store';
import { schemaMetadataToSQL } from '@/lib/schema-parser';
import { HierarchyView, type HierarchyViewRef } from './HierarchyView';
import { LibrarianToggleButton } from './LibrarianToggleButton';
import { StatsPopover } from './StatsPopover';
import { NamespaceFilterBar } from './NamespaceFilterBar';
import { SchemaAwareIssuesPanel } from './SchemaAwareIssuesPanel';
import { SchemaEditor } from './SchemaEditor';
import { SchemaSearchControl } from './SchemaSearchControl';

interface AnalysisViewProps {
graphContainerRef?: React.RefObject<HTMLDivElement | null>;
Expand Down Expand Up @@ -106,14 +109,14 @@ export function AnalysisView({
// Handle navigation target for GraphView - select and focus node/statement when navigating to lineage tab
useEffect(() => {
if (activeTab === 'lineage' && navigationTarget) {
if (navigationTarget.tableId) {
// Navigate to specific table node
actionsRef.current.selectNode(navigationTarget.tableId);
setLineageFocusNodeId(navigationTarget.tableId);
} else if (navigationTarget.fitView) {
// Trigger fitView to show all nodes (e.g., from Issues panel)
setFitViewTrigger((prev) => prev + 1);
}
applyLineageNavigation(navigationTarget, {
expandedTableIds: stateRef.current.expandedTableIds,
selectNode: actionsRef.current.selectNode,
toggleTableExpansion: actionsRef.current.toggleTableExpansion,
setFocusNodeId: setLineageFocusNodeId,
triggerFitView: () => setFitViewTrigger((prev) => prev + 1),
revealNodeInGraph: actionsRef.current.revealNodeInGraph,
});
clearNavigationTarget();
}
}, [activeTab, navigationTarget, clearNavigationTarget]);
Expand Down Expand Up @@ -336,24 +339,29 @@ export function AnalysisView({

if (!result || !summary) {
return (
<div className="flex flex-col items-center justify-center h-full text-muted-foreground bg-muted/5">
<div className="p-6 text-center">
{isAnalyzing ? (
<>
<Loader2 className="h-6 w-6 animate-spin mx-auto mb-3 opacity-70" />
<h3 className="font-semibold mb-2">Analyzing SQL</h3>
<p className="text-sm max-w-xs mx-auto">
Building lineage, schema, and issue details for the current analysis run.
</p>
</>
) : (
<>
<h3 className="font-semibold mb-2">No Analysis Results</h3>
<p className="text-sm max-w-xs mx-auto">
Run analysis on your SQL script to see lineage and schema details here.
</p>
</>
)}
<div className="flex flex-col h-full bg-background">
<div className="px-4 py-2 border-b flex items-center justify-end bg-muted/10 h-[44px] shrink-0">
<LibrarianToggleButton />
</div>
<div className="flex-1 flex flex-col items-center justify-center text-muted-foreground bg-muted/5">
<div className="p-6 text-center">
{isAnalyzing ? (
<>
<Loader2 className="h-6 w-6 animate-spin mx-auto mb-3 opacity-70" />
<h3 className="font-semibold mb-2">Analyzing SQL</h3>
<p className="text-sm max-w-xs mx-auto">
Building lineage, schema, and issue details for the current analysis run.
</p>
</>
) : (
<>
<h3 className="font-semibold mb-2">No Analysis Results</h3>
<p className="text-sm max-w-xs mx-auto">
Run analysis on your SQL script to see lineage and schema details here.
</p>
</>
)}
</div>
</div>
</div>
);
Expand Down Expand Up @@ -413,6 +421,7 @@ export function AnalysisView({
</Tooltip>
</TooltipProvider>
)}
<LibrarianToggleButton />
</div>
</div>

Expand Down Expand Up @@ -484,11 +493,20 @@ export function AnalysisView({
className="h-full mt-0 p-0 absolute inset-0 data-[state=inactive]:hidden"
>
{mountedTabs.has('schema') && (
<SchemaView
schema={schema}
selectedTableName={schemaState.selectedTableName}
onClearSelection={schemaState.clearSelection}
/>
<div className="relative h-full w-full">
<SchemaView
schema={schema}
selectedTableName={schemaState.selectedTableName}
onClearSelection={schemaState.clearSelection}
/>
<div className="absolute top-2 right-2 z-10">
<SchemaSearchControl
tableNames={schema.map((t) => t.name)}
tables={schema}
onSelectTable={schemaState.setSelectedTableName}
/>
</div>
</div>
)}
</TabsContent>

Expand Down
Loading
Loading