agents 0.16.2 → 0.17.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.
Files changed (122) hide show
  1. package/README.md +11 -8
  2. package/dist/{agent-tool-types-CTw3UJUP.d.ts → agent-tool-types-Cd1TZPfB.d.ts} +587 -137
  3. package/dist/agent-tool-types.d.ts +34 -18
  4. package/dist/agent-tool-types.js +20 -1
  5. package/dist/agent-tool-types.js.map +1 -0
  6. package/dist/agent-tools-BXlsuX0d.js +304 -0
  7. package/dist/agent-tools-BXlsuX0d.js.map +1 -0
  8. package/dist/agent-tools-_E8wxUIK.d.ts +119 -0
  9. package/dist/agent-tools.d.ts +24 -18
  10. package/dist/agent-tools.js.map +1 -1
  11. package/dist/ai-chat-agent.d.ts +1 -1
  12. package/dist/ai-chat-agent.js +1 -2
  13. package/dist/ai-chat-agent.js.map +1 -1
  14. package/dist/ai-chat-v5-migration.d.ts +1 -1
  15. package/dist/ai-chat-v5-migration.js +1 -2
  16. package/dist/ai-chat-v5-migration.js.map +1 -1
  17. package/dist/ai-react.d.ts +1 -1
  18. package/dist/ai-react.js +1 -2
  19. package/dist/ai-react.js.map +1 -1
  20. package/dist/ai-types.d.ts +1 -7
  21. package/dist/ai-types.js +2 -8
  22. package/dist/ai-types.js.map +1 -1
  23. package/dist/browser/ai.js +1 -1
  24. package/dist/browser/index.js +1 -1
  25. package/dist/chat/index.d.ts +1918 -72
  26. package/dist/chat/index.js +1730 -245
  27. package/dist/chat/index.js.map +1 -1
  28. package/dist/chat/react.d.ts +602 -0
  29. package/dist/chat/react.js +1506 -0
  30. package/dist/chat/react.js.map +1 -0
  31. package/dist/chat-sdk/index.d.ts +4 -4
  32. package/dist/{classPrivateFieldGet2-CZ7QjTXN.js → classPrivateFieldGet2-DZBYAB34.js} +5 -5
  33. package/dist/{classPrivateMethodInitSpec-D-0__zd9.js → classPrivateMethodInitSpec-qMjJ6sHQ.js} +2 -2
  34. package/dist/{client-BXJ9n2f7.js → client-BZ-B3NhC.js} +2 -2
  35. package/dist/client-BZ-B3NhC.js.map +1 -0
  36. package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
  37. package/dist/client.d.ts +76 -57
  38. package/dist/client.js +33 -5
  39. package/dist/client.js.map +1 -1
  40. package/dist/{connector-CrKhowfD.js → connector-CdldGF3h.js} +5 -5
  41. package/dist/{connector-CrKhowfD.js.map → connector-CdldGF3h.js.map} +1 -1
  42. package/dist/email.js +1 -1
  43. package/dist/email.js.map +1 -1
  44. package/dist/{index-B7IbEeze.d.ts → index-CcbnKkNh.d.ts} +188 -14
  45. package/dist/index.d.ts +91 -71
  46. package/dist/index.js +562 -24
  47. package/dist/index.js.map +1 -1
  48. package/dist/mcp/client.d.ts +18 -14
  49. package/dist/mcp/client.js +1 -1
  50. package/dist/mcp/index.d.ts +30 -30
  51. package/dist/mcp/index.js +7 -7
  52. package/dist/mcp/index.js.map +1 -1
  53. package/dist/{agent-tools-3zLG7MgA.js → message-builder-BymO4N_D.js} +45 -126
  54. package/dist/message-builder-BymO4N_D.js.map +1 -0
  55. package/dist/observability/index.d.ts +1 -1
  56. package/dist/observability/index.js +4 -2
  57. package/dist/observability/index.js.map +1 -1
  58. package/dist/react.d.ts +123 -110
  59. package/dist/react.js +44 -11
  60. package/dist/react.js.map +1 -1
  61. package/dist/serializable.d.ts +1 -1
  62. package/dist/skills/compile.js +1 -1
  63. package/dist/skills/compile.js.map +1 -1
  64. package/dist/skills/index.js +5 -5
  65. package/dist/skills/index.js.map +1 -1
  66. package/dist/sub-routing.d.ts +6 -6
  67. package/dist/utils.js +1 -1
  68. package/dist/utils.js.map +1 -1
  69. package/dist/vite.js +5 -5
  70. package/dist/vite.js.map +1 -1
  71. package/dist/wire-types-nflOzNuU.js +240 -0
  72. package/dist/wire-types-nflOzNuU.js.map +1 -0
  73. package/dist/{workflow-types-SrZK_o9p.d.ts → workflow-types-Baz_PO5v.d.ts} +42 -22
  74. package/dist/workflow-types.d.ts +25 -21
  75. package/dist/workflow-types.js.map +1 -1
  76. package/dist/workflows.d.ts +22 -21
  77. package/dist/workflows.js +31 -7
  78. package/dist/workflows.js.map +1 -1
  79. package/docs/adding-to-existing-project.md +450 -0
  80. package/docs/agent-class.md +503 -0
  81. package/docs/agent-tools.md +552 -0
  82. package/docs/browse-the-web.md +430 -0
  83. package/docs/callable-methods.md +627 -0
  84. package/docs/chat-agents.md +1687 -0
  85. package/docs/chat-sdk.md +181 -0
  86. package/docs/client-sdk.md +520 -0
  87. package/docs/client-tools-continuation.md +177 -0
  88. package/docs/codemode.md +440 -0
  89. package/docs/configuration.md +775 -0
  90. package/docs/cross-domain-authentication.md +171 -0
  91. package/docs/durable-execution.md +537 -0
  92. package/docs/email.md +663 -0
  93. package/docs/get-current-agent.md +204 -0
  94. package/docs/getting-started.md +305 -0
  95. package/docs/http-websockets.md +668 -0
  96. package/docs/human-in-the-loop.md +661 -0
  97. package/docs/index.md +151 -0
  98. package/docs/long-running-agents.md +730 -0
  99. package/docs/mcp-client.md +620 -0
  100. package/docs/mcp-servers.md +526 -0
  101. package/docs/mcp-transports.md +308 -0
  102. package/docs/migration-to-ai-sdk-v5.md +96 -0
  103. package/docs/migration-to-ai-sdk-v6.md +163 -0
  104. package/docs/observability.md +261 -0
  105. package/docs/push-notifications.md +367 -0
  106. package/docs/queue.md +329 -0
  107. package/docs/readonly-connections.md +278 -0
  108. package/docs/resumable-streaming.md +127 -0
  109. package/docs/retries.md +444 -0
  110. package/docs/routing.md +749 -0
  111. package/docs/scheduling.md +898 -0
  112. package/docs/securing-mcp-servers.md +359 -0
  113. package/docs/server-driven-messages.md +477 -0
  114. package/docs/sessions.md +1024 -0
  115. package/docs/state.md +512 -0
  116. package/docs/sub-agents.md +389 -0
  117. package/docs/webhooks.md +604 -0
  118. package/docs/workflows.md +877 -0
  119. package/package.json +41 -14
  120. package/dist/agent-tools-3zLG7MgA.js.map +0 -1
  121. package/dist/agent-tools-DZhI5F6Q.d.ts +0 -14
  122. package/dist/client-BXJ9n2f7.js.map +0 -1
@@ -0,0 +1,627 @@
1
+ # Callable Methods
2
+
3
+ Callable methods let clients invoke agent methods over WebSocket using RPC (Remote Procedure Call). Mark methods with `@callable()` to expose them to external clients like browsers, mobile apps, or other services.
4
+
5
+ ## Overview
6
+
7
+ ```typescript
8
+ import { Agent, callable } from "agents";
9
+
10
+ export class MyAgent extends Agent {
11
+ @callable()
12
+ async greet(name: string): Promise<string> {
13
+ return `Hello, ${name}!`;
14
+ }
15
+ }
16
+ ```
17
+
18
+ ```typescript
19
+ // Client
20
+ const result = await agent.stub.greet("World");
21
+ console.log(result); // "Hello, World!"
22
+ ```
23
+
24
+ ### How It Works
25
+
26
+ ```
27
+ ┌─────────┐ ┌─────────┐
28
+ │ Client │ │ Agent │
29
+ └────┬────┘ └────┬────┘
30
+ │ │
31
+ │ agent.stub.greet("World") │
32
+ │ ──────────────────────────────────▶ │
33
+ │ WebSocket RPC message │
34
+ │ │
35
+ │ Check @callable
36
+ │ Execute method
37
+ │ │
38
+ │ ◀──────────────────────────────── │
39
+ │ "Hello, World!" │
40
+ │ │
41
+ ```
42
+
43
+ ### When to Use @callable
44
+
45
+ | Scenario | Use |
46
+ | ------------------------------------ | ----------------------------- |
47
+ | Browser/mobile calling agent | `@callable()` |
48
+ | External service calling agent | `@callable()` |
49
+ | Worker calling agent (same codebase) | DO RPC (no decorator needed) |
50
+ | Agent calling another agent | DO RPC via `getAgentByName()` |
51
+
52
+ The `@callable()` decorator is specifically for WebSocket-based RPC from external clients. When calling from within the same Worker or another agent, use standard [Durable Object RPC](https://developers.cloudflare.com/durable-objects/best-practices/create-durable-object-stubs-and-send-requests/) directly.
53
+
54
+ ## TypeScript and Vite Configuration
55
+
56
+ The `@callable()` decorator uses TC39 standard decorators, which require two build-time configurations:
57
+
58
+ **1. Add the `agents/vite` plugin** — Vite 8 uses Oxc for transpilation, which does not yet support TC39 decorators ([oxc#9170](https://github.com/oxc-project/oxc/issues/9170)). The plugin adds the required Babel transform:
59
+
60
+ ```typescript
61
+ // vite.config.ts
62
+ import agents from "agents/vite";
63
+
64
+ export default defineConfig({
65
+ plugins: [agents(), react(), cloudflare()]
66
+ });
67
+ ```
68
+
69
+ The plugin only runs the transform on files containing `@` syntax. It is safe to include even if you do not use decorators.
70
+
71
+ **2. Extend `agents/tsconfig`** — this sets `target: "ES2021"` and all other recommended compiler options:
72
+
73
+ ```json
74
+ {
75
+ "extends": "agents/tsconfig"
76
+ }
77
+ ```
78
+
79
+ If you cannot extend the shared config, set `"target": "ES2021"` manually in your `tsconfig.json`.
80
+
81
+ Without both of these, your dev server will fail with `SyntaxError: Invalid or unexpected token`.
82
+
83
+ > **Warning:** Do not set `"experimentalDecorators": true` in your `tsconfig.json`. The Agents SDK uses [TC39 standard decorators](https://github.com/tc39/proposal-decorators), not TypeScript legacy decorators. Enabling `experimentalDecorators` applies an incompatible transform that silently breaks `@callable()` at runtime.
84
+
85
+ ## Basic Usage
86
+
87
+ ### Defining Callable Methods
88
+
89
+ Add the `@callable()` decorator to any method you want to expose:
90
+
91
+ ```typescript
92
+ import { Agent, callable } from "agents";
93
+
94
+ type State = {
95
+ count: number;
96
+ items: string[];
97
+ };
98
+
99
+ export class CounterAgent extends Agent<Env, State> {
100
+ initialState: State = { count: 0, items: [] };
101
+
102
+ @callable()
103
+ increment(): number {
104
+ this.setState({ ...this.state, count: this.state.count + 1 });
105
+ return this.state.count;
106
+ }
107
+
108
+ @callable()
109
+ decrement(): number {
110
+ this.setState({ ...this.state, count: this.state.count - 1 });
111
+ return this.state.count;
112
+ }
113
+
114
+ @callable()
115
+ async addItem(item: string): Promise<string[]> {
116
+ this.setState({ ...this.state, items: [...this.state.items, item] });
117
+ return this.state.items;
118
+ }
119
+
120
+ @callable()
121
+ getStats(): { count: number; itemCount: number } {
122
+ return {
123
+ count: this.state.count,
124
+ itemCount: this.state.items.length
125
+ };
126
+ }
127
+ }
128
+ ```
129
+
130
+ ### Calling from the Client
131
+
132
+ There are two ways to call methods from the client:
133
+
134
+ **Using `agent.stub` (recommended):**
135
+
136
+ ```typescript
137
+ // Clean, typed syntax
138
+ const count = await agent.stub.increment();
139
+ const items = await agent.stub.addItem("new item");
140
+ const stats = await agent.stub.getStats();
141
+ ```
142
+
143
+ **Using `agent.call()`:**
144
+
145
+ ```typescript
146
+ // Explicit method name as string
147
+ const count = await agent.call("increment");
148
+ const items = await agent.call("addItem", ["new item"]);
149
+ const stats = await agent.call("getStats");
150
+ ```
151
+
152
+ The `stub` proxy provides better ergonomics and TypeScript support.
153
+
154
+ ## Method Signatures
155
+
156
+ ### Serializable Types
157
+
158
+ Arguments and return values must be JSON-serializable:
159
+
160
+ ```typescript
161
+ // ✅ Valid - primitives and plain objects
162
+ @callable()
163
+ processData(input: { name: string; count: number }): { result: boolean } {
164
+ return { result: true };
165
+ }
166
+
167
+ // ✅ Valid - arrays
168
+ @callable()
169
+ processItems(items: string[]): number[] {
170
+ return items.map(item => item.length);
171
+ }
172
+
173
+ // ❌ Invalid - non-serializable types
174
+ @callable()
175
+ badMethod(fn: Function, date: Date): Map<string, unknown> {
176
+ // Functions, Dates, Maps, Sets, etc. cannot be serialized
177
+ }
178
+ ```
179
+
180
+ ### Async Methods
181
+
182
+ Both sync and async methods work:
183
+
184
+ ```typescript
185
+ // Sync method
186
+ @callable()
187
+ add(a: number, b: number): number {
188
+ return a + b;
189
+ }
190
+
191
+ // Async method
192
+ @callable()
193
+ async fetchUser(id: string): Promise<User> {
194
+ const user = await this.sql`SELECT * FROM users WHERE id = ${id}`;
195
+ return user[0];
196
+ }
197
+ ```
198
+
199
+ ### Void Methods
200
+
201
+ Methods that don't return a value:
202
+
203
+ ```typescript
204
+ @callable()
205
+ async logEvent(event: string): Promise<void> {
206
+ await this.sql`INSERT INTO events (name) VALUES (${event})`;
207
+ }
208
+ ```
209
+
210
+ On the client, these still return a Promise that resolves when the method completes:
211
+
212
+ ```typescript
213
+ await agent.stub.logEvent("user-clicked");
214
+ // Resolves when the server confirms execution
215
+ ```
216
+
217
+ ## Streaming Responses
218
+
219
+ For methods that produce data over time (like AI text generation), use streaming:
220
+
221
+ ### Defining a Streaming Method
222
+
223
+ ```typescript
224
+ import { Agent, callable, type StreamingResponse } from "agents";
225
+
226
+ export class AIAgent extends Agent {
227
+ @callable({ streaming: true })
228
+ async generateText(stream: StreamingResponse, prompt: string) {
229
+ // First parameter is always StreamingResponse for streaming methods
230
+
231
+ for await (const chunk of this.llm.stream(prompt)) {
232
+ stream.send(chunk); // Send each chunk to the client
233
+ }
234
+
235
+ stream.end(); // Signal completion
236
+ }
237
+
238
+ @callable({ streaming: true })
239
+ async streamNumbers(stream: StreamingResponse, count: number) {
240
+ for (let i = 0; i < count; i++) {
241
+ stream.send(i);
242
+ await new Promise((resolve) => setTimeout(resolve, 100));
243
+ }
244
+ stream.end(count); // Optional final value
245
+ }
246
+ }
247
+ ```
248
+
249
+ ### Consuming Streams on the Client
250
+
251
+ ```typescript
252
+ // Preferred format (supports timeout and other options)
253
+ await agent.call("generateText", [prompt], {
254
+ stream: {
255
+ onChunk: (chunk) => {
256
+ // Called for each chunk
257
+ appendToOutput(chunk);
258
+ },
259
+ onDone: (finalValue) => {
260
+ // Called when stream ends
261
+ console.log("Stream complete", finalValue);
262
+ },
263
+ onError: (error) => {
264
+ // Called if an error occurs
265
+ console.error("Stream error:", error);
266
+ }
267
+ }
268
+ });
269
+
270
+ // Legacy format (still supported for backward compatibility)
271
+ await agent.call("generateText", [prompt], {
272
+ onChunk: (chunk) => appendToOutput(chunk),
273
+ onDone: (finalValue) => console.log("Done", finalValue),
274
+ onError: (error) => console.error("Error:", error)
275
+ });
276
+ ```
277
+
278
+ ### StreamingResponse API
279
+
280
+ | Method | Description |
281
+ | ------------------ | ------------------------------------------------ |
282
+ | `send(chunk)` | Send a chunk to the client |
283
+ | `end(finalChunk?)` | End the stream, optionally with a final value |
284
+ | `error(message)` | Send an error to the client and close the stream |
285
+
286
+ ```typescript
287
+ @callable({ streaming: true })
288
+ async processWithProgress(stream: StreamingResponse, items: string[]) {
289
+ for (let i = 0; i < items.length; i++) {
290
+ await this.process(items[i]);
291
+ stream.send({ progress: (i + 1) / items.length, item: items[i] });
292
+ }
293
+ stream.end({ completed: true, total: items.length });
294
+ }
295
+ ```
296
+
297
+ ## TypeScript Integration
298
+
299
+ ### Typed Client Calls
300
+
301
+ Pass your agent class as a type parameter for full type safety:
302
+
303
+ ```typescript
304
+ import { useAgent } from "agents/react";
305
+ import type { MyAgent } from "./server";
306
+
307
+ function App() {
308
+ const agent = useAgent<MyAgent, MyState>({
309
+ agent: "MyAgent",
310
+ name: "default"
311
+ });
312
+
313
+ // ✅ TypeScript knows the method signature
314
+ const result = await agent.stub.greet("World");
315
+ // ^? string
316
+
317
+ // ✅ TypeScript catches errors
318
+ await agent.stub.greet(123); // Error: Argument of type 'number' is not assignable
319
+ await agent.stub.nonExistent(); // Error: Property 'nonExistent' does not exist
320
+ }
321
+ ```
322
+
323
+ ### Excluding Non-Callable Methods
324
+
325
+ If you have methods that aren't decorated with `@callable()`, you can exclude them from the type:
326
+
327
+ ```typescript
328
+ class MyAgent extends Agent {
329
+ @callable()
330
+ publicMethod(): string {
331
+ return "public";
332
+ }
333
+
334
+ // Not callable from clients
335
+ internalMethod(): void {
336
+ // internal logic
337
+ }
338
+ }
339
+
340
+ // Exclude internal methods from the client type
341
+ const agent = useAgent<Omit<MyAgent, "internalMethod">, {}>({
342
+ agent: "MyAgent"
343
+ });
344
+
345
+ agent.stub.publicMethod(); // ✅ Works
346
+ agent.stub.internalMethod(); // ✅ TypeScript error
347
+ ```
348
+
349
+ ### Type Inference for State
350
+
351
+ When methods return `this.state`, TypeScript correctly infers the type:
352
+
353
+ ```typescript
354
+ type MyState = { count: number; name: string };
355
+
356
+ class MyAgent extends Agent<Env, MyState> {
357
+ @callable()
358
+ async getState(): Promise<MyState> {
359
+ return this.state;
360
+ }
361
+ }
362
+
363
+ // Client
364
+ const state = await agent.stub.getState();
365
+ // ^? MyState
366
+ ```
367
+
368
+ ## Error Handling
369
+
370
+ ### Throwing Errors in Callable Methods
371
+
372
+ Errors thrown in callable methods are propagated to the client:
373
+
374
+ ```typescript
375
+ @callable()
376
+ async riskyOperation(data: unknown): Promise<void> {
377
+ if (!isValid(data)) {
378
+ throw new Error("Invalid data format");
379
+ }
380
+
381
+ try {
382
+ await this.processData(data);
383
+ } catch (e) {
384
+ throw new Error("Processing failed: " + e.message);
385
+ }
386
+ }
387
+ ```
388
+
389
+ ### Client-Side Error Handling
390
+
391
+ ```typescript
392
+ try {
393
+ const result = await agent.stub.riskyOperation(data);
394
+ } catch (error) {
395
+ // Error thrown by the agent method
396
+ console.error("RPC failed:", error.message);
397
+ }
398
+ ```
399
+
400
+ ### Streaming Error Handling
401
+
402
+ For streaming methods, use the `onError` callback:
403
+
404
+ ```typescript
405
+ await agent.call("streamData", [input], {
406
+ stream: {
407
+ onChunk: (chunk) => handleChunk(chunk),
408
+ onError: (errorMessage) => {
409
+ console.error("Stream error:", errorMessage);
410
+ showErrorUI(errorMessage);
411
+ },
412
+ onDone: (result) => handleComplete(result)
413
+ }
414
+ });
415
+ ```
416
+
417
+ Server-side, you can use `stream.error()` to gracefully send an error mid-stream:
418
+
419
+ ```typescript
420
+ @callable({ streaming: true })
421
+ async processItems(stream: StreamingResponse, items: string[]) {
422
+ for (const item of items) {
423
+ try {
424
+ const result = await this.process(item);
425
+ stream.send(result);
426
+ } catch (e) {
427
+ stream.error(`Failed to process ${item}: ${e.message}`);
428
+ return; // Stream is now closed
429
+ }
430
+ }
431
+ stream.end();
432
+ }
433
+ ```
434
+
435
+ ### Connection Errors
436
+
437
+ If the WebSocket connection closes while RPC calls are pending, they automatically reject with a "Connection closed" error:
438
+
439
+ ```typescript
440
+ try {
441
+ const result = await agent.call("longRunningMethod", []);
442
+ } catch (error) {
443
+ if (error.message === "Connection closed") {
444
+ // Handle disconnection
445
+ console.log("Lost connection to agent");
446
+ }
447
+ }
448
+ ```
449
+
450
+ #### Retrying After Reconnection
451
+
452
+ PartySocket automatically reconnects after disconnection. To retry a failed call after reconnection, await `agent.ready` before retrying:
453
+
454
+ ```typescript
455
+ async function callWithRetry<T>(
456
+ agent: AgentClient,
457
+ method: string,
458
+ args: unknown[] = []
459
+ ): Promise<T> {
460
+ try {
461
+ return await agent.call(method, args);
462
+ } catch (error) {
463
+ if (error.message === "Connection closed") {
464
+ await agent.ready; // Wait for reconnection
465
+ return await agent.call(method, args); // Retry once
466
+ }
467
+ throw error;
468
+ }
469
+ }
470
+
471
+ // Usage
472
+ const result = await callWithRetry(agent, "processData", [data]);
473
+ ```
474
+
475
+ > **Note:** Only retry idempotent operations. If the server received the request but the connection dropped before the response arrived, retrying could cause duplicate execution.
476
+
477
+ ## When NOT to Use @callable
478
+
479
+ ### Worker-to-Agent Calls
480
+
481
+ When calling an agent from the same Worker (e.g., in your `fetch` handler), use Durable Object RPC directly:
482
+
483
+ ```typescript
484
+ import { getAgentByName } from "agents";
485
+
486
+ export default {
487
+ async fetch(request: Request, env: Env) {
488
+ // Get the agent stub
489
+ const agent = await getAgentByName(env.MyAgent, "instance-name");
490
+
491
+ // Call methods directly - no @callable needed
492
+ const result = await agent.processData(data);
493
+
494
+ return Response.json(result);
495
+ }
496
+ };
497
+ ```
498
+
499
+ ### Agent-to-Agent Calls
500
+
501
+ When one agent needs to call another:
502
+
503
+ ```typescript
504
+ class OrchestratorAgent extends Agent {
505
+ async delegateWork(taskId: string) {
506
+ // Get another agent
507
+ const worker = await getAgentByName(this.env.WorkerAgent, taskId);
508
+
509
+ // Call its methods directly
510
+ const result = await worker.doWork();
511
+
512
+ return result;
513
+ }
514
+ }
515
+ ```
516
+
517
+ ### Why the Distinction?
518
+
519
+ | RPC Type | Transport | Use Case |
520
+ | ----------- | --------- | --------------------------------- |
521
+ | `@callable` | WebSocket | External clients (browsers, apps) |
522
+ | DO RPC | Internal | Worker ↔ Agent, Agent ↔ Agent |
523
+
524
+ DO RPC is more efficient for internal calls since it doesn't go through WebSocket serialization. The `@callable` decorator adds the necessary WebSocket RPC handling for external clients.
525
+
526
+ ## API Reference
527
+
528
+ ### `@callable(metadata?)` Decorator
529
+
530
+ Marks a method as callable from external clients.
531
+
532
+ ```typescript
533
+ import { callable } from "agents";
534
+
535
+ @callable()
536
+ method(): void {}
537
+
538
+ @callable({ streaming: true })
539
+ streamingMethod(stream: StreamingResponse): void {}
540
+
541
+ @callable({ description: "Fetches user data" })
542
+ getUser(id: string): User {}
543
+ ```
544
+
545
+ ### `CallableMetadata` Type
546
+
547
+ ```typescript
548
+ type CallableMetadata = {
549
+ /** Optional description of what the method does */
550
+ description?: string;
551
+ /** Whether the method supports streaming responses */
552
+ streaming?: boolean;
553
+ };
554
+ ```
555
+
556
+ ### `StreamingResponse` Class
557
+
558
+ Used in streaming callable methods to send data to the client.
559
+
560
+ ```typescript
561
+ import { type StreamingResponse } from "agents";
562
+
563
+ @callable({ streaming: true })
564
+ async streamData(stream: StreamingResponse, input: string) {
565
+ stream.send("chunk 1");
566
+ stream.send("chunk 2");
567
+ stream.end("final");
568
+ }
569
+ ```
570
+
571
+ | Method | Signature | Description |
572
+ | ------- | -------------------------------- | ---------------------------------- |
573
+ | `send` | `(chunk: unknown) => void` | Send a chunk to the client |
574
+ | `end` | `(finalChunk?: unknown) => void` | End the stream |
575
+ | `error` | `(message: string) => void` | Send an error and close the stream |
576
+
577
+ ### Client Methods
578
+
579
+ | Method | Signature | Description |
580
+ | ------------ | -------------------------------------- | --------------------- |
581
+ | `agent.call` | `(method, args?, options?) => Promise` | Call a method by name |
582
+ | `agent.stub` | `Proxy` | Typed method calls |
583
+
584
+ ```typescript
585
+ // Using call()
586
+ await agent.call("methodName", [arg1, arg2]);
587
+ await agent.call("streamMethod", [arg], {
588
+ stream: { onChunk, onDone, onError }
589
+ });
590
+
591
+ // With timeout (rejects if call doesn't complete in time)
592
+ await agent.call("slowMethod", [], { timeout: 5000 });
593
+
594
+ // Using stub
595
+ await agent.stub.methodName(arg1, arg2);
596
+ ```
597
+
598
+ ### `CallOptions` Type
599
+
600
+ ```typescript
601
+ type CallOptions = {
602
+ /** Timeout in milliseconds. Rejects if call doesn't complete in time. */
603
+ timeout?: number;
604
+ /** Streaming options */
605
+ stream?: {
606
+ onChunk?: (chunk: unknown) => void;
607
+ onDone?: (finalChunk: unknown) => void;
608
+ onError?: (error: string) => void;
609
+ };
610
+ };
611
+ ```
612
+
613
+ > **Backward Compatibility**: The legacy format `{ onChunk, onDone, onError }` (without nesting under `stream`) is still supported. The client auto-detects which format you're using.
614
+
615
+ ### `getCallableMethods()` Method
616
+
617
+ Returns a map of all callable methods on the agent with their metadata. Useful for introspection and auto-documentation.
618
+
619
+ ```typescript
620
+ const methods = agent.getCallableMethods();
621
+ // Map<string, CallableMetadata>
622
+
623
+ for (const [name, meta] of methods) {
624
+ console.log(`${name}: ${meta.description || "(no description)"}`);
625
+ if (meta.streaming) console.log(" (streaming)");
626
+ }
627
+ ```