From 911cfe2adc27ba50c700365a44142d13e3ce7ead Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 16:26:24 +0100 Subject: [PATCH] refactor: use structured clone for local copies --- .../telegram/src/bot.create-telegram-bot.test-harness.ts | 2 +- src/agents/pi-embedded-runner/compact.hooks.harness.ts | 8 ++------ src/commands/models.set.e2e.test.ts | 2 +- src/config/schema.shared.ts | 5 +---- src/cron/isolated-agent/run.cron-model-override.test.ts | 2 +- src/cron/service/ops.ts | 2 +- src/gateway/cli-session-history.claude.ts | 2 +- ui/src/ui/controllers/config/form-utils.ts | 5 +---- 8 files changed, 9 insertions(+), 19 deletions(-) diff --git a/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts b/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts index e5f9f8325d0..613e53bd176 100644 --- a/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts +++ b/extensions/telegram/src/bot.create-telegram-bot.test-harness.ts @@ -80,7 +80,7 @@ export function getLoadSessionStoreMock(): AnyMock { } export function setSessionStoreEntriesForTest(entries: SessionStore) { - sessionStoreEntries.value = JSON.parse(JSON.stringify(entries)) as SessionStore; + sessionStoreEntries.value = structuredClone(entries); } const { readChannelAllowFromStore, upsertChannelPairingRequest } = vi.hoisted( diff --git a/src/agents/pi-embedded-runner/compact.hooks.harness.ts b/src/agents/pi-embedded-runner/compact.hooks.harness.ts index b6ce3eb0720..3bbfbda04c6 100644 --- a/src/agents/pi-embedded-runner/compact.hooks.harness.ts +++ b/src/agents/pi-embedded-runner/compact.hooks.harness.ts @@ -240,11 +240,7 @@ export async function loadCompactHooksHarness(): Promise<{ createAgentSession: vi.fn(async () => { const session = { sessionId: "session-1", - messages: sessionMessages.map((message) => - typeof structuredClone === "function" - ? structuredClone(message) - : JSON.parse(JSON.stringify(message)), - ), + messages: sessionMessages.map((message) => structuredClone(message)), agent: { streamFn: vi.fn(), transport: "sse", @@ -253,7 +249,7 @@ export async function loadCompactHooksHarness(): Promise<{ return session.messages; }, set messages(messages: unknown[]) { - session.messages = [...(messages as typeof session.messages)]; + session.messages = [...messages]; }, }, }, diff --git a/src/commands/models.set.e2e.test.ts b/src/commands/models.set.e2e.test.ts index 97de3c15630..767aa4a6f11 100644 --- a/src/commands/models.set.e2e.test.ts +++ b/src/commands/models.set.e2e.test.ts @@ -10,7 +10,7 @@ vi.mock("./models/shared.js", async () => { return { ...actual, updateConfig: async (mutator: (cfg: Record) => Record) => { - const next = mutator(JSON.parse(JSON.stringify(mocks.currentConfig))); + const next = mutator(structuredClone(mocks.currentConfig)); mocks.writtenConfig = next; return next; }, diff --git a/src/config/schema.shared.ts b/src/config/schema.shared.ts index acaf786589b..eb9452953b4 100644 --- a/src/config/schema.shared.ts +++ b/src/config/schema.shared.ts @@ -9,10 +9,7 @@ type JsonSchemaObject = { }; export function cloneSchema(value: T): T { - if (typeof structuredClone === "function") { - return structuredClone(value); - } - return JSON.parse(JSON.stringify(value)) as T; + return structuredClone(value); } export function asSchemaObject(value: unknown): object | null { diff --git a/src/cron/isolated-agent/run.cron-model-override.test.ts b/src/cron/isolated-agent/run.cron-model-override.test.ts index 890392163de..1454af39cab 100644 --- a/src/cron/isolated-agent/run.cron-model-override.test.ts +++ b/src/cron/isolated-agent/run.cron-model-override.test.ts @@ -147,7 +147,7 @@ describe("runCronIsolatedAgentTurn — cron model override (#21057)", () => { | { model?: string; modelProvider?: string; systemSent?: boolean } | undefined; if (entry) { - persistedSnapshots.push(JSON.parse(JSON.stringify(entry))); + persistedSnapshots.push(structuredClone(entry)); } }, ); diff --git a/src/cron/service/ops.ts b/src/cron/service/ops.ts index 067cf35735f..bd7f38be019 100644 --- a/src/cron/service/ops.ts +++ b/src/cron/service/ops.ts @@ -579,7 +579,7 @@ async function prepareManualRun( job, startedAt: preflight.now, }); - const executionJob = JSON.parse(JSON.stringify(job)) as CronJob; + const executionJob = structuredClone(job); return { ok: true, ran: true, diff --git a/src/gateway/cli-session-history.claude.ts b/src/gateway/cli-session-history.claude.ts index 04ca816c154..db2cba974aa 100644 --- a/src/gateway/cli-session-history.claude.ts +++ b/src/gateway/cli-session-history.claude.ts @@ -100,7 +100,7 @@ function resolveClaudeCliUsage(raw: ClaudeCliUsage) { } function cloneJsonValue(value: T): T { - return JSON.parse(JSON.stringify(value)) as T; + return structuredClone(value); } function normalizeClaudeCliContent( diff --git a/ui/src/ui/controllers/config/form-utils.ts b/ui/src/ui/controllers/config/form-utils.ts index ba41387564f..174f4638465 100644 --- a/ui/src/ui/controllers/config/form-utils.ts +++ b/ui/src/ui/controllers/config/form-utils.ts @@ -1,8 +1,5 @@ export function cloneConfigObject(value: T): T { - if (typeof structuredClone === "function") { - return structuredClone(value); - } - return JSON.parse(JSON.stringify(value)) as T; + return structuredClone(value); } export function serializeConfigForm(form: Record): string {