DOCS: Systematic overhaul of Literate source (Granularity & Technical Reasoning)
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 2s
This commit is contained in:
@@ -1,35 +1,35 @@
|
||||
:PROPERTIES:
|
||||
:ID: llm-gateway-skill
|
||||
:CREATED: [2026-04-09 Thu]
|
||||
:EDITED: [2026-04-19 Sun]
|
||||
:END:
|
||||
#+TITLE: SKILL: Unified LLM Gateway (Universal Literate Note)
|
||||
#+STARTUP: content
|
||||
#+AUTHOR: Amr
|
||||
#+FILETAGS: :llm:gateway:infrastructure:autonomy:
|
||||
#+DEPENDS_ON: org-skill-credentials-vault
|
||||
#+STARTUP: content
|
||||
|
||||
* Overview
|
||||
The *Unified LLM Gateway* is the single sensory and reasoning interface for all neural backends. It consolidates the previously fragmented provider skills into a high-integrity dispatch layer, standardizing credential management, error handling, and payload formatting.
|
||||
|
||||
* Phase B: Blueprint (PROTOCOL)
|
||||
** Architectural Intent: The Neural Dispatch
|
||||
The gateway utilizes a functional dispatch pattern. A single entry point, ~execute-llm-request~, resolves the provider-specific nuances (URLs, headers, JSON structures) while exposing a uniform interface to the harness.
|
||||
|
||||
** 1. Architectural Intent
|
||||
The gateway utilizes a functional dispatch pattern. A single entry point, `execute-llm-request`, resolves the provider-specific nuances (URLs, headers, JSON structures) while exposing a uniform interface to the harness.
|
||||
By abstracting the provider details, we allow the agent to swap "brains" mid-thought based on cost, speed, or task complexity without any change to the core reasoning logic.
|
||||
|
||||
* Phase D: Build (Implementation)
|
||||
* Implementation
|
||||
|
||||
** Implementation
|
||||
** Package Initialization
|
||||
#+begin_src lisp
|
||||
(in-package :cl-user)
|
||||
(defpackage :opencortex.skills.org-skill-llm-gateway
|
||||
(:use :cl :opencortex))
|
||||
(in-package :opencortex.skills.org-skill-llm-gateway)
|
||||
#+end_src
|
||||
|
||||
** Data Extraction Helper (get-nested)
|
||||
JSON responses from different providers vary wildly in their nesting depth. ~get-nested~ provides a robust, recursive mechanism to extract values from deeply nested alists, shielding the gateway from parsing errors.
|
||||
|
||||
#+begin_src lisp
|
||||
(defun get-nested (alist &rest keys)
|
||||
"Recursively extracts nested values from an alist, handling both objects and arrays."
|
||||
(let ((val alist))
|
||||
(dolist (k keys)
|
||||
;; Descend into arrays (cl-json style: ((key . val)) or ( ( (key . val) ) ))
|
||||
;; Handle cl-json style arrays and nested alists
|
||||
(loop while (and (listp val) (listp (car val)) (not (keywordp (caar val))))
|
||||
do (setf val (car val)))
|
||||
(let ((pair (or (assoc k val)
|
||||
@@ -39,7 +39,15 @@ The gateway utilizes a functional dispatch pattern. A single entry point, `execu
|
||||
(setf val (cdr pair))
|
||||
(return-from get-nested nil))))
|
||||
val))
|
||||
#+end_src
|
||||
|
||||
** Unified Request Router (execute-llm-request)
|
||||
The primary entry point for all neural reasoning. It handles:
|
||||
1. *Credential Retrieval:* Securely fetching keys from the Vault.
|
||||
2. *Cascade Fallback:* (Logic for future expansion).
|
||||
3. *Provider Normalization:* Translating a generic prompt into provider-specific JSON.
|
||||
|
||||
#+begin_src lisp
|
||||
(defun execute-llm-request (prompt system-prompt &key provider model)
|
||||
"Unified entry point for all LLM providers. Respects the global cascade."
|
||||
(let* ((active-provider (or provider (car opencortex::*provider-cascade*) :openrouter))
|
||||
@@ -49,29 +57,23 @@ The gateway utilizes a functional dispatch pattern. A single entry point, `execu
|
||||
(harness-log "PROBABILISTIC ENGINE: Requesting ~a (Model: ~s)"
|
||||
active-provider (or model "default"))
|
||||
|
||||
;; If the specifically requested provider has no key, try falling back to the cascade
|
||||
;; Guard: API Key Verification
|
||||
(when (or (null api-key) (string= api-key ""))
|
||||
(harness-log "GATEWAY: Provider ~a has no key. Cascade fallback would trigger here." active-provider)
|
||||
(harness-log "GATEWAY ERROR: Provider ~a has no key." active-provider)
|
||||
(return-from execute-llm-request (list :status :error :message "API Key missing.")))
|
||||
|
||||
(case active-provider
|
||||
(:gemini-web
|
||||
(let ((res (uiop:symbol-call :opencortex.skills.org-skill-web-research :ask-gemini-web full-prompt)))
|
||||
(if res (list :status :success :content res) (list :status :error :message "Web Research Failure"))))
|
||||
|
||||
(:ollama
|
||||
(let* ((host (or (uiop:getenv "OLLAMA_HOST") "localhost:11434"))
|
||||
(url (format nil "http://~a/api/generate" host))
|
||||
(body (cl-json:encode-json-to-string `((model . ,(or model "llama3")) (prompt . ,full-prompt) (stream . :false)))))
|
||||
(handler-case
|
||||
(progn
|
||||
(harness-log "LLM DEBUG: Requesting Ollama...")
|
||||
(let* ((response (dex:post url :headers '(("Content-Type" . "application/json")) :content body :connect-timeout 5 :read-timeout 60))
|
||||
(json (cl-json:decode-json-from-string response)))
|
||||
(list :status :success :content (cdr (assoc :response json)))))
|
||||
(let* ((response (dex:post url :headers '(("Content-Type" . "application/json")) :content body :connect-timeout 5 :read-timeout 60))
|
||||
(json (cl-json:decode-json-from-string response)))
|
||||
(list :status :success :content (cdr (assoc :response json))))
|
||||
(error (c) (list :status :error :message (format nil "Ollama Failure: ~a" c))))))
|
||||
|
||||
(t ;; Cloud Providers (Anthropic, Gemini API, Groq, OpenAI, OpenRouter)
|
||||
(t ;; Cloud Provider Normalization (Anthropic, Gemini, OpenAI, OpenRouter)
|
||||
(let* ((endpoint (case active-provider
|
||||
(:anthropic "https://api.anthropic.com/v1/messages")
|
||||
(:gemini-api (format nil "https://generativelanguage.googleapis.com/v1/models/~a:generateContent" (or model "gemini-1.5-flash-latest")))
|
||||
@@ -90,20 +92,22 @@ The gateway utilizes a functional dispatch pattern. A single entry point, `execu
|
||||
(t (cl-json:encode-json-to-string `((model . ,(or model (case active-provider (:groq "llama-3.3-70b-versatile") (t "google/gemini-2.0-flash-001"))))
|
||||
(messages . (( (role . "system") (content . ,system-prompt) ) ( (role . "user") (content . ,prompt) )))))))))
|
||||
(handler-case
|
||||
(progn
|
||||
(harness-log "LLM DEBUG: Requesting ~a..." active-provider)
|
||||
(let* ((response (dex:post endpoint :headers headers :content body :connect-timeout 10 :read-timeout 30))
|
||||
(json (cl-json:decode-json-from-string response)))
|
||||
(let ((content (case active-provider
|
||||
(let* ((response (dex:post endpoint :headers headers :content body :connect-timeout 10 :read-timeout 30))
|
||||
(json (cl-json:decode-json-from-string response)))
|
||||
(let ((content (case active-provider
|
||||
(:anthropic (get-nested json :content :text))
|
||||
(:gemini-api (get-nested json :candidates :parts :text))
|
||||
(t (get-nested json :choices :message :content)))))
|
||||
(if content
|
||||
(list :status :success :content content)
|
||||
(list :status :error :message (format nil "Failed to parse ~a response structure." active-provider))))))
|
||||
(if content
|
||||
(list :status :success :content content)
|
||||
(list :status :error :message (format nil "Failed to parse ~a response structure." active-provider)))))
|
||||
(error (c) (list :status :error :message (format nil "LLM Gateway Failure (~a): ~a" active-provider c)))))))))
|
||||
#+end_src
|
||||
|
||||
;; Initialize Cascade
|
||||
** Cascade Initialization
|
||||
The provider cascade determines the failover logic for the agent's cognition.
|
||||
|
||||
#+begin_src lisp
|
||||
(let* ((env-cascade (uiop:getenv "PROVIDER_CASCADE"))
|
||||
(default-list '(:openrouter :openai :anthropic :groq :gemini-api :ollama))
|
||||
(final-list (if (and env-cascade (not (string= env-cascade "")))
|
||||
@@ -112,12 +116,23 @@ The gateway utilizes a functional dispatch pattern. A single entry point, `execu
|
||||
default-list)))
|
||||
(setf opencortex::*provider-cascade* final-list)
|
||||
(opencortex:harness-log "PROBABILISTIC: Neural Cascade Initialized -> ~a" final-list))
|
||||
#+end_src
|
||||
|
||||
;; Register Providers
|
||||
** Backend Registration
|
||||
Registers all supported providers into the core ~*probabilistic-backends*~ registry.
|
||||
|
||||
#+begin_src lisp
|
||||
(dolist (p '(:anthropic :gemini-api :gemini-web :groq :ollama :openrouter :openai))
|
||||
(opencortex:register-probabilistic-backend p (lambda (prompt system-prompt &key model)
|
||||
(execute-llm-request prompt system-prompt :provider p :model model))))
|
||||
#+end_src
|
||||
|
||||
* Cognitive Tool Integration
|
||||
|
||||
** The ask-llm Tool
|
||||
Provides the agent with the physical capability to query additional neural contexts.
|
||||
|
||||
#+begin_src lisp
|
||||
(def-cognitive-tool :ask-llm
|
||||
"Queries an LLM provider via the unified gateway."
|
||||
((:prompt :type :string :description "The user prompt.")
|
||||
@@ -129,10 +144,13 @@ The gateway utilizes a functional dispatch pattern. A single entry point, `execu
|
||||
(or (getf args :system-prompt) "You are a helpful assistant.")
|
||||
:provider (getf args :provider)
|
||||
:model (getf args :model))))
|
||||
#+end_src
|
||||
|
||||
** Skill Registration
|
||||
#+begin_src lisp
|
||||
(defskill :skill-llm-gateway
|
||||
:priority 150
|
||||
:trigger (lambda (context) (declare (ignore context)) nil)
|
||||
:trigger (lambda (context) (declare (ignore context)) nil) ; Passive responder
|
||||
:probabilistic (lambda (context) (declare (ignore context)) nil)
|
||||
:deterministic (lambda (action context) (declare (ignore context)) action))
|
||||
#+end_src
|
||||
|
||||
Reference in New Issue
Block a user