Routes

A route is a folder under src/app/. Its path becomes the agent endpoint. A route's index.ts exports exactly one entry shape: agent, workflow, graph, or chain.

Route entry

Every route has an index.ts that exports one of:

  • agent — an LLM-driven flow with auto-discovered tools. The default scaffold export. See Agents.
  • workflow — a deterministic async function with typed state. See Routes / workflow below.
  • graph — a LangGraph graph. Branching, looping, conditional edges.
  • chain — a LangChain LCEL Runnable. Simple linear pipelines.

Pathname rules

Routes follow the same conventions as the Next.js App Router:

  • (group)/ — route group, excluded from the path
  • [segment]/ — dynamic segment, preserved in the route id and exposed in generated route params
  • [...rest]/ — catch-all
  • [[...optional]]/ — optional catch-all

Example tree:

text
src/app/
  (public)/
    hello/
      [tenant]/
        index.ts        ← exports agent | workflow | graph | chain
        state.ts        ← optional, route state schema
        tools/
          greet.ts      ← auto-discovered for agents and RuntimeContext

The (public)/ segment is excluded from the path, so this route is /hello/[tenant].

workflow

A workflow is a deterministic async function. The first argument is the typed route state; the second is a RuntimeContext that exposes the route's discovered tools.

src/app/(public)/hello/[tenant]/index.ts
import type { RuntimeContext } from "@dawn-ai/sdk"
import type { RouteTools } from "dawn:routes"
import type { z } from "zod"
import type state from "./state.js"
 
type HelloState = z.infer<typeof state> & { readonly tenant: string }
 
export async function workflow(
  state: HelloState,
  ctx: RuntimeContext<RouteTools<"/hello/[tenant]">>,
) {
  const r = await ctx.tools.greet({ tenant: state.tenant })
  return { ...state, greeting: r.greeting }
}

The RouteTools<"/hello/[tenant]"> generic resolves to the union of tools auto-discovered in this route's tools/ directory.

graph

Export a compiled LangGraph graph as a named graph export:

src/app/(public)/hello/[tenant]/index.ts
import { StateGraph, START, END } from "@langchain/langgraph"
import type { HelloState } from "./state.js"
 
export const graph = new StateGraph<HelloState>({ channels: { /* ... */ } })
  .addNode("greet", async (state) => state)
  .addEdge(START, "greet")
  .addEdge("greet", END)
  .compile()

The graph receives the same typed state and runs through Dawn's runtime. State channels still need to be declared (LangGraph requirement).

chain

Export a LangChain LCEL Runnable as a named chain export:

src/app/(public)/hello/[tenant]/index.ts
import { RunnableSequence } from "@langchain/core/runnables"
 
export const chain = RunnableSequence.from([
  // chain steps
])

Running a route

Routes dispatch by path:

bash
$ echo '{"tenant":"acme"}' | dawn run '/hello/[tenant]'
$ dawn dev    # HMR + dev server

Programmatic dispatch is also available — see Dev Server for the runtime API and the /runs/wait / /runs/stream endpoints.

Related