From fd8353012f260b512f718997fd7b79a995794fec Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 28 May 2026 21:22:05 -0400 Subject: [PATCH] fix: parse diffs numeric options --- extensions/diffs/src/tool.test.ts | 6 +-- extensions/diffs/src/tool.ts | 82 +++++++++++++++---------------- src/agents/schema/typebox.ts | 1 + 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/extensions/diffs/src/tool.test.ts b/extensions/diffs/src/tool.test.ts index 42a07417c6b2..2bcb5f8c9b7b 100644 --- a/extensions/diffs/src/tool.test.ts +++ b/extensions/diffs/src/tool.test.ts @@ -206,7 +206,7 @@ describe("diffs tool", () => { before: "one\n", after: "two\n", mode: "file", - ttlSeconds: 1, + ttlSeconds: "1", }); const filePath = requireString(readDetails(result).filePath, "filePath"); await fs.access(filePath); @@ -263,8 +263,8 @@ describe("diffs tool", () => { after: "two\n", mode: "file", imageQuality: "hq", - imageScale: 2.4, - imageMaxWidth: 1100, + imageScale: "2.4", + imageMaxWidth: "1100", }); expect((result?.details as Record).fileQuality).toBe("hq"); diff --git a/extensions/diffs/src/tool.ts b/extensions/diffs/src/tool.ts index 557f7526aa0b..b2045020abeb 100644 --- a/extensions/diffs/src/tool.ts +++ b/extensions/diffs/src/tool.ts @@ -1,6 +1,7 @@ import fs from "node:fs/promises"; -import { stringEnum } from "openclaw/plugin-sdk/channel-actions"; +import { optionalFiniteNumberSchema, stringEnum } from "openclaw/plugin-sdk/channel-actions"; import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime"; +import { readFiniteNumberParam } from "openclaw/plugin-sdk/param-readers"; import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { Type } from "typebox"; import type { Static } from "typebox"; @@ -82,20 +83,16 @@ const DiffsToolSchema = Type.Object( fileFormat: Type.Optional( stringEnum(DIFF_OUTPUT_FORMATS, { description: "Rendered file format: png or pdf." }), ), - fileScale: Type.Optional( - Type.Number({ - description: "Optional rendered-file device scale factor override (1-4).", - minimum: 1, - maximum: 4, - }), - ), - fileMaxWidth: Type.Optional( - Type.Number({ - description: "Optional rendered-file max width in CSS pixels (640-2400).", - minimum: 640, - maximum: 2400, - }), - ), + fileScale: optionalFiniteNumberSchema({ + description: "Optional rendered-file device scale factor override (1-4).", + minimum: 1, + maximum: 4, + }), + fileMaxWidth: optionalFiniteNumberSchema({ + description: "Optional rendered-file max width in CSS pixels (640-2400).", + minimum: 640, + maximum: 2400, + }), /** @deprecated Use fileQuality. */ imageQuality: Type.Optional( stringEnum(DIFF_IMAGE_QUALITY_PRESETS, { @@ -111,33 +108,27 @@ const DiffsToolSchema = Type.Object( }), ), /** @deprecated Use fileScale. */ - imageScale: Type.Optional( - Type.Number({ - description: "Deprecated alias for fileScale.", - deprecated: true, - minimum: 1, - maximum: 4, - }), - ), + imageScale: optionalFiniteNumberSchema({ + description: "Deprecated alias for fileScale.", + deprecated: true, + minimum: 1, + maximum: 4, + }), /** @deprecated Use fileMaxWidth. */ - imageMaxWidth: Type.Optional( - Type.Number({ - description: "Deprecated alias for fileMaxWidth.", - deprecated: true, - minimum: 640, - maximum: 2400, - }), - ), + imageMaxWidth: optionalFiniteNumberSchema({ + description: "Deprecated alias for fileMaxWidth.", + deprecated: true, + minimum: 640, + maximum: 2400, + }), expandUnchanged: Type.Optional( Type.Boolean({ description: "Expand unchanged sections instead of collapsing them." }), ), - ttlSeconds: Type.Optional( - Type.Number({ - description: "Artifact lifetime in seconds. Default: 1800. Maximum: 21600.", - minimum: 1, - maximum: 21_600, - }), - ), + ttlSeconds: optionalFiniteNumberSchema({ + description: "Artifact lifetime in seconds. Default: 1800. Maximum: 21600.", + minimum: 1, + maximum: 21_600, + }), baseUrl: Type.Optional( Type.String({ description: @@ -171,21 +162,30 @@ export function createDiffsTool(params: { parameters: DiffsToolSchema, execute: async (_toolCallId, rawParams) => { const toolParams = rawParams as DiffsToolRawParams; + const rawRecord = rawParams as Record; const artifactContext = buildArtifactContext(params.context); const input = normalizeDiffInput(toolParams); const mode = normalizeMode(toolParams.mode, params.defaults.mode); const theme = normalizeTheme(toolParams.theme, params.defaults.theme); const layout = normalizeLayout(toolParams.layout, params.defaults.layout); const expandUnchanged = toolParams.expandUnchanged === true; - const ttlMs = normalizeTtlMs(toolParams.ttlSeconds ?? params.defaults.ttlSeconds); + const ttlSeconds = + readFiniteNumberParam(rawRecord, "ttlSeconds") ?? params.defaults.ttlSeconds; + const fileScale = + readFiniteNumberParam(rawRecord, "fileScale") ?? + readFiniteNumberParam(rawRecord, "imageScale"); + const fileMaxWidth = + readFiniteNumberParam(rawRecord, "fileMaxWidth") ?? + readFiniteNumberParam(rawRecord, "imageMaxWidth"); + const ttlMs = normalizeTtlMs(ttlSeconds); const image = resolveDiffImageRenderOptions({ defaults: params.defaults, fileFormat: normalizeOutputFormat( toolParams.fileFormat ?? toolParams.imageFormat ?? toolParams.format, ), fileQuality: normalizeFileQuality(toolParams.fileQuality ?? toolParams.imageQuality), - fileScale: toolParams.fileScale ?? toolParams.imageScale, - fileMaxWidth: toolParams.fileMaxWidth ?? toolParams.imageMaxWidth, + fileScale, + fileMaxWidth, }); const renderTarget = resolveRenderTarget(mode); diff --git a/src/agents/schema/typebox.ts b/src/agents/schema/typebox.ts index 43f65ad9037a..c84815af274c 100644 --- a/src/agents/schema/typebox.ts +++ b/src/agents/schema/typebox.ts @@ -24,6 +24,7 @@ type IntegerSchemaOptions = { type NumberSchemaOptions = { description?: string; + deprecated?: boolean; minimum?: number; maximum?: number; exclusiveMinimum?: number;