Skip to content

Conversation

@whoiskatrin
Copy link
Contributor

@whoiskatrin whoiskatrin commented Dec 10, 2025

Fix client-side tool execution and message duplication

  • Add support for client-defined tools via useAgentChat with automatic and manual (human-in-the-loop) execution modes
  • Fix duplicate assistant messages when client-side tools execute by sending CF_AGENT_TOOL_RESULT to server as source of truth
  • Improve message ID synchronization between client and server by matching on toolCallId when IDs differ
  • Add toolsRequiringConfirmation option for human-in-the-loop workflows
  • Exclude originating connection from CF_AGENT_CHAT_MESSAGES broadcasts to prevent message conflicts

@changeset-bot
Copy link

changeset-bot bot commented Dec 10, 2025

🦋 Changeset detected

Latest commit: 2f2edf6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agents Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 10, 2025

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@729

commit: 2f2edf6

agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 10, 2025
Synced from cloudflare/agents PR #729

Added documentation for:
- clientTools option for client-defined tools
- prepareSendMessagesRequest callback for request customization
- Type definitions for ClientTool, JSONSchemaType, and related types
- Examples showing how to use both features individually and together

Related PR: cloudflare/agents#729
@claude
Copy link

claude bot commented Dec 10, 2025

Claude Code Review

Summary

This PR adds client-side tool execution with automatic/manual modes and fixes duplicate message issues. The implementation is generally solid with comprehensive tests.

Issues Found

1. Race condition in _applyToolResult (ai-chat-agent.ts:1108-1114)

The retry loop uses a hardcoded 10-attempt limit with 100ms delays (1 second total). If the message is not persisted within 1 second, the tool result is lost silently:

for (let attempt = 0; attempt < 10; attempt++) {
  message = this._findMessageByToolCallId(toolCallId);
  if (message) break;
  await new Promise((resolve) => setTimeout(resolve, 100));
}

This is fragile - under load or with slow database operations, tool results can be dropped. Consider:

  • Increase timeout or make it configurable
  • Add warning log with the attempt count when it succeeds after retries
  • Consider throwing an error instead of returning false to make failures visible

2. Potential memory leak in clientToolResults state (ai-react.tsx:590-592)

const [clientToolResults, setClientToolResults] = useState<
  Map<string, unknown>
>(new Map());

This Map grows indefinitely - every tool execution adds an entry but nothing ever removes old ones. In long conversations with many tool calls, this could accumulate significant memory. The state appears to be used for tracking but never cleaned up.

3. Missing validation in createToolsFromClientSchemas (ai-chat-agent.ts:78-86)

The function warns about duplicate tool names but still processes them:

if (seenNames.has(t.name)) {
  console.warn(`Duplicate tool name "${t.name}" found...`);
}

The later definition silently overwrites the earlier one. Consider either:

  • Throwing an error for duplicates (safer)
  • Or skip the duplicate instead of overwriting (preserve first definition)

4. autoContinueAfterToolResult dependency issue (ai-react.tsx:734-740)

The autoContinueAfterToolResult is in the useEffect dependency array but is referenced inside a deeply nested async closure. If the value changes between tool execution start and the server message send, stale values could be used. Consider capturing it at the start of the effect.

5. Test timeout values inconsistency

  • client-tool-duplicate-message.test.ts:208: Uses 800ms timeout for auto-continue test
  • client-tools-broadcast.test.ts:36,101: Uses 2000ms timeout
  • Comment says "wait 500ms" but test waits 800ms

These magic numbers should be constants with documented rationale.

Testing

Excellent test coverage including:

  • Message deduplication via toolCallId
  • Auto-continuation behavior
  • OpenAI metadata stripping
  • Broadcast exclusion
  • Empty reasoning part filtering

Tests are thorough but would benefit from testing the race condition edge cases in _applyToolResult.

agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 10, 2025
…uest

This commit adds comprehensive documentation for two new features in the
Agents SDK useAgentChat hook:

1. clientTools option - allows clients to register their own tools dynamically
   for browser-specific operations like showing alerts, modifying the DOM, or
   accessing client-only APIs

2. prepareSendMessagesRequest callback - provides control over request
   customization including dynamic data, custom headers, and credentials

The documentation includes:
- Type definitions for ClientTool, PrepareSendMessagesRequestOptions, and
  PrepareSendMessagesRequestResult
- Code examples showing both simple and advanced usage patterns
- Combined usage examples demonstrating how both features work together
- Use cases for when to apply each feature

Source: cloudflare/agents#729

🤖 Generated with Claude Code
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 10, 2025
Documents the new clientTools and prepareSendMessagesRequest options
for the useAgentChat React hook, which allow dynamic tool registration
and request customization for embedded chat applications.

Related to cloudflare/agents#729
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 10, 2025
This update documents two new features added in PR #729:

1. **clientTools option**: Allows clients to dynamically register tools that are sent to the Agent with each request. This enables embeddable chat widgets and multi-tenant applications where different clients need different tool capabilities.

2. **prepareSendMessagesRequest callback**: Provides advanced control over request customization, allowing developers to add dynamic context, custom headers, and other request modifications before sending messages to the Agent.

Key additions:
- Updated UseAgentChatOptions type signature to include new options
- Added comprehensive examples showing clientTools usage with tool execution handlers
- Added example demonstrating prepareSendMessagesRequest for dynamic context
- Documented TypeScript types: ClientTool, JSONSchemaType, PrepareSendMessagesRequestOptions, PrepareSendMessagesRequestResult
- Explained use cases for client-defined tools (embeddable widgets, multi-tenant apps, dynamic tool registration)
- Clarified that both options can be combined for hybrid client/server tool capabilities

Synced from: cloudflare/agents PR #729
cloudflare/agents#729

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 10, 2025
Document new client-defined tools feature from cloudflare/agents#729:
- Add comprehensive guide for client-defined tools
- Update API reference with new types and functions
- Document useAgentChat tools parameter
- Document prepareSendMessagesRequest callback
- Document createToolsFromClientSchemas function

Related to: cloudflare/agents#729

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
/** Human-readable description of what the tool does */
description?: string;
/** JSON Schema defining the tool's input parameters */
parameters?: Record<string, unknown>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: naming here. Can we not build this type from ai sdk tools omitting execute

* Supports common JSON Schema properties with an index signature
* for extension properties like $ref, format, minimum, maximum, etc.
*/
export type JSONSchemaType = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are so many different specs for json schema. MCP standardise on 2020-12. you can use https://www.npmjs.com/package/json-schema-typed as a type lib for this.

/**
* @deprecated Use `parameters` instead. Will be removed in a future version.
*/
inputSchema?: unknown;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intereste on this change and why we are vendoring this type ourselves not using ai sdk.

Comment on lines 70 to 77
export type ClientToolSchema = {
/** Unique name for the tool */
name: string;
/** Human-readable description of what the tool does */
description?: string;
/** JSON Schema defining the tool's input parameters */
parameters?: Record<string, unknown>;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a type not a schema? and same as above...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes yes, fixing this, my oversight

Comment on lines 84 to 96
function toParametersRecord(
params: JSONSchemaType | unknown | undefined
): Record<string, unknown> | undefined {
if (params === undefined || params === null) {
return undefined;
}
// JSONSchemaType and plain objects are compatible with Record<string, unknown>
if (typeof params === "object") {
return params as Record<string, unknown>;
}
// Primitive values shouldn't be used as parameters, but handle gracefully
return undefined;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically a boolean is a valid json schema. You want to use the Interface object on the JSONSchema type here to restrict the type to something which will go over wire. this shouldnt be necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed this

Copy link
Contributor

@mattzcarey mattzcarey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tentative approval. I think there is a bit of cleaning that can be done with types.

agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 11, 2025
…sRequest options

This PR syncs documentation changes from cloudflare/agents PR 729, which adds
support for client-defined tools and enhanced request customization options.

Changes:
- Added new "Client-defined tools" section to agents-api.mdx documenting the
  new tools API with execute functions
- Updated human-in-the-loop.mdx to use the new AITool format with JSON Schema
  instead of Zod for client-side tool definitions
- Documented createToolsFromClientSchemas() function for server-side handling
- Documented prepareSendMessagesRequest option for custom headers and body

Related PR: cloudflare/agents#729

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 11, 2025
This PR adds comprehensive documentation for the new client-defined tools feature introduced in cloudflare/agents#729.

Key additions:
- New API reference page for client-defined tools
- Detailed explanation of client-side tool registration
- Examples of browser-specific tool actions (alerts, DOM manipulation)
- Server-side integration using createToolsFromClientSchemas()
- Advanced usage patterns with custom request data
- API reference for AITool, ClientToolSchema, and OnChatMessageOptions types
- Best practices for security, error handling, and TypeScript usage

The documentation follows the Diátaxis framework, providing both reference material and practical examples for implementing dynamic tool registration in embeddable chat widgets and multi-tenant applications.

Related to: cloudflare/agents#729

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 11, 2025
Adds comprehensive documentation for the new client-defined tools feature
introduced in PR #729, which allows clients to dynamically register tools
that execute in the browser.

Changes:
- Added Client-Defined Tools section to agents-api.mdx
- Documented AITool type with execute functions
- Added client-side tool definition examples
- Documented createToolsFromClientSchemas() server-side utility
- Added prepareSendMessagesRequest option documentation
- Updated useAgentChat type definition with new options

This documentation covers:
- How to define tools on the client with execute functions
- Automatic schema extraction and transmission to server
- Server-side handling of client tool schemas
- Advanced custom request data patterns

Related to cloudflare/agents#729
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
This syncs documentation from PR #729 which adds support for
client-defined tools with execute functions in useAgentChat.

Changes:
- Document client-side tool definition with execute functions
- Document server-side createToolsFromClientSchemas() helper
- Document prepareSendMessagesRequest option for custom headers

Related PR: cloudflare/agents#729

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
…uest

Sync documentation from cloudflare/agents PR #729:
- Add comprehensive client-defined tools guide
- Update AIChatAgent API to document options parameter
- Add createToolsFromClientSchemas helper documentation
- Update human-in-the-loop guide with new tool format
- Document prepareSendMessagesRequest option
- Add useAgentChat tools and customization examples

Related PR: cloudflare/agents#729
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
This update documents the new client-defined tools feature that enables
dynamic tool registration from browser clients, essential for embeddable
chat widgets and multi-tenant applications.

Changes:
- Add client-defined tools guide with comprehensive examples
- Update useAgentChat API reference with new options:
  - tools: Client-side tool definitions with execute functions
  - toolsRequiringConfirmation: Human-in-the-loop tool approval
  - prepareSendMessagesRequest: Custom request data/headers
- Document AIChatAgent server-side API updates:
  - OnChatMessageOptions type with clientTools parameter
  - createToolsFromClientSchemas() helper function
  - ClientToolSchema and AITool type definitions

The new guide covers:
- Client-side tool definition with JSON Schema and execute functions
- Server-side tool handling with createToolsFromClientSchemas()
- Human-in-the-loop workflows with toolsRequiringConfirmation
- Custom request data with prepareSendMessagesRequest
- Server-only tools without client execute functions
- Best practices for security and performance

Related to cloudflare/agents#729

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
… update message handling to merge tool results into existing assistant messages
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
…sRequest options

This sync adds documentation for new features introduced in cloudflare/agents PR 729:

## New documentation

- Created comprehensive client-tools concept page explaining:
  - Client-side vs server-side tool execution models
  - Tool definition with JSON Schema for client tools
  - autoContinueAfterToolResult for seamless UX
  - Human-in-the-loop workflows with toolsRequiringConfirmation
  - Hybrid tool definitions mixing client and server tools
  - Custom request preparation with prepareSendMessagesRequest

## Updated documentation

- Updated human-in-the-loop guide:
  - Changed clientTools format to use JSON Schema (not Zod)
  - Added autoContinueAfterToolResult option to useAgentChat example
  - Fixed tool execution to use part.input correctly
  - Added explanation of automatic continuation after tool execution

- Updated agents-api.mdx:
  - Added new useAgentChat options to type definition:
    - tools: client-defined tools
    - toolsRequiringConfirmation: tools requiring approval
    - autoContinueAfterToolResult: automatic continuation
    - prepareSendMessagesRequest: custom request preparation
  - Added three new comprehensive examples:
    - Client-defined tools with browser API access
    - Human-in-the-loop approval workflows
    - Custom request preparation
  - Added links to new client-tools concept page

Source: cloudflare/agents#729
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
…tions

This documentation update corresponds to PR #729 in cloudflare/agents.

Key changes:
- Updated human-in-the-loop guide with new client-side tool definitions using JSON Schema
- Added documentation for autoContinueAfterToolResult option in useAgentChat
- Updated server-side tool processing to properly handle tool results
- Added comprehensive examples for client-side tools with human-in-the-loop workflows
- Updated agents-api documentation with new useAgentChat options:
  - tools: Client-side tools with optional execute functions
  - toolsRequiringConfirmation: List of tools requiring human approval
  - autoContinueAfterToolResult: Automatic continuation after tool execution

Related PR: cloudflare/agents#729
agents-git-bot bot pushed a commit to cloudflare/cloudflare-docs that referenced this pull request Dec 12, 2025
Document new features from cloudflare/agents PR #729:
- Add client-side tools support via useAgentChat
- Add toolsRequiringConfirmation option for human-in-the-loop
- Add autoContinueAfterToolResult for seamless tool execution
- Update human-in-the-loop guide with new patterns
- Update API reference with detailed tool configuration examples

Synced from: cloudflare/agents#729

Generated with Claude Code https://claude.com/claude-code

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@whoiskatrin whoiskatrin merged commit 79843bd into main Dec 12, 2025
5 checks passed
@whoiskatrin whoiskatrin deleted the add-client-tools branch December 12, 2025 18:16
@github-actions github-actions bot mentioned this pull request Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants