Skip to main content
An orchestrator agent dynamically decides what tasks to dispatch, and worker agents execute them. The orchestrator can plan, delegate, and combine results in any order. Restate ensures the orchestrator’s plan and each worker’s result are durably persisted.

Example: research report generation

An orchestrator agent breaks a research topic into sub-tasks, dispatches them to worker agents, and combines the results into a report.
workflow-orchestrator.ts
export const researchWorker = restate.service({
  name: "ResearchWorker",
  handlers: {
    research: async (ctx: restate.Context, {question}: { question: string }) => {
      const model = wrapLanguageModel({
        model: openai("gpt-5.4"),
        middleware: durableCalls(ctx, { maxRetryAttempts: 3 }),
      });
      const { text: answer } = await generateText({
        model,
        system:
          "You are a research assistant. Provide a concise, factual answer.",
        prompt: question,
      });
      return { question, answer };
    },
  },
});

const orchestrator = restate.service({
  name: "ResearchReport",
  handlers: {
    generate: restate.createServiceHandler(
      { input: schema(ResearchRequestSchema) },
      async (ctx: restate.Context, {topic}: { topic: string }) => {
        const model = wrapLanguageModel({
          model: openai("gpt-5.4"),
          middleware: durableCalls(ctx, { maxRetryAttempts: 3 }),
        });

        // Step 1: Orchestrator creates a research plan
        const { output: tasks } = await generateText({
          model,
          system: `You are a research planner. Break the topic into 2-4 research
          sub-tasks. Respond with a JSON array of strings, each a specific
          research question. Example: ["question 1", "question 2"]`,
          prompt: topic,
          output: Output.array({element: z.string()})
        });

        // Step 2: Dispatch workers in parallel
        const workerResults = await RestatePromise.all(
          tasks.map((question) =>
            ctx.serviceClient(researchWorker).research({ question }),
          ),
        );

        // Step 3: Combine results into a report
        const { text: report } = await generateText({
          model,
          system:
            "You are a report writer. Combine the research findings into a cohesive report.",
          prompt: `Topic: ${topic}\n\nResearch findings:\n${JSON.stringify(workerResults)}`,
        });

        return { report, taskCount: tasks.length };
      },
    ),
  },
});
Install Restate and launch it:
npm install --global @restatedev/restate-server@latest @restatedev/restate@latest
restate-server
Get the example:
restate example typescript-vercel-ai-tour-of-agents && cd typescript-vercel-ai-tour-of-agents
npm install
Export your OpenAI API key and run the agent:
export OPENAI_API_KEY=sk-...
npx tsx ./src/workflow-orchestrator.ts
Register the agents with Restate:
restate deployments register http://localhost:9080 --force --yes # dev only: overrides previous registrations
Send a request to the agent:
curl localhost:8080/restate/call/ResearchReport/generate \
--json '{
    "topic": "Benefits of durable execution in distributed systems"
}'
The orchestrator’s plan is persisted as a durable step. If the process crashes after two of four workers have completed, recovery replays those two results from the journal and only runs the remaining two workers.
Invocation overview