fix(agents): make image sanitization dimension configurable

This commit is contained in:
Peter Steinberger
2026-02-18 00:43:31 +01:00
parent 5ee79f80eb
commit b05e89e5e6
21 changed files with 156 additions and 45 deletions

View File

@@ -1,9 +1,11 @@
import { Type } from "@sinclair/typebox";
import crypto from "node:crypto";
import fs from "node:fs/promises";
import { Type } from "@sinclair/typebox";
import type { OpenClawConfig } from "../../config/config.js";
import { writeBase64ToFile } from "../../cli/nodes-camera.js";
import { canvasSnapshotTempPath, parseCanvasSnapshotPayload } from "../../cli/nodes-canvas.js";
import { imageMimeFromFormat } from "../../media/mime.js";
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
import { type AnyAgentTool, imageResult, jsonResult, readStringParam } from "./common.js";
import { callGatewayTool, readGatewayCallOptions } from "./gateway.js";
@@ -48,7 +50,8 @@ const CanvasToolSchema = Type.Object({
jsonlPath: Type.Optional(Type.String()),
});
export function createCanvasTool(): AnyAgentTool {
export function createCanvasTool(options?: { config?: OpenClawConfig }): AnyAgentTool {
const imageSanitization = resolveImageSanitizationLimits(options?.config);
return {
label: "Canvas",
name: "canvas",
@@ -158,6 +161,7 @@ export function createCanvasTool(): AnyAgentTool {
base64: payload.base64,
mimeType,
details: { format: payload.format },
imageSanitization,
});
}
case "a2ui_push": {

View File

@@ -1,5 +1,6 @@
import fs from "node:fs/promises";
import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core";
import fs from "node:fs/promises";
import type { ImageSanitizationLimits } from "../image-sanitization.js";
import { detectMime } from "../../media/mime.js";
import { sanitizeToolResultImages } from "../tool-images.js";
@@ -214,6 +215,7 @@ export async function imageResult(params: {
mimeType: string;
extraText?: string;
details?: Record<string, unknown>;
imageSanitization?: ImageSanitizationLimits;
}): Promise<AgentToolResult<unknown>> {
const content: AgentToolResult<unknown>["content"] = [
{
@@ -230,7 +232,7 @@ export async function imageResult(params: {
content,
details: { path: params.path, ...params.details },
};
return await sanitizeToolResultImages(result, params.label);
return await sanitizeToolResultImages(result, params.label, params.imageSanitization);
}
export async function imageResultFromFile(params: {
@@ -238,6 +240,7 @@ export async function imageResultFromFile(params: {
path: string;
extraText?: string;
details?: Record<string, unknown>;
imageSanitization?: ImageSanitizationLimits;
}): Promise<AgentToolResult<unknown>> {
const buf = await fs.readFile(params.path);
const mimeType = (await detectMime({ buffer: buf.slice(0, 256) })) ?? "image/png";
@@ -248,5 +251,6 @@ export async function imageResultFromFile(params: {
mimeType,
extraText: params.extraText,
details: params.details,
imageSanitization: params.imageSanitization,
});
}

View File

@@ -1,6 +1,7 @@
import crypto from "node:crypto";
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
import { Type } from "@sinclair/typebox";
import crypto from "node:crypto";
import type { OpenClawConfig } from "../../config/config.js";
import {
type CameraFacing,
cameraTempPath,
@@ -16,9 +17,9 @@ import {
writeScreenRecordToFile,
} from "../../cli/nodes-screen.js";
import { parseDurationMs } from "../../cli/parse-duration.js";
import type { OpenClawConfig } from "../../config/config.js";
import { imageMimeFromFormat } from "../../media/mime.js";
import { resolveSessionAgentId } from "../agent-scope.js";
import { resolveImageSanitizationLimits } from "../image-sanitization.js";
import { optionalStringEnum, stringEnum } from "../schema/typebox.js";
import { sanitizeToolResultImages } from "../tool-images.js";
import { type AnyAgentTool, jsonResult, readStringParam } from "./common.js";
@@ -100,6 +101,7 @@ export function createNodesTool(options?: {
sessionKey: options?.agentSessionKey,
config: options?.config,
});
const imageSanitization = resolveImageSanitizationLimits(options?.config);
return {
label: "Nodes",
name: "nodes",
@@ -250,7 +252,7 @@ export function createNodesTool(options?: {
}
const result: AgentToolResult<unknown> = { content, details };
return await sanitizeToolResultImages(result, "nodes:camera_snap");
return await sanitizeToolResultImages(result, "nodes:camera_snap", imageSanitization);
}
case "camera_list": {
const node = readStringParam(params, "node", { required: true });