agents.runtime/statuses / agents.runtime/limits
Clojure (JVM) + cljgo · package net.clojars.muthuishere/toolnexus · SPEC §7D · clojure/src/toolnexus/agents/runtime.cljc
;; the §7D TaskResult status vocabulary — SEVEN valuestoolnexus.agents.runtime/statuses;; => #{"done" "pending" "incomplete" "interrupted" "closed" "timeout" "error"}
;; the §7D TaskResult.limit vocabulary — NINE values, WHICH limit stopped the tasktoolnexus.agents.runtime/limits;; => #{"maxTurns" "maxTokens" "maxToolCalls" "maxWallMs";; "maxChildren" "maxConcurrent" "maxDepth" "completion" "timeout"}
;; the named values, so a caller never types the string literaltoolnexus.agents.runtime/limit-max-turns ; "maxTurns"toolnexus.agents.runtime/limit-max-tokens ; "maxTokens"toolnexus.agents.runtime/limit-max-tool-calls ; "maxToolCalls"toolnexus.agents.runtime/limit-max-wall-ms ; "maxWallMs"toolnexus.agents.runtime/limit-max-children ; "maxChildren"toolnexus.agents.runtime/limit-max-concurrent ; "maxConcurrent"toolnexus.agents.runtime/limit-max-depth ; "maxDepth"toolnexus.agents.runtime/limit-completion ; "completion"toolnexus.agents.runtime/limit-timeout ; "timeout"
;; a SEPARATE, smaller §8 client-level vocabulary — do not confuse the twotoolnexus.client/statuses ; => #{"done" "pending" "incomplete"} — never "timeout"toolnexus.client/limits ; => #{"maxTurns" "contentPart" "timeout"}The canonical, byte-identical-across-ports string constants a host branches on: task statuses, run
statuses, and the nine stop-limit reasons a task can end on. These are the closed vocabularies a
toolnexus.agents.runtime TaskResult — the value spawn, wait
and close hand back — reports on its :status and (when the status is a limit stop) its
:limit fields.
When to use it
Section titled “When to use it”- Branching on a
TaskResult’s:statusreturned byspawn/wait/interrupt/closeontoolnexus.agents.runtime— check membership instatusesrather than hardcoding the string, so a host fails loudly if it ever meets an eighth value instead of silently falling through acase. When the status is"incomplete"or"timeout", the same result carries a:limitnaming which budget stopped it — check that againstlimits. - Building a dashboard or a log line that needs to render every possible outcome a spawned agent can reach, exhaustively, without guessing at undocumented strings.
- Writing a completion/guardrail check in
toolnexus.agents.loopthat inspects:limitto decide whether a stop is retryable (e.g."maxTurns"might be worth bumping and re-running;"maxDepth"is a structural ceiling, not a transient one).
Why this and not the alternative
Section titled “Why this and not the alternative”The vocabularies are plain #{} sets and named defs rather than an enum type or a keyword
namespace, matching this port’s general style of carrying closed vocabularies as data
(clojure/src/toolnexus/agents/runtime.cljc:142, :174) — a host checks membership with
contains? the same way it would check .contains() on any other port’s array/list constant, with
no additional API to learn.
Examples
Section titled “Examples”1. The smallest useful call — check a spawned task’s outcome
Section titled “1. The smallest useful call — check a spawned task’s outcome”(require '[toolnexus.agents.runtime :as rt] '[koine.json :as json])
(println)
(defn- text-response [t] {:choices [{:message {:role "assistant" :content t}}] :usage {:prompt_tokens 10 :completion_tokens 5 :total_tokens 15}})
(def runtime (rt/create-runtime {:registry {"w" {:name "w" :does "writes" :model "wm"}} :llm {:base-url "http://mock.local" :model "default"} :http-client (fn [_url _headers _body] {:status 200 :headers {} :body (json/write-str (text-response "done writing"))})}))
(def h (rt/spawn runtime rt/root "w"))(rt/wake runtime h "go")(let [r (rt/wait runtime h)] (assert (contains? rt/statuses (:status r)) "unrecognised task status") (case (:status r) "done" (println (:text r)) "pending" (println "parked, waiting on" (:pending r)) "incomplete" (println "stopped on limit:" (:limit r)) (println "ended:" (:status r))))(println "OK")2. The realistic case — react to WHICH limit stopped the task
Section titled “2. The realistic case — react to WHICH limit stopped the task”(require '[toolnexus.agents.runtime :as rt] '[koine.json :as json])
(println)
(defn- text-response [t] {:choices [{:message {:role "assistant" :content t}}] :usage {:prompt_tokens 10 :completion_tokens 5 :total_tokens 15}})
(defn handle-stop [r] (when (= "incomplete" (:status r)) (assert (contains? rt/limits (:limit r)) "unrecognised limit reason") (cond (= rt/limit-max-turns (:limit r)) (println "hit the turn budget — consider raising it and re-running")
(= rt/limit-max-depth (:limit r)) (println "hit the delegation depth ceiling — this is structural, don't retry blindly")
(= rt/limit-max-wall-ms (:limit r)) (println "ran out of wall-clock time")
:else (println "stopped on" (:limit r)))))
(def runtime (rt/create-runtime {:registry {"w" {:name "w" :does "writes" :model "wm" :budget {:max-turns 1}}} :llm {:base-url "http://mock.local" :model "default"} :http-client (fn [_url _headers _body] {:status 200 :headers {} :body (json/write-str (text-response "ok"))})}))
(def h (rt/spawn runtime rt/root "w"))(rt/wake runtime h "first")(rt/wait runtime h)(rt/wake runtime h "second") ; exceeds the one-turn budget(def r (rt/wait runtime h))
(assert (= "incomplete" (:status r)))(assert (= rt/limit-max-turns (:limit r)))(handle-stop r)(println "OK")3. The full surface — distinguishing the two vocabularies side by side
Section titled “3. The full surface — distinguishing the two vocabularies side by side”(require '[toolnexus.agents.runtime :as rt] '[toolnexus.client :as client])
(println)
;; the §7D task-level set (seven statuses, nine limits)(assert (= #{"done" "pending" "incomplete" "interrupted" "closed" "timeout" "error"} rt/statuses))(assert (= #{"maxTurns" "maxTokens" "maxToolCalls" "maxWallMs" "maxChildren" "maxConcurrent" "maxDepth" "completion" "timeout"} rt/limits))
;; the §8 client-level set — smaller, and NEVER contains "timeout" as a status(assert (= #{"done" "pending" "incomplete"} client/statuses))(assert (= #{"maxTurns" "contentPart" "timeout"} client/limits))(assert (not (contains? client/statuses "timeout")))
;; a host that gets this wrong learns immediately rather than silently;; mis-branching: membership checks against the WRONG set simply never match(assert (not (contains? client/limits "maxDepth")) "maxDepth is a task-level admission limit; the client run never reports it")(println "OK")See also
Section titled “See also”toolnexus.agents.loop—run-gateddrives a run under a completion check and reads these same status/limit strings to decide whether the gate has passed.toolnexus.agents.runtime— The host verbs (spawn,wait,interrupt,close) whoseTaskResultcarries:statusand, on a limit stop,:limit.