Shadway
Guides

Guides / Wait for a result

Wait for a result

Sometimes you only need to know whether the work finished and what it found. This guide waits for a mandate to end, handles waits that outlast your process, and reads the result along with its evidence.

Wait for a terminal status

wait returns when the mandate reaches completed, failed, canceled, or expired, including work that already finished before you called it.

wait.ts
import { Shadway, ShadwayTimeoutError } from "shadway";

const shadway = new Shadway();
const work = shadway.mandate(mandateId);

try {
  const result = await work.wait({ timeout: "30m" });
  console.log(result.status, "-", result.currentState.summary);
} catch (error) {
  if (!(error instanceof ShadwayTimeoutError)) throw error;
  console.log("Still working. Reconnect later with mandate ID:", work.id);
}

A timeout ends only your local wait. The mandate keeps running on the server, and waiting again later, from the same process or a different one, picks it up wherever it is. With no timeout set, the wait runs until the mandate ends or you cancel the call.

Reconnect across restarts

Real work runs for days. Your process doesn't have to. The pattern is to store the mandate ID when you create the work, and reconnect by ID whenever you need the answer:

reconnect.ts
// In the request that starts the work:
const mandate = await shadway.mandates.create({ agent: agentId, objective });
await store.save({ jobId, mandateId: mandate.id });

// In a worker, any time later. Creating a handle starts nothing:
const { mandateId } = await store.load(jobId);
const result = await shadway.mandate(mandateId).wait({ timeout: "5m" });

If your process does more than wait, prefer short timeouts in a retry loop over one long blocking call. Each attempt is cheap, and checking often has no effect on the mandate.

Read the outcome

completed means every success criterion checked out against verified facts. For any other status, read what the work recorded to understand what happened.

outcome.ts
const result = await work.wait({ timeout: "30m" });

if (result.status === "completed") {
  for await (const fact of work.facts.list()) {
    console.log("fact:", fact.key, "=", fact.value, `(${fact.status})`);
  }
  for await (const evidence of work.evidence.list()) {
    console.log("evidence:", evidence.title, "-", evidence.excerpt);
  }
} else {
  console.log("Ended", result.status, "-", result.currentState.summary);
  for await (const issue of work.issues.list()) {
    console.log("open question:", issue.question, `(${issue.state})`);
  }
}

Facts and evidence are how you trust a completion, and issues are how you diagnose anything else. For how the statuses on facts decide what "completed" means, see Verification.

Wait for an approval instead

If you're waiting for a decision point rather than the end of the work, use waitForApproval. It returns the pending approval, or nothing if the mandate ends without asking. The full pattern is in Handle an approval.

Continue building

On this page