Agents and LLM calls builtins
19 builtins of Soma 3.2.4 in the category Agents and LLM calls, with their exact signatures, as soma describe --builtins --json prints them.
- think
- think_json
- horde
- vote
- horde_status
- horde_results
- horde_cancel
- delegate
- set_budget
- tokens_used
- tokens_remaining
- trace
- clear_trace
- clear_context
- approve
- resume
- deliver
- waiting
- cancel_wait
think
think(prompt: String, system?: String, opts?: {max_tokens, timeout, max_rounds, tools_allowed, requires}) -> StringCall the configured LLM with tool-calling, multi-turn context, and budget enforcement. A think() offers the model every tool of the cell's face, or only those named in map("tools_allowed", ["lookup"]) (a call to another is refused and told to the model); requires lists model capabilities checked by soma check. A timeout is not retried (429/5xx are, up to 3 times).
Used in verified programs:
- agents/budget_guard, line 33: let r = try { think("Summarize in one line: {text}") }
- agents/horde_audit, line 42: let note = think("Risk of: {d.text}", map("max_tokens", 60))
- agents/horde_rounds, line 47: let mood = think("The price is {world.price}. Buy?", map("max_tokens", 20))
- agents/memory_agent, line 42: let r = try { think("Answer using stored facts: {question}") }
think_json
think_json(prompt: String, system?: String, opts?: {as, max_tokens, timeout, max_rounds, tools_allowed, requires}) -> Map | the `cell type` named by `as`Like think(), but parses the response as JSON into a Map (tools are offered too: pass max_rounds 1 to keep the cost bound at one round). There is no schema option — check the fields yourself.
horde
horde(handler, inputs: List, opts?: {concurrency, max_attempts, budget_tokens, seed, snapshot, instance, on_result, apply, on_done, on_error}) -> StringRun handler (mark it [task]) once per input with a bounded pool of workers; returns the horde id (Cell:h1) at once. The queue is persisted with the program's data and resumes after a restart; each result is recorded — and on_result(result) / on_result(input, result) called — with the handler's last step, so once. budget_tokens: a hard ceiling (every think() reserves its bound first; state exhausted). on_error(input, error: {error, kind, detail}) after max_attempts (default 1); on_done(id) once at the end. Rounds: snapshot (handler takes (input, snapshot)), apply (in input order at the end), seed (reproducible random()), instance (per-agent memory). concurrency default 8, at most 1000. Without workers (soma test) it runs right after the caller commits.
Used in verified programs:
- agents/horde_audit, line 23: let h = horde(Reviewer.review, docs, map(
- agents/horde_rounds, line 25: return horde(Shopper.decide, people, map(
vote
vote(handler, input, k: Int) -> Mapk agents (1..25) answer the same input; {winner, count, k, unanimous, errors, votes}. The most common answer wins, ties to the earliest voter. In a [task] step under serve / run the k calls run at once outside the lock, else in turn; each voter starts a fresh model context; a voter that raises counts in errors (all raising: the first error). Voters' writes are theirs — keep them read-only.
horde_status
horde_status(id: String) -> Map{state: running | cancelling | exhausting | done | cancelled | exhausted, total, queued, running, done, failed, cancelled, tokens, budget_tokens?} of a horde (its id names its cell).
Used in verified programs:
- agents/horde_audit, line 32: on progress() { return horde_status(batch.get("current") ?? "") }
horde_results
horde_results(id: String) -> ListThe results of a horde in input order; () for a task not done (failed, cancelled or still queued).
horde_cancel
horde_cancel(id: String) -> BoolStop a horde: no new task starts, running ones finish, on_done is called. false when it was not running.
delegate
delegate(cell: String, signal: String, args...) -> AnyInvoke another cell's handler and return its result.
Used in verified programs:
- agents/multi_agent_pipeline, line 47: let o = delegate("Outliner", "outline", topic)
set_budget
set_budget(max_tokens: Int) -> ()Hard cap on LLM tokens; think() fails once exhausted.
Used in verified programs:
- agents/approval_gate, line 35: set_budget(1500)
- agents/budget_guard, line 24: set_budget(cap)
- agents/memory_agent, line 39: set_budget(2000)
- agents/planner, line 38: set_budget(2000)
tokens_used
tokens_used() -> IntLLM tokens consumed since the budget was set.
Used in verified programs:
- agents/budget_guard, line 40: map("status", "done", "summary", r.value, "used", tokens_used())
- agents/verified_termination, line 43: map("status", "done", "task", task, "tokens", tokens_used())
tokens_remaining
tokens_remaining() -> IntTokens left in the budget, or -1 if unlimited.
Used in verified programs:
- agents/budget_guard, line 25: tokens_remaining()
trace
trace() -> ListStructured execution log: every think(), tool call, and approval.
Used in verified programs:
- agents/trace_audit, line 47: let log = trace()
clear_trace
clear_trace() -> ()Empty the agent trace log.
Used in verified programs:
- agents/trace_audit, line 29: clear_trace()
clear_context
clear_context() -> ()Reset the multi-turn LLM conversation history.
Used in verified programs:
- agents/turn_bounded_chat, line 31: clear_context()
approve
approve(action: String) -> BoolHuman-in-the-loop gate. Answered by mock approve true|false in tests, by SOMA_APPROVE=always|never, or by a person at the terminal under soma run; otherwise (e.g. under soma serve) it RAISES kind "approval_required" — it never approves on its own.
Used in verified programs:
- agents/approval_gate, line 40: let approved = approve("Deploy {version} to production?")
- services/refund_agent, line 94: if amount > 20000 && !approve("refund {amount} on {order_id}") {
resume
resume(wait_id: String, answer) -> AnyAnswer a stored wait (await approve(…) takes true/false) and run the rest of its handler; returns what the handler returns. Kind "not_waiting" when the id is not pending. Refused inside a tool.
deliver
deliver(name: String, key, value) -> AnyHand value to the handler stopped at await signal(name, key) and run the rest of it. Kind "not_waiting" when nothing waits for it.
waiting
waiting() -> List<Map>The stored waits, oldest first: {waiting, kind, message | name, key | until_ms, cell, handler, since_ms}.
cancel_wait
cancel_wait(wait_id: String) -> BoolDrop a stored wait without running the rest of its handler (what it wrote before the wait stays). Refused inside a tool.