fix(telegram): use truncateUtf16Safe for raw update log truncation (#102567)

* fix(telegram): use truncateUtf16Safe for raw update log truncation

* refactor(telegram): own raw log bounds in formatter

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
lsr911 2026-07-09 18:11:35 +08:00 committed by GitHub
parent e39e628a84
commit 6ad8a77b51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 13 deletions

View file

@ -1,8 +1,8 @@
// Telegram tests cover bot core.raw update log plugin behavior.
import { describe, expect, it } from "vitest";
import { stringifyTelegramRawUpdateForLog } from "./raw-update-log.js";
import { formatTelegramRawUpdateForLog } from "./raw-update-log.js";
describe("stringifyTelegramRawUpdateForLog", () => {
describe("formatTelegramRawUpdateForLog", () => {
it("redacts private Telegram raw update fields before verbose logging", () => {
const update = {
update_id: 98765,
@ -45,7 +45,7 @@ describe("stringifyTelegramRawUpdateForLog", () => {
},
};
const rawLog = stringifyTelegramRawUpdateForLog(update);
const rawLog = formatTelegramRawUpdateForLog(update);
expect(rawLog).toContain('"update_id":98765');
expect(rawLog).toContain('"message_id":44');
@ -138,7 +138,7 @@ describe("stringifyTelegramRawUpdateForLog", () => {
},
};
const rawLog = stringifyTelegramRawUpdateForLog(update);
const rawLog = formatTelegramRawUpdateForLog(update);
expect(rawLog).toContain('"update_id":45678');
expect(rawLog).toContain('"message_id":99');
@ -176,7 +176,7 @@ describe("stringifyTelegramRawUpdateForLog", () => {
it("truncates long raw update strings without splitting UTF-16 surrogate pairs", () => {
const prefix = "a".repeat(499);
const rawLog = stringifyTelegramRawUpdateForLog({
const rawLog = formatTelegramRawUpdateForLog({
update_id: 123,
diagnostic: `${prefix}\uD83D\uDE80tail`,
});
@ -188,4 +188,12 @@ describe("stringifyTelegramRawUpdateForLog", () => {
expect(rawLog).not.toContain("\\ud83d");
expect(rawLog).not.toContain("\\ude80");
});
it("truncates the complete raw update log without splitting surrogate pairs", () => {
const keyPrefix = "x".repeat(7997);
const rawLog = formatTelegramRawUpdateForLog({ [`${keyPrefix}😀tail`]: 1 });
expect(rawLog).toBe(`{"${keyPrefix}...`);
expect(rawLog).not.toMatch(/[\uD800-\uDFFF]/u);
});
});

View file

@ -56,7 +56,7 @@ import {
} from "./group-history-window.js";
import { TELEGRAM_TEXT_CHUNK_LIMIT } from "./outbound-adapter.js";
import { registerTelegramOutboundGroupHistoryRecorder } from "./outbound-message-context.js";
import { stringifyTelegramRawUpdateForLog } from "./raw-update-log.js";
import { formatTelegramRawUpdateForLog } from "./raw-update-log.js";
import { TELEGRAM_RICH_TEXT_LIMIT } from "./rich-message.js";
import { createTelegramSendChatActionHandler } from "./sendchataction-401-backoff.js";
import { getTelegramSequentialKey } from "./sequential-key.js";
@ -241,15 +241,11 @@ export function createTelegramBotCore(
bot.use(botRuntime.sequentialize(getTelegramSequentialKey));
const rawUpdateLogger = createSubsystemLogger("gateway/channels/telegram/raw-update");
const MAX_RAW_UPDATE_CHARS = 8000;
bot.use(async (ctx, next) => {
if (shouldLogVerbose()) {
try {
const raw = stringifyTelegramRawUpdateForLog(ctx.update);
const preview =
raw.length > MAX_RAW_UPDATE_CHARS ? `${raw.slice(0, MAX_RAW_UPDATE_CHARS)}...` : raw;
rawUpdateLogger.debug(`telegram update: ${preview}`);
rawUpdateLogger.debug(`telegram update: ${formatTelegramRawUpdateForLog(ctx.update)}`);
} catch (err) {
rawUpdateLogger.debug(`telegram update log failed: ${String(err)}`);
}

View file

@ -3,6 +3,7 @@ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
const MAX_RAW_UPDATE_STRING = 500;
const MAX_RAW_UPDATE_ARRAY = 20;
const MAX_RAW_UPDATE_CHARS = 8000;
const REDACTED_TELEGRAM_FIELD = "[redacted]";
const TELEGRAM_RAW_UPDATE_ALWAYS_REDACT_KEYS = new Set([
"added_to_attachment_menu",
@ -74,7 +75,7 @@ function isTelegramUserObject(value: Record<string, unknown>): boolean {
);
}
export function stringifyTelegramRawUpdateForLog(update: unknown): string {
export function formatTelegramRawUpdateForLog(update: unknown): string {
const seen = new WeakSet<object>();
const transform = (value: unknown, key = "", parentKey?: string): unknown => {
if (shouldRedactTelegramRawUpdateValue(key, parentKey)) {
@ -109,5 +110,8 @@ export function stringifyTelegramRawUpdateForLog(update: unknown): string {
}
return value;
};
return JSON.stringify(transform(update ?? null));
const raw = JSON.stringify(transform(update ?? null));
return raw.length > MAX_RAW_UPDATE_CHARS
? `${truncateUtf16Safe(raw, MAX_RAW_UPDATE_CHARS)}...`
: raw;
}