Liking cljdoc? Tell your friends :D

jj.bettong.agent

The agent loop: prompt in, tool calls executed, final answer out.

The agent starts with no abilities at all. What it can do is exactly what you pass in :capabilities - see jj.bettong.capability.

(require '[jj.bettong.agent :as agent] '[jj.bettong.capabilities :as caps])

(def assistant (agent/deepseek {:capabilities [(caps/filesystem)]})) (agent/run assistant "Create file /tmp/foo.txt with content 'foo'")

The agent loop: prompt in, tool calls executed, final answer out.

The agent starts with no abilities at all. What it can do is exactly what you
pass in :capabilities - see `jj.bettong.capability`.

  (require '[jj.bettong.agent :as agent]
           '[jj.bettong.capabilities :as caps])

  (def assistant (agent/deepseek {:capabilities [(caps/filesystem)]}))
  (agent/run assistant "Create file /tmp/foo.txt with content 'foo'")
raw docstring

jj.bettong.capabilities

Every capability that ships with bettong, in one place to require.

Each also lives in its own namespace - jj.bettong.capability.filesystem, jj.bettong.capability.wikipedia and so on - if you would rather name them individually. None of them is on unless you pass it to an agent.

The search sources are separate capabilities with separate tool names, so an agent can hold several at once and pick between them.

Every capability that ships with bettong, in one place to require.

Each also lives in its own namespace - `jj.bettong.capability.filesystem`,
`jj.bettong.capability.wikipedia` and so on - if you would rather name them
individually. None of them is on unless you pass it to an agent.

The search sources are separate capabilities with separate tool names, so an
agent can hold several at once and pick between them.
raw docstring

jj.bettong.capability

The capability protocol.

An agent can do nothing on its own. Everything it can do - touch the filesystem, run a command, call your API - comes from a capability you hand to jj.bettong.agent/run explicitly. No capability, no tool, no way in.

A capability is anything satisfying Capability. A plain map already does:

{:id :weather :instructions "Temperatures are in celsius." :tools [{:name "get_weather" :description "Current weather for a city." :parameters {:city {:type "string" :description "City name." :required true}} :handler (fn [{:keys [city]}] (str "It is raining in " city))}]}

so does a defrecord or a reify, when you need state or a lifecycle.

The capability protocol.

An agent can do nothing on its own. Everything it can do - touch the
filesystem, run a command, call your API - comes from a capability you hand
to `jj.bettong.agent/run` explicitly. No capability, no tool, no way in.

A capability is anything satisfying `Capability`. A plain map already does:

  {:id :weather
   :instructions "Temperatures are in celsius."
   :tools [{:name "get_weather"
            :description "Current weather for a city."
            :parameters {:city {:type "string" :description "City name." :required true}}
            :handler (fn [{:keys [city]}] (str "It is raining in " city))}]}

so does a defrecord or a reify, when you need state or a lifecycle.
raw docstring

jj.bettong.capability.brave

Searching through brave.

Searching through brave.
raw docstring

jj.bettong.capability.duckduckgo

Searching through duckduckgo.

Searching through duckduckgo.
raw docstring

jj.bettong.capability.edn

Reading and changing values inside EDN files.

Reading and changing values inside EDN files.
raw docstring

jj.bettong.capability.filesystem

Reading files, and writing them only when asked.

Reading files, and writing them only when asked.
raw docstring

jj.bettong.capability.google

Searching through google.

Searching through google.
raw docstring

jj.bettong.capability.search

Turning a search backend into a capability.

Each search source ships as its own capability with its own tool name, so an agent can be given several at once and choose between them by name - wikipedia_search for an encyclopaedic fact, duckduckgo_search for the open web. One capability per source is also what lets the model see, in the tool descriptions, what each one actually covers.

Turning a search backend into a capability.

Each search source ships as its own capability with its own tool name, so an
agent can be given several at once and choose between them by name -
`wikipedia_search` for an encyclopaedic fact, `duckduckgo_search` for the open
web. One capability per source is also what lets the model see, in the tool
descriptions, what each one actually covers.
raw docstring

jj.bettong.capability.serper

Searching through serper.

Searching through serper.
raw docstring

jj.bettong.capability.shell

Running shell commands.

Running shell commands.
raw docstring

jj.bettong.capability.tavily

Searching through tavily.

Searching through tavily.
raw docstring

jj.bettong.capability.wikipedia

Searching through wikipedia.

Searching through wikipedia.
raw docstring

jj.bettong.cli

CLI entry point. Grants a writable filesystem and a shell - the explicit opt-in a program has to make, since reading is all a capability gives by default: lein run "Create file /tmp/foo.txt with content 'foo'"

CLI entry point. Grants a writable filesystem and a shell - the explicit
opt-in a program has to make, since reading is all a capability gives by default:
  lein run "Create file /tmp/foo.txt with content 'foo'"
raw docstring

jj.bettong.edn

Reading and updating values inside EDN files.

Edits are spliced into the file's text, so comments, key order and hand formatting survive - see jj.bettong.impl.edn-text. Pass {:preserve-formatting? false} to rewrite the file from its data instead, which is pretty-printed and loses comments.

Reading and updating values inside EDN files.

Edits are spliced into the file's text, so comments, key order and hand
formatting survive - see `jj.bettong.impl.edn-text`. Pass
{:preserve-formatting? false} to rewrite the file from its data instead,
which is pretty-printed and loses comments.
raw docstring

jj.bettong.impl.edn-text

Editing EDN through a syntax tree that keeps everything a reader throws away.

clojure.edn/read-string gives you data, and data has no comments, no key order and no indentation - so no writer can put them back. The tree here keeps whitespace, comments and #_ discards as nodes of their own, which makes rendering it the exact original text and an edit a change to one node.

Nodes are plain maps:

{:type :whitespace :text " \n\n"} {:type :comment :text ";; why this is 3000"} {:type :token :text "8080"} {:type :map :open "{" :close "}" :children [...]} {:type :wrapper :text "#inst" :children [...]} ; #_ ^meta 'quote #tag

parse and render are inverses: (= s (render (parse s))) for any EDN.

Editing EDN through a syntax tree that keeps everything a reader throws away.

`clojure.edn/read-string` gives you data, and data has no comments, no key
order and no indentation - so no writer can put them back. The tree here
keeps whitespace, comments and `#_` discards as nodes of their own, which
makes rendering it the exact original text and an edit a change to one node.

Nodes are plain maps:

  {:type :whitespace :text " \n\n"}
  {:type :comment    :text ";; why this is 3000"}
  {:type :token      :text "8080"}
  {:type :map        :open "{" :close "}" :children [...]}
  {:type :wrapper    :text "#inst" :children [...]}   ; #_ ^meta 'quote #tag

`parse` and `render` are inverses: (= s (render (parse s))) for any EDN.
raw docstring

jj.bettong.impl.files

Path resolution and the file operations behind the filesystem capability. Every path goes through resolve-path, which is where confinement to a root and the refusal to touch credential files live.

Path resolution and the file operations behind the filesystem capability.
Every path goes through `resolve-path`, which is where confinement to a root
and the refusal to touch credential files live.
raw docstring

jj.bettong.impl.json

The one place JSON lives, so the parser behind it is a single-file change.

clojure.data.json is chosen for its dependency profile rather than its speed: it is pure Clojure and pulls nothing else in, which matters more in a library other applications embed than raw throughput does on payloads this size. The JDK's own JSON API (JEP 540) lands in jdk.incubator.json in JDK 28 and would slot in here.

The one place JSON lives, so the parser behind it is a single-file change.

`clojure.data.json` is chosen for its dependency profile rather than its
speed: it is pure Clojure and pulls nothing else in, which matters more in a
library other applications embed than raw throughput does on payloads this
size. The JDK's own JSON API (JEP 540) lands in jdk.incubator.json in JDK 28
and would slot in here.
raw docstring

jj.bettong.impl.options

Option checks shared by the capabilities.

Option checks shared by the capabilities.
raw docstring

jj.bettong.impl.shell

Running commands behind the shell capability: the command policy, the process itself, and the truncation that keeps its output from swallowing the transcript.

Running commands behind the shell capability: the command policy, the
process itself, and the truncation that keeps its output from swallowing
the transcript.
raw docstring

jj.bettong.llm

Thin client for the DeepSeek chat-completions API (OpenAI-compatible).

Thin client for the DeepSeek chat-completions API (OpenAI-compatible).
raw docstring

jj.bettong.search

Search backends: the functions the search capabilities are built on.

A backend is just (fn [{:keys [query max-results]}] -> [{:title :url :snippet}]), so anything can be one: a public search API, your own index, an internal wiki. The named ones below are conveniences.

Search backends: the functions the search capabilities are built on.

A backend is just (fn [{:keys [query max-results]}] -> [{:title :url :snippet}]),
so anything can be one: a public search API, your own index, an internal wiki.
The named ones below are conveniences.
raw docstring

jj.bettong.secrets

Keeping credentials out of transcripts.

Anything a tool returns is sent to the model provider, so a command like echo $API_KEY does not just print a secret - it uploads one. Two defences here, both on by default: the child process never sees credentials in its environment, and whatever a tool does return is scrubbed of their values on the way back.

Keeping credentials out of transcripts.

Anything a tool returns is sent to the model provider, so a command like
`echo $API_KEY` does not just print a secret - it uploads one. Two defences
here, both on by default: the child process never sees credentials in its
environment, and whatever a tool does return is scrubbed of their values on
the way back.
raw docstring

jj.bettong.usage

Token accounting. Every model response carries a usage block; the agent adds them up across the run so you can see what a task cost.

Token accounting. Every model response carries a usage block; the agent adds
them up across the run so you can see what a task cost.
raw docstring

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