Help with an edge case
I currently have an action which calls other mutations. In this scenario; we're trying to create an AI chat. I'm running into a scenario where the users message is created inside of the chat action before the AI's chat message.
On the first chat the frontend doesn't update until the action fully completes leading the frontend to update with the user message, and AI chat at the same time.
After the first message subsequent chats work as expected where the users message is created, updated on the frontend and then the AI chat message is updated and streamed in.
Any help with understanding what I might be doing wrong would be great!
13 Replies
How is the user's message created, is this an action with two mutations in it?
Ideally the UI is driven by a query that reads from tables that are modified at least twice during the action: first for the user's message, second for the AI message. (or if it's a streaming AI chat response, maybe dozens of times for the AI message)
One thing you might be seeing is that the logs from the Action don't print until the action fully succeeds. However, the data in the DB will be readable once the
runMutation
has completed.
If you have a query looking for the message when the action runs (could be run from the dashboard or CLI), it should show up ~instantlyHey just saw this now! It does have two mutations!
Could you share the chunk of action code where you see this?
Here's the bulk of the start of the action w/ the 2 mutations! I read recently I shouldn't be calling actions from the frontend whenever possible so I may need to re-factor things a bit!
Does it return the chat ID at the end of the action? My guess is the frontend doesn't know what to query for until the action returns the first time
Ahh that would make sense
It does currently
if the first mutation makes the chat and returns it, and kicks off the action to make the new message and update the chat you should be all set
"kicks off" with
ctx.scheduler.runAfter(0, ...
Okay cool I figured. I reread the "zen of convex" and noticed I wasn't technically following the paradigm correctly
Though it's a bit annoying that it can't make the first message until the embedding is created, so the first mutation would just be creating the chatId I guess
Hmm that's true. Not the biggest deal I can create the embedding slightly later and update
I would personally store embeddings in their own table and have message have an
embeddingId
on them, so you can query for messages from a vector search (by adding an index on embeddingId
), but never have to read the embedding value in DB fetches. Pattern covered here: https://docs.convex.dev/vector-search#advanced-patternsVector Search | Convex Developer Hub
Run vector search queries on embeddings