claimCommittedParts walks the chat's buffered message_part events and assigns every in-progress part (committedMessageID == 0) to the supplied assistant message ID. Subsequent subscriber snapshots drop those parts so a reconnecting client does not re-render the content of an assistant turn that has
(chatID uuid.UUID, message database.ChatMessage)
| 5718 | // Tool and user messages do not end an assistant streaming turn, so |
| 5719 | // only assistant-role messages claim parts. |
| 5720 | func (p *Server) claimCommittedParts(chatID uuid.UUID, message database.ChatMessage) { |
| 5721 | if message.Role != database.ChatMessageRoleAssistant { |
| 5722 | return |
| 5723 | } |
| 5724 | val, ok := p.chatStreams.Load(chatID) |
| 5725 | if !ok { |
| 5726 | return |
| 5727 | } |
| 5728 | state, ok := val.(*chatStreamState) |
| 5729 | if !ok { |
| 5730 | return |
| 5731 | } |
| 5732 | state.mu.Lock() |
| 5733 | defer state.mu.Unlock() |
| 5734 | for i := range state.buffer { |
| 5735 | if state.buffer[i].committedMessageID == 0 { |
| 5736 | state.buffer[i].committedMessageID = message.ID |
| 5737 | } |
| 5738 | } |
| 5739 | } |
| 5740 | |
| 5741 | // publishEditedMessage is like publishMessage but uses FullRefresh |
| 5742 | // so remote subscribers re-fetch from the beginning, ensuring the |