LearnNewsExamplesServices
Frontmatter
id13825
titlerefactor(ai): Gemini.mjs mapToolSchema uses the banned JSON.parse(JSON.stringify) deep-clone — use Neo.clone
stateClosed
labels
airefactoring
assigneesneo-opus-ada
createdAtJun 21, 2026, 11:30 PM
updatedAtJun 21, 2026, 11:48 PM
githubUrlhttps://github.com/neomjs/neo/issues/13825
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 21, 2026, 11:48 PM

refactor(ai): Gemini.mjs mapToolSchema uses the banned JSON.parse(JSON.stringify) deep-clone — use Neo.clone

neo-opus-ada
neo-opus-ada commented on Jun 21, 2026, 11:30 PM

Debt (surfaced via tech-debt-radar — the #13822 value-floor dogfood)

ai/provider/Gemini.mjs:50 (mapToolSchema) deep-clones the tool input schema with the banned JSON.parse(JSON.stringify(...)) pattern:

const parameters = JSON.parse(JSON.stringify(tool.inputSchema || { type: 'object', properties: {} }));

The clone is necessary (the following uppercaseTypes mutates it — uppercasing type, deleting additionalProperties — so the original schema must not be touched), so this is a clean replacement, not a dead clone.

Why it's debt

JSON.parse(JSON.stringify(...)) is the banned deep-clone idiom in this codebase — the canonical helper is Neo.clone(x, true) (used at ai/mcp/client/config.mjs:90; structuredClone is the other accepted native form, MetadataManager.mjs:41). The operator corrected this exact pattern previously (#13116). Neo is global in ai/provider (Base extends Neo.core.Base via Neo.setupClass), so Neo.clone is available with no new import.

Fix

const parameters = Neo.clone(tool.inputSchema || { type: 'object', properties: {} }, true);

Behavior-identical for the JSON-safe schema; canonical + consistent with the rest of ai/.

AC

  • Gemini.mjs:mapToolSchema uses Neo.clone(..., true) (or structuredClone); no JSON.parse(JSON.stringify(...)).
  • The schema-uppercasing behavior is unchanged (the clone is still mutated, the original untouched).

Radar note

Surfaced while dogfooding #13822's corrected value-floor (route to tech-debt-radar). A shallow grep-sweep of ai/ is otherwise clean (TODO/FIXME = 0) — the operator's "50–100 lanes" is architectural debt (the deep radar's KB + memory + architectural-deviation vectors), not grep-markers; this is the one grep-surfaced item. Labeled for an SML or quick maintainer fix.

tobiu closed this issue on Jun 21, 2026, 11:48 PM
tobiu referenced in commit 290dd67 - "refactor(ai): Gemini mapToolSchema uses Neo.clone, not JSON.parse(JSON.stringify) (#13825) (#13826) on Jun 21, 2026, 11:48 PM