Conversations
Conversations are immutable data structures that maintain chat history. Each operation returns a new conversation value — the original is never modified. This means you always re-bind the result:
(define conv (conversation/new {:model "claude-haiku-4-5-20251001"}))
(define conv (conversation/set-system conv "You are a concise tutor."))
(define conv (conversation/say conv "Explain closures in 2 bullets."))
(println (conversation/last-reply conv))
;; Branch to explore a different direction
(define alt (conversation/fork conv))
(define alt (conversation/say alt "Now explain with JavaScript examples."))
;; conv is unchanged — alt is an independent conversationCreating Conversations
conversation/new
Create a new conversation, optionally with a model. (conversation/new) is equivalent to (conversation/new {}).
(define conv (conversation/new {:model "claude-haiku-4-5-20251001"}))
(define conv (conversation/new))Interacting
conversation/say
Send a user message to the LLM and get a response. Returns a new conversation with both the user message and the assistant's reply appended.
(define conv (conversation/new {:model "claude-haiku-4-5-20251001"}))
(define conv (conversation/say conv "Remember: the secret number is 7"))
(define conv (conversation/say conv "What is the secret number?"))
(conversation/last-reply conv) ; => "The secret number is 7."With options:
(define conv (conversation/say conv "Explain more"
{:temperature 0.5 :max-tokens 500}))conversation/add-message
Manually add a message without making an LLM call. Useful for constructing conversation history programmatically.
(define c (conversation/new))
(define c (conversation/add-message c :system "You are helpful."))
(define c (conversation/add-message c :user "hello"))
(define c (conversation/add-message c :assistant "hi there"))conversation/say-as
Send a message with a different system prompt for one turn only. The override applies to the API call but doesn't change the conversation's stored system message. Accepts a system string or a prompt value.
;; With a prompt value — uses its system message for this turn
(define argue-for (prompt (system "You argue IN FAVOR of Lisp.")))
(define conv (conversation/new {:model "claude-sonnet-4-20250514"}))
(define conv (conversation/say-as conv argue-for "Make your case."))
;; With a plain string — treated as system content
(define conv (conversation/say-as conv "You argue AGAINST Lisp." "Rebut the argument."))Inspecting
conversation/last-reply
Get the content of the last assistant message.
(conversation/last-reply conv) ; => "The secret number is 7."conversation/messages
Get the full list of messages as message values.
(conversation/messages conv) ; => list of message values
(length (conversation/messages conv)) ; => 5conversation/model
Get the model associated with the conversation.
(conversation/model conv) ; => "claude-haiku-4-5-20251001"System Message
conversation/system
Get the system message content, or nil if none is set.
(define c (conversation/add-message (conversation/new) :system "Be helpful."))
(conversation/system c) ; => "Be helpful."
(conversation/system (conversation/new)) ; => nilconversation/set-system
Set or replace the system message. All existing system messages are replaced with one new one; other messages are preserved.
(define c (conversation/set-system (conversation/new) "You are a code reviewer."))
(conversation/system c) ; => "You are a code reviewer."Filtering & Transforming
conversation/filter
Keep only messages matching a predicate. Returns a new conversation.
;; Keep only user messages
(define user-only
(conversation/filter conv (fn (m) (= (message/role m) :user))))
;; Remove system messages
(define no-system
(conversation/filter conv (fn (m) (not (= (message/role m) :system)))))conversation/map
Apply a function to each message, returning a list of results (not a conversation).
;; Extract all message contents
(conversation/map conv message/content)
;; Build a summary with role prefixes
(conversation/map conv
(fn (m) (string/append "[" (keyword/to-string (message/role m)) "] "
(message/content m))))Usage & Cost
conversation/token-count
Estimated token count for the conversation (heuristic: ~4 characters per token).
(conversation/token-count conv) ; => 342conversation/cost
Estimated input cost in dollars based on the conversation's model pricing. Returns nil if pricing is unavailable for the model.
(conversation/cost conv) ; => 0.00034 (or nil)Branching
conversation/fork
Create an independent copy of a conversation. Since conversations are immutable, forking lets you explore different directions from the same point.
(define conv (conversation/new {:model "claude-haiku-4-5-20251001"}))
(define conv (conversation/say conv "Remember the number 7"))
;; Fork and take two different paths
(define branch-a (conversation/say (conversation/fork conv) "What about Python?"))
(define branch-b (conversation/say (conversation/fork conv) "What about Rust?"))
;; conv, branch-a, branch-b are all independentType Predicate
conversation?
Check if a value is a conversation.
(conversation? conv) ; => #t
(conversation? 42) ; => #f