import { AbstractChat, type ChatInit as BaseChatInit, type ChatState, type ChatStatus, type UIMessage, } from 'ai'; import { ref, type Ref } from 'vue'; class VueChatState< UI_MESSAGE extends UIMessage, > implements ChatState { private messagesRef: Ref; private statusRef = ref('ready'); private errorRef = ref(undefined); constructor(messages?: UI_MESSAGE[]) { this.messagesRef = ref(messages ?? []) as Ref; } get messages(): UI_MESSAGE[] { return this.messagesRef.value; } set messages(messages: UI_MESSAGE[]) { this.messagesRef.value = messages; } get status(): ChatStatus { return this.statusRef.value; } set status(status: ChatStatus) { this.statusRef.value = status; } get error(): Error | undefined { return this.errorRef.value; } set error(error: Error | undefined) { this.errorRef.value = error; } pushMessage = (message: UI_MESSAGE) => { this.messagesRef.value = [...this.messagesRef.value, message]; }; popMessage = () => { this.messagesRef.value = this.messagesRef.value.slice(0, -1); }; replaceMessage = (index: number, message: UI_MESSAGE) => { // message is cloned here because vue's deep reactivity shows unexpected behavior, particularly when updating tool invocation parts this.messagesRef.value[index] = { ...message }; }; snapshot = (value: T): T => value; } export class Chat< UI_MESSAGE extends UIMessage, > extends AbstractChat { constructor({ messages, ...init }: BaseChatInit) { super({ ...init, state: new VueChatState(messages), }); } }