


























@@ -115,6 +115,15 @@ function compactChunks(chunks: readonly string[]): string[] {
115115return out;
116116}
117117118+function isDeliveredPrefix(params: { deliveredText: string | undefined; finalText: string }) {
119+if (!params.deliveredText || params.deliveredText.length === 0) {
120+return false;
121+}
122+return (
123+params.finalText === params.deliveredText || params.finalText.startsWith(params.deliveredText)
124+);
125+}
126+118127export function createLaneTextDeliverer(params: CreateLaneTextDelivererParams) {
119128const followUpPayload = (payload: ReplyPayload, text: string) =>
120129params.applyTextToFollowUpPayload
@@ -270,6 +279,53 @@ export function createLaneTextDeliverer(params: CreateLaneTextDelivererParams) {
270279if (!firstChunk || firstChunk.length > params.draftMaxChars) {
271280return undefined;
272281}
282+const finalText = text.trimEnd();
283+const deliveredStreamTextBeforeUpdate = stream.lastDeliveredText?.();
284+const deliveredPrefixBeforeUpdate =
285+isFinal &&
286+deliveredStreamTextBeforeUpdate !== undefined &&
287+isDeliveredPrefix({
288+deliveredText: deliveredStreamTextBeforeUpdate,
289+ finalText,
290+}) &&
291+deliveredStreamTextBeforeUpdate.length > firstChunk.trimEnd().length;
292+const finalizeDeliveredPrefix = async (
293+deliveredStreamText: string,
294+messageId: number,
295+): Promise<LaneDeliveryResult> => {
296+lane.finalized = true;
297+params.markDelivered();
298+let buttonsAttached = false;
299+if (buttons) {
300+const deliveredChunks = compactChunks(
301+params.splitFinalTextForStream?.(deliveredStreamText) ?? [],
302+);
303+const currentChunk = deliveredChunks.at(-1);
304+if (currentChunk && currentChunk.length <= params.draftMaxChars) {
305+try {
306+await params.editStreamMessage({ laneName, messageId, text: currentChunk, buttons });
307+buttonsAttached = true;
308+} catch (err) {
309+params.log(`telegram: ${laneName} stream button edit failed: ${String(err)}`);
310+}
311+}
312+}
313+const suffix = finalText.slice(deliveredStreamText.length);
314+if (suffix.trim().length > 0) {
315+for (const chunk of compactChunks(params.splitFinalTextForStream?.(suffix) ?? [])) {
316+if (chunk.trim().length === 0) {
317+continue;
318+}
319+await params.sendPayload(followUpPayload(payload, chunk));
320+}
321+}
322+return result("preview-finalized", {
323+content: text,
324+promptContextContent: deliveredStreamText,
325+ messageId,
326+ buttonsAttached,
327+});
328+};
273329274330const retainedPreview =
275331isFinal && remainingChunks.length === 0 && isPotentialTruncatedFinal(text)
@@ -296,8 +352,11 @@ export function createLaneTextDeliverer(params: CreateLaneTextDelivererParams) {
296352}
297353return undefined;
298354}
299-const deliveredStreamText = stream.lastDeliveredText?.();
300-if (deliveredStreamText !== undefined && deliveredStreamText !== previewText) {
355+const deliveredStreamTextAfterStop = stream.lastDeliveredText?.();
356+if (
357+deliveredStreamTextAfterStop !== undefined &&
358+deliveredStreamTextAfterStop !== previewText
359+) {
301360return undefined;
302361}
303362let buttonsAttached = false;
@@ -320,10 +379,12 @@ export function createLaneTextDeliverer(params: CreateLaneTextDelivererParams) {
320379return result("preview-finalized", { content: previewText, messageId, buttonsAttached });
321380}
322381323-lane.lastPartialText = firstChunk;
324-lane.hasStreamedMessage = true;
325-lane.finalized = false;
326-stream.update(firstChunk);
382+if (!deliveredPrefixBeforeUpdate) {
383+lane.lastPartialText = firstChunk;
384+lane.hasStreamedMessage = true;
385+lane.finalized = false;
386+stream.update(firstChunk);
387+}
327388if (isFinal) {
328389await params.stopDraftLane(lane);
329390} else {
@@ -340,15 +401,25 @@ export function createLaneTextDeliverer(params: CreateLaneTextDelivererParams) {
340401return undefined;
341402}
342403343-const deliveredStreamText = stream.lastDeliveredText?.();
404+const deliveredStreamTextAfterStop = stream.lastDeliveredText?.();
344405if (
345406isFinal &&
346-deliveredStreamText !== undefined &&
347-deliveredStreamText !== firstChunk.trimEnd()
407+deliveredStreamTextAfterStop !== undefined &&
408+deliveredStreamTextAfterStop !== firstChunk.trimEnd()
348409) {
410+if (
411+isDeliveredPrefix({ deliveredText: deliveredStreamTextAfterStop, finalText }) &&
412+deliveredStreamTextAfterStop.length > firstChunk.trimEnd().length
413+) {
414+return await finalizeDeliveredPrefix(deliveredStreamTextAfterStop, messageId);
415+}
349416return undefined;
350417}
351418419+if (deliveredPrefixBeforeUpdate && deliveredStreamTextAfterStop === undefined) {
420+return await finalizeDeliveredPrefix(deliveredStreamTextBeforeUpdate, messageId);
421+}
422+352423params.markDelivered();
353424let buttonsAttached = false;
354425if (buttons) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。