Answer.output
Java · package io.github.muthuishere:toolnexus · SPEC §10 · Answer.java
public static Answer output(String id, String output)Wraps a human’s typed string reply into the Answer a suspended run resumes with — the success
counterpart to Answer.declined. output builds
new Answer(id, true, Map.of(Answer.OUTPUT_KEY, output), null) — ok:true, and the payload lives
under the ONE data key ("output") the loop actually reads back out (Answer.outputOf()). A
null output throws IllegalArgumentException rather than letting an ok:true answer carry no
determinable result — an answer that claims success but hands the loop nothing to resume with
would otherwise fabricate a tool result for the model.
When to use it
Section titled “When to use it”Any time a host’s waitFor (or a durable resume path) has a real string result for the
Request a tool parked — a human typed an answer, an approval
was granted with no extra data, an upload finished and its path is the result. Build the Answer
with Answer.output(request.id(), theResult) and hand it back from waitFor, or pass it to
whatever the host’s durable-resume path calls to settle a parked Request by id.
Why this and not the alternative
Section titled “Why this and not the alternative”Examples
Section titled “Examples”1. The smallest useful call — build the Answer for a resolved Request
Section titled “1. The smallest useful call — build the Answer for a resolved Request”import io.github.muthuishere.toolnexus.Answer;
public class Example { public static void main(String[] args) { Answer answer = Answer.output("req-1", "blue");
if (!answer.ok()) throw new AssertionError("output() must be ok:true"); if (!"blue".equals(answer.outputOf())) throw new AssertionError(answer.outputOf()); if (answer.reason() != null) throw new AssertionError("no reason on a success");
System.out.println("ok: " + answer.id() + " -> " + answer.outputOf()); }}2. The realistic case — a waitFor that resolves a pending Request with a human’s typed reply
Section titled “2. The realistic case — a waitFor that resolves a pending Request with a human’s typed reply”import io.github.muthuishere.toolnexus.*;import java.util.Scanner;
public class Example { /** Stands in for a real prompt/durable-queue lookup keyed by request.id(). */ static String humanReplyFor(Request request) { return "staging"; // pretend a human typed this in response to request.prompt() }
public static void main(String[] args) { Request request = new Request("", "input", "Which environment?");
// This is the shape a real client.Options.waitFor(...) callback returns. Answer resolved = Answer.output(request.id(), humanReplyFor(request));
if (!resolved.ok()) throw new AssertionError(resolved); if (!resolved.id().equals(request.id())) throw new AssertionError("id must echo the Request's"); System.out.println("ok: resumed with " + resolved.outputOf()); }}3. The full surface — a null output is refused, never a fabricated success
Section titled “3. The full surface — a null output is refused, never a fabricated success”import io.github.muthuishere.toolnexus.Answer;
public class Example { public static void main(String[] args) { try { Answer.output("req-1", null); throw new AssertionError("expected a rejection"); } catch (IllegalArgumentException e) { if (!e.getMessage().contains("requires a result")) throw new AssertionError(e.getMessage()); }
// The RECOGNISED data keys, in precedence order — `results` (multi-call relay) before // `output` (single value). hasRecognisedKey() is how a host tells "a real answer" from // "ok:true with nothing determinable" before treating it as a tool result. Answer a = Answer.output("req-1", "ok"); if (!a.hasRecognisedKey()) throw new AssertionError("output() must set a recognised key"); if (!Answer.RECOGNISED_KEYS.get(1).equals(Answer.OUTPUT_KEY)) { throw new AssertionError(Answer.RECOGNISED_KEYS); }
System.out.println("ok: null is rejected, output() sets a recognised key"); }}See also
Section titled “See also”Request.pending— Return a Pending from a tool to park the run until someone answers.Answer.declined— The refusal counterpart: wrap a human’s “no” into an Answer.Request.authRequired— The auth-shaped suspension: hand back a URL, resume once the user has granted access.LlmClient.waitFor— The single hook where the host resolves a suspension — in-process prompt or durable queue, same contract.Request.pendingOf— Detect that a RunResult is parked rather than finished, and get the Request that parked it.