feat: Add file management IPC handlers#40
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the
📝 WalkthroughWalkthroughAdds Assistant management: service, IPC handlers, preload APIs, types, React context/hooks/components, mode switcher, and persistence for a per-profile preferred Explorer mode; integrates AssistantService into PineconeService and exposes assistant file operations. Changes
Sequence Diagram(s)sequenceDiagram
participant Renderer as Renderer (UI)
participant Preload as Preload (electronAPI)
participant Main as Main (ipcMain)
participant PineconeSvc as PineconeService
participant AssistantSvc as AssistantService
participant PineconeSDK as Pinecone SDK
Renderer->>Preload: call assistant.list(profileId)
Preload->>Main: invoke 'assistant:list' IPC
Main->>PineconeSvc: ensure connected, getAssistantService()
PineconeSvc->>AssistantSvc: delegate listAssistants()
AssistantSvc->>PineconeSDK: API call -> list assistants
PineconeSDK-->>AssistantSvc: assistants data
AssistantSvc-->>PineconeSvc: mapped AssistantModel[]
PineconeSvc-->>Main: return data
Main-->>Preload: IPC response {success:true,data}
Preload-->>Renderer: resolve Promise with assistants
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In @.linear.toml:
- Around line 1-4: The workspace name in .linear.toml is inconsistent with the
repository comment: update the workspace value to match this project's name (or
correct the comment) by changing the workspace = "chroma-explorer" entry or
replacing the top comment that mentions "Pinecone Explorer" so they align;
locate the workspace key in .linear.toml and make the string match the actual
project/repo name or adjust the descriptive comment accordingly.
In `@electron/assistant-service.ts`:
- Around line 27-30: The call to .map(this.mapAssistantModel) loses the class
instance context; change it to use a bound or arrow wrapper so the method keeps
the correct this (e.g., replace .map(this.mapAssistantModel) with .map(a =>
this.mapAssistantModel(a)) or .map(this.mapAssistantModel.bind(this)) in
listAssistants and in any other places where mapAssistantModel is passed
directly to .map to ensure the method retains its class context if it later uses
instance members.
In `@electron/pinecone-service.ts`:
- Line 40: The disconnect() method currently clears client, embeddingService,
profile, and caches but leaves the old AssistantService instance alive; update
disconnect() to also clear the AssistantService reference by calling any
available cleanup on it (e.g., a close/dispose/shutdown method if
AssistantService exposes one) and then set this.assistantService = null so a
stale AssistantService tied to old credentials cannot be reused; locate the
assistantService field and the disconnect() method and perform this cleanup
there.
In `@electron/types.ts`:
- Around line 53-57: The ExplorerMode type exported from electron/types.ts is
unused and duplicates the definition in ModeContext.tsx; either delete the
ExplorerMode declaration from electron/types.ts or centralize it by
moving/exporting the single ExplorerMode type from electron/types.ts and
updating src/context/ModeContext.tsx to import ExplorerMode instead of
redefining it; locate the ExplorerMode type in electron/types.ts and
ModeContext.tsx and apply one of the two options consistently so only one shared
definition remains.
In `@src/components/assistants/AssistantsPanel.tsx`:
- Around line 155-158: The title attribute on the assistant list item uses a
template literal with "\n" which may not render line breaks across browsers;
update the title to a single-line format (e.g., `${assistant.name} — Status:
${getStatusTooltip(assistant.status)}`) or remove the status from title and rely
on the existing status indicator/tooltip; modify the JSX where onClick uses
handleAssistantClick and onContextMenu uses handleAssistantContextMenu to
replace the multiline title with a single-line string or omit it entirely.
In `@src/context/ModeContext.tsx`:
- Around line 36-52: The keyboard listener's useEffect in ModeContext.tsx
captures a stale setMode because it's omitted from the dependency array; update
the effect to depend on the current setMode (or stabilize setMode with
useCallback) so the handler always calls the latest function: in the useEffect
that defines handleKeyDown, replace the empty deps array with [setMode] (and
remove the eslint-disable-line react-hooks/exhaustive-deps) or alternatively
memoize handleKeyDown via useCallback referencing setMode and keep the effect
deps consistent; ensure the symbols referenced are useEffect, handleKeyDown, and
setMode.
🧹 Nitpick comments (8)
src/context/AssistantSelectionContext.tsx (1)
14-16: UnnecessaryuseCallbackwrapper.The
setActiveAssistantStatefromuseStateis already referentially stable across renders. Wrapping it inuseCallbackadds no benefit here.♻️ Suggested simplification
- const setActiveAssistant = useCallback((assistantName: string | null) => { - setActiveAssistantState(assistantName) - }, []) + const setActiveAssistant = setActiveAssistantStateThen update the imports to remove
useCallback:-import { createContext, useContext, useState, useCallback, useMemo, ReactNode } from 'react' +import { createContext, useContext, useState, useMemo, ReactNode } from 'react'electron/assistant-service.ts (1)
56-64: Extra network round-trip inupdateAssistant.The method makes two API calls: one to update and one to fetch the updated assistant. The comment explains the rationale, but this adds latency and potential inconsistency if the assistant changes between calls.
Consider whether returning the response from
updateAssistantdirectly (if it contains sufficient data) or documenting this behavior for callers would be preferable.src/components/mode/ModeSwitcher.tsx (1)
44-45: Consider using thelabelfrom the modes array for consistency.Line 45 duplicates the label logic rather than reusing the
labelproperty from the modes array. This could lead to inconsistencies if labels change.💡 Suggested improvement
<Icon className="h-3.5 w-3.5" /> - <span className="hidden sm:inline">{value === 'index' ? 'Index' : 'Assistant'}</span> + <span className="hidden sm:inline">{label.replace(' Explorer', '')}</span> </button>Alternatively, add a
shortLabelproperty toModeOptionif you want different display values.src/components/assistants/AssistantsPanel.tsx (1)
84-88: UnnecessaryuseCallbackwrapper.This callback simply forwards to
onCreateNewwithout any additional logic. You can passonCreateNewdirectly to the button'sonClickor inline it.💡 Simplification
- const handleCreateNew = useCallback(() => { - if (onCreateNew) { - onCreateNew() - } - }, [onCreateNew])Then use
onClick={onCreateNew}directly on line 107, since the button already handles undefined gracefully.src/hooks/useAssistantQueries.ts (1)
135-140: Consider also invalidating the list query on successful delete.The optimistic update removes the assistant from the cached list in
onMutate, but if the mutation succeeds, the list query cache isn't explicitly invalidated. This works because the optimistic update persists, but for consistency with create/update mutations and to ensure eventual consistency with the server, consider adding a list invalidation.💡 Suggested addition
onSuccess: (data) => { + // Invalidate list to ensure consistency with server + queryClient.invalidateQueries({ + queryKey: assistantQueryKeys.list(data.profileId), + }) // Remove detail query for the deleted assistant queryClient.removeQueries({ queryKey: assistantQueryKeys.detail(data.profileId, data.assistantName), }) },electron/main.ts (2)
819-832: Consider using imported type for consistency.The handler uses an inline type definition for
paramsinstead of the importedCreateAssistantParamstype. While functionally equivalent, using the imported type improves maintainability.💡 Suggested change
+import { + // ... existing imports + CreateAssistantParams, + UpdateAssistantParams, + UploadAssistantFileParams, + ListAssistantFilesFilter, +} from './types' -ipcMain.handle('assistant:create', async (_event, profileId: string, params: { name: string; instructions?: string; metadata?: Record<string, string>; region?: 'us' | 'eu' }) => { +ipcMain.handle('assistant:create', async (_event, profileId: string, params: CreateAssistantParams) => {Apply similar changes to
assistant:update(line 849),assistant:files:list(line 883), andassistant:files:upload(line 913).
804-877: Consider adding analytics tracking for assistant operations.Index operations include analytics tracking (e.g.,
track('index_created')), but the new assistant handlers don't include similar tracking. If usage analytics are important for assistants, consider adding tracking calls.src/context/ModeContext.tsx (1)
4-4: Consolidate duplicate Electron type definitions.
ExplorerModeis defined in three locations:src/context/ModeContext.tsx(line 4),electron/types.ts(line 55), andsrc/types/electron.d.ts. The more critical issue is thatelectron/types.tsandsrc/types/electron.d.tsdefine the entire Electron API surface identically. Consider consolidating these parallel type definitions and, if theModeContextexport is only used locally, documenting whether it should remain isolated as a React-layer type or be imported from the electron types.
electron/types.ts
Outdated
| /** | ||
| * Explorer mode type - Index Explorer or Assistant Explorer | ||
| */ | ||
| export type ExplorerMode = 'index' | 'assistant' | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Search for ExplorerMode type definitions
rg -n "type ExplorerMode\s*=" --type ts -A 2Repository: stepandel/pinecone-explorer
Length of output: 512
🏁 Script executed:
# Check where ExplorerMode is imported from
rg -n "import.*ExplorerMode|from.*ExplorerMode" --type ts -B 2 -A 2Repository: stepandel/pinecone-explorer
Length of output: 361
🏁 Script executed:
# Show the full context of both definitions
echo "=== electron/types.ts ===" && sed -n '50,60p' electron/types.ts
echo -e "\n=== src/context/ModeContext.tsx ===" && head -10 src/context/ModeContext.tsxRepository: stepandel/pinecone-explorer
Length of output: 676
🏁 Script executed:
# Find all imports of ExplorerMode, showing which file it's imported from
rg -n "import.*ExplorerMode" --type ts --type tsx -B 1 -A 1Repository: stepandel/pinecone-explorer
Length of output: 98
🏁 Script executed:
# Check if electron/types.ts is exported from anywhere
rg -n "from.*electron/types|from.*electron['\"]" --type ts --type tsx | head -20Repository: stepandel/pinecone-explorer
Length of output: 98
🏁 Script executed:
# Check if src/types/electron.d.ts is auto-generated or intentionally maintained
head -20 src/types/electron.d.tsRepository: stepandel/pinecone-explorer
Length of output: 732
🏁 Script executed:
# Search for all imports of ExplorerMode without type filter
rg -n "import.*ExplorerMode" -A 1Repository: stepandel/pinecone-explorer
Length of output: 215
🏁 Script executed:
# Check what exports from electron/types.ts are actually used
rg -n "from.*['\"].*electron/types['\"]"Repository: stepandel/pinecone-explorer
Length of output: 719
🏁 Script executed:
# Find all TypeScript/React files and search for ExplorerMode usage
fd -e ts -e tsx | xargs grep -l "ExplorerMode" | head -20Repository: stepandel/pinecone-explorer
Length of output: 177
🏁 Script executed:
# Check if electron/types.ts is used for main process or IPC types
head -30 electron/types.ts
# Check git history or comments about why ExplorerMode is in electron/types.ts
rg -B 5 "export type ExplorerMode" electron/types.tsRepository: stepandel/pinecone-explorer
Length of output: 989
🏁 Script executed:
# Verify if anything imports ExplorerMode from electron/types.ts
rg "ExplorerMode.*from.*electron/types"Repository: stepandel/pinecone-explorer
Length of output: 53
Remove unused ExplorerMode type from electron/types.ts.
ExplorerMode is defined in three locations but only src/context/ModeContext.tsx is actually imported and used in the codebase. The definition in electron/types.ts (line 56) is dead code. Since electron/types.ts is the central types module for shared Pinecone types, consolidate by either:
- Remove the unused definition from
electron/types.ts, or - Export from
electron/types.tsand import it intoModeContext.tsxto align with other shared types.
🤖 Prompt for AI Agents
In `@electron/types.ts` around lines 53 - 57, The ExplorerMode type exported from
electron/types.ts is unused and duplicates the definition in ModeContext.tsx;
either delete the ExplorerMode declaration from electron/types.ts or centralize
it by moving/exporting the single ExplorerMode type from electron/types.ts and
updating src/context/ModeContext.tsx to import ExplorerMode instead of
redefining it; locate the ExplorerMode type in electron/types.ts and
ModeContext.tsx and apply one of the two options consistently so only one shared
definition remains.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
There was a problem hiding this comment.
Claude finished @stepandel's task in 1m 8s —— View job
Applying proposed fix ✅
- Read
electron/types.tsto confirm the duplicateExplorerModedefinition - Verify
ExplorerModefromelectron/types.tsis unused - Remove the unused type definition
- Commit and push changes
Changes made:
- Removed unused
ExplorerModetype definition fromelectron/types.ts(lines 53-56) - Updated
ConnectionProfile.preferredModeto use inline union type'index' | 'assistant'instead of referencing the removed type
The fix has been applied and pushed to the pine-40-file-handlers branch in commit c3a86ad.
Add file operations scoped to a specific assistant: Types (electron/types.ts): - AssistantFileStatus enum: Processing, Available, Deleting, ProcessingFailed - AssistantFile interface with id, name, status, percentDone, metadata, signedUrl, errorMessage - ListAssistantFilesFilter for filtering files - UploadAssistantFileParams for file upload with metadata AssistantService (electron/assistant-service.ts): - listFiles(assistantName, filter?) - List files for an assistant - describeFile(assistantName, fileId) - Get file details with signed URL - uploadFile(assistantName, params) - Upload file from disk path - deleteFile(assistantName, fileId) - Delete a file IPC handlers (electron/main.ts): - assistant:files:list - assistant:files:describe - assistant:files:upload - assistant:files:delete Preload bindings (electron/preload.ts): - assistant.files.list() - assistant.files.describe() - assistant.files.upload() - assistant.files.delete() TypeScript declarations (src/types/electron.d.ts): - Added all file types and API methods
- AssistantsPanel: Convert assistant row div to button for keyboard accessibility - AssistantsPanel: Add aria-pressed attribute for active state - ModeContext: Fix stale setMode closure by adding to useEffect dependencies - ModeContext: Reorder setMode definition before keyboard effect
859cff8 to
43709fd
Compare
The ExplorerMode type was defined in electron/types.ts but never imported or used. The only active definition is in src/context/ModeContext.tsx. This change removes the duplicate definition and updates ConnectionProfile.preferredMode to use an inline union type. Co-authored-by: Stepan Arsentjev <stepandel@users.noreply.github.com>
* feat: Add ModeContext and ModeSwitcher UI (#37) * feat: Add ModeContext and ModeSwitcher UI - Add ModeContext for managing index/assistant mode state - Add ModeSwitcher segmented control with Database/Bot icons - Persist mode preference per connection profile - Add keyboard shortcuts Cmd+1 (Index) and Cmd+2 (Assistant) Closes PINE-36 * fix: address review comments on PINE-36 - Update .linear.toml workspace from chroma-explorer to pinecone-explorer - Make setPreferredMode throw on missing profile instead of silently no-op - Change ModeSwitcher from tablist/tab to radiogroup/radio for accessibility * fix: add packages field to pnpm-workspace.yaml for CI * fix: add aria-label for accessible name on ModeSwitcher buttons --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * feat: Add AssistantService with CRUD operations (#38) * feat: Add AssistantService with CRUD operations - Add AssistantService class wrapping Pinecone SDK assistant methods - Add IPC handlers for assistant:list/create/describe/update/delete - Add preload bindings for window.electronAPI.assistant - Add TypeScript types for AssistantModel, CreateAssistantParams, UpdateAssistantParams - Wire up service to PineconeService with getAssistantService() method Closes PINE-37 * fix: address review comments on PINE-37 - Normalize metadata null to undefined in mapAssistantModel - Fix stale setMode closure in keyboard shortcut handler (moved setMode before useEffect, added to deps) --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * feat: Add AssistantsPanel component (#39) * feat: Add AssistantsPanel component - Add useAssistantQueries.ts with React Query hooks for assistant CRUD - Add AssistantSelectionContext.tsx for managing selected assistant - Add AssistantsPanel.tsx mirroring IndexesPanel pattern - Status indicators: Ready (green), Initializing (yellow), Failed (red) - Loading, error, and empty states handled Closes PINE-38 * feat(assistant): add file management IPC handlers (PINE-40) Add file operations scoped to a specific assistant: Types (electron/types.ts): - AssistantFileStatus enum: Processing, Available, Deleting, ProcessingFailed - AssistantFile interface with id, name, status, percentDone, metadata, signedUrl, errorMessage - ListAssistantFilesFilter for filtering files - UploadAssistantFileParams for file upload with metadata AssistantService (electron/assistant-service.ts): - listFiles(assistantName, filter?) - List files for an assistant - describeFile(assistantName, fileId) - Get file details with signed URL - uploadFile(assistantName, params) - Upload file from disk path - deleteFile(assistantName, fileId) - Delete a file IPC handlers (electron/main.ts): - assistant:files:list - assistant:files:describe - assistant:files:upload - assistant:files:delete Preload bindings (electron/preload.ts): - assistant.files.list() - assistant.files.describe() - assistant.files.upload() - assistant.files.delete() TypeScript declarations (src/types/electron.d.ts): - Added all file types and API methods * feat: Add FilesPanel component - Add useFilesQuery hook with dynamic polling (5s while processing) - Add FileSelectionContext for tracking selected file - Add FilesPanel component with status indicators and upload button - Add dialog:showOpenDialog IPC handler for native file picker - Wire up providers in ConnectionWindow Closes PINE-41 * feat(files): add UploadFileDialog component with drag-and-drop support PINE-42 - Add useUploadFileMutation hook to useAssistantQueries.ts - Create UploadFileDialog component with: - Drag-and-drop file zone - File picker button using native dialog - Selected file preview with name and size - Optional metadata JSON editor with validation - Multimodal checkbox (enabled only for PDF files) - Upload progress indicator - Error handling with inline message - Dialog closes on successful upload - Wire up FilesPanel upload button to open UploadFileDialog * feat(PINE-43): Create FileDetailPanel component - Create FileDetailPanel.tsx showing file metadata when selected - Add ID field with copy-to-clipboard button - Display status with color indicator (Available/Processing/Failed/Deleting) - Show processing progress bar when file is processing - Show error message section for failed files - Display timestamps (created/updated) with formatted dates - Show custom metadata as JSON - Add Download button that opens signedUrl via shell.openExternal - Add Delete button with confirmation dialog - Add useDeleteFileMutation and useFileDetailQuery hooks to useAssistantQueries.ts - Export FileDetailPanel from files/index.ts Note: File size display not implemented as AssistantFile type from Pinecone API does not include a size field. * feat: Add chat IPC handlers with streaming support - Add ChatMessage, ChatParams, ChatResponse, ChatStreamChunk types - Add chat() and chatStream() methods to AssistantService - Add IPC handlers for assistant:chat, assistant:chat:stream:start/cancel - Add preload bindings with onChunk event listener for streaming - Track active streams with AbortController for cancellation Closes PINE-44 * feat(PINE-45): Create ChatView main component - Create src/components/chat/ChatView.tsx - Layout with scrollable message list and fixed input area - Message display with user/assistant avatars and styling - Model dropdown selector (gpt-4o, claude-3-5-sonnet, gemini-2.0-flash) - Clear conversation button - Auto-scroll to bottom on new messages - Submit on Enter, Shift+Enter for newline - Send button disabled while streaming - Stop generation button during streaming - Citation display for assistant messages - Empty state with helpful instructions - Create src/hooks/useChatStream.ts - Manages streaming state and message accumulation - Handles chunk events (message_start, content, citation, message_end, error) - Returns: messages, isStreaming, sendMessage, clearMessages, cancelStream - Properly cleans up subscriptions on unmount - Update src/components/layout/MainContent.tsx - Import ModeContext and AssistantSelectionContext - Render ChatView when mode === 'assistant' and an assistant is selected - Show empty state message when in assistant mode without selection - Keep existing VectorsView for mode === 'index' * feat(PINE-46): Create ChatMessage component with streaming - Add ChatMessage component with markdown support via react-markdown - User messages right-aligned with blue/primary background - Assistant messages left-aligned with muted background - Typing indicator (animated dots) when streaming with empty content - Live cursor animation during content streaming - Citation numbers as clickable superscripts inline with text - Styled code blocks and inline code - Update ChatView to use new ChatMessage component * feat(chat): add CitationPopover component for interactive citations - Create CitationPopover component using Radix Popover - Shows file name and page numbers for each reference - View File button navigates using FileSelectionContext - Update ChatMessage to wrap citation superscripts with popover - Popover closes on outside click (Radix default behavior) Closes PINE-47 * feat: Wire up Assistant mode in MainContent - Conditionally render AssistantsPanel/IndexesPanel based on mode - Conditionally render FilesPanel/NamespacesPanel based on mode - Conditionally render FileDetailPanel/VectorDetailPanel based on mode - Preserve panel resize handles and widths - Selection state isolated between modes via separate contexts Closes PINE-48 * feat(PINE-49): Add context menus for Assistants and Files - Add IPC handlers in main.ts for context-menu:show-assistant and context-menu:show-file - Add preload bindings for showAssistantMenu, onAssistantAction, showFileMenu, onFileAction - Update AssistantsPanel.tsx with: - Native context menu on right-click with Edit and Delete options - Delete confirmation dialog with name verification - Hook integration with useDeleteAssistantMutation - Update FilesPanel.tsx with: - Native context menu on right-click with Download and Delete options - Delete confirmation dialog - Download via signedUrl fetch and shell.openExternal - Hook integration with useDeleteFileMutation and useFileDetailQuery - Update TypeScript declarations in electron.d.ts Acceptance criteria: - Right-click assistant shows Edit/Delete menu ✓ - Right-click file shows Download/Delete menu ✓ - Delete actions show confirmation dialog ✓ - Menu actions trigger correct operations ✓ * feat(PINE-50): Add keyboard shortcuts for Assistant mode - Update keyboard shortcuts constants with new assistant/chat categories: - INDEX_MODE (Cmd+1): Switch to Index mode - ASSISTANT_MODE (Cmd+2): Switch to Assistant mode - NEW_ASSISTANT (Cmd+Shift+N): Create new assistant - SEND_MESSAGE (Cmd+Enter): Send chat message - FOCUS_CHAT_INPUT (Cmd+K): Focus chat input - CLEAR_CONVERSATION (Cmd+Shift+Backspace): Clear conversation - Update electron menu.ts: - Replace panel toggle items with Index Mode/Assistant Mode in View menu - Add Assistant menu with New Assistant, Chat submenu, Edit/Delete items - Chat submenu includes Send, Focus Input, Clear Conversation - Add IPC bindings in preload.ts for new menu events: - Mode switching: onSwitchToIndexMode, onSwitchToAssistantMode - Assistant: onNewAssistant, onEditAssistant, onDeleteAssistant - Chat: onSendMessage, onFocusChatInput, onClearConversation - Update ModeContext.tsx to listen for menu IPC events - Update ChatView.tsx with keyboard shortcut handlers: - Cmd+K focuses chat input - Cmd+Shift+Backspace clears conversation - Cmd+Enter sends message (via menu) - Update AssistantsPanel.tsx: - Cmd+Shift+N creates new assistant - Handle menu events for edit/delete assistant - Update TypeScript types in electron.d.ts - Clean up obsolete toggle panel handlers from useMenuHandlers.ts --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> * feat: Add file management IPC handlers (#40) * feat(assistant): add file management IPC handlers (PINE-40) Add file operations scoped to a specific assistant: Types (electron/types.ts): - AssistantFileStatus enum: Processing, Available, Deleting, ProcessingFailed - AssistantFile interface with id, name, status, percentDone, metadata, signedUrl, errorMessage - ListAssistantFilesFilter for filtering files - UploadAssistantFileParams for file upload with metadata AssistantService (electron/assistant-service.ts): - listFiles(assistantName, filter?) - List files for an assistant - describeFile(assistantName, fileId) - Get file details with signed URL - uploadFile(assistantName, params) - Upload file from disk path - deleteFile(assistantName, fileId) - Delete a file IPC handlers (electron/main.ts): - assistant:files:list - assistant:files:describe - assistant:files:upload - assistant:files:delete Preload bindings (electron/preload.ts): - assistant.files.list() - assistant.files.describe() - assistant.files.upload() - assistant.files.delete() TypeScript declarations (src/types/electron.d.ts): - Added all file types and API methods * fix: address review comments - pnpm workspace, linear config, AssistantStatus type * fix: address review comments on PINE-40 - AssistantsPanel: Convert assistant row div to button for keyboard accessibility - AssistantsPanel: Add aria-pressed attribute for active state - ModeContext: Fix stale setMode closure by adding to useEffect dependencies - ModeContext: Reorder setMode definition before keyboard effect * fix: remove unused ExplorerMode type from electron/types.ts The ExplorerMode type was defined in electron/types.ts but never imported or used. The only active definition is in src/context/ModeContext.tsx. This change removes the duplicate definition and updates ConnectionProfile.preferredMode to use an inline union type. Co-authored-by: Stepan Arsentjev <stepandel@users.noreply.github.com> --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Stepan Arsentjev <stepandel@users.noreply.github.com> * feat: Add FilesPanel component (#41) * feat: Add FilesPanel component - Add useFilesQuery hook with dynamic polling (5s while processing) - Add FileSelectionContext for tracking selected file - Add FilesPanel component with status indicators and upload button - Add dialog:showOpenDialog IPC handler for native file picker - Wire up providers in ConnectionWindow Closes PINE-41 * fix: address review comments - pnpm workspace, linear config, AssistantStatus type * fix: clear assistantService on disconnect, remove files from later PRs --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * fix build: add stub FileDetailPanel * fix: Address PR review comments - Add registerAccelerator: false to New Index menu item for consistency - Add cancellation guard in ModeContext to prevent stale mode updates - Handle 'InitializationFailed' status in AssistantsPanel - Make citation superscripts keyboard accessible (button with aria-label) - Validate URL protocol before calling openExternal for security - Disable delete button when file status is 'Deleting' - Clear messages when switching assistants in useChatStream * feat: Add AssistantConfigView for create/edit (#51) - Add AssistantConfigView component for creating/editing assistants - Add DraftAssistantContext for managing draft assistant state - Wire up AssistantConfigView in MainContent - Add DraftAssistantProvider to ConnectionWindow Closes PINE-39 Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * fix: address review comments on PINE-42 (#42) Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * fix: address review comments on PINE-44 (#45) - Remove @ts-expect-error, add temperature/contextOptions to chat params - Add isDestroyed check and error handling for streaming in main.ts - Clear assistantService on disconnect in pinecone-service.ts - Make assistant rows keyboard-accessible (use button element) - Add IME composition check (isComposing) to prevent accidental submit - Use stable message keys (message.id) instead of array index - Reset conversation state when assistantName changes - Remove empty assistant placeholder when canceling stream - Pass multimodal flag through file upload flow Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * fix: address review comments on PINE-39 (#47) - Fix .linear.toml workspace (chroma-explorer → pinecone-explorer) - Add packages field to pnpm-workspace.yaml for CI - Add InitializationFailed to AssistantStatus type - Reset assistantService on connect/disconnect Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * fix: address review comments on PINE-49 (#49) - Pass temperature and contextOptions to chat() and chatStream() methods - Add multimodal param to upload file flow (types, hook, service) - Guard handleConfirmDelete against null currentProfile - Use stable message.id key instead of array index in ChatView - Fix download race condition by verifying fileDetail matches fileToDownload - Keep file detail cache consistent during delete operations - Handle early stream chunks before stream ID is set Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> * fix: Address additional PR review comments (round 2) - Add assistant and chat menu event handlers to preload.ts - Add types for new menu handlers in electron.d.ts - Add pending guard to prevent duplicate delete calls in AssistantsPanel - Reset initialization state when profile changes in ModeContext - Extract shared Markdown components to reduce duplication in ChatMessage * fix buid errors * feat: Add E2E test suite for Assistant feature (#53) * feat(e2e): add data-testid attributes to assistant components Add comprehensive data-testid attributes for E2E testing: Mode: - mode-switcher, mode-index, mode-assistant Assistants: - assistants-panel, assistant-item, assistant-status - new-assistant-button, assistant-config-view - assistant-name-input, assistant-instructions-input - assistant-save-button, assistant-cancel-button Files: - files-panel, files-empty-state, file-item - upload-file-button, file-detail-panel - file-detail-empty-state, file-download-button - file-delete-button, upload-file-dialog - browse-files-button, upload-submit-button Chat: - chat-view, chat-message-list, chat-input - chat-send-button, chat-stop-button - chat-clear-button, chat-model-selector - chat-message-user, chat-message-assistant Citations: - citation-superscript, citation-popover - citation-reference, citation-file-name - citation-view-file-button Part of PINE-51 * fix(e2e): Address PR review comments - 13 actionable items Fixes from CodeRabbit review: 1. assistant-citations.spec.ts: - Citation test now explicitly skips with message when no citations - Multiple citations test uses test.skip() when citationCount <= 1 2. assistant-crud.spec.ts: - Added assertion for errorMessage visibility in validation test - Context menu edit test now explicitly skipped (native menu limitation) 3. assistant-file-detail.spec.ts: - File selection test explicitly skips when fileCount === 0 - Delete test now asserts file disappears and count decreases 4. assistant-integration.spec.ts: - Network failure test now uses page.route() to simulate failures 5. assistant-mode.spec.ts: - Cross-platform keyboard shortcuts (Meta on macOS, Control on others) - Mode persistence test asserts switcher visibility (no silent skip) 6. assistant-upload.spec.ts: - API upload test: skip until real file fixture available - Metadata input test: skip until file dialog mocking available - Processing status test: explicit skip when no files - Progress test: skip until upload flow is wired --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> * fix(assistant): wire chatStream API through preload (#54) PINE-55: Fix 'Cannot read properties of undefined (reading onChunk)' Root cause: useChatStream.ts expected assistant.chatStream.* APIs but electron/preload.ts never exposed them. IPC handlers existed in main.ts but weren't wired through the preload bridge. Changes: - Add Chat types to electron/types.ts (ChatMessage, Citation, CitationReference, ChatUsage, ChatParams, ChatResponse, ChatStreamChunk) - Add chatStream namespace to assistant API in preload.ts with start/cancel/onChunk methods - Add corresponding TypeScript types to src/types/electron.d.ts The chatStream API now properly exposes: - start(profileId, assistantName, params) -> streamId - cancel(streamId) -> void - onChunk(callback) -> cleanup function Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> * fix: Phase 6 feedback - dialog API and mode labels (PINE-53, PINE-54) (#55) * fix(assistant): wire chatStream API through preload PINE-55: Fix 'Cannot read properties of undefined (reading onChunk)' Root cause: useChatStream.ts expected assistant.chatStream.* APIs but electron/preload.ts never exposed them. IPC handlers existed in main.ts but weren't wired through the preload bridge. Changes: - Add Chat types to electron/types.ts (ChatMessage, Citation, CitationReference, ChatUsage, ChatParams, ChatResponse, ChatStreamChunk) - Add chatStream namespace to assistant API in preload.ts with start/cancel/onChunk methods - Add corresponding TypeScript types to src/types/electron.d.ts The chatStream API now properly exposes: - start(profileId, assistantName, params) -> streamId - cancel(streamId) -> void - onChunk(callback) -> cleanup function * fix: Phase 6 feedback - dialog API and mode labels PINE-54: Wire dialog API through preload - Add dialog.showOpenDialog to electron/preload.ts - Add corresponding TypeScript types PINE-53: Update mode labels to 'Database' instead of 'Index' - Change 'Index Explorer' → 'Database Explorer' in tooltip - Change 'Index' → 'Database' in button text --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> * fix uploader * fix(assistant): use SDK chatStream method instead of chat with stream flag The Pinecone SDK has a dedicated `assistant.chatStream()` method for streaming. Passing `stream: true` to `assistant.chat()` is invalid and causes an API error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(assistant): update supported models list to match Pinecone Assistant Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style(chat): compact macOS-native chat UI Remove avatars and role labels for an Apple Messages-style layout. Tighten spacing, use pill-shaped bubbles, circular send button, and smaller typography to match the app's TopBar and sidebar density. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat(files): add right-click context menu for file actions (#56) PINE-56: Phase 6 feedback - Part 2 Add file context menu with Download and Delete actions: - Add showFileMenu/onFileAction to electron/preload.ts - IPC handler already existed in main.ts (lines 656-673) - Add onContextMenu handler to FilesPanel file buttons - Delete action shows confirmation dialog, then deletes file - Download action opens signed URL in browser - Add TypeScript types to electron.d.ts Shortcuts in Settings were already implemented (keyboard-shortcuts.ts has 'assistant' and 'chat' categories). Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> * feat(analytics): add tracking for Assistant events (PINE-57) (#57) * feat(files): add right-click context menu for file actions PINE-56: Phase 6 feedback - Part 2 Add file context menu with Download and Delete actions: - Add showFileMenu/onFileAction to electron/preload.ts - IPC handler already existed in main.ts (lines 656-673) - Add onContextMenu handler to FilesPanel file buttons - Delete action shows confirmation dialog, then deletes file - Download action opens signed URL in browser - Add TypeScript types to electron.d.ts Shortcuts in Settings were already implemented (keyboard-shortcuts.ts has 'assistant' and 'chat' categories). * feat(analytics): add tracking for Assistant events PINE-57: Phase 7 - Add analytics Add track() calls to Assistant IPC handlers: - assistant_created (with region) - assistant_deleted - file_uploaded (with multimodal flag) - file_deleted - chat_message_sent (with model, messageCount) - chat_stream_started (with model) Follows existing analytics pattern from index operations. --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> * fix(files): poll for Deleting status to update UI after file removal The files query only polled while files had 'Processing' status, so files stuck in 'Deleting' status never refreshed until a manual page reload. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(assistant): production readiness fixes from audit Address 10 issues found during production readiness audit: 1. Fix IPC wiring for menu-driven mode switching (onIndexMode/onAssistantMode) 2. Add URL protocol validation in shell:openExternal (block non-http(s)) 3. Add confirmation dialog before file deletion in FileDetailPanel 4. Surface file operation errors to users in FilesPanel (upload/delete/download) 5. Resolve keyboard shortcut collision (NEW_ASSISTANT → CmdOrCtrl+Shift+A) 6. Add synchronous ref guard to prevent double-submit in useChatStream 7. Abort active chat streams when window is destroyed 8. Add vitest framework with 17 unit tests for AssistantService and matchesShortcut 9. Add file path validation (exists check) before upload in main process 10. Remove unused dependencies (sharp, dotenv, bufferutil, utf-8-validate) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * clean up --------- Co-authored-by: Atlas (Engineering Lead) <atlas@openclaw.ai> Co-authored-by: Scout (Lead Tester) <scout@openclaw.ai> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Stepan Arsentjev <stepandel@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Extend AssistantService with file operations scoped to a specific assistant.
Changes
AssistantFiletype with status enum (Processing, Available, Deleting, ProcessingFailed)assistant:files:list/describe/upload/deleteassistant.filesAPI
Files Modified
electron/types.tselectron/assistant-service.tselectron/main.tselectron/preload.tssrc/types/electron.d.tsTesting
pnpm test:build✅Closes PINE-40
Summary by CodeRabbit
New Features
Chores