Typed State

You want a typed state shape for a route, including the values needed to run it. Here's how.

The code

import { z } from "zod"
 
export default z.object({
  /** Tenant supplied in the run input */
  tenant: z.string(),
  /** Accumulated tool-call results */
  context: z.string().default(""),
  /** Number of records returned by the lookup tool */
  count: z.number().default(0),
})

Notes

  • Include route values in the schema. [tenant] is part of the route id; the workflow validates tenant from the input by calling state.parse(input).

  • Route ids stay parameterized. Run this route as /hello/[tenant] with input for tenant:

    bash
    echo '{"tenant":"acme"}' | dawn run '/hello/[tenant]'

    For an Agent Protocol run, send the same input in the body:

    json
    { "route": "/hello/[tenant]#workflow", "input": { "tenant": "acme" } }

    A concrete /hello/acme path is not how Dawn populates route state.

  • Parse workflow input explicitly. Workflow routes do not automatically parse state.ts. Calling state.parse(input) validates the input and applies fields declared with .default(...) when the caller omits them.

  • This workflow imports and parses the schema directly. It can keep tenant required. For agent-state discovery, Dawn instead validates {} to extract defaults; if you reuse this schema for an agent route, make every top-level field accept missing input so discovery does not skip it.

  • State is JSON-serializable. It crosses the runtime boundary on every runs/wait and runs/stream call. Use primitives, plain objects, arrays.