
























@@ -110,6 +110,51 @@ const silentReplyDispatchLogger = createSubsystemLogger("telegram/silent-reply-d
110110/** Minimum chars before sending first streaming message (improves push notification UX) */
111111const DRAFT_MIN_INITIAL_CHARS = 30;
112112113+function appendWithOverlap(previous: string, fragment: string): string {
114+const maxOverlap = Math.min(previous.length, fragment.length);
115+for (let overlap = maxOverlap; overlap > 0; overlap -= 1) {
116+if (previous.endsWith(fragment.slice(0, overlap))) {
117+return `${previous}${fragment.slice(overlap)}`;
118+}
119+}
120+return `${previous}${fragment}`;
121+}
122+123+function looksLikeDraftDeltaFragment(previous: string, text: string): boolean {
124+if (!previous || !text) {
125+return false;
126+}
127+if (text.startsWith(previous) || previous.startsWith(text)) {
128+return false;
129+}
130+if (/^\s/.test(text)) {
131+return true;
132+}
133+if (previous.length < DRAFT_MIN_INITIAL_CHARS) {
134+return true;
135+}
136+if (/\s$/.test(previous) && text.length <= DRAFT_MIN_INITIAL_CHARS) {
137+return true;
138+}
139+return text.length <= Math.max(16, Math.floor(previous.length / 2));
140+}
141+142+function resolveDraftPartialText(previous: string, text: string): string | undefined {
143+if (!previous) {
144+return text;
145+}
146+if (text === previous) {
147+return undefined;
148+}
149+if (text.startsWith(previous)) {
150+return text;
151+}
152+if (previous.startsWith(text) && text.length < previous.length) {
153+return undefined;
154+}
155+return looksLikeDraftDeltaFragment(previous, text) ? appendWithOverlap(previous, text) : text;
156+}
157+113158async function resolveStickerVisionSupport(cfg: OpenClawConfig, agentId: string) {
114159try {
115160const catalog = await loadModelCatalog({ config: cfg });
@@ -717,7 +762,8 @@ export const dispatchTelegramMessage = async ({
717762if (!laneStream || !text) {
718763return;
719764}
720-if (text === lane.lastPartialText) {
765+const nextText = resolveDraftPartialText(lane.lastPartialText, text);
766+if (!nextText) {
721767return;
722768}
723769if (lane === answerLane) {
@@ -729,15 +775,8 @@ export const dispatchTelegramMessage = async ({
729775}
730776lane.hasStreamedMessage = true;
731777lane.finalized = false;
732-if (
733-lane.lastPartialText &&
734-lane.lastPartialText.startsWith(text) &&
735-text.length < lane.lastPartialText.length
736-) {
737-return;
738-}
739-lane.lastPartialText = text;
740-laneStream.update(text);
778+lane.lastPartialText = nextText;
779+laneStream.update(nextText);
741780};
742781const ingestDraftLaneSegments = async (text: string | undefined, isReasoning?: boolean) => {
743782const split = splitTextIntoLaneSegments(text, isReasoning);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。