diff options
| -rw-r--r-- | kaagum/openai.scm | 60 | ||||
| -rw-r--r-- | kaagum/web.scm | 82 |
2 files changed, 83 insertions, 59 deletions
diff --git a/kaagum/openai.scm b/kaagum/openai.scm index 4cf643d..436a755 100644 --- a/kaagum/openai.scm +++ b/kaagum/openai.scm @@ -17,15 +17,10 @@ ;;; along with kaagum. If not, see <https://www.gnu.org/licenses/>. (define-module (kaagum openai) - #:use-module (rnrs conditions) #:use-module (rnrs exceptions) - #:use-module (srfi srfi-11) - #:use-module (web client) - #:use-module (web http) - #:use-module (web response) - #:use-module (json) #:use-module (lens) #:use-module (kaagum records) + #:use-module (kaagum web) #:export (get-api-key openai-query openai-models)) @@ -35,59 +30,6 @@ (description model-description) (context-length model-context-length lensed))) -;; TODO: URIs must not be operated on using string operations. Replace with a -;; more principled implementation involving (web uri). -(define (uri-join base uri) - (string-append base uri)) - -(define* (json-request method url #:key (headers '()) body) - "Send a HTTP @var{method} request to @var{url} with @var{body} and -additional @var{headers}. Return JSON response." - (let-values (((response body) - (http-request url - #:method method - #:headers headers - #:body body - #:streaming? #t))) - ;; Guile does not consider application/json responses as textual, and does - ;; not automatically set the port encoding to UTF-8. - (set-port-encoding! body "UTF-8") - (case (quotient (response-code response) - 100) - ((2) (json->scm body)) - ((4) - (raise-exception - (condition (make-violation) - (make-irritants-condition (list method url headers body)) - (make-message-condition - (string-append "JSON API request failed with client error code " - (number->string (response-code response))))))) - (else - (raise-exception - (condition (make-error) - (make-irritants-condition (list method url headers body)) - (make-message-condition - (string-append "JSON API request failed with code " - (number->string (response-code response)))))))))) - -(define* (json-get url #:key (headers '())) - "Send a GET request to @var{url}. Return JSON response." - (json-request 'GET url - #:headers headers)) - -(define* (json-post url #:key (headers '()) json) - "Send a POST request to @var{url} with @var{json} body and additional -@var{headers}. The @samp{Content-Type} header is set to @samp{application/json} -and need not be specified in @var{headers}. Return JSON response." - (json-request 'POST url - #:headers `((content-type application/json) - ,@headers) - #:body (scm->json-string json))) - -;; Declare the Authorization header as opaque so that Guile doesn't try to mess -;; with it. -(declare-opaque-header! "Authorization") - (define (openai-query base-uri api-key model messages tools) "Send a request to the OpenAI completions API and return the JSON response. @var{base-uri} is the base URI of the OpenAI-compatible service. @var{api-key} diff --git a/kaagum/web.scm b/kaagum/web.scm new file mode 100644 index 0000000..ce29bdd --- /dev/null +++ b/kaagum/web.scm @@ -0,0 +1,82 @@ +;;; kaagum --- Tiny, security-focused AI agent in Guile +;;; Copyright © 2026 Arun Isaac <arunisaac@systemreboot.net> +;;; +;;; This file is part of kaagum. +;;; +;;; kaagum is free software: you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation, either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; kaagum is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with kaagum. If not, see <https://www.gnu.org/licenses/>. + +(define-module (kaagum web) + #:use-module (rnrs conditions) + #:use-module (srfi srfi-11) + #:use-module (web client) + #:use-module (web http) + #:use-module (web response) + #:use-module (json) + #:export (uri-join + json-request + json-get + json-post)) + +;; Declare the Authorization header as opaque so that Guile doesn't try to mess +;; with it. +(declare-opaque-header! "Authorization") + +;; TODO: URIs must not be operated on using string operations. Replace with a +;; more principled implementation involving (web uri). +(define (uri-join base uri) + (string-append base uri)) + +(define* (json-request method url #:key (headers '()) body) + "Send a HTTP @var{method} request to @var{url} with @var{body} and +additional @var{headers}. Return JSON response." + (let-values (((response body) + (http-request url + #:method method + #:headers headers + #:body body + #:streaming? #t))) + ;; Guile does not consider application/json responses as textual, and does + ;; not automatically set the port encoding to UTF-8. + (set-port-encoding! body "UTF-8") + (case (quotient (response-code response) + 100) + ((2) (json->scm body)) + ((4) + (raise-exception + (condition (make-violation) + (make-irritants-condition (list method url headers body)) + (make-message-condition + (string-append "JSON API request failed with client error code " + (number->string (response-code response))))))) + (else + (raise-exception + (condition (make-error) + (make-irritants-condition (list method url headers body)) + (make-message-condition + (string-append "JSON API request failed with code " + (number->string (response-code response)))))))))) + +(define* (json-get url #:key (headers '())) + "Send a GET request to @var{url}. Return JSON response." + (json-request 'GET url + #:headers headers)) + +(define* (json-post url #:key (headers '()) json) + "Send a POST request to @var{url} with @var{json} body and additional +@var{headers}. The @samp{Content-Type} header is set to @samp{application/json} +and need not be specified in @var{headers}. Return JSON response." + (json-request 'POST url + #:headers `((content-type application/json) + ,@headers) + #:body (scm->json-string json))) |
