diff options
| -rw-r--r-- | llm-azure.el | 13 | ||||
| -rw-r--r-- | llm-claude.el | 11 | ||||
| -rw-r--r-- | llm-deepseek.el | 17 | ||||
| -rw-r--r-- | llm-gemini.el | 12 | ||||
| -rw-r--r-- | llm-github.el | 15 | ||||
| -rw-r--r-- | llm-gpt4all.el | 15 | ||||
| -rw-r--r-- | llm-llamacpp.el | 16 | ||||
| -rw-r--r-- | llm-ollama.el | 15 | ||||
| -rw-r--r-- | llm-openai.el | 44 | ||||
| -rw-r--r-- | llm-provider-utils.el | 13 | ||||
| -rw-r--r-- | llm-test.el | 17 |
11 files changed, 171 insertions, 17 deletions
diff --git a/llm-azure.el b/llm-azure.el index c717000..1d72de9 100644 --- a/llm-azure.el +++ b/llm-azure.el @@ -29,7 +29,18 @@ (require 'llm-openai) (require 'cl-lib) -(cl-defstruct (llm-azure (:include llm-openai-compatible))) +(cl-defstruct (llm-azure + (:include llm-openai-compatible) + (:constructor make-llm-azure + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "unset") + (embedding-model "unset") + url + &aux + (key (llm-provider-utils--wrap-key raw-key)))))) (cl-defmethod llm-nonfree-message-info ((_ llm-azure)) "Return Azure's nonfree terms of service." diff --git a/llm-claude.el b/llm-claude.el index c349c11..0e5542c 100644 --- a/llm-claude.el +++ b/llm-claude.el @@ -32,7 +32,16 @@ (require 'rx) ;; Models defined at https://docs.anthropic.com/claude/docs/models-overview -(cl-defstruct (llm-claude (:include llm-standard-chat-provider)) +(cl-defstruct (llm-claude + (:include llm-standard-chat-provider) + (:constructor make-llm-claude + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "claude-sonnet-4-6") + &aux + (key (llm-provider-utils--wrap-key raw-key))))) (key nil :read-only t) (chat-model "claude-sonnet-4-6" :read-only t)) diff --git a/llm-deepseek.el b/llm-deepseek.el index 799c627..8855166 100644 --- a/llm-deepseek.el +++ b/llm-deepseek.el @@ -29,9 +29,20 @@ (require 'llm-models) (require 'cl-lib) -(cl-defstruct (llm-deepseek (:include llm-openai-compatible - (url "https://api.deepseek.com") - (chat-model "deepseek-chat")))) +(cl-defstruct (llm-deepseek + (:include llm-openai-compatible + (url "https://api.deepseek.com") + (chat-model "deepseek-chat")) + (:constructor make-llm-deepseek + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "deepseek-chat") + (embedding-model "unset") + (url "https://api.deepseek.com") + &aux + (key (llm-provider-utils--wrap-key raw-key)))))) (cl-defmethod llm-nonfree-message-info ((_ llm-deepseek)) "Location for the terms of service and privacy policy." diff --git a/llm-gemini.el b/llm-gemini.el index 4f9e06d..c7eb222 100644 --- a/llm-gemini.el +++ b/llm-gemini.el @@ -32,7 +32,17 @@ (require 'llm-provider-utils) (require 'json) -(cl-defstruct (llm-gemini (:include llm-google)) +(cl-defstruct (llm-gemini + (:include llm-google) + (:constructor make-llm-gemini + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (embedding-model "embedding-001") + (chat-model "gemini-3.1-pro-preview") + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "A struct representing a Gemini client. KEY is the API key for the client. diff --git a/llm-github.el b/llm-github.el index 4bb1448..063030f 100644 --- a/llm-github.el +++ b/llm-github.el @@ -28,8 +28,19 @@ (require 'llm) (require 'llm-azure) -(cl-defstruct (llm-github (:include llm-azure - (url "https://models.inference.ai.azure.com")))) +(cl-defstruct (llm-github + (:include llm-azure + (url "https://models.inference.ai.azure.com")) + (:constructor make-llm-github + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "unset") + (embedding-model "unset") + (url "https://models.inference.ai.azure.com") + &aux + (key (llm-provider-utils--wrap-key raw-key)))))) (cl-defmethod llm-provider-chat-url ((provider llm-github)) (format "%s/chat/completions" (llm-azure-url provider))) diff --git a/llm-gpt4all.el b/llm-gpt4all.el index 39e4e0d..aa2e445 100644 --- a/llm-gpt4all.el +++ b/llm-gpt4all.el @@ -34,7 +34,20 @@ (require 'llm-openai) (require 'llm-provider-utils) -(cl-defstruct (llm-gpt4all (:include llm-openai-compatible)) +(cl-defstruct (llm-gpt4all + (:include llm-openai-compatible) + (:constructor make-llm-gpt4all + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "unset") + (embedding-model "unset") + url + host + port + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "A structure for holding information needed by GPT4All. CHAT-MODEL is the model to use for chat queries. It must be set. diff --git a/llm-llamacpp.el b/llm-llamacpp.el index 348c8fc..e882f9e 100644 --- a/llm-llamacpp.el +++ b/llm-llamacpp.el @@ -46,7 +46,21 @@ This is needed because there is no API support for previous chat conversation." :type 'string) ;; Obsolete, llm-openai-compatible can be used directly instead. -(cl-defstruct (llm-llamacpp (:include llm-openai-compatible)) +(cl-defstruct (llm-llamacpp + (:include llm-openai-compatible) + (:constructor make-llm-llamacpp + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "unset") + (embedding-model "unset") + url + (scheme "http") + (host "localhost") + (port 8080) + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "A struct representing a llama.cpp instance." (scheme "http") (host "localhost") (port 8080)) diff --git a/llm-ollama.el b/llm-ollama.el index 9048070..bf272c6 100644 --- a/llm-ollama.el +++ b/llm-ollama.el @@ -63,7 +63,20 @@ CHAT-MODEL is the model to use for chat queries. It is required. EMBEDDING-MODEL is the model to use for embeddings. It is required." (scheme "http") (host "localhost") (port 11434) chat-model embedding-model) -(cl-defstruct (llm-ollama-authed (:include llm-ollama)) +(cl-defstruct (llm-ollama-authed + (:include llm-ollama) + (:constructor make-llm-ollama-authed + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + (scheme "http") + (host "localhost") + (port 11434) + chat-model + embedding-model + ((:key raw-key)) + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "Similar to llm-ollama, but also with a key." key) diff --git a/llm-openai.el b/llm-openai.el index f27807c..453d901 100644 --- a/llm-openai.el +++ b/llm-openai.el @@ -42,7 +42,17 @@ :type 'string :group 'llm-openai) -(cl-defstruct (llm-openai (:include llm-standard-full-provider)) +(cl-defstruct (llm-openai + (:include llm-standard-full-provider) + (:constructor make-llm-openai + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "gpt-5.4-mini") + (embedding-model "text-embedding-3-small") + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "A structure for holding information needed by Open AI's API. KEY is the API key for Open AI, which is required. @@ -54,9 +64,20 @@ EMBEDDING-MODEL is the model to use for embeddings. If unset, it will use a reasonable default." key (chat-model "gpt-5.4-mini") (embedding-model "text-embedding-3-small")) -(cl-defstruct (llm-openai-compatible (:include llm-openai - (chat-model "unset") - (embedding-model "unset"))) +(cl-defstruct (llm-openai-compatible + (:include llm-openai + (chat-model "unset") + (embedding-model "unset")) + (:constructor make-llm-openai-compatible + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "unset") + (embedding-model "unset") + url + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "A structure for other APIs that use the Open AI's API. URL is the URL to use for the API, up to the command. So, for @@ -65,8 +86,19 @@ https://api.example.com/v1/chat, then URL should be \"https://api.example.com/v1/\"." url) -(cl-defstruct (llm-openrouter (:include llm-openai-compatible - (url "https://openrouter.ai/api/v1/"))) +(cl-defstruct (llm-openrouter + (:include llm-openai-compatible + (url "https://openrouter.ai/api/v1/")) + (:constructor make-llm-openrouter + (&key default-chat-temperature + default-chat-max-tokens + default-chat-non-standard-params + ((:key raw-key)) + (chat-model "unset") + (embedding-model "unset") + (url "https://openrouter.ai/api/v1/") + &aux + (key (llm-provider-utils--wrap-key raw-key))))) "A structure for Open Router. This is mostly compatible with Open AI's API but has some minor API diff --git a/llm-provider-utils.el b/llm-provider-utils.el index fbfb245..088fdbd 100644 --- a/llm-provider-utils.el +++ b/llm-provider-utils.el @@ -73,6 +73,19 @@ NAME is the tool name. ARG is an alist of arguments to their values." id name args) +(defun llm-provider-utils--wrap-key (key) + "Return KEY wrapped so provider structs do not print secret strings. +Function values are already suitable because providers resolve them +at request time." + (if (or (null key) (functionp key)) + key + (let ((token (make-symbol "llm-key"))) + (put token 'secret key) + (fset token + (lambda () + (get token 'secret))) + token))) + ;; Methods necessary for both embedding and chat requests. (cl-defgeneric llm-provider-request-prelude (provider) diff --git a/llm-test.el b/llm-test.el index 4f0d2d6..8e2747a 100644 --- a/llm-test.el +++ b/llm-test.el @@ -96,6 +96,23 @@ (mapcar #'llm-test-normalize json-obj)))) (t json-obj))) +(ert-deftest llm-test-provider-key-not-printed () + (let* ((secret "llm-test-secret") + (provider (make-llm-openai-compatible + :url "http://127.0.0.1:8000/v1" + :chat-model "model" + :key secret)) + (printed (prin1-to-string provider)) + (key (llm-openai-compatible-key provider))) + (should (functionp key)) + (should (symbolp key)) + (should (equal secret (funcall key))) + (should-not (string-match-p (regexp-quote secret) printed)) + (should-not (string-match-p (regexp-quote secret) + (prin1-to-string (symbol-function key)))) + (should (equal `(("Authorization" . ,(format "Bearer %s" secret))) + (llm-provider-headers provider))))) + (defconst llm-test-chat-requests-to-responses `((:name "Simple request" :prompt (lambda () (llm-make-chat-prompt "Hello world")) |
