Redouble AI Nucleo documentation
Part 13 · Inside the runtime

Inside decision calls and the decision thinker

ai.redouble.nucleo.tools.deciding · nucleo-core

This page is for people working on the runtime itself. What a decision model is, when to use one, and how to write a decision call or a decision thinker are in the guide; this page holds the classes, the exact shape of a thinker's turn, and the contract the tests pin. The vocabulary of a decision (the questions and the answers) is harness.decision, the client family is harness.llm.DecisionClient, and the catalog and admission side is harness.models; this package holds the jobs that put the model to work.

What is here

ClassRole
DecisionCallOne decision as a job: a DecisionRequest in, a DecisionResponse out. Declares the decision seat, so it goes through the whole door: resolution to the deployment's decision model (ModelPicker.decisionSpec, the decision pin), pricing of the request text against the entry's context ceiling, admission on the entry's account, the spend gates. Its requirements are read-only, since a decision reads and writes nothing of the deployment's. Holds the decision client for one round trip. Not a palette tool: it carries no tool name, so no thinker's model can call it; a chat model asking a decision model is a design a caller makes deliberately, by wrapping this in a named tool with a schema it authored. pinModel(spec) names the exact entry; the timeout is DEFAULT_TIMEOUT, one minute, a hung endpoint's worth.
DecisionThinker<I, O>An agent whose model is a decision model: an orchestrator over a palette of DecisionTools, with an objective in words. Every turn the model ranks the legal moves; code runs the winner; the answer is a ListArtifact of the artifacts the model selects when it finishes. Abstract: a subclass names the output type, the key tool, the rest of the palette and the objective in its constructor. paletteNames() is the palette by tool name, in the order the model is offered it.
DecisionTool<I, O>The type of every tool a decision thinker may hold: an AbstractTool whose input and output are both artifacts. Everything around a decision model is an artifact, and this type is where that rule lives.
DecisionTurnThe record of one turn: the distribution over the moves offered, the tool chosen, the distribution over its candidate artifacts, the artifact it ran on, what it produced or how it failed, and the selection probability of every artifact of the output type (an unmodifiable map in the order asked, empty and never null on a turn that put nothing to the model). FINISH is the name of the move that ends a run; finished() says whether the turn did.

One turn of the thinker

The registry is the world (harness.artifacts.ArtifactRegistry, the input artifact its first entry), and a move is a tool applied to an artifact in it whose type the tool takes, or finish. Code lists the legal moves from the types, every turn:

One round trip per turn carries every question at once, independent of one another, since the model's output is free and the state is paid once: a Choice over the offered tools plus finish (question id next), a Choice per offered tool over its candidate artifacts (id <tool>_input, read only for the winner), and a Noul per artifact of the output type, "does this belong in the answer" (id select_<ref key>, read only on a finish). The state the model reads is the objective, one digest line per artifact (ref (alias): words, the words cut at DIGEST_CHARS, 160 characters, with an ellipsis), and the moves made so far with their outcomes (nothing yet before the first). The words are a list's count and iterand type, else what the type's formatter in TextFormatterRegistry says, on one line (an application registers one per artifact type it puts before a decision model: the digest is all the model sees of an artifact, so the formatter is where the application decides what a file, a document or a statement reads as), else a link's title, else the artifact's summarized JSON.

The contract

^