← Back to PRs

#4964: fix: strip null-valued optional parameters from tool calls for provider compatibility

by umut-polat open 2026-01-30 22:03 View on GitHub →
agents size: M
## Summary Some LLMs (e.g., certain configurations of DeepSeek, Llama) return explicit `null` values for optional tool call parameters instead of omitting them entirely. For example: ```json {"message": "hello", "recipient": "Umut", "tags": null} ``` OpenClaw's AJV validation expects optional parameters to be omitted rather than set to `null`, causing validation failures like: ``` Validation failed: must NOT have additional properties ``` This PR adds a normalization step that strips null-valued properties from tool call arguments before validation. ## Changes | File | Change | |------|--------| | `src/agents/tool-call-id.ts` | Added `normalizeToolCallArguments()` and `removeNullProperties()` functions | | `src/agents/pi-embedded-helpers/images.ts` | Integrated normalization into message sanitization pipeline | | `src/agents/tool-call-id.test.ts` | Added 10 new tests including real provider scenario | | `CHANGELOG.md` | Added entry | ## How it works - `removeNullProperties<T>()` recursively strips `null` and `undefined` values from objects - `normalizeToolCallArguments()` processes assistant messages and cleans tool call arguments - Handles `toolCall`, `toolUse`, and `functionCall` block types - Preserves messages without arguments field (doesn't add empty `{}`) **Before:** `{"tags": null}` → AJV validation error **After:** `{"tags": null}` → `{}` → validation passes ## Test plan - [x] Unit tests for `normalizeToolCallArguments` (10 new tests) - [x] Real provider scenario test with actual LLM output - [x] All 192 tests passing - [x] Lint passing - [x] Build passing 🤖 Built with Claude <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR adds a normalization pass for assistant tool-call blocks to improve cross-provider compatibility when models emit explicit `null`/`undefined` for optional tool parameters. It introduces `normalizeToolCallArguments()` (used in the session message sanitization pipeline) plus unit tests covering common and “real provider” cases, and notes the fix in the changelog. In the existing agents pipeline, tool-call IDs are already sanitized for provider constraints; this change extends that compatibility layer to tool-call *arguments* by stripping null-valued optionals before AJV/TypeBox validation. <h3>Confidence Score: 4/5</h3> - This PR is generally safe to merge; main behavior change is localized to tool-call argument normalization. - Tests cover key scenarios and the change is scoped to assistant tool-call blocks, but the implementation currently treats any object as a plain object (prototype loss) and uses JSON.stringify-based change detection, which could have edge-case behavior/perf costs if non-JSON values ever appear in arguments. - src/agents/tool-call-id.ts <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs