From abfb7e5cf86c9528c2683053554802474f733fc5 Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Mon, 4 May 2026 11:41:01 -0400 Subject: [PATCH] setup wizard: verbose descriptions, multi-provider loop, add DeepSeek/NVIDIA/Local, remove Ollama --- lisp/system-config.lisp | 66 +++++++++++++++++++------- lisp/system-model-provider.lisp | 5 +- org/system-config.org | 84 +++++++++++++++++++++++++-------- org/system-model-provider.org | 5 +- 4 files changed, 117 insertions(+), 43 deletions(-) diff --git a/lisp/system-config.lisp b/lisp/system-config.lisp index 5cdeee8..4bc4a5f 100644 --- a/lisp/system-config.lisp +++ b/lisp/system-config.lisp @@ -84,7 +84,9 @@ ("OpenRouter" . "OPENROUTER_API_KEY") ("Groq" . "GROQ_API_KEY") ("Gemini" . "GEMINI_API_KEY") - ("Ollama (local)" . "OLLAMA_URL"))) + ("DeepSeek" . "DEEPSEEK_API_KEY") + ("NVIDIA" . "NVIDIA_API_KEY") + ("Local" . "LOCAL_BASE_URL"))) (defun setup-llm-providers () "Interactive wizard for configuring LLM providers." @@ -97,28 +99,56 @@ when (config-get key) collect name))) (when current-providers - (format t "Current providers: ~{~a~^, ~}~%~%" current-providers)) + (format t "Currently configured: ~{~a~^, ~}~%~%" current-providers)) + (format t "~%") + (format t "★ OpenRouter recommended for new users — free tier, no credit card required.~%") + (format t " Sign up at https://openrouter.ai and paste your API key below.~%") + (format t "~%") (format t "Available providers:~%") + (format t " ~20@A ~25@A ~s~%" "Provider" "Key env var" "Notes") + (format t " ~20@A ~25@A ~s~%" "--------" "----------" "-----") (dolist (p *available-providers*) - (format t " - ~a~%" (car p))) + (let ((name (car p)) + (env-key (cdr p)) + (desc (case (car p) + ("OpenRouter" "free tier, 33+ models") + ("OpenAI" "paid, gpt-4o-mini") + ("Anthropic" "paid, Claude 3.5 Sonnet") + ("Groq" "fast inference, free tier") + ("Gemini" "free via API") + ("DeepSeek" "competitive pricing, coding") + ("NVIDIA" "NVIDIA NIM hosted models") + ("Local" "local server, no API key") + (t "")))) + (format t " ~20@A ~25@A ~a~%" name env-key desc))) (format t "~%") - (when (prompt-yes-no "Configure a new provider?") - (let ((chosen (prompt-choice "Select provider:" (mapcar #'car *available-providers*)))) - (when chosen - (let ((env-key (cdr (assoc chosen *available-providers* :test #'string=)))) - (if (string= chosen "Ollama (local)") - (progn - (format t "Enter Ollama URL (e.g., http://localhost:11434): ") - (let ((url (read-line))) - (config-set env-key url) - (format t "✓ Ollama configured at ~a~%" url))) - (progn - (format t "Enter API key for ~a: " chosen) - (let ((key (read-line))) - (config-set env-key key) - (format t "✓ ~a API key saved~%" chosen))))))))) + (loop + (when (not (prompt-yes-no "Configure a LLM provider?")) + (return)) + (let ((chosen (prompt-choice "Select a provider:" (mapcar #'car *available-providers*)))) + (unless chosen + (format t "Invalid choice.~%") + (return)) + (let ((env-key (cdr (assoc chosen *available-providers* :test #'string=)))) + (cond + ((string= chosen "Local") + (format t "Enter the server URL (e.g., http://localhost:11434 for Ollama,~%") + (format t " or http://localhost:8080 for llama.cpp): ") + (let ((url (read-line))) + (if (> (length url) 0) + (progn (config-set env-key url) + (format t "✓ ~a configured at ~a~%" chosen url)) + (format t "Skipping ~a — no URL entered.~%" chosen)))) + (t + (format t "Enter API key for ~a~%" chosen) + (format t " (get one from the provider's website, paste it here): ") + (let ((key (read-line))) + (if (> (length key) 0) + (progn (config-set env-key key) + (format t "✓ ~a API key saved~%" chosen)) + (format t "Skipping ~a — no key entered.~%" chosen)))))))) (format t "~%")) diff --git a/lisp/system-model-provider.lisp b/lisp/system-model-provider.lisp index c182f4c..6223ab2 100644 --- a/lisp/system-model-provider.lisp +++ b/lisp/system-model-provider.lisp @@ -6,8 +6,7 @@ (:groq . (:base-url "https://api.groq.com/openai/v1" :key-env "GROQ_API_KEY" :default-model "llama-3.1-70b-versatile")) (:gemini . (:base-url "https://generativelanguage.googleapis.com/v1beta/openai" :key-env "GEMINI_API_KEY" :default-model "gemini-2.0-flash")) (:deepseek . (:base-url "https://api.deepseek.com/v1" :key-env "DEEPSEEK_API_KEY" :default-model "deepseek-chat")) - (:nvidia . (:base-url "https://integrate.api.nvidia.com/v1" :key-env "NVIDIA_API_KEY" :default-model "meta/llama-3.1-405b-instruct")) - (:ollama . (:base-url nil :key-env nil :url-env "OLLAMA_HOST" :default-model "llama3")))) + (:nvidia . (:base-url "https://integrate.api.nvidia.com/v1" :key-env "NVIDIA_API_KEY" :default-model "meta/llama-3.1-405b-instruct")))) (defun provider-config (provider) "Returns the configuration plist for a provider keyword." @@ -78,7 +77,7 @@ (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 :ollama))) + (member (car e) '(:local))) *provider-configs*)))))) (defun test-provider-connection (provider &optional api-key) diff --git a/org/system-config.org b/org/system-config.org index f184686..70e4b97 100644 --- a/org/system-config.org +++ b/org/system-config.org @@ -142,11 +142,28 @@ Creates the config directory tree if it does not exist. ("OpenRouter" . "OPENROUTER_API_KEY") ("Groq" . "GROQ_API_KEY") ("Gemini" . "GEMINI_API_KEY") - ("Ollama (local)" . "OLLAMA_URL"))) + ("DeepSeek" . "DEEPSEEK_API_KEY") + ("NVIDIA" . "NVIDIA_API_KEY") + ("Local" . "LOCAL_BASE_URL"))) #+end_src +** Provider descriptions (for setup wizard display) + +These are shown inline when the user runs the setup wizard, so they know what they are choosing. + +| Provider | Description | Where to sign up | Recommendation | +|----------|-------------|------------------|--------------| +| ~OpenRouter~ | Free tier with 33+ models. No credit card required. Routes to best available free model. | openrouter.ai | ★ Recommended for new users | +| ~OpenAI~ | GPT-4o-mini and GPT-4o. Requires billing. | platform.openai.com | | +| ~Anthropic~ | Claude 3.5 Sonnet. Strong reasoning. | console.anthropic.com | | +| ~Groq~ | Very fast inference, free tier available. | console.groq.com | | +| ~Gemini~ | Google's Gemini models. Free tier via API. | aistudio.google.com | | +| ~DeepSeek~ | Competitive pricing, strong coding. | platform.deepseek.com | | +| ~NVIDIA~ | NVIDIA NIM. Hosted models, slower but capable. | build.nvidia.com | | +| ~Local~ | Any OpenAI-compatible local server (llama.cpp, vLLM, LM Studio, Ollama). No API key needed. | Run locally | | + ** setup-llm-providers -;; REPL-VERIFIED: 2026-05-03T13:00:00 +;; REPL-VERIFIED: 2026-05-04 #+begin_src lisp (defun setup-llm-providers () "Interactive wizard for configuring LLM providers." @@ -159,31 +176,60 @@ Creates the config directory tree if it does not exist. when (config-get key) collect name))) (when current-providers - (format t "Current providers: ~{~a~^, ~}~%~%" current-providers)) + (format t "Currently configured: ~{~a~^, ~}~%~%" current-providers)) + (format t "~%") + (format t "★ OpenRouter recommended for new users — free tier, no credit card required.~%") + (format t " Sign up at https://openrouter.ai and paste your API key below.~%") + (format t "~%") (format t "Available providers:~%") + (format t " ~20@A ~25@A ~s~%" "Provider" "Key env var" "Notes") + (format t " ~20@A ~25@A ~s~%" "--------" "----------" "-----") (dolist (p *available-providers*) - (format t " - ~a~%" (car p))) + (let ((name (car p)) + (env-key (cdr p)) + (desc (case (car p) + ("OpenRouter" "free tier, 33+ models") + ("OpenAI" "paid, gpt-4o-mini") + ("Anthropic" "paid, Claude 3.5 Sonnet") + ("Groq" "fast inference, free tier") + ("Gemini" "free via API") + ("DeepSeek" "competitive pricing, coding") + ("NVIDIA" "NVIDIA NIM hosted models") + ("Local" "local server, no API key") + (t "")))) + (format t " ~20@A ~25@A ~a~%" name env-key desc))) (format t "~%") - (when (prompt-yes-no "Configure a new provider?") - (let ((chosen (prompt-choice "Select provider:" (mapcar #'car *available-providers*)))) - (when chosen - (let ((env-key (cdr (assoc chosen *available-providers* :test #'string=)))) - (if (string= chosen "Ollama (local)") - (progn - (format t "Enter Ollama URL (e.g., http://localhost:11434): ") - (let ((url (read-line))) - (config-set env-key url) - (format t "✓ Ollama configured at ~a~%" url))) - (progn - (format t "Enter API key for ~a: " chosen) - (let ((key (read-line))) - (config-set env-key key) - (format t "✓ ~a API key saved~%" chosen))))))))) + (loop + (when (not (prompt-yes-no "Configure a LLM provider?")) + (return)) + (let ((chosen (prompt-choice "Select a provider:" (mapcar #'car *available-providers*)))) + (unless chosen + (format t "Invalid choice.~%") + (return)) + (let ((env-key (cdr (assoc chosen *available-providers* :test #'string=)))) + (cond + ((string= chosen "Local") + (format t "Enter the server URL (e.g., http://localhost:11434 for Ollama,~%") + (format t " or http://localhost:8080 for llama.cpp): ") + (let ((url (read-line))) + (if (> (length url) 0) + (progn (config-set env-key url) + (format t "✓ ~a configured at ~a~%" chosen url)) + (format t "Skipping ~a — no URL entered.~%" chosen)))) + (t + (format t "Enter API key for ~a~%" chosen) + (format t " (get one from the provider's website, paste it here): ") + (let ((key (read-line))) + (if (> (length key) 0) + (progn (config-set env-key key) + (format t "✓ ~a API key saved~%" chosen)) + (format t "Skipping ~a — no key entered.~%" chosen)))))))) (format t "~%")) + #+end_src ** setup-add-provider ;; REPL-VERIFIED: 2026-05-03T13:00:00 diff --git a/org/system-model-provider.org b/org/system-model-provider.org index e17fefd..896f927 100644 --- a/org/system-model-provider.org +++ b/org/system-model-provider.org @@ -25,8 +25,7 @@ Providers register themselves at boot. No API key? That provider doesn't registe (:groq . (:base-url "https://api.groq.com/openai/v1" :key-env "GROQ_API_KEY" :default-model "llama-3.1-70b-versatile")) (:gemini . (:base-url "https://generativelanguage.googleapis.com/v1beta/openai" :key-env "GEMINI_API_KEY" :default-model "gemini-2.0-flash")) (:deepseek . (:base-url "https://api.deepseek.com/v1" :key-env "DEEPSEEK_API_KEY" :default-model "deepseek-chat")) - (:nvidia . (:base-url "https://integrate.api.nvidia.com/v1" :key-env "NVIDIA_API_KEY" :default-model "meta/llama-3.1-405b-instruct")) - (:ollama . (:base-url nil :key-env nil :url-env "OLLAMA_HOST" :default-model "llama3")))) + (:nvidia . (:base-url "https://integrate.api.nvidia.com/v1" :key-env "NVIDIA_API_KEY" :default-model "meta/llama-3.1-405b-instruct")))) #+end_src ** Provider config lookup @@ -112,7 +111,7 @@ Providers register themselves at boot. No API key? That provider doesn't registe (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 :ollama))) + (member (car e) '(:local))) *provider-configs*)))))) #+end_src