Migrate insight creation to the command system with automatic retry logic
to prevent SurrealDB transaction conflicts during batch imports.
Changes:
- Add create_insight_command with retry logic for transaction conflicts
- Add run_transformation_command for async transformation execution
- Make Source.add_insight() fire-and-forget (returns command_id)
- Update POST /sources/{id}/insights to return 202 Accepted immediately
- Frontend polls command status until complete, then refreshes
- Auto-update notebook page icon when source gains insights
- Add i18n keys for insight generation feedback
Related to #489
* feat: decrease chunking size for maximum ollama compatibility
* docs: improve i18n info on Claude.md
* feat: add cascade deletion for notebooks with delete preview
- Add Notebook.get_delete_preview() to show counts of affected items
- Add Notebook.delete(delete_exclusive_sources) for cascade deletion
- Always delete notes when notebook is deleted
- Allow user to choose: delete or keep exclusive sources
- Shared sources are always unlinked but never deleted
- Add NotebookDeleteDialog component with radio button options
- Add delete-preview API endpoint
- Update delete endpoint with delete_exclusive_sources param
- Add i18n support for all 5 locales
Closes#77
* docs: remove harcoded config settings
* feat: content-type aware chunking and unified embedding
- Add chunking.py with HTML, Markdown, and plain text detection
- Add embedding.py with mean pooling for large content
- Create dedicated commands: embed_note, embed_insight, embed_source
- Use fire-and-forget pattern for embedding via submit_command()
- Refactor rebuild_embeddings_command to delegate to individual commands
- Remove legacy commands and needs_embedding() methods
- Reduce chunk size to 1500 chars for Ollama compatibility
- Update CLAUDE.md documentation for new architecture
Fixes#350, #142
* fix: address code review issues
- Note.save() now returns command_id for tracking embedding jobs
- Add length check after generate_embeddings() to fail fast on mismatch
- Add numpy as explicit dependency (was transitive)
- Remove hardcoded chunk sizes from docstrings
* docs: address code review comments
- Rename "SYNC PATH" to "DOMAIN MODEL PATH" in embedding router
- Add test_chunking.py and test_embedding.py to Testing Strategy
- Clarify auto-embedding behavior for each domain model
* fix: clean thinking tags from prompt graph output
Adds clean_thinking_content() to prompt.py to handle extended thinking
models that return <think>...</think> tags. This fixes empty titles
when saving notes from chat.
* chore: remove local docker-compose from git
* fix(frontend): handle null parent_id in search results
Add defensive check for null parent_id in search results to prevent
"Cannot read properties of null (reading 'split')" error. This can
happen with orphaned records in the database.
* fix: cascade delete embeddings and insights when source is deleted
When deleting a Source, now also deletes associated:
- source_embedding records
- source_insight records
This prevents orphaned records that cause null parent_id errors
in vector search results.
* fix: add cleanup for orphan embedding/insight records in migration 10
Deletes source_embedding and source_insight records where the
linked source no longer exists (source.id = NONE).
* chore: bump esperanto to 2.16
Increases ctx_num for Ollama models to accommodate larger notebook
context windows. See: https://github.com/lfnovo/esperanto/pull/69
Only observe DOM mutations when dialog is open, preventing
unnecessary observer activity when the dialog is closed.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added `isEditorFullscreen` state to track fullscreen mode for the Markdown editor.
- Integrated `MutationObserver` to detect changes related to the `.w-md-editor-fullscreen` class.
- Adjusted dialog and editor styles dynamically based on fullscreen state using `cn`.
- Enhanced UX by resetting fullscreen state on dialog close.
- Add pendingModelOverride state to useNotebookChat hook
- Store model selection when no session exists yet
- Apply pending model override when session is auto-created on first message
- Simplify ChatColumn by using new setModelOverride function
Added remark-gfm plugin to enable GitHub Flavored Markdown support,
which includes proper table rendering. Updated all ReactMarkdown
usages with table styling components:
- ChatPanel (source and notebook chat)
- StreamingResponse (search/ask results)
- SourceInsightDialog
- SourceDetailContent
- TransformationPlayground
Tables now render with proper borders, headers with background,
and horizontal scroll for wide tables.
Previously, notebook sources were limited to 50 items due to API default.
This adds pagination with infinite scroll to the sources column:
- Add useNotebookSources hook with useInfiniteQuery for paginated fetching
- Update SourcesColumn with scroll detection to load more sources
- Fetch 30 sources per page, loading more as user scrolls near bottom
- Adjusted `div` class styles to add horizontal scrolling in smaller viewports (`overflow-x-auto`).
- Updated chat column element with additional padding and margin adjustments for better desktop layout.
The search page now reads `q` and `mode` query parameters from the URL,
enabling proper integration with the command palette's search/ask actions.
Changes:
- Read URL params using useSearchParams hook
- Initialize form fields and active tab from URL params
- Auto-trigger search/ask when arriving with URL params
- Handle subsequent navigations while on the search page
* feat(ui): add command palette for quick navigation and search
Replace top bar search with a command palette (⌘K / Ctrl+K) that provides:
- Quick navigation to all app sections
- Create shortcuts for sources, notebooks, and podcasts
- Theme switching (light/dark/system)
- Search and Ask functionality for non-matching queries
This approach saves screen real estate while providing faster access
to common actions through keyboard shortcuts.
Co-authored-by: EmbroiderSnow <1497411439@qq.com>
* chore: bump to 1.2.3
* feat(command-palette): add notebook quick navigation
Users can now type a notebook name in the command palette (⌘K) to
navigate directly to that notebook. Shows up to 8 most recent
notebooks, with cmdk filtering all notebooks when typing.
* fix(command-palette): address code review issues
- Skip ⌘K/Ctrl+K shortcut when focus is inside input, textarea, select,
or contentEditable elements to preserve native keyboard handling
- Remove 8-item limit on notebooks so all notebooks are searchable
via cmdk filtering
* perf(command-palette): memoize command matching and add platform shortcuts
- Memoize hasCommandMatch computation with useMemo to avoid
recalculating on every render
- Show platform-specific keyboard shortcut in sidebar hint:
⌘K on macOS, Ctrl+K on Windows/Linux
* fix(command-palette): add spinner to notebooks loading state
Show a spinning Loader2 icon alongside the "Loading notebooks..." text
for clearer visual feedback when the command palette is fetching data.
---------
Co-authored-by: EmbroiderSnow <1497411439@qq.com>
* fix: add missing overflow wrapper to notebooks list page
Adds flex-1 overflow-y-auto wrapper to enable proper scrolling
when notebook list exceeds viewport height. Matches the layout
pattern used by all other dashboard pages.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: reorder transformation routes to prevent dynamic route interception
Moved static routes (/transformations/execute and /transformations/default-prompt)
before dynamic routes (/transformations/{transformation_id}) to ensure FastAPI
matches them correctly. Previously, requests to static routes were incorrectly
captured by the dynamic route handler.
Fixes#250
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: bump to 1.2.1
* hide source and notes panel - fixes#193
* feat: improve layout for mobile views
* bump version to 1.2.2
* fix: address PR review feedback for collapsible columns
- Remove unused CollapseButton component from CollapsibleColumn.tsx
- Rename useCollapseButton to createCollapseButton (not a React hook)
- Move dialogs outside Card in SourcesColumn.tsx for consistency
- Add useMemo for collapseButton in both columns to prevent re-renders
* feat: support multiple sources
* fix: prevent ChatColumn double mounting on desktop
Add useIsDesktop hook to conditionally render mobile view only on
mobile screens. Previously, the mobile ChatColumn was hidden via CSS
on desktop but still mounted, causing duplicate hooks initialization
and redundant network requests.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add missing overflow wrapper to notebooks list page
Adds flex-1 overflow-y-auto wrapper to enable proper scrolling
when notebook list exceeds viewport height. Matches the layout
pattern used by all other dashboard pages.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: reorder transformation routes to prevent dynamic route interception
Moved static routes (/transformations/execute and /transformations/default-prompt)
before dynamic routes (/transformations/{transformation_id}) to ensure FastAPI
matches them correctly. Previously, requests to static routes were incorrectly
captured by the dynamic route handler.
Fixes#250
Co-Authored-By: Claude <noreply@anthropic.com>
* chore: bump to 1.2.1
---------
Co-authored-by: Claude <noreply@anthropic.com>
Transform verbose inline references to compact footnote-style format:
- Replace [source:abc123] with numbered citations [1], [2], etc.
- Add "References:" section at bottom of messages
- Deduplicate references (same ID gets same number)
- Remove icons from citations for cleaner appearance
- Maintain click-to-open functionality for all reference types
Changes:
- Add convertReferencesToCompactMarkdown() function
- Add createCompactReferenceLinkComponent() function
- Update ChatPanel to use new compact reference functions
- Add ReferenceData interface for type safety
Improves readability by reducing visual clutter while preserving
all existing functionality. References restart numbering at 1 for
each message.
* feat: prevent duplicate model names under same provider
Implement case-insensitive validation to prevent users from creating
duplicate model names under the same provider. This validation is
implemented both in the backend API and the frontend UI.
Changes:
- Backend: Add duplicate check in create_model endpoint (case-insensitive)
- Frontend: Add client-side validation in AddModelForm
- Frontend: Improve error message display from backend
- Tests: Add unit tests for duplicate model validation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: optimize duplicate model validation and improve error handling
- Replace O(n) model iteration with efficient SurrealDB query for duplicate check
- Improve error message to include model name and provider for better UX
- Remove frontend duplicate validation (backend-only enforcement)
- Fix test authentication by setting OPEN_NOTEBOOK_PASSWORD before imports
- Update test mocking to use repo_query instead of Model.get_all()
- Add pytest fixture for TestClient to ensure proper test isolation
All 11 tests passing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* remove unnecessary package
* fix: replace any with unknown type in error handler
- Change error type from 'any' to 'unknown' to satisfy ESLint
- Add proper type assertion for error object structure
- Maintains same runtime behavior with better type safety
---------
Co-authored-by: Claude <noreply@anthropic.com>
Updated help links in DefaultModelsSection and ProviderStatus components
to point to the new AI models documentation location at
docs/features/ai-models.md instead of docs/models.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: small issue where users cant change podcast segments
* chore: remove playwright mcp from gut
* feat: add ability to link existing sources to notebooks (OSS-311)
Implemented bidirectional source-notebook linking functionality:
Backend changes:
- Add POST endpoint to link sources to notebooks
- Include notebook associations in source detail response
- Implement idempotent linking with proper RecordID handling
Frontend changes:
- Add AddExistingSourceDialog with search and multi-select
- Add NotebookAssociations component for source detail view
- Add dropdown menu to "Add Source" button (new/existing)
- Implement useAddSourcesToNotebook hook with graceful error handling
- Fix dialog pointer-events during close animation
- Add loading states and disable checkboxes for linked sources
- Optimize dialog width with proper responsive breakpoints
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: address PR review feedback
- Fix sources.py query to use correct reference direction (OUT where IN)
- Remove debug console.log statements
- Add truncation warning for 100+ source lists
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: small issue where users cant change podcast segments
* feat: display source and note counts on notebook cards (OSS-312)
Add item counters to notebook listing page showing the number of sources
and notes in each notebook. Counts are displayed in a footer section with
FileText and StickyNote icons for visual consistency with ContextIndicator.
Backend changes:
- Add source_count and note_count to NotebookResponse model
- Update /notebooks endpoint to use SurrealDB graph traversal query
- Query: count(<-reference.in) for sources, count(<-artifact.in) for notes
- Update all notebook endpoints to include counts
Frontend changes:
- Add source_count and note_count to TypeScript NotebookResponse interface
- Add footer section to NotebookCard component
- Display counts with FileText and StickyNote icons (h-3 w-3)
- Use border-top separator and muted-foreground styling
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* style: use colorful badges for notebook counts matching ContextIndicator
Update notebook card counts to use Badge components with primary color
styling instead of plain text, matching the visual style of the
ContextIndicator component in the chat window.
Changes:
- Replace plain text divs with Badge components
- Apply text-primary and border-primary/50 styling
- Use same spacing (gap-1.5, px-1.5, py-0.5) as ContextIndicator
- Remove bullet separator (not needed with badge layout)
Visual result matches the colorful badges shown in chat context.
Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
New front-end
Launch Chat API
Manage Sources
Enable re-embedding of all contents
Sources can be added without a notebook now
Improved settings
Enable model selector on all chats
Background processing for better experience
Dark mode
Improved Notes
Improved Docs:
- Remove all Streamlit references from documentation
- Update deployment guides with React frontend setup
- Fix Docker environment variables format (SURREAL_URL, SURREAL_PASSWORD)
- Update docker image tag from :latest to :v1-latest
- Change navigation references (Settings → Models to just Models)
- Update development setup to include frontend npm commands
- Add MIGRATION.md guide for users upgrading from Streamlit
- Update quick-start guide with correct environment variables
- Add port 5055 documentation for API access
- Update project structure to reflect frontend/ directory
- Remove outdated source-chat documentation files