From 218fe8b892b8b4e5532e22f5ac5b973b97e37cc2 Mon Sep 17 00:00:00 2001 From: can1357 Date: Wed, 13 May 2026 05:24:33 +0200 Subject: [PATCH] fix(packages/coding-agent): resolved JS display fallback for noncloneable values - Handled structured-clone failures in JsRuntime.display by falling back to text output. - Added regression coverage for non-structured-cloneable JS display output. --- packages/coding-agent/src/eval/js/shared/runtime.ts | 11 ++++++++++- packages/coding-agent/test/core/js-executor.test.ts | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/eval/js/shared/runtime.ts b/packages/coding-agent/src/eval/js/shared/runtime.ts index 475fa474f..9b97b593b 100644 --- a/packages/coding-agent/src/eval/js/shared/runtime.ts +++ b/packages/coding-agent/src/eval/js/shared/runtime.ts @@ -4,6 +4,8 @@ import * as path from "node:path"; import { pathToFileURL } from "node:url"; import * as util from "node:util"; +import { logger } from "@oh-my-pi/pi-utils"; + import { ToolError } from "../../../tools/tool-errors"; import { createHelpers, type HelperBundle } from "./helpers"; import { awaitMaybePromise, indirectEval } from "./indirect-eval"; @@ -111,7 +113,14 @@ export class JsRuntime { hooks.onDisplay({ type: "image", data: record.data, mimeType: record.mimeType }); return; } - hooks.onDisplay({ type: "json", data: structuredClone(value) }); + try { + hooks.onDisplay({ type: "json", data: structuredClone(value) }); + } catch (err) { + logger.debug("js displayValue: value is not structured-cloneable, falling back to text", { + error: err instanceof Error ? err.message : String(err), + }); + hooks.onText(`${Object.prototype.toString.call(value)}\n`); + } return; } hooks.onText(`${String(value)}\n`); diff --git a/packages/coding-agent/test/core/js-executor.test.ts b/packages/coding-agent/test/core/js-executor.test.ts index 552ee47c3..50a3652eb 100644 --- a/packages/coding-agent/test/core/js-executor.test.ts +++ b/packages/coding-agent/test/core/js-executor.test.ts @@ -409,4 +409,11 @@ describe("executeJs", () => { expect(result.exitCode).toBe(0); expect(result.output.trim()).toBe("7"); }); + it("falls back to text display when the final expression value is not structured-cloneable", async () => { + const result = await executeJs("({ fn: () => 1 });", { sessionId, session, sessionFile }); + expect(result.exitCode).toBe(0); + expect(result.output).toContain("[object Object]"); + // No JSON display because structuredClone fails on the embedded function. + expect(result.displayOutputs.filter(o => o.type === "json")).toHaveLength(0); + }); });