diff --git a/CHANGELOG.md b/CHANGELOG.md index 601b6c5791c..5129436d63a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Docs: https://docs.openclaw.ai - Gateway/startup: split lightweight HTTP auth helpers away from model-override helpers so Gateway bind no longer imports model catalog selection while wiring base HTTP routes. Thanks @vincentkoc. - Gateway/startup: lazy-load plugin HTTP route dispatch when active plugin routes exist so no-plugin Gateway boot skips plugin route runtime scope setup. Thanks @vincentkoc. - Gateway/startup: move chat run/subscriber registries onto a lightweight state module and defer chat/session event projection until the first event so Gateway boot skips session IO imports. Thanks @vincentkoc. +- Gateway/startup: keep node session runtime on a lightweight JSON parser instead of importing gateway method validation helpers during boot. Thanks @vincentkoc. - CLI/Gateway: use a parse-only config snapshot for plain `gateway status` reads and reuse same-path service config context so status no longer spends tens of seconds in full config validation before printing. Thanks @vincentkoc. - Lobster/Gateway: memoize repeated Ajv schema compilation before loading the embedded Lobster runtime so scheduled workflows and `llm.invoke` loops stop growing gateway heap on content-identical schemas. Fixes #71148. Thanks @cmi525, @vsolaz, and @vincentkoc. - Codex harness: normalize cached input tokens before session/context accounting so prompt cache reads are not double-counted in `/status`, `session_status`, or persisted `sessionEntry.totalTokens`. Fixes #69298. Thanks @richardmqq. diff --git a/src/gateway/server-json.ts b/src/gateway/server-json.ts new file mode 100644 index 00000000000..7a83633cb9c --- /dev/null +++ b/src/gateway/server-json.ts @@ -0,0 +1,13 @@ +import { normalizeOptionalString } from "../shared/string-coerce.js"; + +export function safeParseJson(value: string | null | undefined): unknown { + const trimmed = normalizeOptionalString(value); + if (!trimmed) { + return undefined; + } + try { + return JSON.parse(trimmed) as unknown; + } catch { + return { payloadJSON: value }; + } +} diff --git a/src/gateway/server-methods/nodes.helpers.ts b/src/gateway/server-methods/nodes.helpers.ts index 012cddfe7c5..110f7592daa 100644 --- a/src/gateway/server-methods/nodes.helpers.ts +++ b/src/gateway/server-methods/nodes.helpers.ts @@ -1,6 +1,7 @@ import type { ErrorObject } from "ajv"; import { normalizeOptionalString } from "../../shared/string-coerce.js"; import { ErrorCodes, errorShape, formatValidationErrors } from "../protocol/index.js"; +export { safeParseJson } from "../server-json.js"; import { formatForLog } from "../ws-log.js"; import type { RespondFn } from "./types.js"; @@ -38,18 +39,6 @@ export function uniqueSortedStrings(values: unknown[]) { .toSorted(); } -export function safeParseJson(value: string | null | undefined): unknown { - const trimmed = normalizeOptionalString(value); - if (!trimmed) { - return undefined; - } - try { - return JSON.parse(trimmed) as unknown; - } catch { - return { payloadJSON: value }; - } -} - export function respondUnavailableOnNodeInvokeError( respond: RespondFn, res: T, diff --git a/src/gateway/server-node-session-runtime.ts b/src/gateway/server-node-session-runtime.ts index 2b88ff5812b..dc8bd815780 100644 --- a/src/gateway/server-node-session-runtime.ts +++ b/src/gateway/server-node-session-runtime.ts @@ -3,7 +3,7 @@ import { createSessionEventSubscriberRegistry, createSessionMessageSubscriberRegistry, } from "./server-chat-state.js"; -import { safeParseJson } from "./server-methods/nodes.helpers.js"; +import { safeParseJson } from "./server-json.js"; import { hasConnectedMobileNode } from "./server-mobile-nodes.js"; import { createNodeSubscriptionManager } from "./server-node-subscriptions.js";