* Implement inline citation for vault search for both vault QA and Plus chains refactor: enhance citation utilities and improve source handling in chain runners - Introduced new utility functions for citation management, including sanitization and formatting of source catalogs. - Updated CopilotPlusChainRunner and VaultQAChainRunner to utilize the new citation utilities for improved citation handling. - Enhanced ChatSingleMessage component to consolidate duplicate sources and ensure accurate citation numbering. - Added comprehensive tests for citation utilities to ensure functionality and edge case handling. refactor: dedupe chunks for unique titles in search tool sources refactor: enhance citation handling in CopilotPlus and VaultQA chain runners - Introduced a sanitization function to remove pre-existing citation markers from document content, preventing number leakage. - Updated the formatting of retrieved documents in VaultQA to utilize the new sanitization function for cleaner output. - Improved footnote renumbering logic in ChatSingleMessage to prioritize first-mention order, ensuring accurate citation mapping. refactor: streamline source citation handling in ChatSingleMessage component and enhance web search tool instructions - Simplified the processing of source links in ChatSingleMessage to use a more efficient mapping approach. - Updated the web search tool's instruction to clarify the use of footnote-style citations, ensuring compatibility with Markdown formatting. * feat: add inline citation setting toggle and refactor - Introduced a new setting to enable inline citations in AI-generated responses, allowing for footnote-style references within the text. - Updated citation utilities to manage fallback sources and improve citation instructions based on user settings. - Enhanced CopilotPlusChainRunner and VaultQAChainRunner to utilize the new inline citation feature, ensuring accurate source representation. - Modified ChatSingleMessage component to process inline citations based on the new setting, improving the display of sources in chat messages. - Added tests for new citation functionalities to ensure reliability and correctness. * feat: enhance citation utilities and add tests for normalization - Introduced the `normalizeCitations` function to improve citation formatting by removing periods after citations and handling footnote references. - Updated `processInlineCitations` to ensure correct mapping of non-sequential citations and consolidate duplicate sources. - Added comprehensive tests for the new citation functionalities, ensuring accurate citation processing and representation in AI-generated responses. - Modified QASettings description for clarity regarding the inline citations feature. * fix: address critical bug in citation processing for consecutive citations - Enhanced the `normalizeCitations` function to correctly handle consecutive citations without spaces, ensuring accurate mapping and representation in output. - Added a test case to replicate and validate the fix for the identified bug, confirming that both citations are processed and displayed correctly. - Updated existing citation handling logic to improve robustness and prevent unconverted citations in the output. * refactor: improve citation handling and enhance citation utilities - Refactored `CopilotPlusChainRunner` to streamline citation source management, replacing `lastCitationLines` with `lastCitationSources` for better clarity and structure. - Updated the `addFallbackSources` function to handle citation formatting more effectively, ensuring proper display of titles and paths. - Enhanced the `normalizeCitations` function to support multiple citations in brackets, ensuring correct sorting and mapping of citation numbers. - Added new test cases to validate the handling of alternate headings, HTML summaries, and multiple citations, improving overall robustness of citation processing. - Introduced `getWebSearchCitationInstructions` for web-specific citation guidance, enhancing user experience with clear instructions for inline citations. * fix: move documentations * refactor: normalize footnote rendering in ChatSingleMessage component - Introduced `normalizeFootnoteRendering` function to streamline footnote display by removing separators and backreferences, and fixing numbering artifacts. - Updated `ChatSingleMessage` to utilize the new normalization function, enhancing the clarity and presentation of footnotes in chat messages. - Added unit tests for `normalizeFootnoteRendering` to ensure proper functionality and handling of various footnote scenarios. * test: enhance ChatSingleMessage tests and add deduplication tests for search tools - Updated `ChatSingleMessage.test.tsx` to include `TooltipProvider` for improved rendering context. - Refactored mock implementation for `obsidian` to streamline testing setup. - Introduced new test file `SearchTools.dedupe.test.ts` to validate the deduplication logic in search tool sources, ensuring correct handling of duplicate entries while preserving the highest score. - Added tests to verify deduplication behavior for various scenarios, enhancing overall test coverage and reliability.
12 KiB
AGENTS.md
This file provides guidance to any coding agent when working with code in this repository.
Overview
Copilot for Obsidian is an AI-powered assistant plugin that integrates various LLM providers (OpenAI, Anthropic, Google, etc.) with Obsidian. It provides chat interfaces, autocomplete, semantic search, and various AI-powered commands for note-taking and knowledge management.
Development Commands
Build & Development
- NEVER RUN
npm run dev- The user will handle all builds manually npm run build- Production build (TypeScript check + minified output)
Code Quality
npm run lint- Run ESLint checksnpm run lint:fix- Auto-fix ESLint issuesnpm run format- Format code with Prettiernpm run format:check- Check formatting without changing files- Before PR: Always run
npm run format && npm run lint
Testing
npm run test- Run unit tests (excludes integration tests)npm run test:integration- Run integration tests (requires API keys)- Run single test:
npm test -- -t "test name"
High-Level Architecture
Core Systems
-
LLM Provider System (
src/LLMProviders/)- Provider implementations for OpenAI, Anthropic, Google, Azure, local models
LLMProviderManagerhandles provider lifecycle and switching- Stream-based responses with error handling and rate limiting
- Custom model configuration support
-
Chain Factory Pattern (
src/chainFactory.ts)- Different chain types for various AI operations (chat, copilot, adhoc prompts)
- LangChain integration for complex workflows
- Memory management for conversation context
- Tool integration (search, file operations, time queries)
-
Vector Store & Search (
src/search/)VectorStoreManagermanages embeddings and semantic searchChunkedStoragefor efficient large document handling- Event-driven index updates via
IndexManager - Multiple embedding providers support
-
UI Component System (
src/components/)- React functional components with Radix UI primitives
- Tailwind CSS with class variance authority (CVA)
- Modal system for user interactions
- Chat interface with streaming support
- Settings UI with versioned components
-
Message Management Architecture (
src/core/,src/state/)- MessageRepository (
src/core/MessageRepository.ts): Single source of truth for all messages- Stores each message once with both
displayTextandprocessedText - Provides computed views for UI display and LLM processing
- No complex dual-array synchronization
- Stores each message once with both
- ChatManager (
src/core/ChatManager.ts): Central business logic coordinator- Orchestrates MessageRepository, ContextManager, and LLM operations
- Handles message sending, editing, regeneration, and deletion
- Manages context processing and chain memory synchronization
- Project Chat Isolation: Maintains separate MessageRepository per project
- Automatically detects project switches via
getCurrentMessageRepo() - Each project has its own isolated message history
- Non-project chats use
defaultProjectKeyrepository
- Automatically detects project switches via
- ChatUIState (
src/state/ChatUIState.ts): Clean UI-only state manager- Delegates all business logic to ChatManager
- Provides React integration with subscription mechanism
- Replaces legacy SharedState with minimal, focused approach
- ContextManager (
src/core/ContextManager.ts): Handles context processing- Processes message context (notes, URLs, selected text)
- Reprocesses context when messages are edited
- MessageRepository (
-
Settings Management
- Jotai for atomic settings state management
- React contexts for feature-specific state
-
Plugin Integration
- Main entry:
src/main.tsextends Obsidian Plugin - Command registration system
- Event handling for Obsidian lifecycle
- Settings persistence and migration
- Chat history loading via pending message mechanism
- Main entry:
Key Patterns
- Single Source of Truth: MessageRepository stores each message once with computed views
- Clean Architecture: Repository → Manager → UIState → React Components
- Context Reprocessing: Automatic context updates when messages are edited
- Computed Views: Display messages for UI, LLM messages for AI processing
- Project Isolation: Each project maintains its own MessageRepository instance
- Error Handling: Custom error types with detailed interfaces
- Async Operations: Consistent async/await pattern with proper error boundaries
- Caching: Multi-layer caching for files, PDFs, and API responses
- Streaming: Real-time streaming for LLM responses
- Testing: Unit tests adjacent to implementation, integration tests for API calls
Message Management Architecture
For detailed architecture diagrams and documentation, see MESSAGE_ARCHITECTURE.md.
Core Classes and Flow
-
MessageRepository (
src/core/MessageRepository.ts)- Single source of truth for all messages
- Stores
StoredMessageobjects with bothdisplayTextandprocessedText - Provides computed views via
getDisplayMessages()andgetLLMMessages() - No complex dual-array synchronization or ID matching
-
ChatManager (
src/core/ChatManager.ts)- Central business logic coordinator
- Orchestrates MessageRepository, ContextManager, and LLM operations
- Handles all message CRUD operations with proper error handling
- Synchronizes with chain memory for conversation history
- Project Chat Isolation Implementation:
- Maintains
projectMessageRepos: Map<string, MessageRepository>for project-specific storage getCurrentMessageRepo()automatically detects current project and returns correct repository- Seamlessly switches between project repositories when project changes
- Creates new empty repository for each project (no message caching)
- Maintains
-
ChatUIState (
src/state/ChatUIState.ts)- Clean UI-only state manager
- Delegates all business logic to ChatManager
- Provides React integration with subscription mechanism
- Replaces legacy SharedState with minimal, focused approach
-
ContextManager (
src/core/ContextManager.ts)- Handles context processing (notes, URLs, selected text)
- Reprocesses context when messages are edited
- Ensures fresh context for LLM processing
-
ChatPersistenceManager (
src/core/ChatPersistenceManager.ts)- Handles saving and loading chat history to/from markdown files
- Project-aware file naming (prefixes with project ID)
- Parses and formats chat content for storage
- Integrated with ChatManager for seamless persistence
Code Style Guidelines
MAJOR PRINCIPLES
- ALWAYS WRITE GENERALIZABLE SOLUTIONS: Never add edge-case handling or hardcoded logic for specific scenarios (like "piano notes" or "daily notes"). Solutions must work for all cases.
- NEVER MODIFY AI PROMPT CONTENT: Do not update, edit, or change any AI prompts, system prompts, or model adapter prompts unless explicitly asked to do so by the user
- Avoid hardcoding: No hardcoded folder names, file patterns, or special-case logic
- Configuration over convention: If behavior needs to vary, make it configurable, not hardcoded
- Universal patterns: Solutions should work equally well for any folder structure, naming convention, or content type
TypeScript
- Strict mode enabled (no implicit any, strict null checks)
- Use absolute imports with
@/prefix:import { ChainType } from "@/chainFactory" - Prefer const assertions and type inference where appropriate
- Use interface for object shapes, type for unions/aliases
React
- Functional components only (no class components)
- Custom hooks for reusable logic
- Props interfaces defined above components
- Avoid inline styles, use Tailwind classes
General
- File naming: PascalCase for components, camelCase for utilities
- Async/await over promises
- Early returns for error conditions
- Always add JSDoc comments for all functions and methods
- Organize imports: React → external → internal
- Avoid language-specific lists (like stopwords or action verbs) - use language-agnostic approaches instead
Logging
- NEVER use console.log - Use the logging utilities instead:
logInfo()for informational messageslogWarn()for warningslogError()for errors
- Import from logger:
import { logInfo, logWarn, logError } from "@/logger"
Testing Guidelines
- Unit tests use Jest with TypeScript support
- Mock Obsidian API for plugin testing
- Integration tests require API keys in
.env.test - Test files adjacent to implementation (
.test.ts) - Use
@testing-library/reactfor component testing
Development Session Planning
Using TODO.md for Session Management
IMPORTANT: When working on a development session, maintain a comprehensive TODO.md file that serves as the central plan and tracker:
- Session Goal: Define the high-level objective at the start
- Task Tracking:
- List all completed tasks with [x] checkboxes
- Track pending tasks with [ ] checkboxes
- Group related tasks into logical sections
- Architecture Decisions: Document key design choices and rationale
- Progress Updates: Keep the TODO.md updated as tasks complete
- Testing Checklist: Include verification steps for the session
The TODO.md should be:
- The single source of truth for session progress
- Updated frequently as work progresses
- Clear enough that another developer can understand what was done
- Comprehensive enough to serve as a migration guide
Structure Example:
# Development Session TODO
## Session Goal
[Clear statement of what this session aims to achieve]
## Completed Tasks ✅
- [x] Task description with key details
- [x] Another completed task
## Pending Tasks 📋
- [ ] Next task to work on
- [ ] Future enhancement
## Architecture Summary
[Key design decisions and rationale]
## Testing Checklist
- [ ] Functionality verification
- [ ] Performance checks
Important Notes
- The plugin supports multiple LLM providers with custom endpoints
- Vector store requires rebuilding when switching embedding providers
- Settings are versioned - migrations may be needed
- Local model support available via Ollama/LM Studio
- Rate limiting is implemented for all API calls
- For technical debt and known issues, see
TECHDEBT.md - For current development session planning, see
TODO.md
Obsidian Plugin Environment
- Global
appvariable: In Obsidian plugins,appis a globally available variable that provides access to the Obsidian API. It's automatically available in all files without needing to import or declare it.
Architecture Migration Notes
- SharedState Removed: The legacy
src/sharedState.tshas been completely removed - Clean Architecture: New architecture follows Repository → Manager → UIState → UI pattern
- Single Source of Truth: All messages stored once in MessageRepository with computed views
- Context Always Fresh: Context is reprocessed when messages are edited to ensure accuracy
- Chat History Loading: Uses pending message mechanism through CopilotView → Chat component props
- Project Chat Isolation: Each project now has completely isolated chat history
- Automatic detection of project switches via
ProjectManager.getCurrentProjectId() - Separate MessageRepository instances per project ID
- Non-project chats stored in default repository
- Backwards compatible - loads existing messages from ProjectManager cache
- Zero configuration required - works automatically
- Automatic detection of project switches via