



























@@ -2,17 +2,27 @@ import type {
22ChannelAccountSnapshot,
33ChannelStatusIssue,
44} from "openclaw/plugin-sdk/channel-contract";
5+import { formatCliCommand } from "openclaw/plugin-sdk/cli-runtime";
56import {
67appendMatchMetadata,
78asString,
89isRecord,
910resolveEnabledConfiguredAccountId,
1011} from "openclaw/plugin-sdk/status-helpers";
111213+const TELEGRAM_POLLING_CONNECT_GRACE_MS = 120_000;
14+const TELEGRAM_POLLING_STALE_TRANSPORT_MS = 30 * 60_000;
15+1216type TelegramAccountStatus = {
1317accountId?: unknown;
1418enabled?: unknown;
1519configured?: unknown;
20+running?: unknown;
21+connected?: unknown;
22+mode?: unknown;
23+lastStartAt?: unknown;
24+lastTransportActivityAt?: unknown;
25+lastError?: unknown;
1626allowUnmentionedGroups?: unknown;
1727audit?: unknown;
1828};
@@ -38,11 +48,82 @@ function readTelegramAccountStatus(value: ChannelAccountSnapshot): TelegramAccou
3848accountId: value.accountId,
3949enabled: value.enabled,
4050configured: value.configured,
51+running: value.running,
52+connected: value.connected,
53+mode: value.mode,
54+lastStartAt: value.lastStartAt,
55+lastTransportActivityAt: value.lastTransportActivityAt,
56+lastError: value.lastError,
4157allowUnmentionedGroups: value.allowUnmentionedGroups,
4258audit: value.audit,
4359};
4460}
456162+function asFiniteNumber(value: unknown): number | null {
63+return typeof value === "number" && Number.isFinite(value) ? value : null;
64+}
65+66+function appendTelegramRuntimeError(message: string, lastError: unknown): string {
67+const error = asString(lastError);
68+return error ? `${message}: ${error}` : message;
69+}
70+71+function collectTelegramPollingRuntimeIssues(params: {
72+account: TelegramAccountStatus;
73+accountId: string;
74+issues: ChannelStatusIssue[];
75+now: number;
76+}) {
77+const { account, accountId, issues, now } = params;
78+if (account.running !== true || asString(account.mode) !== "polling") {
79+return;
80+}
81+82+const lastStartAt = asFiniteNumber(account.lastStartAt);
83+const lastTransportActivityAt = asFiniteNumber(account.lastTransportActivityAt);
84+const fix = `Run: ${formatCliCommand("openclaw channels status --probe")} (or restart the gateway). Check the bot token, proxy/network settings, and logs if it persists.`;
85+86+if (account.connected === false) {
87+const withinStartupGrace =
88+lastStartAt != null && now - lastStartAt < TELEGRAM_POLLING_CONNECT_GRACE_MS;
89+if (!withinStartupGrace) {
90+issues.push({
91+channel: "telegram",
92+ accountId,
93+kind: "runtime",
94+message: appendTelegramRuntimeError(
95+"Telegram polling is running but has not completed a successful getUpdates call since startup",
96+account.lastError,
97+),
98+ fix,
99+});
100+}
101+return;
102+}
103+104+if (account.connected === true && lastTransportActivityAt != null) {
105+if (lastStartAt != null && lastTransportActivityAt < lastStartAt) {
106+const lifecycleAgeMs = Math.max(0, now - lastStartAt);
107+if (lifecycleAgeMs <= TELEGRAM_POLLING_STALE_TRANSPORT_MS) {
108+return;
109+}
110+}
111+const ageMs = now - lastTransportActivityAt;
112+if (ageMs > TELEGRAM_POLLING_STALE_TRANSPORT_MS) {
113+issues.push({
114+channel: "telegram",
115+ accountId,
116+kind: "runtime",
117+message: appendTelegramRuntimeError(
118+`Telegram polling transport is stale (last successful getUpdates ${Math.max(0, Math.floor(ageMs / 60_000))}m ago)`,
119+account.lastError,
120+),
121+ fix,
122+});
123+}
124+}
125+}
126+46127function readTelegramGroupMembershipAuditSummary(
47128value: unknown,
48129): TelegramGroupMembershipAuditSummary {
@@ -94,6 +175,13 @@ export function collectTelegramStatusIssues(
94175continue;
95176}
96177178+collectTelegramPollingRuntimeIssues({
179+ account,
180+ accountId,
181+ issues,
182+now: Date.now(),
183+});
184+97185if (account.allowUnmentionedGroups === true) {
98186issues.push({
99187channel: "telegram",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。