EditMessage marks the old user message as deleted, soft-deletes all following messages, inserts a new message with the updated content, clears queued messages, and moves the chat into pending status.
( ctx context.Context, opts EditMessageOptions, )
| 2017 | // following messages, inserts a new message with the updated content, |
| 2018 | // clears queued messages, and moves the chat into pending status. |
| 2019 | func (p *Server) EditMessage( |
| 2020 | ctx context.Context, |
| 2021 | opts EditMessageOptions, |
| 2022 | ) (EditMessageResult, error) { |
| 2023 | if opts.ChatID == uuid.Nil { |
| 2024 | return EditMessageResult{}, xerrors.New("chat_id is required") |
| 2025 | } |
| 2026 | if opts.EditedMessageID <= 0 { |
| 2027 | return EditMessageResult{}, xerrors.New("edited_message_id is required") |
| 2028 | } |
| 2029 | if len(opts.Content) == 0 { |
| 2030 | return EditMessageResult{}, xerrors.New("content is required") |
| 2031 | } |
| 2032 | |
| 2033 | content, err := chatprompt.MarshalParts(opts.Content) |
| 2034 | if err != nil { |
| 2035 | return EditMessageResult{}, xerrors.Errorf("marshal message content: %w", err) |
| 2036 | } |
| 2037 | |
| 2038 | var ( |
| 2039 | result EditMessageResult |
| 2040 | editedMsg database.ChatMessage |
| 2041 | ) |
| 2042 | txErr := p.db.InTx(func(tx database.Store) error { |
| 2043 | lockedChat, err := tx.GetChatByIDForUpdate(ctx, opts.ChatID) |
| 2044 | if err != nil { |
| 2045 | return xerrors.Errorf("lock chat: %w", err) |
| 2046 | } |
| 2047 | |
| 2048 | if lockedChat.Archived { |
| 2049 | return ErrChatArchived |
| 2050 | } |
| 2051 | |
| 2052 | if limitErr := p.checkUsageLimit(ctx, tx, lockedChat.OwnerID, uuid.NullUUID{UUID: lockedChat.OrganizationID, Valid: true}); limitErr != nil { |
| 2053 | return limitErr |
| 2054 | } |
| 2055 | |
| 2056 | editedMsg, err = tx.GetChatMessageByID(ctx, opts.EditedMessageID) |
| 2057 | if err != nil { |
| 2058 | if errors.Is(err, sql.ErrNoRows) { |
| 2059 | return ErrEditedMessageNotFound |
| 2060 | } |
| 2061 | return xerrors.Errorf("get edited message: %w", err) |
| 2062 | } |
| 2063 | if editedMsg.ChatID != opts.ChatID { |
| 2064 | return ErrEditedMessageNotFound |
| 2065 | } |
| 2066 | if editedMsg.Role != database.ChatMessageRoleUser { |
| 2067 | return ErrEditedMessageNotUser |
| 2068 | } |
| 2069 | |
| 2070 | // Soft-delete the original message instead of updating in place |
| 2071 | // so that usage/cost data is preserved. |
| 2072 | err = tx.SoftDeleteChatMessageByID(ctx, opts.EditedMessageID) |
| 2073 | if err != nil { |
| 2074 | return xerrors.Errorf("soft-delete edited message: %w", err) |
| 2075 | } |
| 2076 |