






















@@ -795,6 +795,19 @@ describe("block reply coalescer", () => {
795795return { flushes, coalescer };
796796}
797797798+type FlushedPayload = Parameters<Parameters<typeof createBlockReplyCoalescer>[0]["onFlush"]>[0];
799+function createPayloadCoalescerHarness<T>(pick: (payload: FlushedPayload) => T) {
800+const flushes: T[] = [];
801+const coalescer = createBlockReplyCoalescer({
802+config: { minChars: 1, maxChars: 200, idleMs: 0, joiner: " " },
803+shouldAbort: () => false,
804+onFlush: (payload) => {
805+flushes.push(pick(payload));
806+},
807+});
808+return { flushes, coalescer };
809+}
810+798811it("coalesces chunks within the idle window", async () => {
799812vi.useFakeTimers();
800813const { flushes, coalescer } = createBlockCoalescerHarness({
@@ -967,26 +980,107 @@ describe("block reply coalescer", () => {
967980}
968981});
969982970-it("flushes buffered text before media payloads", () => {
971-const flushes: Array<{ text?: string; mediaUrls?: string[] }> = [];
972-const coalescer = createBlockReplyCoalescer({
973-config: { minChars: 1, maxChars: 200, idleMs: 0, joiner: " " },
974-shouldAbort: () => false,
975-onFlush: (payload) => {
976-flushes.push({
977-text: payload.text,
978-mediaUrls: payload.mediaUrls,
979-});
983+it("merges compatible buffered text into following media payloads", async () => {
984+const { flushes, coalescer } = createPayloadCoalescerHarness<{
985+text?: string;
986+mediaUrls?: string[];
987+replyToId?: string;
988+}>((payload) => ({
989+text: payload.text,
990+mediaUrls: payload.mediaUrls,
991+replyToId: payload.replyToId,
992+}));
993+994+coalescer.enqueue({ text: "Hello", replyToId: "thread-1" });
995+coalescer.enqueue({ text: "world" });
996+coalescer.enqueue({ mediaUrls: ["https://example.com/a.png"] });
997+await coalescer.flush({ force: true });
998+999+expect(flushes).toEqual([
1000+{
1001+text: "Hello world",
1002+mediaUrls: ["https://example.com/a.png"],
1003+replyToId: "thread-1",
9801004},
981-});
1005+]);
1006+coalescer.stop();
1007+});
9821008983-coalescer.enqueue({ text: "Hello" });
984-coalescer.enqueue({ text: "world" });
1009+it("keeps reasoning text separate from media payloads", async () => {
1010+const { flushes, coalescer } = createPayloadCoalescerHarness<{
1011+text?: string;
1012+mediaUrls?: string[];
1013+isReasoning?: boolean;
1014+}>((payload) => ({
1015+text: payload.text,
1016+mediaUrls: payload.mediaUrls,
1017+isReasoning: payload.isReasoning,
1018+}));
1019+1020+coalescer.enqueue({ text: "hidden", isReasoning: true });
9851021coalescer.enqueue({ mediaUrls: ["https://example.com/a.png"] });
986-void coalescer.flush({ force: true });
1022+await coalescer.flush({ force: true });
1023+1024+expect(flushes).toEqual([
1025+{ text: "hidden", mediaUrls: undefined, isReasoning: true },
1026+{
1027+text: undefined,
1028+mediaUrls: ["https://example.com/a.png"],
1029+isReasoning: undefined,
1030+},
1031+]);
1032+coalescer.stop();
1033+});
1034+1035+it("keeps buffered text separate when media changes reply target", async () => {
1036+const { flushes, coalescer } = createPayloadCoalescerHarness<{
1037+text?: string;
1038+mediaUrls?: string[];
1039+replyToId?: string;
1040+}>((payload) => ({
1041+text: payload.text,
1042+mediaUrls: payload.mediaUrls,
1043+replyToId: payload.replyToId,
1044+}));
1045+1046+coalescer.enqueue({ text: "Unthreaded caption" });
1047+coalescer.enqueue({ mediaUrls: ["https://example.com/a.png"], replyToId: "thread-2" });
1048+await coalescer.flush({ force: true });
9871049988-expect(flushes[0].text).toBe("Hello world");
989-expect(flushes[1].mediaUrls).toEqual(["https://example.com/a.png"]);
1050+expect(flushes).toEqual([
1051+{ text: "Unthreaded caption", mediaUrls: undefined, replyToId: undefined },
1052+{
1053+text: undefined,
1054+mediaUrls: ["https://example.com/a.png"],
1055+replyToId: "thread-2",
1056+},
1057+]);
1058+coalescer.stop();
1059+});
1060+1061+it("keeps text separate from voice media payloads", async () => {
1062+const { flushes, coalescer } = createPayloadCoalescerHarness<{
1063+text?: string;
1064+mediaUrls?: string[];
1065+audioAsVoice?: boolean;
1066+}>((payload) => ({
1067+text: payload.text,
1068+mediaUrls: payload.mediaUrls,
1069+audioAsVoice: payload.audioAsVoice,
1070+}));
1071+1072+coalescer.enqueue({ text: "Listen to this" });
1073+coalescer.enqueue({ mediaUrls: ["https://example.com/a.ogg"], audioAsVoice: true });
1074+await coalescer.flush({ force: true });
1075+1076+expect(flushes).toEqual([
1077+{ text: "Listen to this", mediaUrls: undefined, audioAsVoice: undefined },
1078+{
1079+text: undefined,
1080+mediaUrls: ["https://example.com/a.ogg"],
1081+audioAsVoice: true,
1082+},
1083+]);
9901084coalescer.stop();
9911085});
9921086});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。