ai icon indicating copy to clipboard operation
ai copied to clipboard

(vue) useChat not responsive to changes in the conversation ID

Open pqnet opened this issue 10 months ago • 1 comments

Description

In Vue it is impossible to change id for useChat component based on a prop value (or a route parameter), since properties are reactive and id value must be fixed at setup stage.

Code example

// App.vue
<script setup lang="ts">
import Chat from "./components/Chat.vue";
import { ref } from "vue";
const chatId = ref("123");
</script>

<template>
  <input v-model="chatId" type="number" />
  <p>
    {{ chatId }}
  </p>
  <Chat :chatId />
</template>

// Chat.vue
<template>
  <p>{{ chatId }}</p>
  <p>{{ id }}</p>
</template>
<script setup lang="ts">
import { useChat } from "@ai-sdk/vue";
const props = defineProps<{ chatId: string }>();
const { id } = useChat({ id: props.chatId });
</script>

AI provider

No response

Additional context

Differently from React, the setup function is not re-executed every time props change, but rather the properties themselves are reactive.

The standard pattern for Vue composables that have to react to their input is to accept a MaybeRef<T> as a parameter and use computed/watch/watchEffect to handle changes to the parameter, rather than rely on useChat being invoked again when they change.

pqnet avatar Feb 15 '25 14:02 pqnet

I'm having the same issue. did you find a work around @pqnet?

yukarlo avatar Apr 28 '25 13:04 yukarlo

I'm having the same issue. did you find a work around @pqnet?

The workaround is to use ref to force the component that hosts useChat to be recreated when it changes. Which is usually all the page. This is quite ugly but at least it works. Alternatively you can keep the same fictitious id in useChat and manually remove and reload all messages when the conversation changes. Third you can ditch it completely and write your own, either using the undocumented low level response/stream parsing functions inside ai-sdk or manually implementing your own (the stream format is documented and specified)

pqnet avatar Apr 29 '25 05:04 pqnet

The workaround is to use ref to force the component that hosts useChat to be recreated when it changes. Which is usually all the page. This is quite ugly but at least it works.

It is not only ugly, but won't work either.

Consider this use case: user switches to another chat before the first one completes streaming, and then comes back to the first, and hit the stop button.

If you force the component to rerender in order to respond to a reactive id, useChat will be called again, which will return a different stop function, which won't cancel the initial unfinished stream.

The current vue composable implementation is very largely not reactive, which makes it very difficult to work with. I think the API should be more native to vue instead of a mimic of the react one.

wicii2120 avatar May 28 '25 08:05 wicii2120

I'm having the same issue, we have some news ?

Met96 avatar Jun 17 '25 10:06 Met96

in ai sdk 5 you cannot change the chat by changing the id any more

lgrammel avatar Jun 26 '25 10:06 lgrammel

@lgrammel sorry but i have a question, because i'm creating a clone of chatgpt for myself, with sidebar chats ecc... And when i'm starting to chat with the assistant i'm going to take the ChatID and save the messages in a KV with this ID. But I need the possibility if i close the blog, after 1 month go back in the old chat i wanna retrieve the last messages a continue to chatting and save in the same KV ID. This is no more possibile right ? Can you give me an alternative ?

Met96 avatar Jun 26 '25 12:06 Met96

should be possible. with vue you can create a new chat instance with the new id and messages, and then use resume (if you have resumable streams set up)

lgrammel avatar Jun 26 '25 13:06 lgrammel

should be possible. with vue you can create a new chat instance with the new id and messages, and then use resume (if you have resumable streams set up)

The issue is exactly about that: how do you create a new chat instance? useChat does not allow us to do that. Lifetime in Vue does not work as in React. Code in setup function in Vue is only executed once in the lifetime of a component, composables are supposed to be able to adapt to a change in their parameters.

Normally we could force creating a new chat instance every time the id changes by doing something like this:

const id = ref(...);
const chatref = computed(() => useChat(id.value))

But this doesn't work because useChat registers lifetime hooks, and as such it must be called on top level setup() scope.

For an explanation of why reactivity in Vue works differently than in React, see tutorial at https://vuejs.org/guide/reusability/composables#async-state-example

@lgrammel Can you please reopen this issue?

pqnet avatar Jul 03 '25 11:07 pqnet

Looking at the code I can see that a new low level Chat class is available in the 2.0 beta version of the library, and the useChat composable has been removed. It is now[^beta] possible to do

const id = ref(...);
const chatref = computed(() => new Chat(id.value))

[^beta]: using @ai-sdk/vue@beta

pqnet avatar Jul 03 '25 13:07 pqnet

Looking at the code I can see that a new low level Chat class is available in the 2.0 beta version of the library, and the useChat composable has been removed. It is now1 possible to do

const id = ref(...); const chatref = computed(() => new Chat(id.value))

Footnotes

1. using `@ai-sdk/vue@beta` [↩](#user-content-fnref-beta-77612ce6a5a825f8d652e478dc0439b5)

Version 2 is now stable. Closing the issue.

pqnet avatar Aug 07 '25 13:08 pqnet