Liking cljdoc? Tell your friends :D

openai-clj

Clojars Project cljdoc test

Idiomatic Clojure wrapper over the stable OpenAI API surface exposed by the official Java SDK.

Stack

Clojure OpenAI

Installation

deps.edn:

net.clojars.savya/openai-clj {:mvn/version "0.9.0"}

Leiningen:

[net.clojars.savya/openai-clj "0.9.0"]

Tracks com.openai/openai-java 4.42.0.

Documentation

Usage

(require '[openai.core :as openai])

(def client (openai/client)) ; reads OPENAI_API_KEY

(def configured-client
  (openai/client {:api-key "sk-..."
                  :organization "org_..."
                  :project "proj_..."
                  :base-url "https://api.openai.com/v1"
                  :timeout-ms 60000
                  :max-retries 2}))

(openai/create-response
 client
 {:model "gpt-5.2"
  :input "Write one sentence about Clojure maps."
  :instructions "Be precise."
  :max-output-tokens 256
  :temperature 0.2
  :top-p 1.0
  :metadata {:app "docs"}
  :store true
  :reasoning {:effort :low}})
;; => {:id "resp_..."
;;     :model "gpt-5.2"
;;     :status :completed
;;     :output [{:type :message
;;               :role :assistant
;;               :id "msg_..."
;;               :content [{:type :text :text "Clojure maps are ..."}]}]
;;     :text "Clojure maps are ..."
;;     :usage {:input-tokens 14 :output-tokens 12 :total-tokens 26}
;;     :created-at 1790000000.0}

Responses API

Request maps support :model, :input, :instructions, :max-output-tokens, :max-tool-calls, :temperature, :top-p, :top-logprobs, :metadata, :previous-response-id, :store, :user, :reasoning, :tools, :tool-choice, :parallel-tool-calls, :background, :include, :truncation, :prompt-cache-key, :safety-identifier, :service-tier, :json-schema, :verbosity (:low/:medium/:high), :conversation (a conversation id string), :stream-options ({:include-obfuscation true}), and :moderation ({:model "..."}).

Input can be a string or a vector of message items. Message content can be a string or a vector of multimodal parts:

{:model "gpt-5.2"
 :input [{:role :user
          :content [{:type :text :text "Summarize this image."}
                    {:type :image
                     :image-url "https://example.test/chart.png"
                     :detail :high}
                    {:type :file
                     :filename "notes.pdf"
                     :file-data "data:application/pdf;base64,..."}]}]}

Structured outputs use :json-schema:

(def request
  {:model "gpt-5.2"
   :input "Return an answer object."
   :json-schema {:name "answer"
                 :description "One answer"
                 :strict true
                 :schema {:type "object"
                          :properties {:answer {:type "string"}}
                          :required ["answer"]}}})

Parse and validate the returned JSON against the same schema:

(def response (openai/create-response client request))
(openai/parse-structured-output response (:json-schema request))
;; => {:data {"answer" "..."} :errors []}

Responses tools cover :function, :web-search, :file-search, :code-interpreter, :programmatic-tool-calling, :image-generation, :computer, :local-shell, :shell, :apply-patch, :custom, :tool-search, and :mcp. Vector input accepts the matching :function-call-output, :computer-call-output, :local-shell-call-output, :shell-call-output, :apply-patch-call-output, :custom-tool-call-output, :tool-search-output, and :mcp-approval-response items.

Response maps preserve all SDK output-item variants as kebab-case Clojure maps. openai/stream normalizes every Responses streaming event and calls its callback with the resulting :type-keyed map; openai/stream-text is the text-delta convenience wrapper.

Realtime API

openai.realtime provides normalized WebSocket events through callbacks or a blocking queue:

(require '[openai.realtime :as realtime])

(def connection
  (realtime/connect {:api-key (System/getenv "OPENAI_API_KEY")
                     :model "gpt-realtime"}))

(realtime/send! connection
                {:type :session.update
                 :session {:type :realtime
                           :instructions "Be concise."}})
(realtime/poll! connection 5000) ; normalized server event, or nil
(realtime/close! connection)

The namespace also exposes client-secret creation, legacy session and transcription-session creation, translation client secrets and WebSockets, and SIP accept-call, hangup-call, refer-call, and reject-call operations.

Chat Completions

Prefer the Responses API for new OpenAI work. Chat Completions is exposed as the compatibility path for OpenAI-compatible endpoints that do not support Responses, including local LLMs and hosted compat providers.

(openai/create-chat-completion
 client
 {:model "gpt-4o-mini"
  :messages [{:role :system :content "Be terse."}
             {:role :user :content "Write one sentence about Clojure maps."}]})
;; => {:id "chatcmpl_..."
;;     :model "gpt-4o-mini"
;;     :created 1790000000
;;     :choices [{:index 0
;;                :finish-reason :stop
;;                :message {:role :assistant
;;                          :content "Clojure maps are ..."}}]
;;     :text "Clojure maps are ..."
;;     :usage {:prompt-tokens 14 :completion-tokens 12 :total-tokens 26}}

Function tools use the same JSON-schema-shaped :parameters maps as Responses:

(openai/create-chat-completion
 client
 {:model "gpt-4o-mini"
  :messages [{:role :user :content "Weather in Denver?"}]
  :tools [{:type :function
           :name "get_weather"
           :description "Get current weather"
           :strict true
           :parameters {:type "object"
                        :properties {:location {:type "string"}}
                        :required ["location"]}}]
  :tool-choice {:type :function :name "get_weather"}})

Streaming returns the concatenated content and calls the callback for each normalized chunk:

(openai/stream-chat-completion-text
 client
 {:model "gpt-4o-mini"
  :messages [{:role :user :content "Count to three."}]
  :stream-options {:include-usage true}}
 println)

API namespaces

Service functions take an openai.core/client as their first argument and accept kebab-case request maps. Realtime WebSockets take a transport config map.

(require '[openai.images :as images]
         '[openai.audio :as audio]
         '[openai.moderations :as moderations]
         '[openai.completions :as completions]
         '[openai.vector-stores :as vector-stores]
         '[openai.uploads :as uploads]
         '[openai.containers :as containers]
         '[openai.conversations :as conversations]
         '[openai.fine-tuning :as fine-tuning]
         '[openai.evals :as evals]
         '[openai.skills :as skills]
         '[openai.videos :as videos]
         '[openai.realtime :as realtime]
         '[openai.webhooks :as webhooks]
         '[openai.admin :as admin]
         '[openai.admin.projects :as admin-projects])

(images/generate client {:model "gpt-image-1" :prompt "A Clojure logo"})
(audio/create-speech client {:model "gpt-4o-mini-tts" :voice :alloy
                             :input "Hello"})
(moderations/create client {:input "text"})
(completions/create client {:model "gpt-3.5-turbo-instruct" :prompt "Once"})
(vector-stores/create client {:name "docs" :file-ids ["file_..."]})
(uploads/create client {:filename "data.jsonl" :bytes 100
                        :mime-type "application/jsonl" :purpose :fine-tune})
(containers/create client {:name "sandbox"})
(conversations/create client {:items [{:role :user :content "Hello"}]})
(fine-tuning/create-job client {:model "gpt-4.1-mini"
                                :training-file "file_..."})
(evals/list client {:limit 20})
(skills/list client {:limit 20})
(videos/create client {:model "sora-2" :prompt "Ocean sunrise"
                       :size "1280x720" :seconds "8"})
(webhooks/unwrap webhook-client raw-body request-headers)
(admin/project-list admin-client {:limit 20})
(admin-projects/service-account-list admin-client "proj_...")

openai.core also contains Responses, Chat Completions, embeddings, files, batches, models, and stored Chat Completions. openai.realtime contains WebSocket, session, client-secret, transcription, translation, and SIP call helpers. openai.graders reflects the stable grader-model service, which exposes no operations in SDK 4.42.0.

Out of scope: other beta APIs, async clients, raw-response accessors, and per-call RequestOptions.

Running tests

clojure -M:test

Unit tests are no-network; ^:integration tests, if added later, should be skipped without OPENAI_API_KEY.

License

Copyright © 2026 Savyasachi.

Distributed under the Eclipse Public License 2.0.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close