#+TITLE: SKILL: Model Dispatch (org-skill-model.org) #+AUTHOR: Agent #+FILETAGS: :skill:model:dispatch: #+PROPERTY: header-args:lisp :tangle ../lisp/system-model.lisp * Architectural Intent ~system-model~ is the dispatcher. It sits between the reason pipeline and the provider backends registered in ~*probabilistic-backends*~. The reason pipeline calls ~model-request~ with a provider keyword and a model name; ~model-request~ looks up that provider's handler function, calls it, and returns the result. This is intentionally thin. All the provider-specific logic (URL construction, API key headers, JSON parsing) lives in ~system-model-provider~. All the routing logic (which model for which task) lives in ~system-model-router~. This skill is the seam — it decouples "who to call" from "how to call them" and "why to call them." When every provider fails (not registered, or all return errors), ~model-request~ returns an error plist with ~:status :error~. The reason pipeline's ~backend-cascade-call~ catches this and falls through to the next provider in the cascade. If no provider can serve the request, the cascade returns the "Neural Cascade Failure" signal. ~model-request~ replaces the old ~gateway-llm-request~ with the same contract but renamed for consistency with the ~system-model-*~ family. * Implementation ** Request execution #+begin_src lisp (in-package :passepartout) (defun model-request (&key prompt system-prompt (provider :openrouter) model) "Central dispatcher for LLM requests." (let ((backend (gethash provider *probabilistic-backends*))) (if backend (handler-case (funcall backend prompt system-prompt :model model) (error (c) (list :status :error :message (format nil "~a Failure: ~a" provider c)))) (list :status :error :message (format nil "Provider ~a not registered" provider))))) #+end_src ** Skill registration #+begin_src lisp (defskill :passepartout-system-model :priority 100 :trigger (lambda (ctx) (getf ctx :user-input)) :deterministic (lambda (action ctx) (declare (ignore ctx)) action)) #+end_src