


























@@ -15,6 +15,8 @@ import {
1515REQUIRED_PARAM_GROUPS,
1616assertRequiredParams,
1717getToolParamsRecord,
18+stripMalformedXmlArgValueSuffix,
19+stripMalformedXmlArgValueSuffixFromKeys,
1820wrapToolParamValidation,
1921} from "./agent-tools.params.js";
2022import type { AnyAgentTool } from "./agent-tools.types.js";
@@ -80,6 +82,10 @@ function resolveAdaptiveReadMaxBytes(options?: OpenClawReadToolOptions): number
8082return clamp(fromContext, DEFAULT_READ_PAGE_MAX_BYTES, MAX_ADAPTIVE_READ_MAX_BYTES);
8183}
828485+function malformedXmlArgValuePathError(key: string): Error {
86+return new Error(`Malformed path parameter: ${key}. Supply correct parameters before retrying.`);
87+}
88+8389function formatBytes(bytes: number): string {
8490if (bytes >= 1024 * 1024) {
8591return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
@@ -631,9 +637,14 @@ export function wrapToolMemoryFlushAppendOnlyWrite(
631637description: `${tool.description} During memory flush, this tool may only append to ${options.relativePath}.`,
632638execute: async (toolCallId, args, signal, onUpdate) => {
633639const record = getToolParamsRecord(args);
634-assertRequiredParams(record, REQUIRED_PARAM_GROUPS.write, tool.name);
640+const normalizedRecord = record
641+ ? stripMalformedXmlArgValueSuffixFromKeys(record, ["path"])
642+ : undefined;
643+assertRequiredParams(normalizedRecord, REQUIRED_PARAM_GROUPS.write, tool.name);
635644const filePath =
636-typeof record?.path === "string" && record.path.trim() ? record.path : undefined;
645+typeof normalizedRecord?.path === "string" && normalizedRecord.path.trim()
646+ ? normalizedRecord.path
647+ : undefined;
637648const content = typeof record?.content === "string" ? record.content : undefined;
638649if (!filePath || content === undefined) {
639650return tool.execute(toolCallId, args, signal, onUpdate);
@@ -737,10 +748,18 @@ export function wrapToolWorkspaceRootGuardWithOptions(
737748const record = getToolParamsRecord(args);
738749let normalizedRecord: Record<string, unknown> | undefined;
739750for (const key of pathParamKeys) {
740-const filePath = record?.[key];
741-if (typeof filePath !== "string" || !filePath.trim()) {
751+const rawFilePath = record?.[key];
752+if (typeof rawFilePath !== "string" || !rawFilePath.trim()) {
742753continue;
743754}
755+const filePath = stripMalformedXmlArgValueSuffix(rawFilePath);
756+if (!filePath.trim()) {
757+throw malformedXmlArgValuePathError(key);
758+}
759+if (filePath !== rawFilePath && record) {
760+normalizedRecord ??= { ...record };
761+normalizedRecord[key] = filePath;
762+}
744763let guardedRoot = root;
745764const workspaceMapping = mapContainerPathToRoot({
746765 filePath,
@@ -836,15 +855,19 @@ export function createOpenClawReadTool(
836855 ...base,
837856execute: async (toolCallId, params, signal) => {
838857const record = getToolParamsRecord(params);
839-assertRequiredParams(record, REQUIRED_PARAM_GROUPS.read, base.name);
858+const normalizedRecord = record
859+ ? stripMalformedXmlArgValueSuffixFromKeys(record, ["path"])
860+ : undefined;
861+assertRequiredParams(normalizedRecord, REQUIRED_PARAM_GROUPS.read, base.name);
840862const result = await executeReadWithAdaptivePaging({
841863 base,
842864 toolCallId,
843-args: record ?? {},
865+args: normalizedRecord ?? {},
844866 signal,
845867maxBytes: resolveAdaptiveReadMaxBytes(options),
846868});
847-const filePath = typeof record?.path === "string" ? record.path : "<unknown>";
869+const filePath =
870+typeof normalizedRecord?.path === "string" ? normalizedRecord.path : "<unknown>";
848871const strippedDetailsResult = stripReadTruncationContentDetails(result);
849872const normalizedResult = await normalizeReadImageResult(strippedDetailsResult, filePath);
850873return sanitizeToolResultImages(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。