@@ -877,40 +877,77 @@ impl OpenFangKernel {
877877 None
878878 }
879879 }
880- } else if std:: env:: var ( "OPENAI_API_KEY" ) . is_ok ( ) {
881- let model = if configured_model == "all-MiniLM-L6-v2" {
882- default_embedding_model_for_provider ( "openai" )
883- } else {
884- configured_model. as_str ( )
885- } ;
886- let openai_url = config. provider_urls . get ( "openai" ) . map ( |s| s. as_str ( ) ) ;
887- match create_embedding_driver ( "openai" , model, "OPENAI_API_KEY" , openai_url) {
888- Ok ( d) => {
889- info ! ( model = %model, "Embedding driver auto-detected: OpenAI" ) ;
890- Some ( Arc :: from ( d) )
891- }
892- Err ( e) => {
893- warn ! ( error = %e, "OpenAI embedding auto-detect failed" ) ;
894- None
895- }
896- }
897880 } else {
898- // Try Ollama (local, no key needed)
899- let model = if configured_model == "all-MiniLM-L6-v2" {
900- default_embedding_model_for_provider ( "ollama" )
881+ // Auto-detect embedding provider by checking API key env vars in
882+ // priority order. First match wins.
883+ const API_KEY_PROVIDERS : & [ ( & str , & str ) ] = & [
884+ ( "OPENAI_API_KEY" , "openai" ) ,
885+ ( "GROQ_API_KEY" , "groq" ) ,
886+ ( "MISTRAL_API_KEY" , "mistral" ) ,
887+ ( "TOGETHER_API_KEY" , "together" ) ,
888+ ( "FIREWORKS_API_KEY" , "fireworks" ) ,
889+ ( "COHERE_API_KEY" , "cohere" ) ,
890+ ] ;
891+
892+ let detected_from_key = API_KEY_PROVIDERS
893+ . iter ( )
894+ . find ( |( env_var, _) | std:: env:: var ( env_var) . is_ok ( ) )
895+ . and_then ( |( env_var, provider) | {
896+ let model = if configured_model == "all-MiniLM-L6-v2" {
897+ default_embedding_model_for_provider ( provider)
898+ } else {
899+ configured_model. as_str ( )
900+ } ;
901+ let custom_url = config. provider_urls . get ( * provider) . map ( |s| s. as_str ( ) ) ;
902+ match create_embedding_driver ( provider, model, env_var, custom_url) {
903+ Ok ( d) => {
904+ info ! ( provider = %provider, model = %model, "Embedding driver auto-detected via {}" , env_var) ;
905+ Some ( Arc :: from ( d) )
906+ }
907+ Err ( e) => {
908+ warn ! ( provider = %provider, error = %e, "Embedding auto-detect failed for {}" , provider) ;
909+ None
910+ }
911+ }
912+ } ) ;
913+
914+ if detected_from_key. is_some ( ) {
915+ detected_from_key
901916 } else {
902- configured_model. as_str ( )
903- } ;
904- let ollama_url = config. provider_urls . get ( "ollama" ) . map ( |s| s. as_str ( ) ) ;
905- match create_embedding_driver ( "ollama" , model, "" , ollama_url) {
906- Ok ( d) => {
907- info ! ( model = %model, "Embedding driver auto-detected: Ollama (local)" ) ;
908- Some ( Arc :: from ( d) )
917+ // No API key found — try local providers in order:
918+ // Ollama, vLLM, LM Studio (no key needed).
919+ const LOCAL_PROVIDERS : & [ & str ] = & [ "ollama" , "vllm" , "lmstudio" ] ;
920+
921+ let mut local_result = None ;
922+ for provider in LOCAL_PROVIDERS {
923+ let model = if configured_model == "all-MiniLM-L6-v2" {
924+ default_embedding_model_for_provider ( provider)
925+ } else {
926+ configured_model. as_str ( )
927+ } ;
928+ let custom_url = config. provider_urls . get ( * provider) . map ( |s| s. as_str ( ) ) ;
929+ match create_embedding_driver ( provider, model, "" , custom_url) {
930+ Ok ( d) => {
931+ info ! ( provider = %provider, model = %model, "Embedding driver auto-detected: {} (local)" , provider) ;
932+ local_result = Some ( Arc :: from ( d) ) ;
933+ break ;
934+ }
935+ Err ( e) => {
936+ debug ! ( provider = %provider, error = %e, "Local embedding provider {} not available" , provider) ;
937+ }
938+ }
909939 }
910- Err ( e) => {
911- debug ! ( "No embedding driver available (Ollama probe failed: {e}) — using text search fallback" ) ;
912- None
940+
941+ if local_result. is_none ( ) {
942+ warn ! (
943+ "No embedding provider available. Memory recall will use text search only. \
944+ Configure [memory] embedding_provider in config.toml or set an API key \
945+ (OPENAI_API_KEY, GROQ_API_KEY, MISTRAL_API_KEY, TOGETHER_API_KEY, \
946+ FIREWORKS_API_KEY, COHERE_API_KEY)."
947+ ) ;
913948 }
949+
950+ local_result
914951 }
915952 }
916953 } ;
@@ -5663,7 +5700,10 @@ fn apply_budget_defaults(
56635700fn default_embedding_model_for_provider ( provider : & str ) -> & ' static str {
56645701 match provider {
56655702 "openai" => "text-embedding-3-small" ,
5703+ "groq" => "nomic-embed-text" ,
56665704 "mistral" => "mistral-embed" ,
5705+ "together" => "togethercomputer/m2-bert-80M-8k-retrieval" ,
5706+ "fireworks" => "nomic-ai/nomic-embed-text-v1.5" ,
56675707 "cohere" => "embed-english-v3.0" ,
56685708 // Local providers use nomic-embed-text as a good default
56695709 "ollama" | "vllm" | "lmstudio" => "nomic-embed-text" ,
0 commit comments