mirror of
https://github.com/we-promise/sure.git
synced 2026-04-08 06:44:52 +00:00
* Add SearchFamilyImportedFiles assistant function with vector store support Implement per-Family document search using OpenAI vector stores, allowing the AI assistant to search through uploaded financial documents (tax returns, statements, contracts, etc.). The architecture is modular with a provider- agnostic VectorStoreConcept interface so other RAG backends can be added. Key components: - Assistant::Function::SearchFamilyImportedFiles - tool callable from any LLM - Provider::VectorStoreConcept - abstract vector store interface - Provider::Openai vector store methods (create, upload, search, delete) - Family::VectorSearchable concern with document management - FamilyDocument model for tracking uploaded files - Migration adding vector_store_id to families and family_documents table https://claude.ai/code/session_01TSkKc7a9Yu2ugm1RvSf4dh * Extract VectorStore adapter layer for swappable backends Replace the Provider::VectorStoreConcept mixin with a standalone adapter architecture under VectorStore::. This cleanly separates vector store concerns from the LLM provider and makes it trivial to swap backends. Components: - VectorStore::Base — abstract interface (create/delete/upload/remove/search) - VectorStore::Openai — uses ruby-openai gem's native vector_stores.search - VectorStore::Pgvector — skeleton for local pgvector + embedding model - VectorStore::Qdrant — skeleton for Qdrant vector DB - VectorStore::Registry — resolves adapter from VECTOR_STORE_PROVIDER env - VectorStore::Response — success/failure wrapper (like Provider::Response) Consumers updated to go through VectorStore.adapter: - Family::VectorSearchable - Assistant::Function::SearchFamilyImportedFiles - FamilyDocument Removed: Provider::VectorStoreConcept, vector store methods from Provider::Openai https://claude.ai/code/session_01TSkKc7a9Yu2ugm1RvSf4dh * Add Vector Store configuration docs to ai.md Documents how to configure the document search feature, covering all three supported backends (OpenAI, pgvector, Qdrant), environment variables, Docker Compose examples, supported file types, and privacy considerations. https://claude.ai/code/session_01TSkKc7a9Yu2ugm1RvSf4dh * No need to specify `imported` in code * Missed a couple more places * Tiny reordering for the human OCD * Update app/models/assistant/function/search_family_files.rb Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Juan José Mata <jjmata@jjmata.com> * PR comments * More PR comments --------- Signed-off-by: Juan José Mata <jjmata@jjmata.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
71 lines
1.8 KiB
Ruby
71 lines
1.8 KiB
Ruby
class VectorStore::Registry
|
|
ADAPTERS = {
|
|
openai: "VectorStore::Openai",
|
|
pgvector: "VectorStore::Pgvector",
|
|
qdrant: "VectorStore::Qdrant"
|
|
}.freeze
|
|
|
|
class << self
|
|
# Returns the configured adapter instance.
|
|
# Reads from VECTOR_STORE_PROVIDER env var, falling back to :openai
|
|
# when OpenAI credentials are present.
|
|
def adapter
|
|
name = adapter_name
|
|
return nil unless name
|
|
|
|
build_adapter(name)
|
|
end
|
|
|
|
def configured?
|
|
adapter.present?
|
|
end
|
|
|
|
def adapter_name
|
|
explicit = ENV["VECTOR_STORE_PROVIDER"].presence
|
|
return explicit.to_sym if explicit && ADAPTERS.key?(explicit.to_sym)
|
|
|
|
# Default: use OpenAI when credentials are available
|
|
:openai if openai_access_token.present?
|
|
end
|
|
|
|
private
|
|
|
|
def build_adapter(name)
|
|
klass = ADAPTERS[name]&.safe_constantize
|
|
raise VectorStore::ConfigurationError, "Unknown vector store adapter: #{name}" unless klass
|
|
|
|
case name
|
|
when :openai then build_openai
|
|
when :pgvector then build_pgvector
|
|
when :qdrant then build_qdrant
|
|
else raise VectorStore::ConfigurationError, "No builder defined for adapter: #{name}"
|
|
end
|
|
end
|
|
|
|
def build_openai
|
|
token = openai_access_token
|
|
return nil unless token.present?
|
|
|
|
VectorStore::Openai.new(
|
|
access_token: token,
|
|
uri_base: ENV["OPENAI_URI_BASE"].presence || Setting.openai_uri_base
|
|
)
|
|
end
|
|
|
|
def build_pgvector
|
|
VectorStore::Pgvector.new
|
|
end
|
|
|
|
def build_qdrant
|
|
url = ENV.fetch("QDRANT_URL", "http://localhost:6333")
|
|
api_key = ENV["QDRANT_API_KEY"].presence
|
|
|
|
VectorStore::Qdrant.new(url: url, api_key: api_key)
|
|
end
|
|
|
|
def openai_access_token
|
|
ENV["OPENAI_ACCESS_TOKEN"].presence || Setting.openai_access_token
|
|
end
|
|
end
|
|
end
|