From d8af69cb07b2d8f800ee99afd21bd05f12e62679 Mon Sep 17 00:00:00 2001 From: Vikranth Reddimasu Date: Fri, 17 Apr 2026 18:24:47 -0400 Subject: [PATCH] fix(ci): clear pre-existing ruff + tsc failures on main CI has been red on main since the research trust layer merge (#8). None of these issues were caught before merge, and every PR since has inherited the failure. This commit resolves both jobs. Backend (ruff): - chat.py model: wrap Field() description so the line fits in 120 cols. - chat stream route: drop the unused persist_warning flag. - conversation_store: drop unused `field` and `Path` imports. - conversation store + cross-notebook tests: drop unused locals / imports (c2 binding, VectorStoreManager import). Kept the ordering assertion by calling create_conversation without binding the returned value. Desktop (tsc): - types.ts: extend StreamSource and SourceChunk with the fields the backend actually returns (relevance_score, notebook_id). This removes the need for unsafe `as Record` casts at read sites. - useChat / SourcePanel: read the typed fields directly now that the shape is honest. - DocumentPreview: use a proper `'str' in item` narrow for the pdfjs TextItem | TextMarkedContent union instead of an ad-hoc structural type. - SetupWizard: drop the unused fetchConfig import and the dead uploadedFilename state (only the setter was ever called). - ZoteroImport: drop the unused useAppStore import. Verified locally: `uv run ruff check .` clean; `npm run build` clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/desktop/src/DocumentPreview.tsx | 2 +- apps/desktop/src/components/layout/SourcePanel.tsx | 2 +- apps/desktop/src/components/ui/SetupWizard.tsx | 4 +--- apps/desktop/src/components/ui/ZoteroImport.tsx | 1 - apps/desktop/src/hooks/useChat.ts | 2 +- apps/desktop/src/types.ts | 3 +++ backend/notebooklm_backend/models/chat.py | 5 ++++- backend/notebooklm_backend/routes/chat.py | 1 - backend/notebooklm_backend/services/conversation_store.py | 3 +-- backend/tests/test_conversation_store.py | 4 ++-- backend/tests/test_cross_notebook.py | 2 +- 11 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/desktop/src/DocumentPreview.tsx b/apps/desktop/src/DocumentPreview.tsx index 672b663..09e8a71 100644 --- a/apps/desktop/src/DocumentPreview.tsx +++ b/apps/desktop/src/DocumentPreview.tsx @@ -58,7 +58,7 @@ function DocumentPreview({ isOpen, onClose, documentUrl, filename, highlightText const page = await pdf.getPage(i); const textContent = await page.getTextContent(); const pageText = normalizeText( - textContent.items.map((item: { str?: string }) => item.str || '').join(' ') + textContent.items.map((item) => ('str' in item ? item.str : '')).join(' ') ); if (pageText.includes(searchSnippet)) { setPageNumber(i); diff --git a/apps/desktop/src/components/layout/SourcePanel.tsx b/apps/desktop/src/components/layout/SourcePanel.tsx index 1a49557..0d211b5 100644 --- a/apps/desktop/src/components/layout/SourcePanel.tsx +++ b/apps/desktop/src/components/layout/SourcePanel.tsx @@ -27,7 +27,7 @@ export function SourcePanel({ onSourceClick }: SourcePanelProps) {
{activeSources.map((source, i) => { - const nbId = (source as Record).notebook_id as string | undefined; + const nbId = source.notebook_id; const nbName = nbId ? notebooks.find((nb) => nb.notebook_id === nbId)?.title : null; return ( diff --git a/apps/desktop/src/components/ui/SetupWizard.tsx b/apps/desktop/src/components/ui/SetupWizard.tsx index 8d20cb2..42310fc 100644 --- a/apps/desktop/src/components/ui/SetupWizard.tsx +++ b/apps/desktop/src/components/ui/SetupWizard.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react'; -import { fetchConfig, uploadDocument } from '../../api'; +import { uploadDocument } from '../../api'; import { useAppStore } from '../../store/app-store'; import { useNotebooks } from '../../hooks/useNotebooks'; import { showToast } from './Toast'; @@ -34,7 +34,6 @@ export function SetupWizard({ onComplete }: { onComplete: () => void }) { const [ollamaStatus, setOllamaStatus] = useState({ state: 'checking' }); const [selectedModel, setSelectedModel] = useState(null); const [uploading, setUploading] = useState(false); - const [uploadedFilename, setUploadedFilename] = useState(null); const fileInputRef = useRef(null); const { refresh: refreshNotebooks } = useNotebooks(); @@ -95,7 +94,6 @@ export function SetupWizard({ onComplete }: { onComplete: () => void }) { const result = await uploadDocument(file); useAppStore.getState().setActiveNotebookId(result.notebook_id); await refreshNotebooks(); - setUploadedFilename(file.name); showToast(`${file.name} indexed successfully`, 'success'); // Mark wizard complete and hand off diff --git a/apps/desktop/src/components/ui/ZoteroImport.tsx b/apps/desktop/src/components/ui/ZoteroImport.tsx index 211de6d..09b6a13 100644 --- a/apps/desktop/src/components/ui/ZoteroImport.tsx +++ b/apps/desktop/src/components/ui/ZoteroImport.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react'; -import { useAppStore } from '../../store/app-store'; import { useNotebooks } from '../../hooks/useNotebooks'; import { showToast } from './Toast'; import './zotero-import.css'; diff --git a/apps/desktop/src/hooks/useChat.ts b/apps/desktop/src/hooks/useChat.ts index ed56838..34e5b30 100644 --- a/apps/desktop/src/hooks/useChat.ts +++ b/apps/desktop/src/hooks/useChat.ts @@ -47,7 +47,7 @@ export function useChat() { const sources: SourceChunk[] = (event.sources ?? []).map((src) => ({ ...src, document_name: src.source_path.split(/[/\\]/).pop() ?? src.source_path, - relevance_score: (src as Record).relevance_score as number | undefined, + relevance_score: src.relevance_score, })); s.setActiveSources(sources); // Capture conversation_id from backend (created on first message) diff --git a/apps/desktop/src/types.ts b/apps/desktop/src/types.ts index 9c48dc7..d425e3f 100644 --- a/apps/desktop/src/types.ts +++ b/apps/desktop/src/types.ts @@ -21,6 +21,8 @@ export interface StreamSource { source_path: string; preview: string; distance?: number | null; + relevance_score?: number; + notebook_id?: string; } export type ChatStreamEvent = @@ -94,6 +96,7 @@ export interface SourceChunk { distance?: number | null; document_name: string; relevance_score?: number; + notebook_id?: string; } export interface CreateNotebookRequest { diff --git a/backend/notebooklm_backend/models/chat.py b/backend/notebooklm_backend/models/chat.py index 76c2d30..5ac3fcb 100644 --- a/backend/notebooklm_backend/models/chat.py +++ b/backend/notebooklm_backend/models/chat.py @@ -14,7 +14,10 @@ class ChatRequest(BaseModel): prompt: str history: List[ChatMessage] | None = None notebook_id: str | None = Field(None, description="Optional notebook ID for RAG-enabled chat") - notebook_ids: List[str] | None = Field(None, description="Optional list of notebook IDs for cross-notebook synthesis") + notebook_ids: List[str] | None = Field( + None, + description="Optional list of notebook IDs for cross-notebook synthesis", + ) conversation_id: str | None = Field(None, description="Optional conversation ID for persistence") diff --git a/backend/notebooklm_backend/routes/chat.py b/backend/notebooklm_backend/routes/chat.py index aadddb5..7f20377 100644 --- a/backend/notebooklm_backend/routes/chat.py +++ b/backend/notebooklm_backend/routes/chat.py @@ -46,7 +46,6 @@ async def event_generator(): accumulated_reply = "" sources_data: list[dict] | None = None conversation_id = payload.conversation_id - persist_warning = False try: # Create conversation on first message if no conversation_id provided diff --git a/backend/notebooklm_backend/services/conversation_store.py b/backend/notebooklm_backend/services/conversation_store.py index 7a9df0e..bc8518f 100644 --- a/backend/notebooklm_backend/services/conversation_store.py +++ b/backend/notebooklm_backend/services/conversation_store.py @@ -5,8 +5,7 @@ import uuid from contextlib import contextmanager from datetime import datetime, timezone -from dataclasses import dataclass, field -from pathlib import Path +from dataclasses import dataclass from typing import Iterable from ..config import AppConfig diff --git a/backend/tests/test_conversation_store.py b/backend/tests/test_conversation_store.py index aefec72..6627c76 100644 --- a/backend/tests/test_conversation_store.py +++ b/backend/tests/test_conversation_store.py @@ -143,9 +143,9 @@ def test_messages_ordered_by_created_at(store): def test_conversations_ordered_by_updated_at(store): c1 = store.create_conversation(notebook_id="nb1", title="Older") - c2 = store.create_conversation(notebook_id="nb1", title="Newer") + store.create_conversation(notebook_id="nb1", title="Newer") - # c2 was created after c1, so it should appear first (DESC order) + # The newer conversation was created after c1, so it should appear first (DESC order) convs = store.list_conversations("nb1") assert convs[0].title == "Newer" assert convs[1].title == "Older" diff --git a/backend/tests/test_cross_notebook.py b/backend/tests/test_cross_notebook.py index 595b0e8..e5bc5eb 100644 --- a/backend/tests/test_cross_notebook.py +++ b/backend/tests/test_cross_notebook.py @@ -2,7 +2,7 @@ import pytest from notebooklm_backend.config import AppConfig -from notebooklm_backend.services.vector_store import VectorStoreManager, create_vector_store +from notebooklm_backend.services.vector_store import create_vector_store from notebooklm_backend.services.chunking import TextChunk