Packages

Production adapters and pipelines for PortfolioCore. Vector stores, graph stores, embedders, Broadway pipelines, and advanced RAG strategies.

Current section

Files

Jump to
portfolio_index CHANGELOG.md
Raw

CHANGELOG.md

# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.4.0] - 2026-01-08
### Added
#### Local LLM Support
- `PortfolioIndex.Adapters.LLM.Ollama` - Ollama LLM adapter using ollixir client
- Local model orchestration with configurable base URL
- OpenAI-style message formatting
- Streaming support with delta normalization
- Rate limiting and telemetry instrumentation
- Configurable model info and supported models list
- `PortfolioIndex.Adapters.LLM.VLLM` - vLLM adapter for OpenAI-compatible endpoints
- Uses openai_ex for OpenAI-compatible API
- Configurable base URL for local clusters
- SSE stream parsing with finish reason normalization
- Rate limiting and failure detection
#### Local Embeddings Support
- `PortfolioIndex.Adapters.Embedder.Ollama` - Ollama embeddings adapter using ollixir
- Support for nomic-embed-text, mxbai-embed-large models
- Batch embedding support via native API
- Token count extraction from response or estimation fallback
- Rate limiting and telemetry instrumentation
#### Telemetry Enhancements
- `PortfolioIndex.Telemetry.Context` - Lineage context helpers for telemetry metadata
- Standard context keys: `trace_id`, `work_id`, `plan_id`, `step_id`
- `merge/2` for combining context with telemetry metadata
- Integrated into all LLM adapters (Anthropic, Codex, Gemini, OpenAI, Ollama, vLLM)
#### Backend Integration
- `PortfolioIndex.LLM.BackendBridge` - Bridge for CrucibleIR backend prompts
- `prompt_to_messages/1` - Convert backend prompt structs to messages and opts
- `completion_from_result/3` - Build completion maps from adapter results
- Usage normalization across provider formats
#### Examples
- `examples/ollama_embedder.exs` - Ollama embedder demonstration
- `examples/ollama_llm.exs` - Ollama LLM with streaming demonstration
- `examples/ollama_setup.exs` - Automated Ollama model installation script
- `examples/vllm_llm.exs` - vLLM adapter demonstration
- `examples/support/ollama_helpers.exs` - Shared helpers for Ollama examples
### Changed
- LLM adapters now pass opts to telemetry for lineage context propagation
- Gemini embedder and LLM adapters support SDK injection via `:sdk` option
- RateLimiter uses rescue instead of try for ETS table creation
- Updated run_all.sh to include Ollama examples (vLLM skipped by default)
### Dependencies
- Changed portfolio_core from path to hex: `~> 0.4.0`
- Changed foundation from path to hex: `~> 0.2.0`
- Changed gemini_ex from path to hex: `~> 0.8.8`
- Changed claude_agent_sdk from path to hex: `~> 0.7.6`
- Changed codex_sdk from path to hex: `~> 0.5.0`
- Added ollixir `~> 0.1.0` for Ollama integration
## [0.3.1] - 2025-12-30
### Added
#### Collection Selection & Self-Correction
- `PortfolioIndex.Adapters.CollectionSelector.LLM` - LLM-based collection routing
- Routes queries to relevant collections based on descriptions
- Returns JSON with selected collections and reasoning
- Custom prompt support via `:prompt` option
- `PortfolioIndex.Adapters.CollectionSelector.RuleBased` - Rule-based collection routing
- Keyword matching with configurable boost factors
- Deterministic routing without LLM calls
- Useful for testing and predictable behavior
- `PortfolioIndex.RAG.SelfCorrectingSearch` - Search with sufficiency evaluation and query rewriting
- Evaluates if results are sufficient for answering the question
- Rewrites query and retries if insufficient
- Configurable max iterations and custom prompts
- Tracks correction history in context
- `PortfolioIndex.RAG.SelfCorrectingAnswer` - Answer generation with grounding evaluation
- Evaluates if answer is grounded in provided context
- Identifies ungrounded claims and generates corrections
- Configurable max corrections and grounding threshold
- Tracks correction history for debugging
- `PortfolioIndex.RAG.Reranker` - Pipeline-integrated reranking utilities
- `rerank/2` - Rerank context results with threshold filtering
- `rerank_chunks/3` - Direct chunk reranking
- `deduplicate/2` - Remove duplicate chunks by id or content
- Score tracking in context
#### Enhanced Agentic Strategy
- `PortfolioIndex.RAG.Strategies.Agentic.execute_pipeline/2` - Full pipeline execution with all enhancements
- Query rewriting, expansion, decomposition
- Collection selection and routing
- Self-correcting search with sufficiency evaluation
- Reranking with threshold filtering
- Self-correcting answer with grounding evaluation
- `PortfolioIndex.RAG.Strategies.Agentic.with_context/2` - Pipeline execution with Context struct
- Enables functional composition with pipe operator
- Configurable step skipping via `:skip` option
- Returns full Context with all intermediate results
#### Telemetry Standardization
- `PortfolioIndex.Telemetry.Logger` - Human-readable telemetry logger with one-line attach
- Text and JSON output formats
- Component-level filtering (embedder, llm, rag, vector_store, evaluation)
- Duration formatting (ms, s)
- Context-aware metadata display
- `PortfolioIndex.Telemetry.LLM` - LLM-specific telemetry with token tracking
- `span/2` for wrapping LLM calls with detailed metadata
- `estimate_tokens/1` for token count estimation
- `extract_usage/1` for parsing provider-specific usage data
- `PortfolioIndex.Telemetry.Embedder` - Embedder telemetry utilities
- `span/2` for single embedding operations
- `batch_span/2` for batch embedding operations
- `PortfolioIndex.Telemetry.RAG` - RAG pipeline step telemetry
- `step_span/3` for wrapping pipeline steps (rewrite, expand, decompose, etc.)
- `search_span/3` for search-specific telemetry
- `rerank_span/3` for rerank-specific telemetry
- `correction_event/2` for self-correction tracking
- `PortfolioIndex.Telemetry.VectorStore` - Vector store operation telemetry
- `search_span/2` for search operations
- `insert_span/2` for single insert operations
- `batch_insert_span/2` for batch insert operations
#### Vector Store Enhancements
- `PortfolioIndex.Adapters.VectorStore.Memory` - In-memory HNSWLib vector store
- GenServer-based in-memory storage for testing and development
- Uses HNSWLib for approximate nearest neighbor (ANN) search
- Soft deletion support (marks as deleted without index rebuild)
- Optional file-based persistence via save/load
- Thread-safe for concurrent reads and writes
- Configurable dimensions, max_elements, ef_construction, and m parameters
- `PortfolioIndex.VectorStore.Backend` - Backend resolution with per-call override
- Runtime backend switching via `:backend` option
- Backend aliases: `:pgvector`, `:memory`, `:qdrant`
- Module and tuple configuration support: `{Memory, store: pid}`
- Unified API for search, insert, insert_batch, delete, get
- `PortfolioIndex.VectorStore.IndexManager` - Index auto-creation and management
- `ensure_index/2` - Create index if not exists
- `index_exists?/2` - Check index existence
- `index_stats/2` - Get index statistics
- `rebuild_index/2` - Rebuild index after bulk inserts
- `drop_index/2` - Remove index
- Backend-specific options for pgvector (HNSW, IVFFlat) and memory stores
- `PortfolioIndex.VectorStore.Collections` - Collection-based organization
- Logical grouping of vectors via metadata filtering
- `search_collection/3` - Search within specific collection
- `insert_to_collection/5` - Insert with collection tag
- `list_collections/1` - List all collections
- `collection_stats/2` - Get collection statistics
- `clear_collection/2` - Delete all vectors in collection
- `PortfolioIndex.VectorStore.SoftDelete` - Soft deletion support
- `soft_delete/2` - Mark item as deleted without removal
- `soft_delete_where/2` - Soft delete matching items
- `restore/2` - Restore soft-deleted item
- `purge_deleted/2` - Permanently delete old soft-deleted items
- `count_deleted/1` - Count soft-deleted items
- `PortfolioIndex.VectorStore.Search` - Enhanced search with hybrid support
- `similarity_search/2` - Vector search with threshold and collection filtering
- `hybrid_search/3` - Combine vector and keyword search with RRF
- `filter_results/2` - Post-filter by metadata
- `normalize_scores/2` - Normalize across distance metrics
- `deduplicate/2` - Remove duplicate results by id or content_hash
#### Embedder Enhancements
- `PortfolioIndex.Adapters.Embedder.OpenAI` - OpenAI text-embedding API adapter
- Full implementation replacing placeholder with actual API calls
- Support for text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002
- Batch embedding support via native API
- Telemetry instrumentation for monitoring
- `PortfolioIndex.Adapters.Embedder.Bumblebee` - Local Bumblebee/Nx.Serving embeddings
- HuggingFace model loading with EXLA compilation
- Support for BGE, MiniLM, and other sentence-transformers
- Supervision tree integration via `child_spec/1`
- No API calls required - fully local inference
- `PortfolioIndex.Adapters.Embedder.Function` - Custom function wrapper adapter
- Wrap any function as an embedder
- Optional batch function support
- Useful for testing and custom integrations
- `PortfolioIndex.Embedder.Registry` - Model dimension registry
- Pre-configured dimensions for OpenAI, Voyage, Bumblebee, Ollama models
- Runtime registration for custom models
- Provider lookup by model name
- `PortfolioIndex.Embedder.Config` - Unified embedder configuration
- Shorthand syntax (:openai, :bumblebee, etc.)
- Module and tuple configuration support
- Function wrapper auto-resolution
- `current/0` and `current_dimensions/0` helpers
- `PortfolioIndex.Embedder.DimensionDetector` - Automatic dimension detection
- Multiple detection strategies (explicit, registry, probe)
- Dimension validation for embeddings
- Fallback probing for unknown models
#### Retrieval Evaluation System
- `PortfolioIndex.Adapters.RetrievalMetrics.Standard` - Standard IR metrics adapter
- Implements `PortfolioCore.Ports.RetrievalMetrics` behaviour
- `recall_at_k/3` - Recall at K (fraction of relevant items retrieved)
- `precision_at_k/3` - Precision at K (fraction of retrieved items relevant)
- `mrr/2` - Mean Reciprocal Rank (inverse of first relevant rank)
- `hit_rate_at_k/3` - Hit Rate at K (1 if any relevant item in top K)
- Aggregation with mean calculation across test cases
- `PortfolioIndex.Schemas.TestCase` - Ecto schema for evaluation test cases
- Links questions to ground truth chunks via many-to-many
- Source: `:synthetic` (LLM-generated) or `:manual`
- Collection and metadata support
- `PortfolioIndex.Schemas.EvaluationRun` - Ecto schema for evaluation runs
- Status tracking: `:running`, `:completed`, `:failed`
- Aggregate metrics and per-case results storage
- Timing and configuration tracking
- `PortfolioIndex.Evaluation.Generator` - LLM-powered test case generation
- `generate/2` - Sample chunks and generate synthetic questions
- `generate_question/2` - Generate single question from chunk content
- Chunk sampling with collection/source filtering
- `PortfolioIndex.Evaluation` - Main evaluation orchestrator
- `run/2` - Execute evaluation against test cases
- `list_test_cases/2` - List with filtering options
- `create_test_case/2` - Create manual test cases
- `add_ground_truth/3` - Link chunks as ground truth
- `list_runs/2` - Get historical evaluation runs
- `compare_runs/2` - Compare metrics between runs
- Database migration for evaluation tables
- `portfolio_evaluation_test_cases` with source and collection indexes
- `portfolio_evaluation_test_case_chunks` join table
- `portfolio_evaluation_runs` with status index
#### Production Maintenance Utilities
- `PortfolioIndex.Maintenance` - Production maintenance utilities (reembed, diagnostics, retry)
- `reembed/2` - Re-embed all chunks or filtered subset with progress tracking
- `diagnostics/1` - Get system diagnostics including counts and storage usage
- `retry_failed/2` - Reset failed documents to pending for reprocessing
- `cleanup_deleted/2` - Permanently remove soft-deleted documents and chunks
- `verify_embeddings/1` - Verify embedding consistency across chunks
- `PortfolioIndex.Maintenance.Progress` - Progress reporting for maintenance operations
- `cli_reporter/1` - Prints progress to stdout with percentage
- `silent_reporter/0` - No-op reporter for silent operations
- `telemetry_reporter/1` - Emits telemetry events for monitoring
- `build_event/4` - Create progress events from components
#### Mix Tasks
- `mix portfolio.install` - Installation task for new projects
- Generates database migrations for collections, documents, and chunks tables
- Creates pgvector extension setup with HNSW index
- Prints configuration instructions and next steps
- Options: `--repo`, `--dimension`, `--no-migrations`
- `mix portfolio.gen.embedding_migration` - Generate migration for dimension changes
- Creates migration to alter vector column dimensions
- Drops and recreates HNSW index for new dimensions
- Options: `--dimension` (required), `--table`, `--column`
#### Document Management Schemas
- `PortfolioIndex.Schemas.Collection` - Ecto schema for document collections
- Groups related documents for organized retrieval and routing
- Unique name constraint with metadata support
- Virtual `document_count` field for aggregation
- `PortfolioIndex.Schemas.Document` - Ecto schema for ingested documents with status tracking
- Status enum: `:pending`, `:processing`, `:completed`, `:failed`, `:deleted`
- Content hash for deduplication via `compute_hash/1`
- Collection relationship for document organization
- Error message tracking for failed ingestions
- `PortfolioIndex.Schemas.Chunk` - Ecto schema for document chunks with pgvector embeddings
- Native `Pgvector.Ecto.Vector` type for similarity search
- Document relationship with cascade delete
- Character offset tracking (`start_char`, `end_char`)
- Token count for LLM context budgeting
- `PortfolioIndex.Schemas.Queries` - Query helpers for schema operations
- `get_collection_by_name/2` - Fetch collection by name
- `get_or_create_collection/3` - Upsert collection
- `list_documents_by_status/3` - Filter documents by processing status
- `get_document_with_chunks/2` - Load document with preloaded chunks
- `similarity_search/3` - pgvector cosine similarity search
- `count_chunks_without_embedding/1` - Count unprocessed chunks
- `get_failed_documents/2` - Fetch documents for retry
- `soft_delete_document/2` - Mark document as deleted
- Database migration for document management tables
- `portfolio_collections` with unique name index
- `portfolio_documents` with status, source_id, and content_hash indexes
- `portfolio_chunks` with HNSW vector index for fast similarity search
#### Query Processing Pipeline
- `PortfolioIndex.RAG.Pipeline.Context` struct for pipeline state tracking
- Flows through RAG pipeline accumulating intermediate results
- Tracks query transformations, routing, retrieval, and generation
- Supports functional composition with pipe operator
- Error propagation and halt semantics
- `PortfolioIndex.Adapters.QueryRewriter.LLM` - LLM-based query cleaning
- Removes greetings, filler phrases, conversational noise
- Preserves technical terms and entity names
- Custom prompt support
- `PortfolioIndex.Adapters.QueryExpander.LLM` - LLM-based query expansion
- Adds synonyms and related terms for better recall
- Expands abbreviations (ML -> machine learning)
- Tracks added terms for debugging
- `PortfolioIndex.Adapters.QueryDecomposer.LLM` - LLM-based query decomposition
- Breaks complex questions into 2-4 simpler sub-questions
- Enables parallel retrieval for multi-faceted queries
- JSON response parsing with fallback handling
- `PortfolioIndex.RAG.QueryProcessor` - unified query processing module
- `rewrite/2` - Apply query rewriting to pipeline context
- `expand/2` - Apply query expansion to pipeline context
- `decompose/2` - Apply query decomposition to pipeline context
- `process/2` - Run all processing steps with skip options
- `effective_query/1` - Get best query for retrieval
#### Chunker Enhancements
- **Separators module** - Centralized language-specific separators for 17+ formats
- Language support: Elixir, Ruby, PHP, Python, JavaScript, TypeScript, Vue, HTML
- Document formats: doc, docx, epub, latex, odt, pdf, rtf
- Markdown with header-aware splitting
- **Config module** - NimbleOptions-based configuration validation with compile-time schema
- **Pluggable `get_chunk_size` function** - Token-based chunking support across all strategies
- Character, byte, word, or custom tokenizer-based sizing
- Defaults to `String.length/1` for backwards compatibility
#### Token Utilities
- **Tokens module** - Centralized token estimation utilities
- `Tokens.estimate/2` - Estimate token count from text (~4 chars/token heuristic)
- `Tokens.sizer/1` - Get sizing function for token-based chunking
- `Tokens.to_chars/2` - Convert token count to character count
- `Tokens.from_chars/2` - Convert character count to token count
- `Tokens.default_ratio/0` - Returns the default chars-per-token ratio (4)
#### Chunker Config Enhancement
- **`size_unit` option** - Specify `:characters` or `:tokens` for chunk sizing
- `:tokens` auto-configures `get_chunk_size` with token estimation
- `:characters` (default) uses `String.length/1`
- Implements `PortfolioCore.Ports.Chunker` port specification for `size_unit`
#### Chunker Output Enhancement
- **`token_count` in metadata** - All chunkers now include estimated token count
- Useful for LLM context window budgeting
- Approximately `char_count / 4`
- Included in: Recursive, Character, Paragraph, Sentence, Semantic chunkers
### Changed
- All chunker adapters now support `:get_chunk_size` option for custom size measurement
- Recursive chunker uses new Separators module for format-specific splitting
- Added nimble_options dependency for robust configuration validation
### Documentation
- Added technical documentation in `docs/20251230/chunker-enhancements/`
- `overview.md` - Feature overview and migration guide
- `separators.md` - Language separator reference
- `tokenization.md` - Token-based chunking guide
## [0.3.0] - 2025-12-28
### Added
#### Chunker Adapters
- Character chunker with boundary modes (`:word`, `:sentence`, `:none`)
- Paragraph chunker with intelligent merging and splitting
- Sentence chunker with NLP tokenization and abbreviation handling
- Semantic chunker using embedding-based similarity grouping
#### GraphRAG Components
- `CommunityDetector` with label propagation algorithm
- `CommunitySummarizer` with LLM-based summarization and embedding generation
- `EntityExtractor` with batch support and entity resolution
#### Graph Store Enhancements (Neo4j)
- `EntitySearch` module for vector-based entity search
- `Community` module for community CRUD and vector search
- `Traversal` module for BFS, subgraph extraction, and path finding
#### Reranker Adapters
- LLM-based reranker with customizable prompts
- Passthrough reranker for testing and baselines
#### Retriever Enhancements
- GraphRAG local/global/hybrid search modes
- PostgreSQL tsvector-based full-text search
### Changed
- GraphRAG strategy now supports `:mode` option (`:local`, `:global`, `:hybrid`)
- Updated portfolio_core dependency to path reference for development
## [0.2.0] - 2025-12-27
### Added
- Anthropic LLM adapter via claude_agent_sdk with streaming
- OpenAI LLM adapter via codex_sdk with streaming
- GraphRAG strategy combining vector search with graph traversal
- Agentic strategy for tool-based iterative retrieval
- Telemetry events for new adapters and strategies
### Dependencies
- Added claude_agent_sdk ~> 0.6.10
- Added codex_sdk ~> 0.4.3
- Updated portfolio_core to 0.2.0
## [0.1.1] - 2025-12-27
### Added
- OpenAI embedder adapter placeholder (`PortfolioIndex.Adapters.Embedder.OpenAI`)
- Anthropic LLM adapter placeholder (`PortfolioIndex.Adapters.LLM.Anthropic`)
- `AdapterResolver` for dynamic adapter resolution from context or registry
- Agentic RAG strategy placeholder (`PortfolioIndex.RAG.Strategies.Agentic`)
- GraphRAG strategy placeholder (`PortfolioIndex.RAG.Strategies.GraphRAG`)
- `enqueue/2` function to Ingestion pipeline for ad-hoc file indexing
### Changed
- Pgvector adapter: idempotent index creation with dimension validation
- Pgvector adapter: normalize metric and index type from string or atom inputs
- Application startup: conditional child process loading via config flags
- Hybrid and SelfRAG strategies now use AdapterResolver for dynamic adapter selection
- Updated `portfolio_core` dependency to `~> 0.1.1`
## [0.1.0] - 2025-12-27
### Added
- Initial release of PortfolioIndex
[Unreleased]: https://github.com/nshkrdotcom/portfolio_index/compare/v0.4.0...HEAD
[0.4.0]: https://github.com/nshkrdotcom/portfolio_index/compare/v0.3.1...v0.4.0
[0.3.1]: https://github.com/nshkrdotcom/portfolio_index/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/nshkrdotcom/portfolio_index/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/nshkrdotcom/portfolio_index/compare/v0.1.1...v0.2.0
[0.1.1]: https://github.com/nshkrdotcom/portfolio_index/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/nshkrdotcom/portfolio_index/releases/tag/v0.1.0