Commit ac7a732
committed
fix(chat): deduplicate chat sends server-side instead of probing for them
A client cannot tell whether a request it aborted reached the server: the chat
route never reads `request.signal`, so an accepted one still opens the chat,
persists the user message, and bills the turn after the socket drops. #6525
answered that by polling the orphaned stream before retrying — a 2.5s guess
that had to distinguish "no such stream" from "we stopped looking", and still
left a window open.
The codebase already owns the right tool. `IdempotencyService` backs webhook,
polling, and billing dedup, and `billingIdempotency` exists for exactly this
hazard: "a retry would double-record usage — real money". Chat sends now claim
the same way, keyed on the client-generated `userMessageId` and scoped to the
caller so nobody can probe another user's sends. A repeat gets 409 naming the
chat the first attempt opened — deliberately the shape the pending-stream lock
already returns, so the client's existing conflict handler reattaches instead
of starting a turn, with only the chat-adoption line added.
The claim fails open at every step. Deduplication saves a duplicate chat; the
send IS the user's message, so an unreachable bookkeeping store degrades chat
rather than taking it down. It is released when a send fails before recording a
chat, and deliberately kept once recorded.
Retrying now just reuses the id, which deletes the probe outright: the poll and
its two constants, the three-state result, the epoch plumbing that kept a
superseded poll from re-sending, and the chat-adoption branch it needed. The
client hook nets 67 lines smaller.
Idle sends go back to calling `startSendMessage` directly. #6525 routed them
through the durable queue so recovery had a backing entry, which put every
message in the product through the queue store, sessionStorage, and the
dispatch loop for the sake of a rare path — and the recovery never needed it,
since the message, attachments, contexts, and id are all in scope at the abort.
Both callers now share one `handOffWithdrawnSend`.
`startSendMessage` takes its optional tail as an options object; it was at six
positional parameters and the retry id would have been a seventh.
Tests cover both halves: the server dedups, scopes the key per user, records
the chat, and still sends when the claim store is down; the client reuses the
original id on retry and adopts the chat a deduplicated retry names. Each was
confirmed red without its fix.1 parent 9277e7d commit ac7a732
11 files changed
Lines changed: 577 additions & 492 deletions
File tree
- apps/sim
- app/workspace/[workspaceId]
- home
- hooks
- w/[workflowId]/components/panel
- lib
- copilot/chat
- core
- idempotency
- utils
- mothership
- stores/mothership-queue
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
342 | 342 | | |
343 | 343 | | |
344 | 344 | | |
345 | | - | |
| 345 | + | |
346 | 346 | | |
347 | 347 | | |
348 | 348 | | |
| |||
373 | 373 | | |
374 | 374 | | |
375 | 375 | | |
376 | | - | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
377 | 379 | | |
378 | 380 | | |
379 | 381 | | |
| |||
Lines changed: 140 additions & 248 deletions
Large diffs are not rendered by default.
Lines changed: 140 additions & 215 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
490 | 490 | | |
491 | 491 | | |
492 | 492 | | |
493 | | - | |
| 493 | + | |
494 | 494 | | |
495 | 495 | | |
496 | 496 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
39 | 42 | | |
40 | 43 | | |
41 | 44 | | |
| |||
51 | 54 | | |
52 | 55 | | |
53 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
54 | 60 | | |
55 | 61 | | |
56 | 62 | | |
| |||
103 | 109 | | |
104 | 110 | | |
105 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
106 | 120 | | |
107 | 121 | | |
108 | 122 | | |
| |||
132 | 146 | | |
133 | 147 | | |
134 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
135 | 157 | | |
136 | 158 | | |
137 | 159 | | |
| |||
725 | 747 | | |
726 | 748 | | |
727 | 749 | | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
728 | 851 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| 61 | + | |
| 62 | + | |
61 | 63 | | |
62 | 64 | | |
63 | 65 | | |
| |||
943 | 945 | | |
944 | 946 | | |
945 | 947 | | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
946 | 1017 | | |
947 | 1018 | | |
948 | 1019 | | |
949 | 1020 | | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
950 | 1028 | | |
951 | 1029 | | |
952 | 1030 | | |
| |||
981 | 1059 | | |
982 | 1060 | | |
983 | 1061 | | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
984 | 1067 | | |
985 | 1068 | | |
986 | 1069 | | |
| |||
1073 | 1156 | | |
1074 | 1157 | | |
1075 | 1158 | | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
1076 | 1181 | | |
1077 | 1182 | | |
1078 | 1183 | | |
| |||
1377 | 1482 | | |
1378 | 1483 | | |
1379 | 1484 | | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
1380 | 1498 | | |
1381 | 1499 | | |
1382 | 1500 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
733 | 733 | | |
734 | 734 | | |
735 | 735 | | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
0 commit comments