> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt
> Use this file to discover all available pages before exploring further.

# AgentWorkflow

> Base class for Workflows that integrate with Agents

## Overview

`AgentWorkflow` extends Cloudflare's `WorkflowEntrypoint` to provide seamless access to the Agent that started the workflow, enabling bidirectional communication and typed RPC.

```typescript theme={null}
import { AgentWorkflow } from "agents/workflows";
import type { MyAgent } from "./agent";

type TaskParams = { taskId: string; data: string };

export class ProcessingWorkflow extends AgentWorkflow<MyAgent, TaskParams> {
  async run(event: AgentWorkflowEvent<TaskParams>, step: AgentWorkflowStep) {
    // Access the originating Agent
    await this.agent.updateTaskStatus(event.payload.taskId, "processing");

    const result = await step.do("process", async () => {
      // Processing logic
      return { processed: true };
    });

    // Report progress
    await step.reportComplete(result);

    return result;
  }
}
```

## Type Parameters

<ParamField path="AgentType" type="Agent" default="Agent">
  The Agent class type (for typed RPC access)
</ParamField>

<ParamField path="Params" type="unknown" default="unknown">
  User-defined params passed to the workflow
</ParamField>

<ParamField path="ProgressType" type="DefaultProgress" default="DefaultProgress">
  Type for progress reporting
</ParamField>

<ParamField path="Env" type="Cloudflare.Env" default="Cloudflare.Env">
  Environment type
</ParamField>

## Properties

### agent

<ResponseField name="agent" type="DurableObjectStub<AgentType>" required>
  The Agent stub for RPC calls. Provides typed access to the Agent's methods.

  ```typescript theme={null}
  // Call any public method on the Agent
  await this.agent.updateStatus("processing");
  const data = await this.agent.getData();
  ```
</ResponseField>

### workflowId

<ResponseField name="workflowId" type="string" required>
  Workflow instance ID (from Cloudflare Workflows)
</ResponseField>

### workflowName

<ResponseField name="workflowName" type="string" required>
  Workflow binding name (from environment)
</ResponseField>

## Lifecycle

### run()

<ParamField path="event" type="AgentWorkflowEvent<Params>" required>
  Workflow event with user-defined params
</ParamField>

<ParamField path="step" type="AgentWorkflowStep" required>
  Durable step object with Agent communication methods
</ParamField>

Main workflow implementation. Override this method with your workflow logic.

```typescript theme={null}
async run(
  event: AgentWorkflowEvent<Params>,
  step: AgentWorkflowStep
) {
  // Your workflow logic
  const result = await step.do("step1", async () => {
    return { data: "result" };
  });

  await step.reportComplete(result);
  return result;
}
```

**Returns:** `Promise<unknown>` - Workflow result

## AgentWorkflowStep

The `step` parameter is a standard `WorkflowStep` extended with Agent communication methods:

### step.reportComplete()

Report successful completion to the Agent.

<ParamField path="result" type="T">
  Result data to send
</ParamField>

```typescript theme={null}
const result = await step.do("process", async () => {
  return { status: "success", data: "result" };
});

await step.reportComplete(result);
```

**Returns:** `Promise<void>`

### step.reportError()

Report an error to the Agent.

<ParamField path="error" type="Error | string" required>
  Error to report
</ParamField>

```typescript theme={null}
try {
  await step.do("risky", async () => {
    throw new Error("Something went wrong");
  });
} catch (err) {
  await step.reportError(err);
  throw err; // Re-throw to fail the workflow
}
```

**Returns:** `Promise<void>`

<Note>
  Errors are automatically reported if a workflow throws without explicitly calling `reportError()`.
</Note>

### step.sendEvent()

Send a custom event to the Agent.

<ParamField path="event" type="T" required>
  Event data to send
</ParamField>

```typescript theme={null}
await step.sendEvent({
  type: "progress",
  percent: 0.5,
  message: "Processing..."
});
```

**Returns:** `Promise<void>`

### step.updateAgentState()

Replace the Agent's entire state.

<ParamField path="state" type="unknown" required>
  New state
</ParamField>

```typescript theme={null}
await step.updateAgentState({
  status: "processing",
  progress: 0.5
});
```

**Returns:** `Promise<void>`

### step.mergeAgentState()

Merge partial state into the Agent's state.

<ParamField path="partialState" type="Record<string, unknown>" required>
  Partial state to merge
</ParamField>

```typescript theme={null}
await step.mergeAgentState({
  progress: 0.75
  // Other state fields remain unchanged
});
```

**Returns:** `Promise<void>`

### step.resetAgentState()

Reset the Agent's state to initialState.

```typescript theme={null}
await step.resetAgentState();
```

**Returns:** `Promise<void>`

## Protected Methods

### reportProgress()

Report typed progress to the Agent.

<ParamField path="progress" type="ProgressType" required>
  Typed progress data
</ParamField>

```typescript theme={null}
protected async reportProgress(progress: ProgressType): Promise<void>
```

**Example:**

```typescript theme={null}
type MyProgress = { stage: string; percent: number };

class MyWorkflow extends AgentWorkflow<MyAgent, Params, MyProgress> {
  async run(event, step) {
    await this.reportProgress({ stage: "fetch", percent: 0.25 });
    // ...
    await this.reportProgress({ stage: "process", percent: 0.75 });
  }
}
```

### broadcastToClients()

Broadcast a message to all connected WebSocket clients via the Agent.

<ParamField path="message" type="unknown" required>
  Message to broadcast (will be JSON-stringified)
</ParamField>

```typescript theme={null}
protected broadcastToClients(message: unknown): void
```

**Example:**

```typescript theme={null}
this.broadcastToClients({
  type: "workflow-progress",
  workflowId: this.workflowId,
  percent: 0.5
});
```

<Warning>
  `broadcastToClients()` is non-durable and may repeat on workflow retry. Use `step.sendEvent()` for durable messages.
</Warning>

### waitForApproval()

Wait for approval from the Agent.

<ParamField path="step" type="AgentWorkflowStep" required>
  Step object
</ParamField>

<ParamField path="options" type="WaitForApprovalOptions">
  <ParamField path="timeout" type="string">
    Timeout duration (e.g., "7 days", "1 hour")
  </ParamField>

  <ParamField path="eventType" type="string" default="approval">
    Event type to wait for
  </ParamField>

  <ParamField path="stepName" type="string" default="wait-for-approval">
    Step name for the workflow
  </ParamField>
</ParamField>

```typescript theme={null}
protected async waitForApproval<T>(step, options?): Promise<T>
```

**Example:**

```typescript theme={null}
type ApprovalMetadata = { approvedBy: string; notes: string };

class ApprovalWorkflow extends AgentWorkflow {
  async run(event, step) {
    // Report progress before waiting
    await this.reportProgress({ stage: "awaiting-approval" });

    try {
      const approval = await this.waitForApproval<ApprovalMetadata>(step, {
        timeout: "7 days"
      });

      console.log(`Approved by ${approval.approvedBy}`);
      // Continue workflow
    } catch (err) {
      if (err instanceof WorkflowRejectedError) {
        console.log("Workflow rejected:", err.reason);
        throw err;
      }
    }
  }
}
```

**Returns:** `Promise<T>` - Approval metadata

**Throws:** `WorkflowRejectedError` if rejected

## Running Workflows from Agents

### runWorkflow()

Start a workflow from an Agent.

```typescript theme={null}
class MyAgent extends Agent {
  @callable()
  async startProcessing(taskId: string) {
    const instanceId = await this.runWorkflow("ProcessingWorkflow", {
      taskId,
      data: "input"
    });

    return { workflowId: instanceId };
  }
}
```

See [Agent.runWorkflow()](/api/agent-class#runworkflow) for full documentation.

### approveWorkflow()

Approve a waiting workflow.

```typescript theme={null}
@callable()
async approve(workflowId: string) {
  await this.approveWorkflow(workflowId, {
    approvedBy: "admin",
    notes: "Looks good!"
  });
}
```

### rejectWorkflow()

Reject a waiting workflow.

```typescript theme={null}
@callable()
async reject(workflowId: string, reason: string) {
  await this.rejectWorkflow(workflowId, reason);
}
```

## Agent Callbacks

### onWorkflowProgress()

Called when a workflow reports progress.

```typescript theme={null}
class MyAgent extends Agent {
  async onWorkflowProgress(event: WorkflowProgressCallback) {
    console.log(`Workflow ${event.workflowId} progress:`, event.progress);

    // Update UI
    this.broadcast(JSON.stringify({
      type: "workflow-progress",
      workflowId: event.workflowId,
      progress: event.progress
    }));
  }
}
```

### onWorkflowComplete()

Called when a workflow completes successfully.

```typescript theme={null}
async onWorkflowComplete(event: WorkflowCompleteCallback) {
  console.log(`Workflow ${event.workflowId} completed:`, event.result);

  // Update state
  this.setState({
    ...this.state,
    lastWorkflowResult: event.result
  });
}
```

### onWorkflowError()

Called when a workflow errors.

```typescript theme={null}
async onWorkflowError(event: WorkflowErrorCallback) {
  console.error(`Workflow ${event.workflowId} failed:`, event.error);

  // Notify user
  this.broadcast(JSON.stringify({
    type: "workflow-error",
    workflowId: event.workflowId,
    error: event.error
  }));
}
```

## Full Example

```typescript theme={null}
// workflow.ts
import { AgentWorkflow } from "agents/workflows";
import type { TaskAgent } from "./agent";

type TaskParams = {
  taskId: string;
  input: string;
};

type TaskProgress = {
  stage: "fetch" | "process" | "complete";
  percent: number;
};

export class TaskWorkflow extends AgentWorkflow<
  TaskAgent,
  TaskParams,
  TaskProgress
> {
  async run(
    event: AgentWorkflowEvent<TaskParams>,
    step: AgentWorkflowStep
  ) {
    const { taskId, input } = event.payload;

    // Fetch data
    await this.reportProgress({ stage: "fetch", percent: 0.25 });
    const data = await step.do("fetch", async () => {
      return await this.agent.fetchData(taskId);
    });

    // Process data
    await this.reportProgress({ stage: "process", percent: 0.5 });
    const result = await step.do("process", async () => {
      return await processData(data, input);
    });

    // Wait for approval
    const approval = await this.waitForApproval(step, {
      timeout: "7 days"
    });

    // Save result
    await this.reportProgress({ stage: "complete", percent: 1.0 });
    await step.do("save", async () => {
      await this.agent.saveResult(taskId, result);
    });

    await step.reportComplete({ taskId, result });
    return result;
  }
}

// agent.ts
import { Agent, callable } from "agents";
import type { TaskWorkflow } from "./workflow";

class TaskAgent extends Agent {
  @callable()
  async startTask(taskId: string, input: string) {
    const instanceId = await this.runWorkflow<typeof TaskWorkflow>("TaskWorkflow", {
      taskId,
      input
    });
    return { workflowId: instanceId };
  }

  async onWorkflowProgress(event: WorkflowProgressCallback) {
    console.log(`Task ${event.workflowId}:`, event.progress);
    this.broadcast(JSON.stringify({ type: "task-progress", ...event }));
  }

  async onWorkflowComplete(event: WorkflowCompleteCallback) {
    console.log(`Task ${event.workflowId} complete!`);
  }
}
```

## Related

* [Agent Class](/api/agent-class) - Agent workflow methods
* [Cloudflare Workflows](https://developers.cloudflare.com/workflows/) - Workflows documentation
