Skip to content

fix(ai): reject non-finite tool schema numbers#104470

Merged
steipete merged 15 commits into
openclaw:mainfrom
VectorPeak:fix/tool-schema-non-finite-json
Jul 11, 2026
Merged

fix(ai): reject non-finite tool schema numbers#104470
steipete merged 15 commits into
openclaw:mainfrom
VectorPeak:fix/tool-schema-non-finite-json

Conversation

@VectorPeak

Copy link
Copy Markdown
Contributor

Closes #104469

What Problem This Solves

Fixes an issue where tool schemas containing non-finite numeric values could be projected into provider-facing schemas with those values silently changed to null.

The trigger is a runtime/custom tool schema that contains a JavaScript-only numeric value such as Number.POSITIVE_INFINITY or Number.NaN in a JSON Schema numeric constraint/default. The shared projector serialized the schema with JSON.stringify() before validating the projected JSON value, so those values could become explicit null fields while reporting no schema violation.

Why This Change Was Made

The shared runtime tool schema projector now detects non-finite numbers before JSON serialization and reports the exact offending schema path as non-JSON-serializable.

This keeps the existing quarantine behavior narrow: the invalid tool is dropped with diagnostics, healthy sibling tools remain available, and provider-specific schema cleanup is left unchanged. The changed shared path is used by OpenAI and Anthropic tool projection; sibling provider paths such as Google/Gemini and Mistral use separate schema handling and are not changed by this PR.

User Impact

Plugin/tool authors and operators get safer tool schema handling. Invalid non-finite numeric schema values now produce a clear projection violation instead of being silently rewritten into materially different provider payloads.

For example, a bad bad_limits tool with maximum: Number.POSITIVE_INFINITY is quarantined, while a healthy sibling lookup tool remains available for provider use.

Evidence

Behavior proof:

JSON.stringify({
  type: object,
  properties: {
    amount: { type: number, maximum: Number.POSITIVE_INFINITY },
    score: { type: number, default: Number.NaN },
  },
})

// Before this PR, JSON serialization could turn both values into null:
// {type:object,properties:{amount:{type:number,maximum:null},score:{type:number,default:null}}}

Focused regression coverage added:

  • src/agents/tool-schema-projection.test.ts covers Number.NaN at the shared runtime schema projection layer and expects parameters.properties.score.default is not JSON-serializable.
  • packages/ai/src/providers/openai-tool-projection.test.ts covers OpenAI tool projection quarantining a bad maximum: Number.POSITIVE_INFINITY tool while preserving a healthy sibling.
  • packages/ai/src/providers/anthropic-tool-projection.test.ts covers Anthropic tool projection quarantining the bad original tool while preserving a healthy sibling.

Validation run:

git diff --check
node scripts/run-vitest.mjs run packages/ai/src/providers/openai-tool-projection.test.ts packages/ai/src/providers/openai-tool-schema.test.ts packages/ai/src/providers/anthropic-tool-projection.test.ts src/agents/tool-schema-projection.test.ts

[test] passed 2 Vitest shards in 7.22s
Test Files  1 passed (1), 3 passed (3)
Tests       11 passed (11), 26 passed (26)

Additional local validation note:

pnpm check:test-types

was attempted separately but did not reach useful typechecking in this checkout because workspace package resolution reports @openclaw/gateway-protocol@workspace:* from packages/gateway-client while no @openclaw/gateway-protocol package is present in the local workspace. That appears unrelated to the four files changed here.

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Jul 11, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 11, 2026
@clawsweeper

clawsweeper Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Codex review: stale review; fresh review needed.

Summary
The latest durable ClawSweeper review was for head e088561cdaa8fe00e299ca406736303d07801c28, but the PR head is now f8f9058c4d524a7ac2d53977548bbb6bba8f3484. Its old verdict and PR readiness labels are no longer current.

Next step
Run or wait for a fresh ClawSweeper review on the current PR head.

Review history (9 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-11T12:49:45.493Z sha eda7f08 :: needs real behavior proof before merge. :: [P2] Validate values produced by toJSON()
  • reviewed 2026-07-11T13:05:37.298Z sha 5b3ceab :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-11T13:27:15.547Z sha 3b18ade :: needs maintainer review before merge. :: none
  • reviewed 2026-07-11T13:40:30.408Z sha 9b1ac7f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-11T14:25:20.450Z sha 8f20a8c :: needs maintainer review before merge. :: none
  • reviewed 2026-07-11T15:01:13.041Z sha 80b395f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-11T15:08:52.730Z sha 80b395f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-11T16:03:44.241Z sha c80b514 :: needs maintainer review before merge. :: none

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
@VectorPeak

Copy link
Copy Markdown
Contributor Author

Updated this PR for the ClawSweeper review findings.

What changed:

  • Fixed the supported toJSON() path by validating non-finite numeric values inside the effective JSON.stringify() serialization pass.
  • Added regression coverage where parameters.toJSON() returns maximum: Number.POSITIVE_INFINITY; the invalid bad_limits tool is quarantined, the healthy lookup sibling remains projected, and serialization still occurs once.
  • Updated the PR body with redacted terminal output showing both provider projection and runtime-compatible filtering behavior.

Real behavior proof now included in the PR body:

  • OpenAI provider projection output: projectedToolNames: [lookup] plus diagnostic bad_limits.parameters.properties.amount.maximum is not JSON-serializable.
  • Runtime filtering output: runtimeCompatibleToolNames: [lookup] plus the same bad-tool diagnostic.

Validation:

git diff --check
node scripts/run-vitest.mjs run packages/ai/src/providers/openai-tool-projection.test.ts packages/ai/src/providers/openai-tool-schema.test.ts packages/ai/src/providers/anthropic-tool-projection.test.ts src/agents/tool-schema-projection.test.ts

[test] passed 2 Vitest shards in 7.39s
Test Files  1 passed (1), 3 passed (3)
Tests       11 passed (11), 27 passed (27)

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@VectorPeak

Copy link
Copy Markdown
Contributor Author

Added one more focused regression for the reviewer concern around path tracking through custom serializers.

What changed in the latest commit:

  • Added src/agents/tool-schema-projection.test.ts coverage for a nested schema node whose toJSON() returns { maximum: Number.POSITIVE_INFINITY }.
  • The expected diagnostic is the nested path: parameters.properties.score.maximum is not JSON-serializable.
  • This specifically proves the effective JSON.stringify() replacer path tracking is not only handling root-level parameters.toJSON().

Validation:

git diff --check
node scripts/run-vitest.mjs run packages/ai/src/providers/openai-tool-projection.test.ts packages/ai/src/providers/openai-tool-schema.test.ts packages/ai/src/providers/anthropic-tool-projection.test.ts src/agents/tool-schema-projection.test.ts

[test] passed 2 Vitest shards in 7.11s
Test Files  1 passed (1), 3 passed (3)
Tests       12 passed (12), 27 passed (27)

This is intentionally test-only; the production fix remains the shared single-serialization projection path already pushed in 5b3ceab49e0a0770abf1ebf7453073aecfd06b20.

@clawsweeper clawsweeper Bot removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 11, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 11, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 11, 2026
VectorPeak and others added 5 commits July 11, 2026 22:17
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jul 11, 2026
@steipete steipete self-assigned this Jul 11, 2026
@clawsweeper clawsweeper Bot removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 11, 2026
@steipete
steipete merged commit f8c7f67 into openclaw:main Jul 11, 2026
99 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 12, 2026
* fix(ai): reject non-finite tool schema numbers

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): catch non-finite values from tool schema serializers

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>

* test(ai): cover nested tool schema serializers

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): satisfy schema projection lint

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): satisfy schema projection lint

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>

* fix(ai): preserve empty-key schema diagnostic paths

* fix(ai): reject boxed non-finite schema numbers

* fix(ai): ignore spoofed boxed-number tags

* fix(ai): isolate boxed-number brand probes

* refactor(ai): use intrinsic boxed-number detection

---------

Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling P2 Normal backlog priority with limited blast radius. size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tool schema projection silently converts non-finite numbers to null

2 participants