anthropics / anthropics/anthropic-sdk-php
Bedrock: body round-trip flattens empty JSON objects ({} -> []), so a no-argument tool_use gets a 400
- Lingua principale
- PHP
- Stelle
- 180
- Fork
- 54
- Merge medio
- 12h 17m
- PR unite (30g)
- 6
Descrizione
**Environment**
- `anthropic-ai/sdk` v0.42.0 (latest; the code is unchanged on `main`)
- PHP 8.3, Bedrock transport (`Anthropic\Bedrock`), EU inference profile for Claude Sonnet
**Summary**
`RequestTransformer::decodedBody()` decodes the request body with `json_decode($body, true)` ([src/Core/RequestTransformer.php#L98](https://github.com/anthropics/anthropic-sdk-php/blob/main/src/Core/RequestTransformer.php#L98)). A PHP associative array cannot represent an empty JSON object. When `serialize()` re-encodes the body ([#L162](https://github.com/anthropics/anthropic-sdk-php/blob/main/src/Core/RequestTransformer.php#L162)), every `{}` in the request becomes `[]`.
The direct Anthropic API path does not show this: the transformer re-encodes only when the body was modified (`bodyDirty`). But `BedrockMiddleware` always rewrites the body (it moves `model` into the URL and injects `anthropic_version`), so on Bedrock every request is re-encoded and every empty object flattens.
**Impact**
A multi-turn conversation that replays an assistant `tool_use` block with an empty `input` (any tool that takes no arguments) is rejected by Bedrock with a 400 whose validation error points at `messages.N.content.M.tool_use.input`. The same request succeeds on `api.anthropic.com`.
The same flattening hits every other empty object in the body, for example a no-parameter tool's `input_schema.properties: {}` or an empty `metadata: {}`.
This makes the failure intermittent and hard to diagnose in an agent loop: simple turns work, and only a turn whose history contains a no-argument tool call fails.
**Repro**
The core defect in isolation:
```php
$body = '{"messages":[{"role":"assistant","content":[{"type":"tool_use","id":"toolu_1","name":"list_stores","input":{}}]}]}';
echo json_encode(json_decode($body, true));
// ...,"input":[]}]}]} — Bedrock rejects this
```
Full path: send a Messages request through the Bedrock client with a conversation history that contains an assistant `tool_use` block whose `input` is `{}`. Bedrock returns a 400; the direct API accepts the identical request.
**Suggested fix**
Decode without `assoc` and keep nested values as `stdClass`:
```php
$decoded = (array) json_decode((string) $stream, false);
```
The transformer reads and writes only top-level params (`model`, `anthropic_version`, `anthropic_beta`, `stream`), so the top-level array cast keeps the current API, and nested `stdClass` values re-encode as `{}` correctly. (`BedrockMiddleware`'s `base64_encode(json_encode($r->getBody(), ...))` for streaming also re-encodes nested objects correctly then.)
**Workaround we use**
A PSR-18 decorator on the Bedrock transporter restores the structural `"input":[]` back to `"input":{}` and then re-signs the request with SigV4 — the middleware signs before the transporter runs, so any body change after it must re-sign or AWS rejects the payload hash.
Guida per i contributori
Apri la guida per i contributori
Valutazione
Questa issue non è ancora stata valutata.