diff --git a/extensions/telegram/src/channel-actions.ts b/extensions/telegram/src/channel-actions.ts index 50f7826da70..26cf762fe77 100644 --- a/extensions/telegram/src/channel-actions.ts +++ b/extensions/telegram/src/channel-actions.ts @@ -71,6 +71,7 @@ function readTelegramMessageIdParam( required, integer: true, strict: true, + strictInteger: true, }); if (required && typeof messageId !== "number") { throw new Error("messageId is required."); diff --git a/src/agents/tools/common.params.test.ts b/src/agents/tools/common.params.test.ts index 32eb63d036e..b8aef7b631e 100644 --- a/src/agents/tools/common.params.test.ts +++ b/src/agents/tools/common.params.test.ts @@ -63,6 +63,13 @@ describe("readNumberParam", () => { expect(readNumberParam(params, "messageId", { integer: true })).toBe(42); }); + it("rejects fractional values when strictInteger is true", () => { + const params = { messageId: "42.9" }; + expect(() => + readNumberParam(params, "messageId", { integer: true, strictInteger: true }), + ).toThrow(/messageId must be an integer/); + }); + it("accepts snake_case aliases for camelCase keys", () => { const params = { message_id: "42" }; expect(readNumberParam(params, "messageId")).toBe(42); diff --git a/src/agents/tools/common.ts b/src/agents/tools/common.ts index 81d3f4efc00..4a1146f34de 100644 --- a/src/agents/tools/common.ts +++ b/src/agents/tools/common.ts @@ -116,9 +116,16 @@ export function readStringOrNumberParam( export function readNumberParam( params: Record, key: string, - options: { required?: boolean; label?: string; integer?: boolean; strict?: boolean } = {}, + options: { + required?: boolean; + label?: string; + integer?: boolean; + strict?: boolean; + strictInteger?: boolean; + } = {}, ): number | undefined { - const { required = false, label = key, integer = false, strict = false } = options; + const { required = false, label = key, integer = false, strict = false, strictInteger = false } = + options; const raw = readParamRaw(params, key); let value: number | undefined; if (typeof raw === "number" && Number.isFinite(raw)) { @@ -138,7 +145,13 @@ export function readNumberParam( } return undefined; } - return integer ? Math.trunc(value) : value; + if (integer) { + if (strictInteger && !Number.isInteger(value)) { + throw new ToolInputError(`${label} must be an integer`); + } + return Math.trunc(value); + } + return value; } export function readStringArrayParam( diff --git a/src/agents/tools/telegram-actions.ts b/src/agents/tools/telegram-actions.ts index ec270ab32b0..3294ce1d917 100644 --- a/src/agents/tools/telegram-actions.ts +++ b/src/agents/tools/telegram-actions.ts @@ -136,6 +136,8 @@ export async function handleTelegramAction( }); const messageId = readNumberParam(params, "messageId", { integer: true, + strict: true, + strictInteger: true, }); if (typeof messageId !== "number" || !Number.isFinite(messageId) || messageId <= 0) { return jsonResult({ @@ -328,6 +330,7 @@ export async function handleTelegramAction( required: true, integer: true, strict: true, + strictInteger: true, }); const token = resolveTelegramToken(cfg, { accountId }).token; if (!token) { @@ -380,6 +383,8 @@ export async function handleTelegramAction( const messageId = readNumberParam(params, "messageId", { required: true, integer: true, + strict: true, + strictInteger: true, }); const content = readStringParam(params, "content", { required: true,