Skip to content

Commit 3ff492a

Browse files
Add task management and workflow integration documentation
Sync documentation for PR #683 from cloudflare/agents repository. This update adds comprehensive documentation for the new task management system: - New @task() decorator for tracked background operations - @task({ durable: true }) for long-running tasks backed by Workflows - DurableTaskWorkflow and AgentWorkflow classes - Task management API (this.tasks.get(), list(), cancel(), delete()) - Real-time progress updates via WebSocket - Integration with Cloudflare Workflows Changes: - Add api-reference/tasks.mdx - Complete API reference for the task system - Add concepts/durable-tasks.mdx - Guide for durable tasks with Workflows - Update api-reference/run-workflows.mdx - Add section on task system integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
1 parent 4e3cb5c commit 3ff492a

File tree

3 files changed

+392
-0
lines changed

3 files changed

+392
-0
lines changed

src/content/docs/agents/api-reference/run-workflows.mdx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,51 @@ You can also call a Workflow that is defined in a different Workers script from
106106
</WranglerConfig>
107107

108108
Refer to the [cross-script calls](/workflows/build/workers-api/#cross-script-calls) section of the Workflows documentation for more examples.
109+
110+
## Trigger Workflows with the Task System
111+
112+
The Agents SDK provides a higher-level task system that integrates Workflows with automatic progress tracking and real-time updates. Use `this.workflow()` to dispatch a workflow that is automatically tracked as a task:
113+
114+
<TypeScriptExample>
115+
116+
```ts
117+
class MyAgent extends Agent<Env> {
118+
@callable()
119+
async startAnalysis(input: { repoUrl: string }) {
120+
// Dispatches a workflow and returns a task handle
121+
return this.workflow("ANALYSIS_WORKFLOW", input);
122+
}
123+
}
124+
```
125+
126+
</TypeScriptExample>
127+
128+
For workflows that need to send progress updates back to the agent, extend `AgentWorkflow`:
129+
130+
<TypeScriptExample>
131+
132+
```ts
133+
import { AgentWorkflow, type WorkflowTaskContext } from "agents";
134+
135+
export class AnalysisWorkflow extends AgentWorkflow<Env, { repoUrl: string }> {
136+
async run(ctx: WorkflowTaskContext<{ repoUrl: string }>) {
137+
// Each step is checkpointed and survives restarts
138+
const files = await ctx.step("fetch", async () => {
139+
ctx.emit("phase", { name: "fetching" });
140+
return fetchRepoFiles(ctx.params.repoUrl);
141+
});
142+
143+
// Durable sleep
144+
await ctx.sleep("rate-limit", "1h");
145+
146+
return await ctx.step("analyze", async () => {
147+
ctx.setProgress(50);
148+
return analyzeFiles(files);
149+
});
150+
}
151+
}
152+
```
153+
154+
</TypeScriptExample>
155+
156+
The workflow is automatically tracked as a task, and progress updates are broadcast to connected clients. Refer to [Tasks](/agents/api-reference/tasks/) and [Durable tasks](/agents/concepts/durable-tasks/) for more details.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
title: Tasks
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 5
6+
---
7+
8+
import { TypeScriptExample, WranglerConfig } from "~/components";
9+
10+
Tasks are tracked background operations with progress updates, cancellation support, and real-time sync to connected clients.
11+
12+
## Quick start
13+
14+
<TypeScriptExample>
15+
16+
```ts
17+
import { Agent, task, type TaskContext } from "agents";
18+
19+
class MyAgent extends Agent<Env> {
20+
@task({ timeout: "5m" })
21+
async processData(input: { url: string }, ctx: TaskContext) {
22+
ctx.emit("started", { url: input.url });
23+
ctx.setProgress(25);
24+
25+
const data = await fetch(input.url);
26+
ctx.setProgress(75);
27+
28+
return { processed: true };
29+
}
30+
}
31+
```
32+
33+
</TypeScriptExample>
34+
35+
The client receives real-time updates automatically via WebSocket.
36+
37+
## TaskContext
38+
39+
Every task method receives a `TaskContext` with:
40+
41+
- `emit(type, data)` - Send events to connected clients
42+
- `setProgress(n)` - Set progress percentage (0-100)
43+
- `signal` - AbortSignal for cancellation
44+
45+
<TypeScriptExample>
46+
47+
```ts
48+
@task({ timeout: "2m" })
49+
async analyze(input: Input, ctx: TaskContext) {
50+
ctx.emit("phase", { name: "fetching" });
51+
52+
if (ctx.signal.aborted) {
53+
throw new Error("Cancelled");
54+
}
55+
56+
ctx.setProgress(50);
57+
// ...
58+
}
59+
```
60+
61+
</TypeScriptExample>
62+
63+
## Managing tasks
64+
65+
Access tasks via `this.tasks`:
66+
67+
<TypeScriptExample>
68+
69+
```ts
70+
// Get a task
71+
const task = this.tasks.get(taskId);
72+
73+
// List all tasks
74+
const all = this.tasks.list();
75+
76+
// List by status
77+
const running = this.tasks.list({ status: "running" });
78+
79+
// Cancel a task
80+
await this.tasks.cancel(taskId, "User requested");
81+
82+
// Delete completed task
83+
this.tasks.delete(taskId);
84+
```
85+
86+
</TypeScriptExample>
87+
88+
## Client updates
89+
90+
Tasks broadcast updates to all connected WebSocket clients:
91+
92+
<TypeScriptExample>
93+
94+
```ts
95+
// React client
96+
const agent = useAgent({ agent: "my-agent", name: "default" });
97+
98+
agent.addEventListener("message", (event) => {
99+
const data = JSON.parse(event.data);
100+
if (data.type === "CF_AGENT_TASK_UPDATE") {
101+
const { taskId, task } = data;
102+
// task.status, task.progress, task.events, task.result
103+
}
104+
});
105+
```
106+
107+
</TypeScriptExample>
108+
109+
## Options
110+
111+
<TypeScriptExample>
112+
113+
```ts
114+
@task({
115+
timeout: "5m", // Cancel if exceeds duration
116+
})
117+
async myTask(input: Input, ctx: TaskContext) {
118+
// ...
119+
}
120+
```
121+
122+
</TypeScriptExample>
123+
124+
Timeout accepts: `"30s"`, `"5m"`, `"1h"`, or milliseconds.
125+
126+
## Task status
127+
128+
Tasks transition through these states:
129+
130+
- `pending` - Created, waiting to run
131+
- `running` - Currently executing
132+
- `completed` - Finished successfully
133+
- `failed` - Threw an error
134+
- `aborted` - Cancelled or timed out
135+
136+
## Durable tasks
137+
138+
For long-running operations that need to survive restarts, use durable tasks backed by Cloudflare Workflows:
139+
140+
<TypeScriptExample>
141+
142+
```ts
143+
@task({ durable: true })
144+
async longProcess(input: Input, ctx: TaskContext) {
145+
// Durable step - survives restarts
146+
const data = await ctx.step("fetch", () => fetchData(input));
147+
148+
// Durable sleep - can sleep for days
149+
await ctx.sleep("rate-limit", "1h");
150+
151+
return await ctx.step("process", () => process(data));
152+
}
153+
```
154+
155+
</TypeScriptExample>
156+
157+
Refer to [Durable tasks](/agents/concepts/durable-tasks/) for setup and details.
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
---
2+
title: Durable tasks
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 4
6+
---
7+
8+
import { TypeScriptExample, WranglerConfig } from "~/components";
9+
10+
Durable tasks are long-running operations backed by [Cloudflare Workflows](/workflows/). They survive agent restarts and automatically retry on failure.
11+
12+
## Setup
13+
14+
1. Export `DurableTaskWorkflow` from your worker:
15+
16+
<TypeScriptExample>
17+
18+
```ts
19+
// src/index.ts
20+
import { Agent, routeAgentRequest, DurableTaskWorkflow } from "agents";
21+
22+
export { DurableTaskWorkflow };
23+
24+
export class MyAgent extends Agent<Env> {
25+
// ...
26+
}
27+
```
28+
29+
</TypeScriptExample>
30+
31+
2. Add the workflow binding to your Wrangler configuration:
32+
33+
<WranglerConfig>
34+
35+
```json
36+
{
37+
"workflows": [
38+
{
39+
"name": "durable-tasks",
40+
"binding": "DURABLE_TASKS_WORKFLOW",
41+
"class_name": "DurableTaskWorkflow"
42+
}
43+
]
44+
}
45+
```
46+
47+
</WranglerConfig>
48+
49+
## Usage
50+
51+
Mark a task as durable with `durable: true`:
52+
53+
<TypeScriptExample>
54+
55+
```ts
56+
import { Agent, task, type TaskContext } from "agents";
57+
58+
class MyAgent extends Agent<Env> {
59+
@task({ durable: true })
60+
async longAnalysis(input: { repoUrl: string }, ctx: TaskContext) {
61+
ctx.emit("started");
62+
const files = await fetchRepoFiles(input.repoUrl);
63+
ctx.setProgress(50);
64+
const analysis = await analyzeFiles(files);
65+
return analysis;
66+
}
67+
}
68+
```
69+
70+
</TypeScriptExample>
71+
72+
Durable tasks provide:
73+
74+
- **Automatic retries** on failure (configurable)
75+
- **Survives restarts** - the workflow engine manages execution
76+
- **Real-time updates** via `ctx.emit()` and `ctx.setProgress()`
77+
78+
## Retry configuration
79+
80+
Configure automatic retries:
81+
82+
<TypeScriptExample>
83+
84+
```ts
85+
@task({
86+
durable: true,
87+
retry: {
88+
limit: 3,
89+
delay: "10s",
90+
backoff: "exponential"
91+
}
92+
})
93+
async unreliableTask(input: Input, ctx: TaskContext) {
94+
// Automatically retries on failure
95+
}
96+
```
97+
98+
</TypeScriptExample>
99+
100+
## When to use durable tasks
101+
102+
Use `@task()` (simple) for:
103+
104+
- Operations under 30 seconds
105+
- Tasks that can restart from scratch
106+
107+
Use `@task({ durable: true })` for:
108+
109+
- Long-running operations that need retry guarantees
110+
- Operations that must survive agent restarts
111+
112+
## Custom workflows
113+
114+
For multi-step workflows with individual checkpoints, extend `AgentWorkflow`:
115+
116+
<TypeScriptExample>
117+
118+
```ts
119+
import { AgentWorkflow, type WorkflowTaskContext } from "agents";
120+
121+
export class AnalysisWorkflow extends AgentWorkflow<Env, { repoUrl: string }> {
122+
async run(ctx: WorkflowTaskContext<{ repoUrl: string }>) {
123+
// Each step is checkpointed - survives restarts
124+
const files = await ctx.step("fetch", async () => {
125+
ctx.emit("phase", { name: "fetching" });
126+
return fetchRepoFiles(ctx.params.repoUrl);
127+
});
128+
129+
// Durable sleep - can wait for hours or days
130+
await ctx.sleep("rate-limit", "1h");
131+
132+
return await ctx.step("analyze", async () => {
133+
ctx.setProgress(50);
134+
return analyzeFiles(files);
135+
});
136+
}
137+
}
138+
```
139+
140+
</TypeScriptExample>
141+
142+
Add to your Wrangler configuration:
143+
144+
<WranglerConfig>
145+
146+
```json
147+
{
148+
"workflows": [
149+
{
150+
"name": "analysis-workflow",
151+
"binding": "ANALYSIS_WORKFLOW",
152+
"class_name": "AnalysisWorkflow"
153+
}
154+
]
155+
}
156+
```
157+
158+
</WranglerConfig>
159+
160+
Dispatch via `this.workflow()`:
161+
162+
<TypeScriptExample>
163+
164+
```ts
165+
class MyAgent extends Agent<Env> {
166+
@callable()
167+
async startAnalysis(input: { repoUrl: string }) {
168+
return this.workflow("ANALYSIS_WORKFLOW", input);
169+
}
170+
}
171+
```
172+
173+
</TypeScriptExample>
174+
175+
### WorkflowTaskContext methods
176+
177+
Custom workflows have access to:
178+
179+
- `ctx.step(name, fn)` - Checkpointed step, replayed on restart
180+
- `ctx.sleep(name, duration)` - Durable sleep (for example, `"1h"`, `"7d"`)
181+
- `ctx.emit(type, data)` - Send events to clients
182+
- `ctx.setProgress(n)` - Set progress percentage
183+
184+
## Related resources
185+
186+
- [Tasks API reference](/agents/api-reference/tasks/) - Complete API reference for the task system
187+
- [Cloudflare Workflows](/workflows/) - Learn more about Cloudflare Workflows

0 commit comments

Comments
 (0)