Duo Agentic Chat processes opening thread at least 2 times
Due to a combination of event handlers and watchers, loading a thread is not optimal in Duo Chat, initiating processing of the whole thread at least two times.
Discovery
The current implementation drives things in two parallel streams (can be read as "race conditions"):
Updates on the thread-selected event
- while on the history view, user clicks one of the listed threads
- the
web-agentic-duo-chatcomponent emitsthread-selectedthat triggers theonThreadSelected()handler - the
onThreadSelectedhandler callshydrateActiveThread, among other things - the
hydrateActiveThreadcallsloadActiveThread. That one, in its turn, fetches all the messages for the selected thread (acriveThread) - after the messages are fetched, they are currently stored in
chatMessageHistory.
So far, so good.
However, the story doesn't end here. The action of selecting a thread from the history view also triggers another reaction chain.
Updates in the mode watcher
- while on the history view, the
modeprop is set tohistory - when user selects a thread, it also switches the mode to
active, which, in its turn… - triggers the watcher for the
modeprop - the watcher calls
switchMode - the
switchMode, when the mode is set toactivebranches into two options:hydrateActiveThread()(whenthis.shouldLoadThread === true) again, even though it was done in the algorithm above, or starts a new chat withonNewChat(). - the only reason, this still works on
masteris thatchatMessageHistorycover that duplicatesthis.messagesin a lot of cases and is about to be removed in the course of Reduced Duo Agentic Chat messages processing (!212409 - merged)
This processing is not only fundamentally wrong, but also prone to producing a real bug where, in case we use state's messages as a SSOT:
- in the course of reacting to the event (first algorithm) we store messages in the store
- that updates the
shouldLoadThreadcomputed prop to returntrue(because of!this.messages?.lengthcheck) - that leads to
switchModepicking theonNewChat, instead ofhydrateActiveThread()in the second algorithm (triggered in the watcher), that wipes off all the messages and leaves the opened thread without any messages.
Edited by Denys Mishunov