Skip to content

useChat V5 appears to cache the onToolCall callback but offers no possibility to invalidate #8148

@oliverlukesch

Description

@oliverlukesch

Description

Despite not offering a dependency array, useChat appears to cache the initial version / value of the passed onToolCall callback.

What does not work:

// users can change the used resources in a different component inside the same
// context. the resources get used by executeGenerateText within onToolCall
const {resources} = useResources()

const {messages, sendMessage, stop, status, setMessages, addToolResult} = useChat({
  transport: new DefaultChatTransport({
    api: ApiEndpoints.aiChat,
  }),

  sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,

  onToolCall: async ({toolCall}) => {
    let result: string = 'Done'

    // BUG
    // retains the initial value of resources on component mount, even after
    // mutations by the user
    console.log(resources)

    switch (toolCall.toolName) {
      case TextTools.generate_new_text:
        result = await executeGenerateText(
          toolCall.toolCallId,
          toolCall.input as GenerateNewTextArgs,
          // BUG
          // retains the initial value of resources on component mount, even
          // after mutations by the user
          resources,
        )
        break
    }

    addToolResult({
      tool: toolCall.toolName,
      toolCallId: toolCall.toolCallId,
      output: result,
    })
  },
  onError: console.error,
})

What does work:

// users can change the used resources in a different component inside the same
// context. the resources get used by executeGenerateText within onToolCall
const {resources} = useResources()

// writing the resources inside a ref
const resourcesRef = useRef<Resource[]>(resources)
resourcesRef.current = resources

const {messages, sendMessage, stop, status, setMessages, addToolResult} = useChat({
  transport: new DefaultChatTransport({
    api: ApiEndpoints.aiChat,
  }),

  sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,

  onToolCall: async ({toolCall}) => {
    let result: string = 'Done'

    // WORKS
    // has the the correct value, even after mutations by the user
    console.log(resourcesRef.current)

    switch (toolCall.toolName) {
      case TextTools.generate_new_text:
        result = await executeGenerateText(
          toolCall.toolCallId,
          toolCall.input as GenerateNewTextArgs,
          // WORKS
          // has the the correct value, even after mutations by the user
          resourcesRef.current,
        )
        break
    }

    addToolResult({
      tool: toolCall.toolName,
      toolCallId: toolCall.toolCallId,
      output: result,
    })
  },
  onError: console.error,
})

AI SDK Version

  • "ai": "^5.0.11",
  • "@ai-sdk/react": "^2.0.11",

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions