Skip to content

@tanstack/ai-react: useChat does not update the underlying ChatClient when tools changes #775

@manish-baghel

Description

@manish-baghel

TanStack AI version

v0.29.0

Framework/Library version

v0.15.5

Describe the bug and the steps to reproduce it

The React useChat hook accepts a tools option and passes it to ChatClient during initial construction. However, if the tools array changes during the component lifecycle, the existing ChatClient is not updated.

This causes the client-side tool registry to become stale. Tools with same name can have different implementaion overtime. For eg, an App with "worspaces" or "projects" toggle can contain a tool like updateTask which updates tasks in the current project and on project toggle that implementation will change due to their dependency on things like projectId or workspaceId

The core ChatClient already supports this via client.updateOptions({ tools })

type ChatClientUpdateOptionsWithoutContext<
The fix surface seems small.

Expected Behavior
When tools changes on client-side(React), useChat should update the existing ChatClient:

  useEffect(() => {
    client.updateOptions({
      tools: options.tools ?? [],
    })
  }, [client, options.tools])

Reproducible Example
A project management app with a persistent AI chat sidebar. The chat component stays mounted while the user switches between projects.

Steps -

  1. User opens Project A.
  2. useChat creates a ChatClient with updateTaskTool closed over projectId = "A".
  3. User switches to Project B.
  4. React re-renders ProjectChat with projectId = "B".
  5. A new updateTaskTool is created, now closed over projectId = "B".
  6. But useChat does not call client.updateOptions({ tools }).
function ProjectChat({ projectId }: { projectId: string }) {
  const updateTaskTool = useMemo(
    () =>
      updateTaskDef.client(async ({ taskId, status }) => {
        // Captures the current projectId
        await updateTaskInProject(projectId, taskId, status)

        return {
          ok: true,
          projectId,
        }
      }),
    [projectId],
  )

  const tools = useMemo(
    () => clientTools(updateTaskTool),
    [updateTaskTool],
  )

  const chat = useChat({
    connection: fetchServerSentEvents('/api/chat'),
    tools,
  })

  return <ChatUI chat={chat} />
}

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)

Shared Code, reproducible example would require API keys

Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

None

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions