Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
202 lines
9.3 KiB
Org Mode
202 lines
9.3 KiB
Org Mode
#+TITLE: Zero-to-One Setup (setup.org)
|
|
#+AUTHOR: Amr
|
|
#+FILETAGS: :harness:setup:
|
|
#+STARTUP: content
|
|
|
|
* Zero-to-One Setup (setup.org)
|
|
The ~setup.org~ file defines the automated installation and initialization sequence for the OpenCortex.
|
|
|
|
* Phase A: Demand (Thinking)
|
|
** The Agnostic LLM Provider Registry
|
|
To fulfill the mandate of sovereignty and extensibility, the setup process must move away from a single hardcoded LLM provider (like OpenRouter).
|
|
|
|
** Design Goals:
|
|
1. **Modular Adapters:** Each provider (Ollama, Groq, OpenAI, etc.) is a data-driven structure defining its required fields (API_KEY, BASE_URL) and its "ping" validation logic.
|
|
2. **Interactive Selection:** The user should be presented with a multi-select list of providers.
|
|
3. **Local-First Default:** If no cloud keys are provided, the system must default to a local Ollama/llama.cpp configuration.
|
|
4. **State Persistence:** Configuration is saved to `providers.lisp` in the XDG Config directory.
|
|
5. **Secret Splitting:** Sensitive keys go to `.env`, while metadata (models, URLs) lives in `state/providers.lisp`.
|
|
|
|
* Phase B: Protocol (Success Criteria)
|
|
|
|
** Test Suite Context
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/tests"))
|
|
(defpackage :opencortex-setup-tests
|
|
(:use :cl :fiveam :opencortex)
|
|
(:export #:setup-suite))
|
|
#+end_src
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/tests"))
|
|
(in-package :opencortex-setup-tests)
|
|
#+end_src
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/tests"))
|
|
(def-suite setup-suite :description "Verification of the Lisp Setup Wizard")
|
|
#+end_src
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/tests"))
|
|
(in-suite setup-suite)
|
|
#+end_src
|
|
|
|
** Persistence Tests
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/tests"))
|
|
(test test-provider-registry-persistence
|
|
"Verify that multiple providers can be registered and saved."
|
|
(let ((opencortex::*providers* nil))
|
|
(opencortex:register-provider :ollama '(:url "http://localhost:11434" :model "llama3"))
|
|
(opencortex:register-provider :groq '(:key "gsk_123" :model "mixtral-8x7b"))
|
|
(is (equal "gsk_123" (getf (getf opencortex::*providers* :groq) :key)))))
|
|
#+end_src
|
|
|
|
** Fallback Tests
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard-tests.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/tests"))
|
|
(test test-sovereign-fallback-logic
|
|
"Verify that the system identifies as healthy with only local providers."
|
|
(let ((opencortex::*providers* (list :ollama '(:url "http://localhost:11434"))))
|
|
(is (opencortex:system-ready-p))))
|
|
#+end_src
|
|
|
|
* Phase C: Implementation (Build)
|
|
|
|
** Package Context
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(in-package :opencortex)
|
|
#+end_src
|
|
|
|
** Global Provider Registry
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defvar *providers* nil "Global registry of configured LLM providers.")
|
|
#+end_src
|
|
|
|
** Provider Templates
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defvar *provider-templates*
|
|
'((:ollama . (:name "Ollama (Local)" :fields ((:url :label "URL") (:model :label "Model")) :default-url "http://localhost:11434" :default-model "llama3"))
|
|
(:openrouter . (:name "OpenRouter" :fields ((:key :label "API Key" :secret t) (:model :label "Model")) :default-model "anthropic/claude-3-opus-20240229"))
|
|
(:openai . (:name "OpenAI" :fields ((:key :label "API Key" :secret t) (:model :label "Model")) :default-model "gpt-4-turbo"))
|
|
(:groq . (:name "Groq" :fields ((:key :label "API Key" :secret t) (:model :label "Model")) :default-model "mixtral-8x7b-32768"))
|
|
(:gemini . (:name "Google Gemini" :fields ((:key :label "API Key" :secret t) (:model :label "Model")) :default-model "gemini-1.5-pro"))
|
|
(:anthropic . (:name "Anthropic" :fields ((:key :label "API Key" :secret t) (:model :label "Model")) :default-model "claude-3-5-sonnet-20240620")))
|
|
"Templates for supported LLM providers. Fields marked :secret go to .env.")
|
|
#+end_src
|
|
|
|
** XDG Configuration Utilities
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun get-oc-config-dir ()
|
|
"Resolves the OpenCortex configuration directory following XDG standards."
|
|
(let ((env (uiop:getenv "OC_CONFIG_DIR")))
|
|
(if (and env (> (length env) 0))
|
|
(uiop:ensure-directory-pathname env)
|
|
(merge-pathnames ".config/opencortex/" (user-homedir-pathname)))))
|
|
#+end_src
|
|
|
|
** Secret Persistence
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun save-secret (id key value)
|
|
"Appends a secret to the XDG config .env file and updates the current environment."
|
|
(let* ((env-key (format nil "~:@(~a_~a~)" id key))
|
|
(path (merge-pathnames ".env" (get-oc-config-dir))))
|
|
(ensure-directories-exist path)
|
|
(with-open-file (s path :direction :output :if-exists :append :if-does-not-exist :create)
|
|
(format s "~%~a=\"~a\"" env-key value))
|
|
(setf (uiop:getenv env-key) value)))
|
|
#+end_src
|
|
|
|
** Provider Metadata Persistence
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun save-providers ()
|
|
"Persist provider configuration to XDG config directory."
|
|
(let ((path (merge-pathnames "providers.lisp" (get-oc-config-dir))))
|
|
(ensure-directories-exist path)
|
|
(with-open-file (s path :direction :output :if-exists :supersede)
|
|
(format s ";;; OpenCortex Provider Metadata~%~s~%" *providers*))))
|
|
#+end_src
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun load-providers ()
|
|
"Load provider configuration from XDG config directory."
|
|
(let ((path (merge-pathnames "providers.lisp" (get-oc-config-dir))))
|
|
(when (uiop:file-exists-p path)
|
|
(with-open-file (s path)
|
|
(setf *providers* (read s))))))
|
|
#+end_src
|
|
|
|
** Registry API
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun register-provider (id config)
|
|
"Update the global provider registry."
|
|
(setf (getf *providers* id) config))
|
|
#+end_src
|
|
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun system-ready-p ()
|
|
"Predicate verifying if at least one provider is configured."
|
|
(and *providers* (> (length *providers*) 0)))
|
|
#+end_src
|
|
|
|
** User Interface Primitives
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun prompt-for (label &optional default)
|
|
"Interactively prompt the user for input with an optional default."
|
|
(format t "~a~@[ [~a]~]: " label default)
|
|
(finish-output)
|
|
(let ((input (read-line)))
|
|
(if (and (string= input "") default)
|
|
default
|
|
input)))
|
|
#+end_src
|
|
|
|
** Provider Configuration Loop
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun configure-provider (id)
|
|
"Guided configuration for a specific LLM provider template."
|
|
(let* ((template (cdr (assoc id *provider-templates*)))
|
|
(fields (getf template :fields))
|
|
(config nil))
|
|
(format t "~%--- Configuring ~a ---~%" (getf template :name))
|
|
(dolist (field-spec fields)
|
|
(let* ((field (first field-spec))
|
|
(label (getf (rest field-spec) :label))
|
|
(is-secret (getf (rest field-spec) :secret))
|
|
(default-key (intern (format nil "DEFAULT-~a" field) :keyword))
|
|
(default (getf template default-key))
|
|
(val (prompt-for label default)))
|
|
(if is-secret
|
|
(save-secret id field val)
|
|
(setf (getf config field) val))))
|
|
(register-provider id config)
|
|
(format t "✓ ~a metadata registered.~%" (getf template :name))))
|
|
#+end_src
|
|
|
|
** Main Setup Orchestrator
|
|
#+begin_src lisp :tangle (expand-file-name "setup-wizard.lisp" (concat (or (getenv "INSTALL_DIR") ".") "/harness"))
|
|
(defun run-setup-wizard ()
|
|
"Entry point for the interactive OpenCortex Lisp Setup Wizard."
|
|
(format t "=== OpenCortex: Advanced Setup Wizard ===~%")
|
|
|
|
;; 1. Identity
|
|
(let ((user (prompt-for "Your Name" "User"))
|
|
(agent (prompt-for "Agent Name" "OpenCortex")))
|
|
(format t "Welcome, ~a. I am ~a.~%" user agent))
|
|
|
|
;; 2. Providers
|
|
(format t "~%Available Providers:~%")
|
|
(loop for (id . data) in *provider-templates*
|
|
do (format t " ~a: ~a~%" id (getf data :name)))
|
|
|
|
(format t "~%Enter provider IDs to configure (comma separated, or 'all'): ")
|
|
(finish-output)
|
|
(let* ((input (read-line))
|
|
(ids (if (string= input "all")
|
|
(mapcar #'car *provider-templates*)
|
|
(mapcar (lambda (s) (intern (string-upcase (string-trim " " s)) :keyword))
|
|
(uiop:split-string input :separator ",")))))
|
|
(dolist (id ids)
|
|
(when (assoc id *provider-templates*)
|
|
(configure-provider id))))
|
|
|
|
(save-providers)
|
|
(format t "~%Setup complete. Running doctor check...~%")
|
|
(doctor-run-all))
|
|
#+end_src
|