























@@ -10,21 +10,7 @@ import { normalizeTelegramReplyToMessageId } from "./outbound-params.js";
10101111const TELEGRAM_STREAM_MAX_CHARS = 4096;
1212const DEFAULT_THROTTLE_MS = 1000;
13-const TELEGRAM_DRAFT_ID_MAX = 2_147_483_647;
1413const THREAD_NOT_FOUND_RE = /400:\s*Bad Request:\s*message thread not found/i;
15-const DRAFT_METHOD_UNAVAILABLE_RE =
16-/(unknown method|method .*not (found|available|supported)|unsupported)/i;
17-const DRAFT_CHAT_UNSUPPORTED_RE = /(can't be used|can be used only)/i;
18-19-type TelegramSendMessageDraft = (
20-chatId: Parameters<Bot["api"]["sendMessage"]>[0],
21-draftId: number,
22-text: string,
23-params?: {
24-message_thread_id?: number;
25-parse_mode?: "HTML";
26-},
27-) => Promise<unknown>;
28142915type TelegramSendMessageParams = Parameters<Bot["api"]["sendMessage"]>[2];
3016@@ -38,71 +24,18 @@ function hasNumericMessageThreadId(
3824);
3925}
402641-/**
42- * Keep draft-id allocation shared across bundled chunks so concurrent preview
43- * lanes do not accidentally reuse draft ids when code-split entries coexist.
44- */
45-const TELEGRAM_DRAFT_STREAM_STATE_KEY = Symbol.for("openclaw.telegramDraftStreamState");
46-let draftStreamState: { nextDraftId: number } | undefined;
47-48-function getDraftStreamState(): { nextDraftId: number } {
49-if (!draftStreamState) {
50-const globalStore = globalThis as Record<PropertyKey, unknown>;
51-draftStreamState = (globalStore[TELEGRAM_DRAFT_STREAM_STATE_KEY] as
52-| { nextDraftId: number }
53-| undefined) ?? {
54-nextDraftId: 0,
55-};
56-globalStore[TELEGRAM_DRAFT_STREAM_STATE_KEY] = draftStreamState;
57-}
58-return draftStreamState;
59-}
60-61-function allocateTelegramDraftId(): number {
62-const state = getDraftStreamState();
63-state.nextDraftId = state.nextDraftId >= TELEGRAM_DRAFT_ID_MAX ? 1 : state.nextDraftId + 1;
64-return state.nextDraftId;
65-}
66-67-function resolveSendMessageDraftApi(api: Bot["api"]): TelegramSendMessageDraft | undefined {
68-const sendMessageDraft = (api as Bot["api"] & { sendMessageDraft?: TelegramSendMessageDraft })
69-.sendMessageDraft;
70-if (typeof sendMessageDraft !== "function") {
71-return undefined;
72-}
73-return sendMessageDraft.bind(api as object);
74-}
75-76-function shouldFallbackFromDraftTransport(err: unknown): boolean {
77-const text =
78-typeof err === "string"
79- ? err
80- : err instanceof Error
81- ? err.message
82- : typeof err === "object" && err && "description" in err
83- ? typeof err.description === "string"
84- ? err.description
85- : ""
86- : "";
87-if (!/sendMessageDraft/i.test(text)) {
88-return false;
89-}
90-return DRAFT_METHOD_UNAVAILABLE_RE.test(text) || DRAFT_CHAT_UNSUPPORTED_RE.test(text);
91-}
92-9327export type TelegramDraftStream = {
9428update: (text: string) => void;
9529flush: () => Promise<void>;
9630messageId: () => number | undefined;
9731visibleSinceMs?: () => number | undefined;
98-previewMode?: () => "message" | "draft";
9932previewRevision?: () => number;
10033lastDeliveredText?: () => string;
10134clear: () => Promise<void>;
10235stop: () => Promise<void>;
10336/** Stop without a final flush or delete. */
10437discard?: () => Promise<void>;
105-/** Convert the current draft preview into a permanent message (sendMessage). */
38+/** Return the current preview message id after pending updates settle. */
10639materialize?: () => Promise<number | undefined>;
10740/** Reset internal state so the next update creates a new message instead of editing. */
10841forceNewMessage: () => void;
@@ -127,7 +60,6 @@ export function createTelegramDraftStream(params: {
12760chatId: Parameters<Bot["api"]["sendMessage"]>[0];
12861maxChars?: number;
12962thread?: TelegramThreadSpec | null;
130-previewTransport?: "auto" | "message" | "draft";
13163replyToMessageId?: number;
13264throttleMs?: number;
13365/** Minimum chars before sending first message (debounce for push notifications) */
@@ -146,13 +78,6 @@ export function createTelegramDraftStream(params: {
14678const throttleMs = Math.max(250, params.throttleMs ?? DEFAULT_THROTTLE_MS);
14779const minInitialChars = params.minInitialChars;
14880const chatId = params.chatId;
149-const requestedPreviewTransport = params.previewTransport ?? "auto";
150-const prefersDraftTransport =
151-requestedPreviewTransport === "draft"
152- ? true
153- : requestedPreviewTransport === "message"
154- ? false
155- : params.thread?.scope === "dm";
15681const threadParams = buildTelegramThreadParams(params.thread);
15782const replyToMessageId = normalizeTelegramReplyToMessageId(params.replyToMessageId);
15883const replyParams =
@@ -163,22 +88,11 @@ export function createTelegramDraftStream(params: {
16388allow_sending_without_reply: true,
16489}
16590 : threadParams;
166-const resolvedDraftApi = prefersDraftTransport
167- ? resolveSendMessageDraftApi(params.api)
168- : undefined;
169-const usesDraftTransport = Boolean(prefersDraftTransport && resolvedDraftApi);
170-if (prefersDraftTransport && !usesDraftTransport) {
171-params.warn?.(
172-"telegram stream preview: sendMessageDraft unavailable; falling back to sendMessage/editMessageText",
173-);
174-}
1759117692const streamState = { stopped: false, final: false };
17793let messageSendAttempted = false;
17894let streamMessageId: number | undefined;
17995let streamVisibleSinceMs: number | undefined;
180-let streamDraftId = usesDraftTransport ? allocateTelegramDraftId() : undefined;
181-let previewTransport: "message" | "draft" = usesDraftTransport ? "draft" : "message";
18296let lastSentText = "";
18397let lastDeliveredText = "";
18498let lastSentParseMode: "HTML" | undefined;
@@ -275,26 +189,6 @@ export function createTelegramDraftStream(params: {
275189streamVisibleSinceMs = visibleSinceMs;
276190return true;
277191};
278-const sendDraftTransportPreview = async ({
279- renderedText,
280- renderedParseMode,
281-}: PreviewSendParams): Promise<boolean> => {
282-const draftId = streamDraftId ?? allocateTelegramDraftId();
283-streamDraftId = draftId;
284-const draftParams = {
285- ...(threadParams?.message_thread_id != null
286- ? { message_thread_id: threadParams.message_thread_id }
287- : {}),
288- ...(renderedParseMode ? { parse_mode: renderedParseMode } : {}),
289-};
290-await resolvedDraftApi!(
291-chatId,
292-draftId,
293-renderedText,
294-Object.keys(draftParams).length > 0 ? draftParams : undefined,
295-);
296-return true;
297-};
298192299193const sendOrEditStreamMessage = async (text: string): Promise<boolean> => {
300194if (streamState.stopped && !streamState.final) {
@@ -331,36 +225,11 @@ export function createTelegramDraftStream(params: {
331225lastSentText = renderedText;
332226lastSentParseMode = renderedParseMode;
333227try {
334-let sent = false;
335-if (previewTransport === "draft") {
336-try {
337-sent = await sendDraftTransportPreview({
338- renderedText,
339- renderedParseMode,
340- sendGeneration,
341-});
342-} catch (err) {
343-if (!shouldFallbackFromDraftTransport(err)) {
344-throw err;
345-}
346-previewTransport = "message";
347-streamDraftId = undefined;
348-params.warn?.(
349-"telegram stream preview: sendMessageDraft rejected by API; falling back to sendMessage/editMessageText",
350-);
351-sent = await sendMessageTransportPreview({
352- renderedText,
353- renderedParseMode,
354- sendGeneration,
355-});
356-}
357-} else {
358-sent = await sendMessageTransportPreview({
359- renderedText,
360- renderedParseMode,
361- sendGeneration,
362-});
363-}
228+const sent = await sendMessageTransportPreview({
229+ renderedText,
230+ renderedParseMode,
231+ sendGeneration,
232+});
364233if (sent) {
365234previewRevision += 1;
366235lastDeliveredText = trimmed;
@@ -396,16 +265,6 @@ export function createTelegramDraftStream(params: {
396265}
397266return;
398267}
399-if (previewTransport !== "draft" || resolvedDraftApi == null || streamDraftId == null) {
400-return;
401-}
402-const clearDraftId = streamDraftId;
403-streamDraftId = undefined;
404-try {
405-await resolvedDraftApi(chatId, clearDraftId, "", threadParams);
406-} catch (err) {
407-params.warn?.(`telegram stream preview cleanup failed: ${formatErrorMessage(err)}`);
408-}
409268};
410269411270const discard = async () => {
@@ -419,9 +278,6 @@ export function createTelegramDraftStream(params: {
419278messageSendAttempted = false;
420279streamMessageId = undefined;
421280streamVisibleSinceMs = undefined;
422-if (previewTransport === "draft") {
423-streamDraftId = allocateTelegramDraftId();
424-}
425281lastSentText = "";
426282lastSentParseMode = undefined;
427283loop.resetPending();
@@ -430,41 +286,7 @@ export function createTelegramDraftStream(params: {
430286431287const materialize = async (): Promise<number | undefined> => {
432288await stop();
433-if (previewTransport === "message" && typeof streamMessageId === "number") {
434-return streamMessageId;
435-}
436-const renderedText = lastSentText || lastDeliveredText;
437-if (!renderedText) {
438-return undefined;
439-}
440-const renderedParseMode = lastSentText ? lastSentParseMode : undefined;
441-try {
442-const { sent, usedThreadParams } = await sendRenderedMessageWithThreadFallback({
443- renderedText,
444- renderedParseMode,
445-fallbackWarnMessage:
446-"telegram stream preview materialize send failed with message_thread_id, retrying without thread",
447-});
448-const sentId = sent?.message_id;
449-if (typeof sentId === "number" && Number.isFinite(sentId)) {
450-streamMessageId = Math.trunc(sentId);
451-streamVisibleSinceMs = Date.now();
452-if (resolvedDraftApi != null && streamDraftId != null) {
453-const clearDraftId = streamDraftId;
454-const clearThreadParams =
455-usedThreadParams && threadParams?.message_thread_id != null
456- ? { message_thread_id: threadParams.message_thread_id }
457- : undefined;
458-try {
459-await resolvedDraftApi(chatId, clearDraftId, "", clearThreadParams);
460-} catch {}
461-}
462-return streamMessageId;
463-}
464-} catch (err) {
465-params.warn?.(`telegram stream preview materialize failed: ${formatErrorMessage(err)}`);
466-}
467-return undefined;
289+return streamMessageId;
468290};
469291470292params.log?.(`telegram stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
@@ -474,7 +296,6 @@ export function createTelegramDraftStream(params: {
474296flush: loop.flush,
475297messageId: () => streamMessageId,
476298visibleSinceMs: () => streamVisibleSinceMs,
477-previewMode: () => previewTransport,
478299previewRevision: () => previewRevision,
479300lastDeliveredText: () => lastDeliveredText,
480301 clear,
@@ -485,9 +306,3 @@ export function createTelegramDraftStream(params: {
485306sendMayHaveLanded: () => messageSendAttempted && typeof streamMessageId !== "number",
486307};
487308}
488-489-export const __testing = {
490-resetTelegramDraftStreamForTests() {
491-getDraftStreamState().nextDraftId = 0;
492-},
493-};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。