#19094: Fix empty tool_call_id and function names in provider transcript payloads
docs
agents
size: M
Cluster:
Error Handling in Agent Tools
## Summary
Fixes malformed tool transcript entries that can generate provider payloads with empty `tool_call_id` / empty function names.
This change adds a global malformed-entry pruning pass before request build and blocks malformed tool results from being persisted going forward.
Issue: https://github.com/openclaw/openclaw/issues/19003
## Root cause
- `2026.2.15` removed OpenAI tool-id sanitization in `src/agents/transcript-policy.ts`.
- OpenAI request sanitation still skipped pairing repair by policy, so malformed historical tool-result entries could survive into outbound payloads.
- `installSessionToolResultGuard(...)` in `src/agents/session-tool-result-guard.ts` allowed persisting `toolResult` entries even when id extraction was empty/missing.
- Strict providers reject payloads containing invalid tool messages (for example `role: "tool"` with empty `tool_call_id`).
## Fix
- Added global malformed tool-entry pruning in `src/agents/session-transcript-repair.ts`:
- New `repairMalformedToolEntries(...)` and `sanitizeMalformedToolEntries(...)` APIs.
- Expanded tool-call block type recognition to include aliases: `tool_call`, `tool_use`, `function_call`.
- Drops malformed `toolResult` entries with missing/blank ids.
- Applied malformed pruning in `sanitizeSessionHistory(...)` (`src/agents/pi-embedded-runner/google.ts`) before provider-specific pairing repair.
- Added warning logging in the sanitize path when malformed entries are dropped.
- Tightened id parsing in `src/agents/tool-call-id.ts`:
- trims/rejects whitespace-only IDs and names
- keeps valid canonical ids unchanged (including OpenAI `call_x|fc_y` form)
- Added persistence-time guard in `src/agents/session-tool-result-guard.ts`:
- malformed tool results with missing/blank ids are not persisted.
## Tests
### Added/updated tests
- `src/agents/session-transcript-repair.e2e.test.ts`
- drops blank/missing-id tool results
- drops alias tool calls with blank names
- preserves canonical OpenAI ids (`call_123|fc_123`)
- `src/agents/pi-embedded-runner.sanitize-session-history.test.ts`
- OpenAI path prunes malformed tool results and malformed alias tool calls
- `src/agents/session-tool-result-guard.e2e.test.ts`
- malformed tool results are not persisted
- pending tool calls remain flushable
### Verification commands
- `pnpm install` ✅
- `pnpm check` ✅
- `pnpm test` ✅ (`620` files passed, `5136` tests passed)
- `pnpm build` ✅
## Notes
- No CLI flags, config schema, or RPC schema changes.
- OpenAI id rewriting remains disabled by policy; malformed entries are pruned without rewriting canonical ids.
- Updated docs in `docs/reference/transcript-hygiene.md` to describe global malformed tool-result pruning behavior.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR adds a global malformed-entry pruning pass for tool transcript entries to prevent strict providers (e.g., OpenAI) from rejecting payloads with empty `tool_call_id` or blank function names. The fix operates at two levels: (1) a pre-request sanitization step via `repairMalformedToolEntries` in `sanitizeSessionHistory` that drops tool results with missing/blank IDs and tool calls with blank names (including snake_case alias types), and (2) a persistence-time guard in `installSessionToolResultGuard` that rejects malformed tool results before they are written to the session transcript.
- `repairMalformedToolEntries` in `session-transcript-repair.ts` composes the existing `repairToolCallInputs` with new tool-result pruning, and expands type recognition to include `tool_call`, `tool_use`, `function_call` aliases
- `asNonEmptyString` helper in `tool-call-id.ts` ensures consistent trim + reject-whitespace behavior across all ID extraction points (`extractToolCallsFromAssistant`, `extractToolResultId`, and ID rewrite functions)
- The persistence guard in `session-tool-result-guard.ts` now early-returns for malformed tool results, keeping the pending tool call flushable
- Warning logging added in `sanitizeSessionHistory` when malformed entries are dropped
- Tests added at unit, integration, and e2e levels covering blank/missing IDs, alias types, and canonical OpenAI ID preservation
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — it adds defensive pruning of invalid entries with consistent behavior across extraction and persistence layers.
- Score of 4 reflects well-structured changes with good test coverage and consistent behavior. The trimming behavior change in `extractToolResultId` (now returns trimmed strings via `asNonEmptyString`) is correctly applied at all call sites. One minor doc inconsistency noted (the "malformed tool calls" docs section still references `sanitizeToolCallInputs` as the direct implementation in `sanitizeSessionHistory` even though code now uses `repairMalformedToolEntries`), which doesn't affect runtime behavior. The `sanitizeMalformedToolEntries` export is unused but follows existing module patterns.
- No files require special attention — the logic changes are straightforward defensive pruning with consistent behavior across all paths.
<sub>Last reviewed commit: 69d25e6</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#19024: fix: Fix normalise toolid
by chetaniitbhilai · 2026-02-17
86.8%
#12487: fix(agents): strip orphaned tool_result when tool_use is sanitized ...
by skylarkoo7 · 2026-02-09
86.4%
#6687: fix(session-repair): strip malformed tool_use blocks to prevent per...
by NSEvent · 2026-02-01
86.2%
#8345: fix: prevent synthetic error repair from creating tool_result for d...
by vishaltandale00 · 2026-02-03
86.1%
#3647: fix: sanitize tool arguments in session history
by nhangen · 2026-01-29
86.0%
#22011: fix(transcript): drop empty toolCallId toolResults during persisten...
by sauerdaniel · 2026-02-20
86.0%
#15143: fix(transcript-repair): validate tool call id and name to prevent G...
by GreyC · 2026-02-13
84.6%
#21166: fix(agents): sanitize tool names in session transcript repair (#8595)
by dinakars777 · 2026-02-19
84.5%
#15050: fix: transcript corruption resilience — strip aborted tool_use bloc...
by yashchitneni · 2026-02-12
84.4%
#8312: fix: add logging and markers for tool result repair
by ekson73 · 2026-02-03
84.1%