* fix(claude): passthrough tool_use names must match client-declared casing
A mapless restoreClaudePassthroughToolUseName upgraded known Claude Code
tool names (bash -> Bash) on every Claude-format SSE passthrough. Clients
that declared lowercase tool names (pi, OpenCode, ... on claude-format
executors like devin-cli-agentic) received a tool_use name they never
declared: client-side tool dispatch fails and echoing the history back
hard-fails with devin-cli-agentic undeclared_historical_tool (live repro:
pi + dva/glm-5-2 on a self-hosted router, 400 on every agentic turn).
- restoreClaudePassthroughToolUseName: alias map first (renamed ->
original), then normalize to the request's declared tools[] casing,
never canonicalize undeclared names. Genuine Claude Code clients keep
their #7926 protection (upstream downcase -> declared PascalCase).
- devin-agentic serializer: case-insensitive fallback for historical
tool_use names + render the declared spelling, so case drift can no
longer kill a whole turn.
Tests: tests/unit/claude-passthrough-tool-name-mapless-leak.test.ts,
tests/unit/devin-agentic-serializer-case-insensitive-history.test.ts
* fix(stream): direct ledger lookups in claude passthrough restore
restoreClaudeToolName's canonical-upgrade fallback fires even when an alias
ledger exists (canonical beats the identity match). The claude passthrough
lane always carries a non-empty proxy_ ledger
(buildClaudePassthroughToolNameMap), so every lowercase tool_use name was
upgraded to Claude Code PascalCase on the SSE path while the JSON path
(direct map.get) stayed correct — the live leak behind #12721.
* docs(changelog): add fragment for claude passthrough tool_use casing fix
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
---------
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>