agents 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -1
- package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-B2XLNMxq.d.ts} +1094 -443
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +26 -26
- package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-Dj5Mzlw7.d.ts} +7 -7
- package/dist/agent-tools.d.ts +21 -21
- package/dist/browser/ai.js +4 -1
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
- package/dist/callable-decorator.d.ts +18 -0
- package/dist/callable-decorator.js +71 -0
- package/dist/callable-decorator.js.map +1 -0
- package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
- package/dist/capability-B4WbF81e.js.map +1 -0
- package/dist/capability-runner-BUBa6Ake.d.ts +484 -0
- package/dist/channel-Bnm4S7T2.d.ts +491 -0
- package/dist/channels/ai-sdk.d.ts +46 -0
- package/dist/channels/ai-sdk.js +120 -0
- package/dist/channels/ai-sdk.js.map +1 -0
- package/dist/channels/email.d.ts +95 -0
- package/dist/channels/email.js +323 -0
- package/dist/channels/email.js.map +1 -0
- package/dist/channels/index.d.ts +233 -0
- package/dist/channels/index.js +608 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/slack.d.ts +140 -0
- package/dist/channels/slack.js +614 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/tanstack-ai.d.ts +39 -0
- package/dist/channels/tanstack-ai.js +17 -0
- package/dist/channels/tanstack-ai.js.map +1 -0
- package/dist/channels/telegram.d.ts +106 -0
- package/dist/channels/telegram.js +427 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/voice.d.ts +45 -0
- package/dist/channels/voice.js +122 -0
- package/dist/channels/voice.js.map +1 -0
- package/dist/chat/index.d.ts +2319 -2010
- package/dist/chat/index.js +892 -518
- package/dist/chat/index.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +7 -7
- package/dist/chat-sdk/index.js +1 -1
- package/dist/client-BxdkCuVy.d.ts +411 -0
- package/dist/client-C9DAjZIY.js +518 -0
- package/dist/client-C9DAjZIY.js.map +1 -0
- package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
- package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
- package/dist/client.d.ts +27 -283
- package/dist/client.js +2 -274
- package/dist/context/index.d.ts +216 -0
- package/dist/context/index.js +454 -0
- package/dist/context/index.js.map +1 -0
- package/dist/current-agent-C4w86kcN.d.ts +93 -0
- package/dist/current-agent-DhoDkSnH.js.map +1 -1
- package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
- package/dist/diagnostics-BzvaX2UT.js.map +1 -0
- package/dist/diagnostics-C4jcz3VK.js +360 -0
- package/dist/diagnostics-C4jcz3VK.js.map +1 -0
- package/dist/durable-object-lifecycle-ei7M7lqB.d.ts +157 -0
- package/dist/index-BB0kqhIz.d.ts +101 -0
- package/dist/index-BVVgDSdq.d.ts +1 -0
- package/dist/index-Dlgtd3Mj.d.ts +78 -0
- package/dist/index-XDkuQ7zm.d.ts +89 -0
- package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
- package/dist/index.d.ts +92 -83
- package/dist/index.js +4 -3
- package/dist/ingress-BfetZbMO.js +83 -0
- package/dist/ingress-BfetZbMO.js.map +1 -0
- package/dist/internal-CYlgHl1l.js +59 -0
- package/dist/internal-CYlgHl1l.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +39 -19
- package/dist/lifecycle/index.js +2 -2
- package/dist/lifecycle-Mm_jQh7r.js +1314 -0
- package/dist/lifecycle-Mm_jQh7r.js.map +1 -0
- package/dist/mcp/client/index.d.ts +20 -20
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/index.d.ts +35 -35
- package/dist/mcp/index.js +2 -2
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +1 -1
- package/dist/queue/index.d.ts +123 -0
- package/dist/queue/index.js +2 -0
- package/dist/queue-BC9F5cUo.js +406 -0
- package/dist/queue-BC9F5cUo.js.map +1 -0
- package/dist/react.d.ts +34 -16
- package/dist/react.js +31 -8
- package/dist/react.js.map +1 -1
- package/dist/{retries-CAvxtG9d.d.ts → retries-D9B2UCq3.d.ts} +23 -6
- package/dist/retries.d.ts +10 -6
- package/dist/retries.js +21 -1
- package/dist/retries.js.map +1 -1
- package/dist/routing/index.d.ts +137 -0
- package/dist/routing/index.js +244 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/sanitize-D9TujEK8.js +79 -0
- package/dist/sanitize-D9TujEK8.js.map +1 -0
- package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-BGq6M5Kd.d.ts} +20 -21
- package/dist/scheduler-D_KHqxBa.js +658 -0
- package/dist/scheduler-D_KHqxBa.js.map +1 -0
- package/dist/schedules/index.d.ts +1 -1
- package/dist/schedules/index.js +1 -1
- package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +441 -0
- package/dist/sessions/index.js +2063 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/skills/index.d.ts +99 -0
- package/dist/skills/index.js +254 -5
- package/dist/skills/index.js.map +1 -1
- package/dist/{src-5W6JNKVb.js → src-BNU3ZiJM.js} +1524 -1441
- package/dist/src-BNU3ZiJM.js.map +1 -0
- package/dist/state/index.d.ts +6 -0
- package/dist/state/index.js +137 -0
- package/dist/state/index.js.map +1 -0
- package/dist/streams/index.d.ts +120 -0
- package/dist/streams/index.js +107 -0
- package/dist/streams/index.js.map +1 -0
- package/dist/streams-BcE8JP2X.d.ts +370 -0
- package/dist/streams-CCPRV6dt.js +709 -0
- package/dist/streams-CCPRV6dt.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/surface-bZZJqBka.js +17 -0
- package/dist/surface-bZZJqBka.js.map +1 -0
- package/dist/tasks/index.d.ts +64 -0
- package/dist/tasks/index.js +2 -0
- package/dist/tasks-D4nLqVSI.js +1656 -0
- package/dist/tasks-D4nLqVSI.js.map +1 -0
- package/dist/tasks-V2lCT8ZV.d.ts +517 -0
- package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
- package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
- package/dist/text-stream-CpdiKrJB.js +272 -0
- package/dist/text-stream-CpdiKrJB.js.map +1 -0
- package/dist/tokens-nHAKcN6M.js +52 -0
- package/dist/tokens-nHAKcN6M.js.map +1 -0
- package/dist/tool-schema-CBjGPrsQ.js +31 -0
- package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
- package/dist/transport-protocol-BxyngQ_R.js +25 -0
- package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
- package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
- package/dist/types-B7LojTe4.d.ts +202 -0
- package/dist/types-DCD6BNZH.d.ts +70 -0
- package/dist/types-_Faxb570.d.ts +439 -0
- package/dist/voice/client.d.ts +226 -0
- package/dist/voice/client.js +932 -0
- package/dist/voice/client.js.map +1 -0
- package/dist/voice/errors.d.ts +43 -0
- package/dist/voice/errors.js +41 -0
- package/dist/voice/errors.js.map +1 -0
- package/dist/voice/index.d.ts +271 -0
- package/dist/voice/index.js +1812 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/react.d.ts +167 -0
- package/dist/voice/react.js +234 -0
- package/dist/voice/react.js.map +1 -0
- package/dist/voice/sfu.d.ts +71 -0
- package/dist/voice/sfu.js +157 -0
- package/dist/voice/sfu.js.map +1 -0
- package/dist/voice/text.d.ts +6 -0
- package/dist/voice/text.js +2 -0
- package/dist/voice/types.d.ts +58 -0
- package/dist/voice/types.js +18 -0
- package/dist/voice/types.js.map +1 -0
- package/dist/voice/workers-ai.d.ts +136 -0
- package/dist/voice/workers-ai.js +568 -0
- package/dist/voice/workers-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +301 -0
- package/dist/websockets/index.js +3 -0
- package/dist/websockets-D7IzWbZb.js +1005 -0
- package/dist/websockets-D7IzWbZb.js.map +1 -0
- package/dist/workflow-types.d.ts +25 -25
- package/dist/workflows.d.ts +21 -21
- package/dist/workflows.js +1 -1
- package/docs/agent-class.md +4 -4
- package/docs/agent-tools.md +2 -1
- package/docs/channels.md +323 -0
- package/docs/chat-agents.md +6 -13
- package/docs/client-sdk.md +30 -0
- package/docs/context.md +131 -0
- package/docs/index.md +16 -13
- package/docs/lifecycle.md +179 -57
- package/docs/long-running-agents.md +2 -2
- package/docs/mcp-servers.md +5 -1
- package/docs/queue.md +135 -241
- package/docs/resumable-streaming.md +1 -1
- package/docs/retries.md +1 -1
- package/docs/routing.md +105 -0
- package/docs/sessions.md +237 -871
- package/docs/streams.md +213 -0
- package/docs/sub-agents.md +184 -124
- package/docs/tasks.md +246 -0
- package/docs/voice.md +745 -0
- package/package.json +126 -14
- package/dist/capability-BjSKYpzg.js.map +0 -1
- package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
- package/dist/client.js.map +0 -1
- package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
- package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
- package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
- package/dist/current-agent-CuMErtly.d.ts +0 -283
- package/dist/diagnostics-CaBjfz4J.js.map +0 -1
- package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
- package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
- package/dist/experimental/memory/session/index.d.ts +0 -671
- package/dist/experimental/memory/session/index.js +0 -2379
- package/dist/experimental/memory/session/index.js.map +0 -1
- package/dist/experimental/memory/utils/index.d.ts +0 -96
- package/dist/experimental/memory/utils/index.js +0 -79
- package/dist/experimental/memory/utils/index.js.map +0 -1
- package/dist/scheduler-CR9RHGos.js +0 -857
- package/dist/scheduler-CR9RHGos.js.map +0 -1
- package/dist/src-5W6JNKVb.js.map +0 -1
- package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
- package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
package/docs/mcp-servers.md
CHANGED
|
@@ -78,7 +78,11 @@ createMcpHandler(() => createServer(), {
|
|
|
78
78
|
});
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
`createMcpHandler` supports upstream SDK v2 handler options except `bus`, which is not exposed by the Agents SDK. Supplying `bus` throws a `TypeError`.
|
|
82
|
+
|
|
83
|
+
To publish change events, use the returned handler's `notify` methods, such as `handler.notify.toolsChanged()`. Create the handler once at module scope and reuse it for requests and notifications. Notifications are isolate-local: they do not reach subscriptions in other Worker isolates. See the [handler notification API](https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/#publish-list-and-resource-changes) for the available methods.
|
|
84
|
+
|
|
85
|
+
Use `createLegacyMcpHandler` for SDK v1 WorkerTransport, storage, session, and event-store options. The SDK v2 `bus` option is not available on that handler either.
|
|
82
86
|
|
|
83
87
|
The handler validates every present `Origin` header before serving the request. It rejects malformed, opaque, and non-HTTP origins. Requests without `Origin` remain valid for non-browser MCP clients.
|
|
84
88
|
|
package/docs/queue.md
CHANGED
|
@@ -1,218 +1,157 @@
|
|
|
1
|
-
# Queue
|
|
1
|
+
# Queue
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Durable background work for an Agent or any Lifecycle Object. A queued item
|
|
4
|
+
persists a callback name and a payload, runs from the Durable Object's alarm
|
|
5
|
+
loop one item at a time in push order, retries when the callback throws, and
|
|
6
|
+
survives the object leaving memory.
|
|
4
7
|
|
|
5
|
-
##
|
|
8
|
+
## Queue Lifecycle capability
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
> **Experimental.** The `Queue` capability and the `agents/lifecycle` surface
|
|
11
|
+
> it builds on may change between releases. Agent's established queue methods
|
|
12
|
+
> (`this.queue()` and friends) are stable.
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
`Queue` is a reusable Lifecycle capability. A plain Lifecycle Object can
|
|
15
|
+
install it without extending `Agent`:
|
|
10
16
|
|
|
11
17
|
```typescript
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
callback: keyof Agent<unknown>; // Name of the method to call
|
|
16
|
-
created_at: number; // Timestamp when the task was created
|
|
17
|
-
retry?: RetryOptions; // Retry options (if configured)
|
|
18
|
-
};
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Core Methods
|
|
22
|
-
|
|
23
|
-
### queue()
|
|
24
|
-
|
|
25
|
-
Adds a task to the queue for future execution.
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
async queue<T = unknown>(
|
|
29
|
-
callback: keyof this,
|
|
30
|
-
payload: T,
|
|
31
|
-
options?: { retry?: RetryOptions }
|
|
32
|
-
): Promise<string>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**Parameters:**
|
|
36
|
-
|
|
37
|
-
- `callback`: The name of the method to call when processing the task
|
|
38
|
-
- `payload`: Data to pass to the callback method
|
|
39
|
-
- `options.retry`: Optional retry configuration. See [Retries](./retries.md) for details.
|
|
40
|
-
|
|
41
|
-
**Returns:** The unique ID of the queued task
|
|
42
|
-
|
|
43
|
-
**Example:**
|
|
18
|
+
import { DurableObject } from "cloudflare:workers";
|
|
19
|
+
import { Lifecycle } from "agents/lifecycle";
|
|
20
|
+
import { Queue, type QueueItem } from "agents/queue";
|
|
44
21
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
22
|
+
export class UploadObject extends DurableObject<Env> {
|
|
23
|
+
readonly queue = new Queue({
|
|
24
|
+
callbacks: {
|
|
25
|
+
processUpload: (
|
|
26
|
+
payload: { fileName: string },
|
|
27
|
+
item: QueueItem<{ fileName: string }>
|
|
28
|
+
) => {
|
|
29
|
+
console.log(item.id, payload.fileName);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
51
33
|
|
|
52
|
-
|
|
53
|
-
// Queue an email processing task
|
|
54
|
-
const taskId = await this.queue("processEmail", {
|
|
55
|
-
email: "user@example.com",
|
|
56
|
-
subject: "Welcome!"
|
|
57
|
-
});
|
|
34
|
+
readonly lifecycle = Lifecycle.install(this).use(this.queue);
|
|
58
35
|
|
|
59
|
-
|
|
36
|
+
async enqueueUpload(fileName: string): Promise<string> {
|
|
37
|
+
const item = await this.queue.push("processUpload", { fileName });
|
|
38
|
+
return item.id;
|
|
60
39
|
}
|
|
61
40
|
}
|
|
62
41
|
```
|
|
63
42
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
dequeue(id: string): void
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Parameters:**
|
|
73
|
-
|
|
74
|
-
- `id`: The ID of the task to remove
|
|
75
|
-
|
|
76
|
-
**Example:**
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
// Remove a specific task
|
|
80
|
-
agent.dequeue("abc123def");
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### dequeueAll()
|
|
84
|
-
|
|
85
|
-
Removes all tasks from the queue.
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
dequeueAll(): void
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
**Example:**
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
// Clear the entire queue
|
|
95
|
-
agent.dequeueAll();
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### dequeueAllByCallback()
|
|
99
|
-
|
|
100
|
-
Removes all tasks that match a specific callback method.
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
dequeueAllByCallback(callback: string): void
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**Parameters:**
|
|
107
|
-
|
|
108
|
-
- `callback`: Name of the callback method
|
|
109
|
-
|
|
110
|
-
**Example:**
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
// Remove all email processing tasks
|
|
114
|
-
agent.dequeueAllByCallback("processEmail");
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### getQueue()
|
|
118
|
-
|
|
119
|
-
Retrieves a specific queued task by ID.
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
getQueue(id: string): QueueItem<string> | undefined
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Parameters:**
|
|
43
|
+
Queue owns no storage of its own. Each item is one job in the Lifecycle job
|
|
44
|
+
queue, due immediately; Lifecycle owns the physical Durable Object alarm, the
|
|
45
|
+
alarm event loop, retry policy, the deadman pre-arm, and the memory-limit
|
|
46
|
+
circuit breaker. See [Durable Object lifecycle](./lifecycle.md#the-job-queue).
|
|
126
47
|
|
|
127
|
-
|
|
48
|
+
Queue's API is small: callbacks are registered by name in the constructor,
|
|
49
|
+
`push()` creates items typed against that registration, and `get()`,
|
|
50
|
+
`list()`, `cancel()`, and `cancelAll()` manage them. All of these are
|
|
51
|
+
asynchronous and work inside routed sub-agents.
|
|
128
52
|
|
|
129
|
-
|
|
53
|
+
Queue Lifecycle hooks run without ambient host context. Registered callbacks
|
|
54
|
+
are user code, so they run inside the host invocation context with the
|
|
55
|
+
Lifecycle Object available through `getCurrentAgent()`.
|
|
130
56
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
**Example:**
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
const task = agent.getQueue("abc123def");
|
|
137
|
-
if (task) {
|
|
138
|
-
console.log(`Task callback: ${task.callback}`);
|
|
139
|
-
console.log(`Task payload:`, task.payload);
|
|
140
|
-
}
|
|
141
|
-
```
|
|
57
|
+
### `new Queue(options?)`
|
|
142
58
|
|
|
143
|
-
|
|
59
|
+
| Option | Description |
|
|
60
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------- |
|
|
61
|
+
| `callbacks` | Named callbacks `(payload, item) => unknown`. Register in a field initializer so names re-bind on every wake. |
|
|
62
|
+
| `retry` | Default retry policy: `{ maxAttempts: 3, baseDelayMs: 100, maxDelayMs: 3000 }`. See [Retries](./retries.md). |
|
|
63
|
+
| `onError` | Observes an item's terminal failure after its attempts are exhausted. Runs without host context. |
|
|
144
64
|
|
|
145
|
-
|
|
65
|
+
### `push(callback, payload?, options?)`
|
|
146
66
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
67
|
+
Queues one item and returns the `QueueItem`. The item is durable before the
|
|
68
|
+
returned promise resolves, and it runs from the next alarm, so the caller
|
|
69
|
+
never waits for the callback.
|
|
150
70
|
|
|
151
|
-
|
|
71
|
+
- `options.retry` overrides the Queue's retry policy for this item.
|
|
72
|
+
- `options.id` sets a stable id. A push with an existing id replaces that
|
|
73
|
+
item in place, keeping its position in the queue (and superseding a
|
|
74
|
+
dispatch of it still in flight); use it for idempotent enqueues keyed by
|
|
75
|
+
your own identifier.
|
|
152
76
|
|
|
153
|
-
|
|
154
|
-
|
|
77
|
+
Once the Lifecycle has started, the item row is written synchronously before
|
|
78
|
+
`push()` returns its promise, so a push made in the same synchronous block as
|
|
79
|
+
your own SQL writes commits atomically with them.
|
|
155
80
|
|
|
156
|
-
|
|
81
|
+
### `get(id)`, `list(criteria?)`, `cancel(id)`, `cancelAll(callback?)`
|
|
157
82
|
|
|
158
|
-
|
|
83
|
+
`list()` returns pending items in push order; `{ callback }` filters by
|
|
84
|
+
callback name. `cancel()` returns whether an item was removed; `cancelAll()`
|
|
85
|
+
returns how many were.
|
|
159
86
|
|
|
160
|
-
|
|
87
|
+
### QueueItem
|
|
161
88
|
|
|
162
89
|
```typescript
|
|
163
|
-
|
|
164
|
-
|
|
90
|
+
type QueueItem<T = unknown> = {
|
|
91
|
+
id: string; // Unique identifier
|
|
92
|
+
callback: string; // Callback name
|
|
93
|
+
payload: T; // Data passed to the callback
|
|
94
|
+
createdAt: number; // Unix timestamp in seconds
|
|
95
|
+
retry?: RetryOptions; // Resolved retry policy
|
|
96
|
+
};
|
|
165
97
|
```
|
|
166
98
|
|
|
167
|
-
##
|
|
168
|
-
|
|
169
|
-
1. **Validation**: When calling `queue()`, the method validates that the callback exists as a function on the agent
|
|
170
|
-
2. **Automatic Processing**: After queuing, the system automatically attempts to flush the queue
|
|
171
|
-
3. **FIFO Order**: Tasks are processed in the order they were created (`created_at` timestamp)
|
|
172
|
-
4. **Context Preservation**: Each queued task runs with the same agent context (connection, request, email)
|
|
173
|
-
5. **Automatic Retries**: If a callback fails, it is retried with exponential backoff (configurable per task)
|
|
174
|
-
6. **Automatic Dequeue**: Tasks are removed from the queue after successful execution or after all retry attempts are exhausted
|
|
175
|
-
7. **Error Handling**: If a callback method does not exist at execution time, an error is logged and the task is skipped
|
|
176
|
-
8. **Persistence**: Tasks are stored in the `cf_agents_queues` table and survive agent restarts
|
|
99
|
+
## Using the queue through Agent
|
|
177
100
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
When defining callback methods for queued tasks, they must follow this signature:
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
async callbackMethod(payload: unknown, queueItem: QueueItem<string>): Promise<void>
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**Example:**
|
|
101
|
+
`Agent` installs a `Queue` and resolves callback names to its own methods, so
|
|
102
|
+
`this.queue("methodName", payload)` keeps working with no registration:
|
|
187
103
|
|
|
188
104
|
```typescript
|
|
189
105
|
class MyAgent extends Agent {
|
|
190
|
-
async
|
|
191
|
-
payload: {
|
|
192
|
-
|
|
106
|
+
async processEmail(
|
|
107
|
+
payload: { email: string; subject: string },
|
|
108
|
+
item: QueueItem<{ email: string; subject: string }>
|
|
193
109
|
) {
|
|
194
|
-
console.log(`Processing
|
|
195
|
-
console.log(
|
|
196
|
-
`Sending notification to user ${payload.userId}: ${payload.message}`
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
// Your notification logic here
|
|
200
|
-
await this.notificationService.send(payload.userId, payload.message);
|
|
110
|
+
console.log(`Processing ${item.id}: ${payload.subject}`);
|
|
201
111
|
}
|
|
202
112
|
|
|
203
|
-
async
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
message: "Welcome to our platform!"
|
|
113
|
+
async onMessage(message: string) {
|
|
114
|
+
const id = await this.queue("processEmail", {
|
|
115
|
+
email: "user@example.com",
|
|
116
|
+
subject: "Welcome!"
|
|
208
117
|
});
|
|
118
|
+
console.log(`Queued task ${id}`);
|
|
209
119
|
}
|
|
210
120
|
}
|
|
211
121
|
```
|
|
212
122
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
123
|
+
| Method | Description |
|
|
124
|
+
| ------------------------------------ | ------------------------------------------------------------------- |
|
|
125
|
+
| `queue(callback, payload, options?)` | Queue a method by name. Returns the item id. Accepts `retry`, `id`. |
|
|
126
|
+
| `dequeue(id)` | Remove a pending item. Resolves to whether one was removed. |
|
|
127
|
+
| `dequeueAll()` | Remove every pending item. Resolves to the count. |
|
|
128
|
+
| `dequeueAllByCallback(callback)` | Remove every pending item for one callback. Resolves to the count. |
|
|
129
|
+
| `getQueue(id)` | Read a pending item. |
|
|
130
|
+
| `getQueues(key, value)` | Pending items whose payload has `key` equal to `value`. |
|
|
131
|
+
|
|
132
|
+
## How queue processing works
|
|
133
|
+
|
|
134
|
+
1. **Validation**: `queue()` checks the callback exists and validates any
|
|
135
|
+
retry options. Invalid input throws immediately.
|
|
136
|
+
2. **Durable first**: the item is a row in the `cf_agents_jobs` job queue
|
|
137
|
+
before `queue()` resolves. Items created before this capability existed
|
|
138
|
+
are migrated out of the old `cf_agents_queues` table on the next start.
|
|
139
|
+
3. **Alarm-driven**: every push re-arms the Durable Object alarm. The
|
|
140
|
+
Lifecycle event loop runs due items in push order, awaiting each callback
|
|
141
|
+
before starting the next, in a fresh invocation rather than the request
|
|
142
|
+
that queued them.
|
|
143
|
+
4. **Retries**: a throwing callback is retried with exponential backoff per
|
|
144
|
+
its retry policy, emitting `queue:retry` on each extra attempt.
|
|
145
|
+
5. **Terminal failure**: after the last attempt the item is dropped, a
|
|
146
|
+
`queue:error` event is emitted, and Agent's `onError` (or the Queue's
|
|
147
|
+
`onError` option) observes the error.
|
|
148
|
+
6. **Recovery**: an isolate that dies mid-callback wakes again on the
|
|
149
|
+
Lifecycle deadman alarm and resumes the queue, so callbacks should be
|
|
150
|
+
idempotent.
|
|
151
|
+
|
|
152
|
+
## Use cases
|
|
153
|
+
|
|
154
|
+
Queue work that must not block the current request or WebSocket message:
|
|
216
155
|
|
|
217
156
|
```typescript
|
|
218
157
|
class DataProcessor extends Agent {
|
|
@@ -221,52 +160,31 @@ class DataProcessor extends Agent {
|
|
|
221
160
|
await this.notifyUser(data.userId, results);
|
|
222
161
|
}
|
|
223
162
|
|
|
224
|
-
async onDataUpload(uploadData:
|
|
225
|
-
// Queue the processing instead of doing it synchronously
|
|
163
|
+
async onDataUpload(uploadData: { id: string; userId: string }) {
|
|
226
164
|
await this.queue("processLargeDataset", {
|
|
227
165
|
datasetId: uploadData.id,
|
|
228
166
|
userId: uploadData.userId
|
|
229
167
|
});
|
|
230
|
-
|
|
231
168
|
return { message: "Data upload received, processing started" };
|
|
232
169
|
}
|
|
233
170
|
}
|
|
234
171
|
```
|
|
235
172
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
class ReminderAgent extends Agent {
|
|
240
|
-
async sendReminder(data: { userId: string; message: string }) {
|
|
241
|
-
await this.emailService.send(data.userId, data.message);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async scheduleReminder(userId: string, message: string, delayMs: number) {
|
|
245
|
-
// Note: For true delayed execution, combine with the scheduling system
|
|
246
|
-
// This example shows queueing for later processing
|
|
247
|
-
await this.queue("sendReminder", { userId, message });
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Batch Operations
|
|
173
|
+
Split large requests into batches that run one after another:
|
|
253
174
|
|
|
254
175
|
```typescript
|
|
255
176
|
class BatchProcessor extends Agent {
|
|
256
|
-
async processBatch(data: { items:
|
|
177
|
+
async processBatch(data: { items: unknown[]; batchId: string }) {
|
|
257
178
|
for (const item of data.items) {
|
|
258
179
|
await this.processItem(item);
|
|
259
180
|
}
|
|
260
|
-
console.log(`Completed batch ${data.batchId}`);
|
|
261
181
|
}
|
|
262
182
|
|
|
263
|
-
async onLargeRequest(items:
|
|
264
|
-
// Split large requests into smaller batches
|
|
183
|
+
async onLargeRequest(items: unknown[]) {
|
|
265
184
|
const batchSize = 10;
|
|
266
185
|
for (let i = 0; i < items.length; i += batchSize) {
|
|
267
|
-
const batch = items.slice(i, i + batchSize);
|
|
268
186
|
await this.queue("processBatch", {
|
|
269
|
-
items:
|
|
187
|
+
items: items.slice(i, i + batchSize),
|
|
270
188
|
batchId: `batch-${i / batchSize + 1}`
|
|
271
189
|
});
|
|
272
190
|
}
|
|
@@ -274,56 +192,32 @@ class BatchProcessor extends Agent {
|
|
|
274
192
|
}
|
|
275
193
|
```
|
|
276
194
|
|
|
277
|
-
|
|
195
|
+
For work that should run at a specific time or on a schedule, use
|
|
196
|
+
[Scheduling](./scheduling.md) instead. Both ride the same Lifecycle job queue.
|
|
278
197
|
|
|
279
|
-
|
|
280
|
-
2. **Idempotent Operations**: Design callback methods to be safe to retry
|
|
281
|
-
3. **Error Handling**: Include proper error handling in callback methods
|
|
282
|
-
4. **Monitoring**: Use logging to track queue processing
|
|
283
|
-
5. **Cleanup**: Regularly clean up completed or failed tasks if needed
|
|
198
|
+
## Best practices
|
|
284
199
|
|
|
285
|
-
|
|
200
|
+
1. **Keep payloads small**: payloads are JSON-serialized into the job row.
|
|
201
|
+
2. **Idempotent callbacks**: an item can run again after an isolate reset.
|
|
202
|
+
3. **Bounded callbacks**: the event loop awaits each callback, so a long one
|
|
203
|
+
delays every other job on the object. Detach unbounded work and return.
|
|
204
|
+
4. **Stable ids for dedupe**: pass `id` when the same logical task may be
|
|
205
|
+
queued more than once.
|
|
286
206
|
|
|
287
|
-
|
|
207
|
+
## Error handling and retries
|
|
288
208
|
|
|
289
209
|
```typescript
|
|
290
|
-
// Retry up to 5 times with custom backoff
|
|
291
210
|
await this.queue("reliableTask", payload, {
|
|
292
211
|
retry: { maxAttempts: 5, baseDelayMs: 500 }
|
|
293
212
|
});
|
|
294
213
|
```
|
|
295
214
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
class RobustAgent extends Agent {
|
|
300
|
-
async reliableTask(payload: { data: string }, queueItem: QueueItem<string>) {
|
|
301
|
-
try {
|
|
302
|
-
await this.doSomethingRisky(payload);
|
|
303
|
-
} catch (error) {
|
|
304
|
-
console.error(`Task ${queueItem.id} failed:`, error);
|
|
305
|
-
// The retry system will catch this error and retry automatically
|
|
306
|
-
throw error;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
See [Retries](./retries.md) for full documentation on retry options and patterns.
|
|
313
|
-
|
|
314
|
-
## Integration with Other Features
|
|
315
|
-
|
|
316
|
-
The queue system works seamlessly with other Agent SDK features:
|
|
317
|
-
|
|
318
|
-
- **State Management**: Access agent state within queued callbacks
|
|
319
|
-
- **Scheduling**: Combine with `schedule()` for time-based queue processing
|
|
320
|
-
- **Retries**: Built-in retry with exponential backoff. See [Retries](./retries.md).
|
|
321
|
-
- **Context**: Queued tasks maintain the original request context
|
|
322
|
-
- **Database**: Uses the same database as other agent data
|
|
215
|
+
See [Retries](./retries.md) for full documentation on retry options, and
|
|
216
|
+
[Observability](./observability.md) for the `queue:create`, `queue:retry`,
|
|
217
|
+
and `queue:error` events.
|
|
323
218
|
|
|
324
219
|
## Limitations
|
|
325
220
|
|
|
326
|
-
-
|
|
327
|
-
- No priority system (FIFO only)
|
|
328
|
-
-
|
|
329
|
-
- Failed tasks are dequeued after all retry attempts are exhausted (no dead-letter queue)
|
|
221
|
+
- Items run sequentially, not in parallel.
|
|
222
|
+
- No priority system (FIFO only).
|
|
223
|
+
- Failed items are dropped after all retry attempts (no dead-letter queue).
|
|
@@ -70,7 +70,7 @@ function Chat() {
|
|
|
70
70
|
- Chunks are batched (every 10 chunks) and flushed to SQLite for performance
|
|
71
71
|
- When a client sends `CF_AGENT_STREAM_RESUME_REQUEST`, the server checks for active streams and responds with `CF_AGENT_STREAM_RESUMING`
|
|
72
72
|
- Stale streams (older than 5 minutes) are cleaned up on restore
|
|
73
|
-
- Stream buffers are
|
|
73
|
+
- Stream buffers are deleted in the same transaction that persists the assistant message (the cutover), so a finished turn leaves nothing behind and no cleanup alarm is armed. A buffer a crash left behind is reclaimed when the next stream starts: finished streams immediately, abandoned in-flight streams after 1 hour without a chunk (recovery has until then to rebuild the message from it)
|
|
74
74
|
|
|
75
75
|
### Client-side (`useAgentChat`)
|
|
76
76
|
|
package/docs/retries.md
CHANGED
|
@@ -188,7 +188,7 @@ await this.queue("processWebhook", webhookData, {
|
|
|
188
188
|
});
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
-
If the callback throws, it is retried before the
|
|
191
|
+
If the callback throws, it is retried before the item is removed. After all attempts are exhausted, the item is dropped, a `queue:error` event is emitted, and the error is logged.
|
|
192
192
|
|
|
193
193
|
## Validation
|
|
194
194
|
|
package/docs/routing.md
CHANGED
|
@@ -601,6 +601,94 @@ Each agent is accessed via its own path:
|
|
|
601
601
|
|
|
602
602
|
---
|
|
603
603
|
|
|
604
|
+
## Routing to independent Agents
|
|
605
|
+
|
|
606
|
+
A hub Agent often owns an open-ended set of independent peers: one Durable Object per chat, document, or session for a user. `RoutedAgents` from `agents/routing` codifies that topology as a Lifecycle capability. The hub keeps a durable catalog of public IDs mapped to opaque physical names, and forwards requests under one route segment to the selected Agent:
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
import { Agent, callable, routeAgentRequest } from "agents";
|
|
610
|
+
import { RoutedAgents } from "agents/routing";
|
|
611
|
+
|
|
612
|
+
export class ChatAgent extends Agent<Env> {
|
|
613
|
+
// An ordinary top-level Agent: its own storage, alarms, and placement.
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
export class UserAgent extends Agent<Env> {
|
|
617
|
+
readonly chats = new RoutedAgents<ChatAgent, { title: string }>({
|
|
618
|
+
namespace: this.env.ChatAgent,
|
|
619
|
+
route: "chats"
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
constructor(ctx: DurableObjectState, env: Env) {
|
|
623
|
+
super(ctx, env);
|
|
624
|
+
this.lifecycle.use(this.chats);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
@callable()
|
|
628
|
+
createChat(title: string) {
|
|
629
|
+
return this.chats.create({ metadata: { title } });
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
@callable()
|
|
633
|
+
listChats() {
|
|
634
|
+
return this.chats.list();
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
@callable()
|
|
638
|
+
deleteChat(id: string) {
|
|
639
|
+
return this.chats.delete(id);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
export default {
|
|
644
|
+
async fetch(request: Request, env: Env) {
|
|
645
|
+
// Routes both /agents/user-agent/{id} and the forwarded
|
|
646
|
+
// /agents/user-agent/{id}/chats/{id}/... paths — RoutedAgents claims
|
|
647
|
+
// the latter from inside UserAgent once the request reaches it.
|
|
648
|
+
return (
|
|
649
|
+
(await routeAgentRequest(request, env)) ??
|
|
650
|
+
new Response("Not found", { status: 404 })
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
} satisfies ExportedHandler<Env>;
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
The client keeps one connection to the hub and one to the active chat, both addressed through the hub:
|
|
657
|
+
|
|
658
|
+
```
|
|
659
|
+
/agents/user-agent/alice -> UserAgent "alice"
|
|
660
|
+
/agents/user-agent/alice/chats/{id} -> the ChatAgent behind that entry
|
|
661
|
+
/agents/user-agent/alice/chats/{id}/... -> same ChatAgent, suffix preserved
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
```tsx
|
|
665
|
+
const user = useAgent({ agent: "UserAgent", name: "alice" });
|
|
666
|
+
const chat = useAgent({
|
|
667
|
+
agent: "ChatAgent",
|
|
668
|
+
basePath: `agents/user-agent/alice/chats/${encodeURIComponent(chatId)}`
|
|
669
|
+
});
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
What the capability guarantees:
|
|
673
|
+
|
|
674
|
+
- `create()`, `list()`, and `setMetadata()` touch only the hub's SQLite. No target wakes.
|
|
675
|
+
- `list()` orders most-recently-updated first, ties broken by write order rather than by the random entry ID. Each write scans the route's own entries to derive that order — an intentional trade for a route sized like one owner's own catalog, not a route meant to hold thousands of entries.
|
|
676
|
+
- `get(id)` returns an initialized, typed stub for RPC, or `null` for an unknown or deleted ID.
|
|
677
|
+
- A WebSocket upgrade is answered by the target, which then owns the socket. Chat frames never wake the hub. This is the same two-socket shape as connecting to the chat directly, but the hub stays the authority that resolves an ID, so it can gate, migrate, or redirect entries later.
|
|
678
|
+
- `delete(id)` hides the entry first, condemns the target, then removes the row. The target wipes its own storage on its next wake, moments later, and the condemned marker survives interruption. A failed call leaves a hidden row, and calling `delete` again retries.
|
|
679
|
+
- Physical names are random UUIDs that never leave the hub. Clients only ever see entry IDs.
|
|
680
|
+
- `namespace` is any `DurableObjectNamespace`, including a binding to a class exported by another Worker via `script_name`, so the hub and its targets can be deployed and scaled independently.
|
|
681
|
+
- Destroying the hub retries condemning every remaining entry before its own storage is wiped, but this is best-effort: the platform wipes the hub's storage right after disposal regardless of outcome, so a target that is still unreachable after retries is orphaned, with no catalog row left to retry from later.
|
|
682
|
+
|
|
683
|
+
The catalog stores existence, ownership, and application metadata. Conversation data stays in the target, and a target that needs its hub calls back with `getAgentByName(this.env.UserAgent, ownerName)`. When to prefer this over facets is covered in [Dynamic agents](./sub-agents.md#when-to-use-dynamic-agents).
|
|
684
|
+
|
|
685
|
+
Two sharp edges to design around:
|
|
686
|
+
|
|
687
|
+
- **Pick a route that can't collide.** Forwarding matches every occurrence of the route segment anywhere in the path, so if the hub's own name, class, or another one of its own routes is also literally `"chats"`, a coincidental match with no active entry behind it returns `404` instead of reaching the hub's own handler for that path.
|
|
688
|
+
- **A routed suffix can't address a target's own dynamic agents.** `Agent.fetch()` resolves a `/sub/{class}/{name}` marker against the _hub's_ exported classes before this capability's request handling ever runs, so `/chats/{id}/sub/{class}/{name}` is served as a facet of the hub, not forwarded to the chat. Reach a target's dynamic agents through a direct connection to that target instead of through the hub's route.
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
604
692
|
## Routing with Authentication
|
|
605
693
|
|
|
606
694
|
Check authentication before routing to agents:
|
|
@@ -737,6 +825,23 @@ Get an agent instance by name for server-side RPC or request forwarding.
|
|
|
737
825
|
|
|
738
826
|
**Returns:** `Promise<DurableObjectStub<T>>` - Typed stub for calling agent methods or forwarding requests
|
|
739
827
|
|
|
828
|
+
### `new RoutedAgents(options)` (from `agents/routing`)
|
|
829
|
+
|
|
830
|
+
A Lifecycle capability installed on a hub Agent with `this.lifecycle.use(...)`. See [Routing to independent Agents](#routing-to-independent-agents).
|
|
831
|
+
|
|
832
|
+
| Parameter | Type | Description |
|
|
833
|
+
| ------------------- | --------------------------- | ------------------------------------------------ |
|
|
834
|
+
| `options.namespace` | `DurableObjectNamespace<T>` | Target binding the entries are created in |
|
|
835
|
+
| `options.route` | `string` | One URL-safe path segment this capability claims |
|
|
836
|
+
|
|
837
|
+
| Method | Returns | Description |
|
|
838
|
+
| --------------------------- | ---------------------------------------------------- | ----------------------------------------------------- |
|
|
839
|
+
| `create(options?)` | `Promise<RoutedAgentEntry<Metadata>>` | Create an entry without waking the target |
|
|
840
|
+
| `get(id)` | `Promise<DurableObjectStub<T> \| null>` | Resolve an active entry to an initialized stub |
|
|
841
|
+
| `list()` | `Promise<ReadonlyArray<RoutedAgentEntry<Metadata>>>` | Active entries, most recently updated first |
|
|
842
|
+
| `setMetadata(id, metadata)` | `Promise<boolean>` | Replace an active entry's metadata |
|
|
843
|
+
| `delete(id)` | `Promise<boolean>` | Hide the entry, condemn the target, then drop the row |
|
|
844
|
+
|
|
740
845
|
### `useAgent(options)` / `AgentClient` Options
|
|
741
846
|
|
|
742
847
|
Client connection options:
|