Claude Opus 5.5

agents-0-22-0-11-b

Claude Code's read-only tools, web search on, ludion sync off

Question

How do I make useAgentChat update the UI on every token?

Answer key

A correct answer says
`useAgentChat` throttles UI updates to every 50ms by default; pass `throttle: false` to render every chunk or a number to change the interval.
The stale answer
useAgentChat re-renders on every streamed chunk unless you set `experimental_throttle`.

The change's lesson

Answer

Pass `throttle: false` to `useAgentChat`:

```ts
const chat = useAgentChat({ agent, throttle: false });
```

By default, the installed `agents` package groups chat state updates into one re-render every 50 ms. The first chunk is never delayed. Setting `throttle: false` re-renders on every streamed chunk as it arrives (`node_modules/agents/dist/chat/react.d.ts:251-260`). Each chunk is usually a token or a small text delta. You can also pass a smaller number of milliseconds, like `throttle: 10`, if re-rendering on every chunk turns out to be too heavy. `experimental_throttle` is deprecated in favor of `throttle`.

Answering cost $0.11.

Grade

correct

The judge's reason: It says the default is a 50ms throttle, that throttle: false renders every chunk, and that a number changes the interval, and it doesn't present the stale behavior as current.

The judge's log

Session log

What the agent wrote, the tools it called, and what they returned, from docs/bench/2026-10-11-done3/runs/B-project/agents-0-22-0-11-b.jsonl. Thinking and the session's settings are left out. The raw log

  1. Tool call: Grep

    {
      "pattern": "useAgentChat|throttle",
      "output_mode": "content",
      "head_limit": 30
    }
  2. Tool output

    node_modules\rolldown\dist\shared\create-bundler-option-2b9QJDoZ.mjs:1999:			throttle: 1e3,
    node_modules\rolldown\dist\shared\create-bundler-option-2b9QJDoZ.mjs:2000:			throttleMin: 5,
    node_modules\rolldown\dist\shared\create-bundler-option-2b9QJDoZ.mjs:2239:			const repeated = (this._lastLog.count || 0) - this.options.throttleMin;
    node_modules\rolldown\dist\shared\create-bundler-option-2b9QJDoZ.mjs:2257:		if (diffTime < this.options.throttle) try {
    node_modules\rolldown\dist\shared\create-bundler-option-2b9QJDoZ.mjs:2267:				if (this._lastLog.count > this.options.throttleMin) {
    node_modules\rolldown\dist\shared\create-bundler-option-2b9QJDoZ.mjs:2268:					this._lastLog.timeout = setTimeout(resolveLog, this.options.throttle);
    node_modules\wrangler\wrangler-dist\cli.js:163067:                  "Asset upload concurrency throttled to 1 after a gateway error."
    node_modules\wrangler\wrangler-dist\cli.js:183398:          if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file3, 5))
    node_modules\wrangler\wrangler-dist\cli.js:183433:          if (!this.fsw._throttle(EV.ADD, file3, 0))
    node_modules\wrangler\wrangler-dist\cli.js:183482:      _handleRead(directory, initialAdd, wh, target, dir2, depth, throttler) {
    node_modules\wrangler\wrangler-dist\cli.js:183484:        throttler = this.fsw._throttle("readdir", directory, 1e3);
    node_modules\wrangler\wrangler-dist\cli.js:183485:        if (!throttler)
    node_modules\wrangler\wrangler-dist\cli.js:183524:            const wasThrottled = throttler ? throttler.clear() : false;
    node_modules\wrangler\wrangler-dist\cli.js:183533:              this._handleRead(directory, false, wh, target, dir2, depth, throttler);
    node_modules\wrangler\wrangler-dist\cli.js:183556:        let throttler;
    node_modules\wrangler\wrangler-dist\cli.js:183561:            await this._handleRead(dir2, initialAdd, wh, target, dir2, depth, throttler);
    node_modules\wrangler\wrangler-dist\cli.js:183568:            this._handleRead(dirPath, false, wh, target, dir2, depth, throttler);
    node_modules\wrangler\wrangler-dist\cli.js:183866:        this._throttled = /* @__PURE__ */ new Map();
    node_modules\wrangler\wrangler-dist\cli.js:184033:        this._throttled.clear();
    node_modules\wrangler\wrangler-dist\cli.js:184118:          const isThrottled = !this._throttle(EVENTS.CHANGE, path107, 50);
    node_modules\wrangler\wrangler-dist\cli.js:184149:       * @param actionType type being throttled
    node_modules\wrangler\wrangler-dist\cli.js:184154:      _throttle(actionType, path107, timeout2) {
    node_modules\wrangler\wrangler-dist\cli.js:184155:        if (!this._throttled.has(actionType)) {
    node_modules\wrangler\wrangler-dist\cli.js:184156:          this._throttled.set(actionType, /* @__PURE__ */ new Map());
    node_modules\wrangler\wrangler-dist\cli.js:184158:        const action = this._throttled.get(actionType);
    node_modules\wrangler\wrangler-dist\cli.js:184160:          throw new Error("invalid throttle");
    node_modules\wrangler\wrangler-dist\cli.js:184297:        if (!this._throttle("remove", path107, 100))
    node_modules\workerd\worker.mjs:388:[Omitted long matching line]
    node_modules\workerd\worker.mjs:397:[Omitted long matching line]
    node_modules\workerd\worker.mjs:404:[Omitted long matching line]
    
    [Showing results with pagination = limit: 30]
  3. Tool call: Grep

    {
      "pattern": "throttle|Throttle",
      "path": "node_modules/@cloudflare/ai-chat",
      "output_mode": "content",
      "head_limit": 30
    }
  4. Tool output (error)

    Path does not exist: node_modules/@cloudflare/ai-chat. Note: your current working directory is C:\Users\haya0\AppData\Local\Temp\ludion-bench-l4vkWh\work.
  5. Tool call: Grep

    {
      "pattern": "useAgentChat",
      "path": "node_modules",
      "glob": "*.d.ts",
      "head_limit": 10
    }
  6. Tool output

    Found 4 files
    node_modules\agents\dist\ws-chat-transport-BbT1A5Lc.d.ts
    node_modules\agents\dist\socket-address.d.ts
    node_modules\agents\dist\react.d.ts
    node_modules\agents\dist\chat\react.d.ts
  7. Tool call: Grep

    {
      "pattern": "throttle|Throttle|UseAgentChatOptions|experimental_",
      "path": "node_modules/agents/dist/chat/react.d.ts",
      "output_mode": "content",
      "-C": 4
    }
  8. Tool output

    222-}) => void | Promise<void>;
    223-/**
    224- * Options for the useAgentChat hook
    225- */
    226:type UseAgentChatOptions<
    227-  State = unknown,
    228-  ChatMessage extends UIMessage = UIMessage
    229-> = Omit<
    230-  UseChatParams<ChatMessage>,
    231:  "fetch" | "onToolCall" | "throttle" | "experimental_throttle"
    232-> & {
    233-  /** Agent connection from useAgent (accepts both typed and untyped agents) */ agent: AgentConnection & {
    234-    agent: string;
    235-    name: string;
    --
    251-  /**
    252-   * Milliseconds to coalesce chat state updates before re-rendering,
    253-   * defaulting to 50.
    254-   *
    255:   * Streaming writes chat state once per chunk, so without a throttle a fast
    256-   * burst of chunks renders once per chunk. The first chunk is never delayed.
    257-   * Pass `false` to render every chunk as it arrives.
    258-   */
    259:  throttle?: number | false /** @deprecated Use `throttle`. */;
    260:  experimental_throttle?: number;
    261-  /**
    262-   * Callback for handling client-side tool execution.
    263-   * Called when a tool without server-side `execute` is invoked by the LLM.
    264-   * It fires once the response stream ends, for each tool call still waiting
    --
    303-   * @deprecated Use `onToolCall` callback instead for automatic tool execution.
    304-   * @description Whether to automatically resolve tool calls that do not require human interaction.
    305-   * @experimental
    306-   */
    307:  experimental_automaticToolResolution?: boolean;
    308-  /**
    309-   * Tools that can be executed on the client. Tool schemas are automatically
    310-   * sent to the server and tool calls are routed back for client execution.
    311-   *
    --
    421-declare function useAgentChat<
    422-  State = unknown,
    423-  ChatMessage extends UIMessage = UIMessage
    424->(
    425:  options: UseAgentChatOptions<State, ChatMessage>
    426-): Omit<ReturnType<typeof useChat<ChatMessage>>, "addToolOutput"> & {
    427-  clearHistory: () => void;
    428-  /**
    429-   * Provide output for a tool call. Use this for tools that require user interaction
    --
    486-  JSONSchemaType,
    487-  OnToolCallCallback,
    488-  PrepareSendMessagesRequestOptions,
    489-  PrepareSendMessagesRequestResult,
    490:  UseAgentChatOptions,
    491-  WebSocketChatTransport,
    492-  type WebSocketChatTransportOptions,
    493-  detectToolsRequiringConfirmation,
    494-  extractClientToolSchemas,
  9. Agent

    Pass `throttle: false` to `useAgentChat`:
    
    ```ts
    const chat = useAgentChat({ agent, throttle: false });
    ```
    
    By default, the installed `agents` package groups chat state updates into one re-render every 50 ms. The first chunk is never delayed. Setting `throttle: false` re-renders on every streamed chunk as it arrives (`node_modules/agents/dist/chat/react.d.ts:251-260`). Each chunk is usually a token or a small text delta. You can also pass a smaller number of milliseconds, like `throttle: 10`, if re-rendering on every chunk turns out to be too heavy. `experimental_throttle` is deprecated in favor of `throttle`.