mirror of
https://github.com/we-promise/sure.git
synced 2026-05-31 00:09:01 +00:00
The provider-agnostic vector store stack (VectorStore::Pgvector + the Embeddable concern) already shipped to main. This PR closes the Anthropic loop: - VectorStore::Registry.adapter_name now returns :pgvector when Setting.llm_provider == "anthropic" and no explicit VECTOR_STORE_PROVIDER override is set. Anthropic has no hosted vector store, so falling back to the local pgvector adapter is the only correct default. Explicit VECTOR_STORE_PROVIDER still wins. - SearchFamilyFiles surfaces a longer message when no adapter is wired up — calling out pgvector + EMBEDDING_URI_BASE as the supported Anthropic-only path so the user is not stuck with an "OpenAI required" hint that is no longer accurate. The Embeddable concern already pulls embeddings from EMBEDDING_URI_BASE / EMBEDDING_ACCESS_TOKEN (with OpenAI as fallback), so Anthropic installs point this at Voyage AI, a local Ollama instance, or OpenAI embeddings — independent of the chat provider. Tests cover the new default routing, the existing OpenAI default staying intact, and explicit VECTOR_STORE_PROVIDER overriding the Anthropic default. Stacked on #1985 (PR 3/5). 5/5 settings UI + retention disclosure next.
78 lines
2.3 KiB
Ruby
78 lines
2.3 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 routing:
|
|
# - When the configured LLM provider is Anthropic (which has no hosted
|
|
# vector store), fall back to the local pgvector adapter. The
|
|
# Embeddable concern still pulls embeddings from EMBEDDING_URI_BASE /
|
|
# OPENAI_ACCESS_TOKEN — Anthropic users typically point this at
|
|
# Voyage AI, a local Ollama instance, or OpenAI embeddings.
|
|
# - Otherwise, use OpenAI when credentials are available.
|
|
return :pgvector if Setting.llm_provider == "anthropic"
|
|
: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
|