From 9362c56678b2d4dde6786f60ed24b3ceec9253a3 Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Wed, 6 May 2026 08:26:57 -0400 Subject: [PATCH] fix: cl-dotenv quote contamination breaks provider cascade parsing cl-dotenv preserves surrounding quotes in .env values (unlike bash). PROVIDER_CASCADE="deepseek,..." resulted in keywords like :"DEEPSEEK instead of :DEEPSEEK, causing all cascade lookups to fail silently. Fixes: - .env.example: remove quotes from PROVIDER_CASCADE - provider-cascade-initialize: add #" and #' to string-trim chars - system-model-router: same fix for LOCAL_BACKENDS parsing --- .env.example | 2 +- lisp/system-model-provider.lisp | 2 +- lisp/system-model-router.lisp | 2 +- org/system-model-provider.org | 2 +- org/system-model-router.org | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env.example b/.env.example index d77b5ff..5c0e574 100644 --- a/.env.example +++ b/.env.example @@ -20,7 +20,7 @@ NVIDIA_API_KEY="your_nvidia_nim_key_here" # Cascade order (first available provider wins) # Default (if unset): openrouter,openai,anthropic,groq,gemini-api,deepseek,nvidia -PROVIDER_CASCADE="deepseek,openrouter,openai,anthropic,groq,gemini,nvidia" +PROVIDER_CASCADE=deepseek,openrouter,openai,anthropic,groq,gemini,nvidia # ============================================================================= # LOCAL LLM (generic OpenAI-compatible endpoint) diff --git a/lisp/system-model-provider.lisp b/lisp/system-model-provider.lisp index af5acd8..a8d7efa 100644 --- a/lisp/system-model-provider.lisp +++ b/lisp/system-model-provider.lisp @@ -81,7 +81,7 @@ (let ((cascade-str (uiop:getenv "PROVIDER_CASCADE"))) (if cascade-str (setf *provider-cascade* - (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space) s)) :keyword)) + (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space #\" #\') s)) :keyword)) (uiop:split-string cascade-str :separator '(#\,)))) (setf *provider-cascade* (mapcar #'car (remove-if (lambda (e) (member (car e) '(:local))) diff --git a/lisp/system-model-router.lisp b/lisp/system-model-router.lisp index 9960ab4..06b031a 100644 --- a/lisp/system-model-router.lisp +++ b/lisp/system-model-router.lisp @@ -77,7 +77,7 @@ Returns model name or :skip." *model-cascade-background* (parse-cascade (uiop:getenv "MODEL_CASCADE_BACKGROUND")) *local-backends* (let ((env (uiop:getenv "LOCAL_BACKENDS"))) (if env - (mapcar (lambda (s) (intern (string-upcase (string-trim " " s)) :keyword)) + (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space #\" #\') s)) :keyword)) (uiop:split-string env :separator '(#\,))) '(:ollama :llama-cpp))))) (setf *model-selector* #'model-select) diff --git a/org/system-model-provider.org b/org/system-model-provider.org index 08eeb6b..f8d46ad 100644 --- a/org/system-model-provider.org +++ b/org/system-model-provider.org @@ -127,7 +127,7 @@ Providers register themselves at boot. No API key? That provider doesn't registe (let ((cascade-str (uiop:getenv "PROVIDER_CASCADE"))) (if cascade-str (setf *provider-cascade* - (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space) s)) :keyword)) + (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space #\" #\') s)) :keyword)) (uiop:split-string cascade-str :separator '(#\,)))) (setf *provider-cascade* (mapcar #'car (remove-if (lambda (e) (member (car e) '(:local))) diff --git a/org/system-model-router.org b/org/system-model-router.org index 7803146..4bc8d9c 100644 --- a/org/system-model-router.org +++ b/org/system-model-router.org @@ -193,7 +193,7 @@ Reads cascade configuration from environment variables and registers *model-cascade-background* (parse-cascade (uiop:getenv "MODEL_CASCADE_BACKGROUND")) *local-backends* (let ((env (uiop:getenv "LOCAL_BACKENDS"))) (if env - (mapcar (lambda (s) (intern (string-upcase (string-trim " " s)) :keyword)) + (mapcar (lambda (s) (intern (string-upcase (string-trim '(#\Space #\" #\') s)) :keyword)) (uiop:split-string env :separator '(#\,))) '(:ollama :llama-cpp))))) (setf *model-selector* #'model-select)