You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let the openai embedding provider use semantic_embedding_api_base and semantic_embedding_api_key, so it can be pointed at any OpenAI-compatible embeddings endpoint. Right now only the litellm provider reads those two config fields.
Problem This Feature Solves
If you run a local OpenAI-compatible embedding server (llama.cpp's llama-server --embedding, vLLM, Text Embeddings Inference, LM Studio, Ollama's OpenAI shim), the only way to reach it from Basic Memory today is the litellm provider, which the docs mark as "Experimental - advanced users only".
That forces extra requirements that have nothing to do with the endpoint itself: semantic_embedding_dimensions becomes mandatory for any non-default model, the model string has to be written in LiteLLM's openai/... form, and there is the per-model input_type handling to think about. Meanwhile the plain openai provider is a thin wrapper over the OpenAI client, which already speaks to any compatible base URL.
Nothing is broken here. It is a small wiring gap that pushes people onto the experimental path for a case the stable path could already handle.
Proposed Solution
OpenAIEmbeddingProvider.__init__ already accepts both parameters (src/basic_memory/repository/openai_provider.py):
They are just never passed from config. In src/basic_memory/repository/embedding_provider_factory.py, the openai branch constructs the provider with only the model, batch size, concurrency, and **extra_kwargs (which carries dimensions and, for FastEmbed, cache/thread knobs):
The litellm branch immediately below it does pass api_key=app_config.semantic_embedding_api_key and api_base=app_config.semantic_embedding_api_base.
So the change looks like:
Pass api_key=app_config.semantic_embedding_api_key and base_url=app_config.semantic_embedding_api_base in the openai branch.
Include those two values in _provider_cache_key, which currently digests them only when provider_name == "litellm". Without this, switching endpoints in-process would keep returning the cached provider.
Update docs/semantic-search.md, which describes semantic_embedding_api_base as being for the LiteLLM provider only.
One design question for the maintainers: whether the two fields should stay shared across providers, or whether the openai provider deserves its own pair. Shared is less config surface and matches how they are named now, but it does mean one field with two meanings.
Set OPENAI_BASE_URL in the environment. The OpenAI Python client reads it, so this may work by accident depending on how the client is constructed, but it is not a documented Basic Memory setting and it applies process-wide rather than per-provider. Not something to rely on.
Leave it alone and document it. A note in the semantic search docs saying "to use a custom endpoint, use the litellm provider" would at least stop people looking for a setting that is not there.
Additional Context
Verified against v0.23.2 as installed, and re-checked against current main on GitHub: the openai branch of the factory still omits both values, and the provider constructor still accepts them.
Related prior work: #1005 and #1043 added api_base and api_key for the LiteLLM provider. #899 marked that provider experimental. This issue is the equivalent for the non-experimental openai provider.
Impact
It makes local and self-hosted embeddings a supported path on the stable provider rather than the experimental one. That matters most for people indexing a large knowledge base, where a local server can be much faster and cheaper than a hosted API, and for anyone who cannot send note content to a third-party endpoint at all.
Happy to open a PR if this is wanted. It looks like passing two existing config values into a constructor that already accepts them, plus the cache-key and docs updates above. Say the word on the shared-versus-separate config question and I will follow whichever you prefer.
Feature Description
Let the
openaiembedding provider usesemantic_embedding_api_baseandsemantic_embedding_api_key, so it can be pointed at any OpenAI-compatible embeddings endpoint. Right now only thelitellmprovider reads those two config fields.Problem This Feature Solves
If you run a local OpenAI-compatible embedding server (llama.cpp's
llama-server --embedding, vLLM, Text Embeddings Inference, LM Studio, Ollama's OpenAI shim), the only way to reach it from Basic Memory today is thelitellmprovider, which the docs mark as "Experimental - advanced users only".That forces extra requirements that have nothing to do with the endpoint itself:
semantic_embedding_dimensionsbecomes mandatory for any non-default model, the model string has to be written in LiteLLM'sopenai/...form, and there is the per-modelinput_typehandling to think about. Meanwhile the plainopenaiprovider is a thin wrapper over the OpenAI client, which already speaks to any compatible base URL.Nothing is broken here. It is a small wiring gap that pushes people onto the experimental path for a case the stable path could already handle.
Proposed Solution
OpenAIEmbeddingProvider.__init__already accepts both parameters (src/basic_memory/repository/openai_provider.py):They are just never passed from config. In
src/basic_memory/repository/embedding_provider_factory.py, theopenaibranch constructs the provider with only the model, batch size, concurrency, and**extra_kwargs(which carriesdimensionsand, for FastEmbed, cache/thread knobs):The
litellmbranch immediately below it does passapi_key=app_config.semantic_embedding_api_keyandapi_base=app_config.semantic_embedding_api_base.So the change looks like:
api_key=app_config.semantic_embedding_api_keyandbase_url=app_config.semantic_embedding_api_basein theopenaibranch._provider_cache_key, which currently digests them only whenprovider_name == "litellm". Without this, switching endpoints in-process would keep returning the cached provider.docs/semantic-search.md, which describessemantic_embedding_api_baseas being for the LiteLLM provider only.Config would then look like:
{ "semantic_embedding_provider": "openai", "semantic_embedding_model": "my-embedding-model", "semantic_embedding_api_base": "http://localhost:8080/v1", "semantic_embedding_api_key": "not-used-but-required-by-client", "semantic_embedding_dimensions": 1024 }One design question for the maintainers: whether the two fields should stay shared across providers, or whether the
openaiprovider deserves its own pair. Shared is less config surface and matches how they are named now, but it does mean one field with two meanings.Alternative Solutions
litellmprovider. This works, and it is what [FEATURE] Add api_base support for LiteLLM semantic embedding providers #1005 and feat(core): add LiteLLM API base and API key config #1043 addedapi_basefor. It just means running on a provider the docs flag as experimental, and carrying its extra requirements, for a setup the stable provider could serve.OPENAI_BASE_URLin the environment. The OpenAI Python client reads it, so this may work by accident depending on how the client is constructed, but it is not a documented Basic Memory setting and it applies process-wide rather than per-provider. Not something to rely on.Additional Context
Verified against v0.23.2 as installed, and re-checked against current
mainon GitHub: theopenaibranch of the factory still omits both values, and the provider constructor still accepts them.Related prior work: #1005 and #1043 added
api_baseandapi_keyfor the LiteLLM provider. #899 marked that provider experimental. This issue is the equivalent for the non-experimentalopenaiprovider.Impact
It makes local and self-hosted embeddings a supported path on the stable provider rather than the experimental one. That matters most for people indexing a large knowledge base, where a local server can be much faster and cheaper than a hosted API, and for anyone who cannot send note content to a third-party endpoint at all.
Happy to open a PR if this is wanted. It looks like passing two existing config values into a constructor that already accepts them, plus the cache-key and docs updates above. Say the word on the shared-versus-separate config question and I will follow whichever you prefer.