agents 0.17.4 → 0.18.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 (46) hide show
  1. package/dist/{agent-tool-types-OhWqAbCp.d.ts → agent-tool-types-BNUGGBzQ.d.ts} +30 -11
  2. package/dist/agent-tool-types.d.ts +1 -1
  3. package/dist/{agent-tools-LdNKGZT9.d.ts → agent-tools-BFbzVLFc.d.ts} +2 -2
  4. package/dist/agent-tools.d.ts +1 -1
  5. package/dist/chat/index.d.ts +29 -9
  6. package/dist/chat/index.js +31 -41
  7. package/dist/chat/index.js.map +1 -1
  8. package/dist/chat/react.d.ts +25 -1
  9. package/dist/chat/react.js +249 -93
  10. package/dist/chat/react.js.map +1 -1
  11. package/dist/chat-sdk/index.d.ts +1 -1
  12. package/dist/{client-C7F0MaVz.js → client-CcjiFpTf.js} +176 -42
  13. package/dist/client-CcjiFpTf.js.map +1 -0
  14. package/dist/client.d.ts +1 -1
  15. package/dist/cloudflare-BldFV0Pa.js +117 -0
  16. package/dist/cloudflare-BldFV0Pa.js.map +1 -0
  17. package/dist/index.d.ts +5 -3
  18. package/dist/index.js +118 -43
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp/client.d.ts +1 -1
  21. package/dist/mcp/client.js +1 -1
  22. package/dist/mcp/index.d.ts +1 -1
  23. package/dist/mcp/index.js +1 -1
  24. package/dist/observability/ai/index.d.ts +155 -0
  25. package/dist/observability/ai/index.js +1845 -0
  26. package/dist/observability/ai/index.js.map +1 -0
  27. package/dist/react.d.ts +1 -1
  28. package/dist/{retries-CvHJwSuh.d.ts → retries-CAvxtG9d.d.ts} +16 -7
  29. package/dist/retries.d.ts +8 -6
  30. package/dist/retries.js +20 -2
  31. package/dist/retries.js.map +1 -1
  32. package/dist/serializable.d.ts +1 -1
  33. package/dist/sub-routing.d.ts +1 -1
  34. package/dist/vite.d.ts +4 -4
  35. package/dist/vite.js +4 -2
  36. package/dist/vite.js.map +1 -1
  37. package/dist/{wire-types-nflOzNuU.js → wire-types-CU9rLoeS.js} +33 -2
  38. package/dist/wire-types-CU9rLoeS.js.map +1 -0
  39. package/dist/workflows.d.ts +1 -1
  40. package/docs/agent-class.md +9 -1
  41. package/docs/configuration.md +20 -0
  42. package/docs/mcp-client.md +13 -4
  43. package/docs/observability.md +282 -0
  44. package/package.json +7 -2
  45. package/dist/client-C7F0MaVz.js.map +0 -1
  46. package/dist/wire-types-nflOzNuU.js.map +0 -1
@@ -259,3 +259,285 @@ These events are emitted by `AIChatAgent` from `@cloudflare/ai-chat`. They track
259
259
  | --------------- | ------------------------ | --------------------- |
260
260
  | `email:receive` | `{ from, to, subject? }` | An email is received |
261
261
  | `email:reply` | `{ from, to, subject? }` | A reply email is sent |
262
+
263
+ ## Agent initialization span
264
+
265
+ When Worker traces are enabled, every `Agent` constructor runs its setup —
266
+ method wrapping, schema creation, and MCP client manager initialization —
267
+ inside an `agent_initialization` span. Constructor-time child spans group under
268
+ this one stable parent instead of appearing as top-level clutter. The span
269
+ carries `cloudflare.agents.agent.name` (the agent class),
270
+ `cloudflare.agents.agent.id` (the named instance, omitted when the name is not
271
+ yet readable during construction), and `cloudflare.agents.operation.name`
272
+ (`agent_initialization`). Like the rest of the tracing in this package, it is a
273
+ no-op when the runtime has no native tracing capability.
274
+
275
+ ## AI SDK tracing
276
+
277
+ `agents/observability/ai` instruments the Vercel AI SDK with Workers' native
278
+ custom spans. It projects the scalar subset supported by the Workers `Span` API
279
+ onto the current
280
+ [OpenTelemetry GenAI semantic conventions](https://github.com/open-telemetry/semantic-conventions-genai).
281
+ Spans flow to Workers Observability and configured OTLP destinations. The
282
+ integration is a no-op when the runtime has no native tracing capability.
283
+
284
+ **Think agents are traced out of the box.** Enable
285
+ `observability.traces.enabled` in `wrangler.jsonc`; no Think option is required.
286
+ A turn gets an `invoke_agent {agent class}` operation span, `chat {model}` model
287
+ spans, and `execute_tool {tool}` spans. Think always supplies its durable
288
+ identity: `gen_ai.agent.name` is the class name, `gen_ai.agent.id` is the named
289
+ instance, and `gen_ai.conversation.id` is the opaque Durable Object ID. These
290
+ are defaults; `beforeTurn` can override `functionId` or the corresponding
291
+ metadata fields for applications with a different identity model. Payload
292
+ storage is off by default. Set `storeMessages` and/or `storeTools` on the Think
293
+ agent to opt in; these are wrapper settings, not span attributes.
294
+
295
+ ### AI SDK v6
296
+
297
+ Wrap the SDK namespace:
298
+
299
+ ```ts
300
+ import * as ai from "ai";
301
+ import { wrapAISDK } from "agents/observability/ai";
302
+
303
+ const { generateText, streamText } = wrapAISDK(ai);
304
+ ```
305
+
306
+ `wrapAISDK` instruments `generateText`, `streamText`, `generateObject`, and
307
+ `streamObject`. Span names use `{operation} {target}` and fall back to the bare
308
+ operation past 64 UTF-8 bytes; the full target remains on its semantic
309
+ attribute. A model object is wrapped with the SDK's `wrapLanguageModel` helper,
310
+ so provider work is a `chat {model}` child of the operation span. Tool
311
+ execution is wrapped as `execute_tool {tool}`. AI SDK v6 approval lifecycle
312
+ segments appear as bounded `tool_approval {tool}` children of an
313
+ `execute_tool {tool}` span, correlated by `gen_ai.tool.call.id` and carrying
314
+ `cloudflare.agents.tool.approval.state` (`requested`, `approved`, or `denied`).
315
+ They never remain open while waiting for a human across invocations. Stream
316
+ spans close on completion, cancellation, an in-band error, or early consumer
317
+ return. Async-generator tools stay open until iteration ends.
318
+
319
+ Pass `storeMessages: true` to write full input/output message arrays to `chat`.
320
+ The JSON follows the OpenTelemetry GenAI schemas: messages use `{ role, parts }`,
321
+ text and reasoning parts use `{ type, content }`, tool parts use `tool_call` /
322
+ `tool_call_response`, and every output message includes `finish_reason`. Pass
323
+ `storeTools: true` to write tool arguments and results to `execute_tool`:
324
+
325
+ ```ts
326
+ const traced = wrapAISDK(ai, {
327
+ storeMessages: true,
328
+ storeTools: true
329
+ });
330
+ ```
331
+
332
+ ### AI SDK v7
333
+
334
+ AI SDK v7 ships a first-class telemetry lifecycle. Register the adapter once and
335
+ every `generateText`, `streamText`, `generateObject`, and `streamObject` call is
336
+ instrumented:
337
+
338
+ ```ts
339
+ import { registerTelemetry } from "ai";
340
+ import { createAISDKTelemetry } from "agents/observability/ai";
341
+
342
+ registerTelemetry(
343
+ createAISDKTelemetry({ storeMessages: true, storeTools: true })
344
+ );
345
+ ```
346
+
347
+ Or scope it to a single call through `experimental_telemetry`:
348
+
349
+ ```ts
350
+ import { createAISDKTelemetry } from "agents/observability/ai";
351
+
352
+ await generateText({
353
+ model,
354
+ prompt: "...",
355
+ experimental_telemetry: {
356
+ integrations: [createAISDKTelemetry()]
357
+ }
358
+ });
359
+ ```
360
+
361
+ The v7 adapter uses `cloudflare.agents.call.id` to correlate operation, model,
362
+ and tool spans. Its execution hooks keep provider work under the `chat` span and
363
+ nested work performed by a tool under the `execute_tool` span. It handles both
364
+ `onEnd` and `onAbort` terminal paths. `wrapAISDK` and `createAISDKTelemetry`
365
+ project into the same span schema, so the two SDK versions are dashboard-
366
+ compatible.
367
+
368
+ When a gateway-backed provider exposes its AI Gateway log ID through response
369
+ headers, provider metadata, or the Workers AI binding, the corresponding
370
+ `chat` span includes `cloudflare.ai_gateway.log.id`. The attribute is omitted
371
+ when no actual response exposes an ID; the adapter does not infer one or make an
372
+ extra request.
373
+
374
+ ### Identity
375
+
376
+ The AI SDK's canonical OpenTelemetry integration maps `functionId` to
377
+ `gen_ai.agent.name`. For direct `wrapAISDK` calls, `functionId` should therefore
378
+ be a low-cardinality logical agent name, not a request, user, session, or
379
+ Durable Object identifier. In v6, the other identity values are read from
380
+ `experimental_telemetry.metadata`; an explicit `agentName` takes precedence
381
+ over `functionId`.
382
+
383
+ Think sets all three fields automatically on every inference:
384
+
385
+ ```text
386
+ gen_ai.agent.name = this.constructor.name
387
+ gen_ai.agent.id = this.name
388
+ gen_ai.conversation.id = this.ctx.id.toString()
389
+ ```
390
+
391
+ For direct v6 wrapper calls, supply identity explicitly:
392
+
393
+ ```ts
394
+ await generateText({
395
+ model,
396
+ prompt: "...",
397
+ experimental_telemetry: {
398
+ functionId: "booking-agent",
399
+ metadata: {
400
+ // Stable agent resource/instance identifier.
401
+ agentId: "asst_123",
402
+ agentVersion: "2026-07-01",
403
+ conversationId: "conversation-123"
404
+ }
405
+ }
406
+ });
407
+ ```
408
+
409
+ AI SDK v7 has no telemetry metadata bag. Put additional identity in
410
+ `runtimeContext` and explicitly include those fields:
411
+
412
+ ```ts
413
+ await generateText({
414
+ model,
415
+ prompt: "...",
416
+ runtimeContext: {
417
+ conversationId: "conversation-123"
418
+ },
419
+ telemetry: {
420
+ functionId: "booking-agent",
421
+ includeRuntimeContext: {
422
+ conversationId: true
423
+ }
424
+ }
425
+ });
426
+ ```
427
+
428
+ ### Emitted data
429
+
430
+ | Standard attributes | Source and scope |
431
+ | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
432
+ | `gen_ai.operation.name` | `invoke_agent`, `chat`, or `execute_tool` on every span |
433
+ | `gen_ai.agent.id`, `gen_ai.agent.name`, `gen_ai.agent.version` | Explicit operation identity; Think defaults ID and name, but not version |
434
+ | `gen_ai.conversation.id` | Explicit operation conversation; Think defaults to its opaque Durable Object ID |
435
+ | `gen_ai.provider.name` | Normalized provider on operation/model spans when known |
436
+ | `gen_ai.output.type` | Requested `text` or `json` output on operation/model spans |
437
+ | `gen_ai.request.model` | Requested model when known |
438
+ | `gen_ai.request.frequency_penalty`, `gen_ai.request.presence_penalty` | Numeric request settings when supplied |
439
+ | `gen_ai.request.max_tokens`, `gen_ai.request.seed`, `gen_ai.request.top_k` | Integer request settings when supplied |
440
+ | `gen_ai.request.stream` | `true` on streaming operations; omitted otherwise |
441
+ | `gen_ai.request.temperature`, `gen_ai.request.top_p` | Numeric request settings when supplied |
442
+ | `gen_ai.response.id`, `gen_ai.response.model` | Model-call response metadata when actually reported; never inferred from the requested model |
443
+ | `gen_ai.response.time_to_first_chunk` | Model-call streaming latency in seconds |
444
+ | `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens` | Aggregate usage on operations and per-call usage on model spans |
445
+ | `gen_ai.usage.cache_creation.input_tokens`, `gen_ai.usage.cache_read.input_tokens` | Provider cache usage when reported |
446
+ | `gen_ai.usage.reasoning.output_tokens` | Reasoning output usage when reported |
447
+ | `gen_ai.tool.name`, `gen_ai.tool.type`, `gen_ai.tool.call.id` | Tool identity; call ID also correlates approval lifecycle segments |
448
+ | `cloudflare.agents.tool.approval.state` | AI SDK v6 approval lifecycle segment: `requested`, `approved`, or `denied` |
449
+ | `gen_ai.input.messages`, `gen_ai.output.messages` | Opt-in OTel-schema model messages on `chat`, including tool parts and output finish reasons |
450
+ | `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result` | Opt-in tool arguments/results on `execute_tool` |
451
+ | `user.id` | Explicit v6 metadata key `user.id` |
452
+ | `error.type` | Low-cardinality error class; raw error messages are never recorded |
453
+
454
+ The adapter also emits a small vendor namespace where no standard equivalent
455
+ exists:
456
+
457
+ | Attribute | Meaning |
458
+ | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
459
+ | `cloudflare.ai_gateway.log.id` | AI Gateway log reference on `chat`, when exposed by the actual response |
460
+ | `cloudflare.agents.integration.name` | Instrumentation source (`ai-sdk`) |
461
+ | `cloudflare.agents.operation.name` | Original SDK operation (`streamText`, `doStream`, `tool.execute`, etc.) |
462
+ | `cloudflare.agents.call.id` | AI SDK v7 callback correlation ID |
463
+ | `cloudflare.agents.response.finish_reason` | One finish reason as a scalar |
464
+ | `cloudflare.agents.tool.count` | Precomputed tool-call count for dashboards |
465
+ | `cloudflare.agents.usage.total_tokens` | Provider total, or input plus output when both are known |
466
+ | `cloudflare.agents.runtime_context.{key}` | Explicitly included scalar runtime context |
467
+ | `cloudflare.agents.tool_context.{tool}.{key}` | Explicitly included scalar context on the executed tool span |
468
+ | `cloudflare.agents.metadata.{key}` | Other scalar v6 telemetry metadata |
469
+ | `cloudflare.agents.turn.{request_id,trigger,admission,channel,continuation,generation}` | Think turn context |
470
+ | `cloudflare.agents.canceled` | Recognized cancellation, not a failure |
471
+
472
+ `gen_ai.response.finish_reasons` and `gen_ai.request.stop_sequences` are arrays
473
+ in OTel. Workers' custom `Span.setAttribute` currently accepts only a string,
474
+ number, or boolean, so the adapter omits those attributes rather than placing
475
+ JSON text under an array-typed key. Similarly, span status is state rather than
476
+ an attribute: failures emit `error.type`, but the adapter does not invent an
477
+ `otel.status_code` attribute when Workers exposes no custom-span status setter.
478
+
479
+ ### Context and safety
480
+
481
+ Payload storage is explicit and off by default. `storeMessages` writes only
482
+ `gen_ai.input.messages` / `gen_ai.output.messages` on `chat`; when the message
483
+ attribute exceeds its budget, the adapter repeatedly drops the oldest
484
+ unprotected message (index 2), preserving the first two messages and newest
485
+ tail. `storeTools` writes only `gen_ai.tool.call.arguments` /
486
+ `gen_ai.tool.call.result` on `execute_tool`. The flags themselves are never
487
+ written to telemetry metadata or spans.
488
+
489
+ System instructions that the AI SDK presents to the model as a system-role chat
490
+ message remain in `gen_ai.input.messages`, which OTel explicitly permits for
491
+ instructions that are part of chat history. The adapter does not separately
492
+ copy the raw `system` parameter into `gen_ai.system_instructions`. Schemas,
493
+ request headers, provider options, and raw error messages are never recorded.
494
+ The optional AI Gateway reference is a bounded opaque log ID; response headers
495
+ and provider metadata themselves are not recorded. Metadata and context values
496
+ must be scalar; objects and arrays are dropped.
497
+
498
+ For v6, only `experimental_context` exists. Configure its allowlist on the
499
+ wrapper:
500
+
501
+ ```ts
502
+ const traced = wrapAISDK(ai, {
503
+ includeRuntimeContext: ["requestId", "tenantId"]
504
+ });
505
+
506
+ await traced.generateText({
507
+ model,
508
+ prompt: "Will I need an umbrella?",
509
+ experimental_context: {
510
+ requestId: "req-123",
511
+ tenantId: "tenant-42"
512
+ }
513
+ });
514
+ ```
515
+
516
+ For v7, the AI SDK filters runtime and per-tool context before the adapter sees
517
+ it. Its allowlists are boolean maps, not arrays:
518
+
519
+ ```ts
520
+ await generateText({
521
+ model,
522
+ prompt: "Will I need an umbrella?",
523
+ runtimeContext: { requestId: "req-123", tenantId: "tenant-42" },
524
+ toolsContext: {
525
+ weather: { defaultUnit: "celsius", cacheHit: true }
526
+ },
527
+ telemetry: {
528
+ includeRuntimeContext: {
529
+ requestId: true,
530
+ tenantId: true
531
+ },
532
+ includeToolsContext: {
533
+ weather: {
534
+ defaultUnit: true,
535
+ cacheHit: true
536
+ }
537
+ }
538
+ }
539
+ });
540
+ ```
541
+
542
+ Do not include tokens, credentials, user input, or other secrets. Context
543
+ filtering reduces accidental exposure; it is not a security boundary.
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "durable objects"
10
10
  ],
11
11
  "type": "module",
12
- "version": "0.17.4",
12
+ "version": "0.18.0",
13
13
  "license": "MIT",
14
14
  "repository": {
15
15
  "directory": "packages/agents",
@@ -26,7 +26,7 @@
26
26
  "dependencies": {
27
27
  "@babel/plugin-proposal-decorators": "^8.0.2",
28
28
  "@cfworker/json-schema": "^4.1.1",
29
- "@cloudflare/codemode": "^0.4.3",
29
+ "@cloudflare/codemode": "^0.4.4",
30
30
  "@modelcontextprotocol/sdk": "1.29.0",
31
31
  "@rolldown/plugin-babel": "^0.2.3",
32
32
  "cron-schedule": "^6.0.0",
@@ -140,6 +140,11 @@
140
140
  "import": "./dist/observability/index.js",
141
141
  "require": "./dist/observability/index.js"
142
142
  },
143
+ "./observability/ai": {
144
+ "types": "./dist/observability/ai/index.d.ts",
145
+ "import": "./dist/observability/ai/index.js",
146
+ "require": "./dist/observability/ai/index.js"
147
+ },
143
148
  "./react": {
144
149
  "types": "./dist/react.d.ts",
145
150
  "import": "./dist/react.js",