TaskResult.STATUSES / TaskResult.LIMITS / TaskResult.canonicalLimit
Java · package io.github.muthuishere:toolnexus · SPEC §7D · TaskResult.java
// TaskResult (agents package) — the §7D AGENT-RUNTIME status vocabulary, SEVEN valuespublic static final String STATUS_DONE = "done";public static final String STATUS_PENDING = "pending";public static final String STATUS_INCOMPLETE = "incomplete";public static final String STATUS_INTERRUPTED = "interrupted";public static final String STATUS_CLOSED = "closed";public static final String STATUS_TIMEOUT = "timeout";public static final String STATUS_ERROR = "error";public static final List<String> STATUSES; // the 7, in SPEC §7D order
// the CLOSED `limit` vocabulary — NINE values, identical in all seven portspublic static final String LIMIT_MAX_TURNS = "maxTurns";public static final String LIMIT_MAX_TOKENS = "maxTokens";public static final String LIMIT_MAX_TOOL_CALLS = "maxToolCalls";public static final String LIMIT_MAX_WALL_MS = "maxWallMs";public static final String LIMIT_MAX_CHILDREN = "maxChildren";public static final String LIMIT_MAX_CONCURRENT = "maxConcurrent";public static final String LIMIT_MAX_DEPTH = "maxDepth";public static final String LIMIT_COMPLETION = "completion";public static final String LIMIT_TIMEOUT = "timeout";public static final List<String> LIMITS; // the 9, in the order above
static String canonicalLimit(String internal); // package-private — maps an internal pool // name onto the canonical spelling aboveThe canonical, byte-identical-across-ports string constants a host branches on: TaskResult.STATUSES
is the closed seven-string §7D agent/task vocabulary (done, pending, incomplete, interrupted, closed, timeout, error), TaskResult.LIMITS is the closed nine-string stop-limit vocabulary a
task can end on, and canonicalLimit maps an internal pool/dimension name ("tokens", "wallMs",
…) onto the pinned spelling before it ever reaches a TaskResult.limit field. A TaskResult’s
compact constructor (TaskResult.java, the record body) enforces both rules structurally, on
every construction site: a limit-stop status (incomplete / timeout) gets its limit
canonicalised through this function, and every other status gets limit explicitly emptied — so a
done or pending result can never carry a stale limit that contradicts its own status (ADR 0025 /
A18 / A21).
When to use it
Section titled “When to use it”Reference TaskResult.STATUSES / TaskResult.LIMITS — instead of retyping the string literals —
anywhere a host validates or displays what a sub-agent run ended on: a dashboard rendering a task’s
final state, a switch/case over taskResult.status(), or an assertion in a test that wants to
fail loudly if a ninth limit or an eighth status is ever added without updating the doc. Use
canonicalLimit only if you are implementing a NEW driver over the §7D runtime that produces its
own internal limit names — ordinary callers never call it directly; it runs automatically inside
every TaskResult construction.
Why this and not the alternative
Section titled “Why this and not the alternative”Examples
Section titled “Examples”1. The smallest useful call — read the two closed vocabularies
Section titled “1. The smallest useful call — read the two closed vocabularies”import io.github.muthuishere.toolnexus.agents.TaskResult;
public class Example { public static void main(String[] args) { if (TaskResult.STATUSES.size() != 7) throw new AssertionError(TaskResult.STATUSES); if (!TaskResult.STATUSES.contains(TaskResult.STATUS_DONE)) throw new AssertionError("done missing"); if (!TaskResult.STATUSES.contains(TaskResult.STATUS_ERROR)) throw new AssertionError("error missing");
if (TaskResult.LIMITS.size() != 9) throw new AssertionError(TaskResult.LIMITS); if (!TaskResult.LIMITS.contains(TaskResult.LIMIT_MAX_TURNS)) throw new AssertionError("maxTurns missing"); if (!TaskResult.LIMITS.contains(TaskResult.LIMIT_TIMEOUT)) throw new AssertionError("timeout missing");
System.out.println("ok: " + TaskResult.STATUSES.size() + " statuses, " + TaskResult.LIMITS.size() + " limits"); }}2. The realistic case — a host validates a TaskResult against the vocabulary
Section titled “2. The realistic case — a host validates a TaskResult against the vocabulary”import io.github.muthuishere.toolnexus.Request;import io.github.muthuishere.toolnexus.agents.TaskResult;import java.util.List;
public class Example { static String describe(TaskResult r) { if (!TaskResult.STATUSES.contains(r.status())) { throw new IllegalStateException("unknown status: " + r.status()); } boolean limitStop = TaskResult.STATUS_INCOMPLETE.equals(r.status()) || TaskResult.STATUS_TIMEOUT.equals(r.status()); if (limitStop && !TaskResult.LIMITS.contains(r.limit())) { throw new IllegalStateException("unknown limit: " + r.limit()); } return r.status() + (r.limit() != null ? " (limit=" + r.limit() + ")" : ""); }
public static void main(String[] args) { TaskResult done = new TaskResult("finished", false, TaskResult.STATUS_DONE, null, List.of(), 3, 100); TaskResult stopped = new TaskResult("ran out of turns", false, TaskResult.STATUS_INCOMPLETE, null, List.of(), 10, 500, 500, "turns"); // "turns" is an internal name
if (!describe(done).equals("done")) throw new AssertionError(describe(done)); // canonicalLimit runs INSIDE the constructor: "turns" -> the canonical "maxTurns" if (!"maxTurns".equals(stopped.limit())) throw new AssertionError(stopped.limit()); if (!describe(stopped).equals("incomplete (limit=maxTurns)")) throw new AssertionError(describe(stopped));
System.out.println("ok: " + describe(done) + " / " + describe(stopped)); }}3. The full surface — the structural guarantee: status and limit can never contradict
Section titled “3. The full surface — the structural guarantee: status and limit can never contradict”import io.github.muthuishere.toolnexus.agents.TaskResult;import java.util.List;
public class Example { public static void main(String[] args) { // A `done` result is constructed WITH a limit anyway — the compact constructor empties // it, because a settled result contradicting itself is the bug this guarantee prevents. TaskResult done = new TaskResult("ok", false, TaskResult.STATUS_DONE, null, List.of(), 1, 10, 10, "maxTokens"); if (done.limit() != null) throw new AssertionError("done must never carry a limit: " + done.limit());
// A limit-stop status canonicalises an internal pool name automatically. TaskResult timedOut = new TaskResult("too slow", true, TaskResult.STATUS_TIMEOUT, null, List.of(), 5, 200, 200, "wallMs"); if (!"maxWallMs".equals(timedOut.limit())) throw new AssertionError(timedOut.limit());
// An already-canonical name passes through unchanged. TaskResult noTokens = new TaskResult("budget exhausted", true, TaskResult.STATUS_INCOMPLETE, null, List.of(), 5, 200, 200, TaskResult.LIMIT_MAX_TOKENS); if (!TaskResult.LIMIT_MAX_TOKENS.equals(noTokens.limit())) throw new AssertionError(noTokens.limit());
System.out.println("ok: done=" + done.limit() + ", timeout=" + timedOut.limit() + ", incomplete=" + noTokens.limit()); }}- The three §8 client-level run statuses (
done,pending,incomplete— notimeout) exist in Java only as inline literals; there is noRunStatuses/RUN_STATUSESconstant to import, unlike most of the other six ports. Spell them directly if you need them. Loop.Outcome.statusreuses these same shipped strings (done | incomplete | pending | error, per its doc comment atLoop.java:87) rather than minting a fourth vocabulary — seeLoop.
See also
Section titled “See also”Loop— The gated door beside the plain agent run;Loop.Outcome.statusreuses these same shipped strings.agents.Agent— Define a sub-agent with its own toolkit, prompt and budget, callable as a tool by its parent.agents.Runtime— The six host verbs that drive sub-agents, plus the read-only list and inspect views.agents.Handle— The state machine for one spawned agent: pending, running, suspended, done.agents.Budget— Cap tool calls and wall-clock per agent and per team, enforced while the run is in flight.