# AGENTS.md This file provides guidance to LLM Code Agents when working with code in this repository. ## Overview This is a DokuWiki plugin that enables AI-powered chat functionality using LLMs (Large Language Models) and RAG (Retrieval-Augmented Generation). The plugin indexes wiki pages as embeddings in a vector database and allows users to ask questions about wiki content. ## Development Commands ### Testing ```bash ../../../bin/plugin.php dev test ``` The command does not accept any additional arguments or parameters and runs all tests in the `_test/` directory. PHPUnit can also be called directly, when special options are needed: ```bash ../../../_test/vendor/bin/phpunit -c ../../../_test/phpunit.xml --group plugin_aichat ``` ### CLI Commands The plugin provides a CLI interface via `cli.php`: ```bash # Get a list of available commands ../../../bin/plugin.php aichat --help ``` ## Architecture ### Core Components **helper.php (helper_plugin_aichat)** - Main entry point for plugin functionality - Manages model factory and configuration - Handles question answering with context retrieval - Prepares messages with chat history and token limits - Implements question rephrasing for better context search **Embeddings.php** - Manages the vector embeddings index - Splits pages into chunks using TextSplitter - Creates and retrieves embeddings via embedding models - Performs similarity searches through storage backends - Handles incremental indexing (only updates changed pages) **TextSplitter.php** - Splits text into token-sized chunks (configurable, typically ~1000 tokens) - Prefers sentence boundaries using Vanderlee\Sentence - Handles long sentences by splitting at word boundaries - Maintains overlap between chunks (MAX_OVERLAP_LEN = 200 tokens) for context preservation **ModelFactory.php** - Creates and caches model instances (chat, rephrase, embedding) - Loads model configurations from Model/*/models.json files - Supports multiple providers: OpenAI, Gemini, Anthropic, Mistral, Ollama, Groq, Reka, VoyageAI ### Model System **Model/AbstractModel.php** - Base class for all LLM implementations - Handles API communication with retry logic (MAX_RETRIES = 3) - Tracks usage statistics (tokens, costs, time, requests) - Implements debug mode for API inspection - Uses DokuHTTPClient for HTTP requests **Model Interfaces** - `ChatInterface`: For conversational models (getAnswer method) - `EmbeddingInterface`: For embedding models (getEmbedding method, getDimensions method) - `ModelInterface`: Base interface with token limits and pricing info **Model Providers** Each provider has its own namespace under Model/: - OpenAI/, Gemini/, Anthropic/, Mistral/, Ollama/, Groq/, Reka/, VoyageAI/ - Each contains ChatModel.php and/or EmbeddingModel.php - Model info (token limits, pricing, dimensions) defined in models.json ### Storage Backends **Storage/AbstractStorage.php** - Abstract base for vector storage implementations - Defines interface for chunk storage and similarity search **Available Implementations:** - SQLiteStorage: Local SQLite database - ChromaStorage: Chroma vector database - PineconeStorage: Pinecone cloud service - QdrantStorage: Qdrant vector database ### Data Flow 1. **Indexing**: Pages → TextSplitter → Chunks → EmbeddingModel → Vector Storage 2. **Querying**: Question → EmbeddingModel → Vector → Storage.getSimilarChunks() → Filtered Chunks 3. **Chat**: Question + History + Context Chunks → ChatModel → Answer ### Key Features **Question Rephrasing** - Converts follow-up questions into standalone questions using chat history - Controlled by `rephraseHistory` config (number of history entries to use) - Only applied when rephraseHistory > chatHistory to avoid redundancy **Context Management** - Chunks include breadcrumb trail (namespace hierarchy + page title) - Token counting uses tiktoken-php for accurate limits - Respects model's max input token length - Filters chunks by ACL permissions and similarity threshold **Language Support** - `preferUIlanguage` setting controls language behavior: - LANG_AUTO_ALL: Auto-detect from question - LANG_UI_ALL: Always use UI language - LANG_UI_LIMITED: Use UI language and limit sources to that language ### AJAX Integration **action.php** - Handles `AJAX_CALL_UNKNOWN` event for 'aichat' calls - Processes questions with chat history - Returns JSON with answer (as rendered Markdown), sources, and similarity scores - Implements access restrictions via helper->userMayAccess() - Optional logging of all interactions ### Frontend - **script/**: JavaScript for UI integration - **syntax/**: DokuWiki syntax components - **renderer.php**: Custom renderer for AI chat output ## Configuration Plugin configuration is in `conf/`: - **default.php**: Default config values - **metadata.php**: Config field definitions and validation Key settings: - Model selection: chatmodel, rephrasemodel, embedmodel - Storage: storage backend type - API keys: openai_apikey, gemini_apikey, etc. - Chunk settings: chunkSize, contextChunks, similarityThreshold - History: chatHistory, rephraseHistory - Access: restrict (user/group restrictions) - Indexing filters: skipRegex, matchRegex ## Testing Tests are in `_test/` directory: - Extends DokuWikiTest base class - Uses @group plugin_aichat annotation ## Important Implementation Notes - All token counting uses TikToken encoder for rough estimates - Chunk IDs are calculated as: pageID * 100 + chunk_sequence (pageIDs come from DokuWiki's internal search index) - Models are cached in ModelFactory to avoid re-initialization - API retries use exponential backoff (sleep for retry count seconds) - Breadcrumb trails provide context to AI without requiring full page content - Storage backends handle similarity search differently but provide unified interface - UTF-8 handling is critical for text splitting (uses dokuwiki\Utf8\PhpString)