Skip to content

Commit 62e83df

Browse files
authored
Fixing structured tool response + non-multimodal content (#326)
1 parent 6df4905 commit 62e83df

8 files changed

+466
-2
lines changed

.pre-commit-config.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ repos:
4848
- id: codespell
4949
additional_dependencies: [".[toml]"]
5050
exclude_types: [jupyter]
51-
exclude: '.*\.b64$|labbench/tests/stub_data'
5251
- repo: https://github.com/pappasam/toml-sort
5352
rev: v0.24.3
5453
hooks:

.secrets.allowlist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
authorization
22
x-api-key
3+
PENGUIN

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ preview = true
111111
check-filenames = true
112112
check-hidden = true
113113
ignore-words-list = "aadd,astroid,ser"
114+
skip = [
115+
"packages/labbench/tests/stub_data/*",
116+
"tests/cassettes/*",
117+
"tests/fixtures/test_images/*",
118+
"tests/stub_data/*",
119+
]
114120

115121
[tool.markdown_toc_creator]
116122
horizontal-rule-style = "prettier"

src/aviary/message.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,16 @@ def _serialize(self, handler, info: SerializationInfo):
9191
9292
This overrides Field-level exclusion to allow us to call:
9393
`model_dump(context={"include_info": True})`.
94+
95+
For content:
96+
- Multimodal content gets deserialized to a list,
97+
as LLM APIs expect multimodal content as structured blocks.
98+
- Other structured content stays as a JSON string,
99+
as tool response content must be a string for LLM API compatibility.
94100
"""
95101
data = handler(self)
96102
if (
97-
self.content_is_json_str
103+
self.is_multimodal
98104
and "content" in data
99105
and (info.context or {}).get("deserialize_content", True)
100106
):
@@ -106,6 +112,22 @@ def _serialize(self, handler, info: SerializationInfo):
106112
def __str__(self) -> str:
107113
return self.content or ""
108114

115+
@property
116+
def is_multimodal(self) -> bool:
117+
"""Check if content is encoded multimodal data."""
118+
if not self.content_is_json_str:
119+
return False
120+
# content_is_json_str=True guarantees content is a valid JSON string
121+
parsed = json.loads(self.content) # type: ignore[arg-type]
122+
# Check the content is multimodal content following
123+
# the OpenAI/Anthropic format of list[dict] containing text or image URLs
124+
if not isinstance(parsed, list) or not parsed:
125+
return False
126+
return all(
127+
isinstance(item, dict) and item.get("type") in {"text", "image_url"}
128+
for item in parsed
129+
)
130+
109131
def append_text(self, text: str, delim: str = "\n", inplace: bool = True) -> Self:
110132
"""Append text to the content.
111133
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
interactions:
2+
- request:
3+
body:
4+
'{"model":"claude-haiku-4-5-20251001","messages":[{"role":"user","content":[{"type":"text","text":"Call
5+
the capture tool, then tell me what word is written in the image. Reply with
6+
only the word and nothing else. If you are unsure what is in the image, reply
7+
''Unsure''."}]},{"role":"assistant","content":[{"type":"tool_use","id":"91c2778d9","name":"capture_image_with_text","input":{}}]},{"role":"user","content":[{"type":"tool_result","tool_use_id":"91c2778d9","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"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"}},{"type":"text","text":"Here
8+
is the captured image containing text.","cache_control":null}]}]}],"tools":[{"name":"capture_image_with_text","input_schema":{"type":"object","properties":{},"required":[]},"description":"Capture
9+
an image containing text and return it with a description."}],"tool_choice":{"type":"none"},"max_tokens":64000}'
10+
headers:
11+
accept:
12+
- application/json
13+
accept-encoding:
14+
- gzip, deflate
15+
anthropic-version:
16+
- "2023-06-01"
17+
connection:
18+
- keep-alive
19+
content-length:
20+
- "3773"
21+
content-type:
22+
- application/json
23+
host:
24+
- api.anthropic.com
25+
user-agent:
26+
- litellm/1.80.11
27+
method: POST
28+
uri: https://api.anthropic.com/v1/messages
29+
response:
30+
body:
31+
string: !!binary |
32+
H4sIAAAAAAAA/3WQy2rDMBBF/2XWNthp3ICXfRC6aCilgUApQkhTW0SWXGlU0hj/e8ehpi+ykrjn
33+
aC6jATqv0UINysqkMW+l2ad8mVf5olhUZVGUkIHRLHSxEUX5uEvH3evyurlZ4eFpnY5xe3XfskMf
34+
PU4Wxigb5CB4OwUyRhNJOuJIeUfIt/p5mH3Cw0RORw0Pt5v19m4D40sGkXwvAsroHRN0WlAKDr5A
35+
xLeETvEIl6zNIJ1a6wGM6xMJ8nt0EepVecG1UrUoFM8i4534bRQzZ6zPsfntVIB9ix0GaUXV/fe/
36+
adn+pWMGPtHP6JK3wfBuFAoyGHjP6au0DBrG8RO0YgrDnAEAAA==
37+
headers:
38+
CF-RAY:
39+
- 9b95da0eac41eb35-SJC
40+
Connection:
41+
- keep-alive
42+
Content-Encoding:
43+
- gzip
44+
Content-Type:
45+
- application/json
46+
Date:
47+
- Mon, 05 Jan 2026 20:51:07 GMT
48+
Server:
49+
- cloudflare
50+
Transfer-Encoding:
51+
- chunked
52+
X-Robots-Tag:
53+
- none
54+
anthropic-organization-id:
55+
- f2c99ed9-038a-406f-9cb5-1f840b758a20
56+
anthropic-ratelimit-input-tokens-limit:
57+
- "4000000"
58+
anthropic-ratelimit-input-tokens-remaining:
59+
- "4000000"
60+
anthropic-ratelimit-input-tokens-reset:
61+
- "2026-01-05T20:51:07Z"
62+
anthropic-ratelimit-output-tokens-limit:
63+
- "800000"
64+
anthropic-ratelimit-output-tokens-remaining:
65+
- "800000"
66+
anthropic-ratelimit-output-tokens-reset:
67+
- "2026-01-05T20:51:07Z"
68+
anthropic-ratelimit-requests-limit:
69+
- "4000"
70+
anthropic-ratelimit-requests-remaining:
71+
- "3999"
72+
anthropic-ratelimit-requests-reset:
73+
- "2026-01-05T20:51:06Z"
74+
anthropic-ratelimit-tokens-limit:
75+
- "4800000"
76+
anthropic-ratelimit-tokens-remaining:
77+
- "4800000"
78+
anthropic-ratelimit-tokens-reset:
79+
- "2026-01-05T20:51:07Z"
80+
cf-cache-status:
81+
- DYNAMIC
82+
request-id:
83+
- req_011CWpthJFhYTqp8RUkfSvpS
84+
strict-transport-security:
85+
- max-age=31536000; includeSubDomains; preload
86+
x-envoy-upstream-service-time:
87+
- "574"
88+
status:
89+
code: 200
90+
message: OK
91+
version: 1
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
interactions:
2+
- request:
3+
body:
4+
'{"model":"claude-sonnet-4-5-20250929","messages":[{"role":"user","content":[{"type":"text","text":"Call
5+
the capture tool, then tell me what word is written in the image. Reply with
6+
only the word and nothing else. If you are unsure what is in the image, reply
7+
''Unsure''."}]},{"role":"assistant","content":[{"type":"tool_use","id":"6265cf572","name":"capture_image_with_text","input":{}}]},{"role":"user","content":[{"type":"tool_result","tool_use_id":"6265cf572","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"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"}},{"type":"text","text":"Here
8+
is the captured image containing text.","cache_control":null}]}]}],"tools":[{"name":"capture_image_with_text","input_schema":{"type":"object","properties":{},"required":[]},"description":"Capture
9+
an image containing text and return it with a description."}],"tool_choice":{"type":"none"},"max_tokens":64000}'
10+
headers:
11+
accept:
12+
- application/json
13+
accept-encoding:
14+
- gzip, deflate
15+
anthropic-version:
16+
- "2023-06-01"
17+
connection:
18+
- keep-alive
19+
content-length:
20+
- "3774"
21+
content-type:
22+
- application/json
23+
host:
24+
- api.anthropic.com
25+
user-agent:
26+
- litellm/1.80.11
27+
method: POST
28+
uri: https://api.anthropic.com/v1/messages
29+
response:
30+
body:
31+
string: !!binary |
32+
H4sIAAAAAAAA/3WQ3UrEMBBG32WuW2i7dmV7J7KKCIuKeyUSQjK0wTSpyURWS9/d6WLxj71K+M7J
33+
TGZG6L1GCw0oK5PGPHrnkPKzvM6roqqLTbWBDIxmo4+tKMpVqfZpW/fdg+vax8PF1f364/aSHXof
34+
cLYwRtkiB8HbOZAxmkjSEUfKO0K+NU/j4hMeZnI8Grjb7q73NzuYnjOI5AcRUPKXmKDTglJw8AUi
35+
viZ0iku4ZG0G6di1GcG4IZEg/4IuQnNerritVB0KxbXIeCd+G8XCGetTbHk7N8Chwx6DtKLu//vf
36+
tOz+0ikDn+hntOZpMLwZhYIMBp5zXpWWQcM0fQKBPql6nQEAAA==
37+
headers:
38+
CF-RAY:
39+
- 9b95da132cc6e612-SJC
40+
Connection:
41+
- keep-alive
42+
Content-Encoding:
43+
- gzip
44+
Content-Type:
45+
- application/json
46+
Date:
47+
- Mon, 05 Jan 2026 20:51:09 GMT
48+
Server:
49+
- cloudflare
50+
Transfer-Encoding:
51+
- chunked
52+
X-Robots-Tag:
53+
- none
54+
anthropic-organization-id:
55+
- f2c99ed9-038a-406f-9cb5-1f840b758a20
56+
anthropic-ratelimit-input-tokens-limit:
57+
- "50000000"
58+
anthropic-ratelimit-input-tokens-remaining:
59+
- "50000000"
60+
anthropic-ratelimit-input-tokens-reset:
61+
- "2026-01-05T20:51:09Z"
62+
anthropic-ratelimit-output-tokens-limit:
63+
- "10000000"
64+
anthropic-ratelimit-output-tokens-remaining:
65+
- "10000000"
66+
anthropic-ratelimit-output-tokens-reset:
67+
- "2026-01-05T20:51:09Z"
68+
anthropic-ratelimit-tokens-limit:
69+
- "60000000"
70+
anthropic-ratelimit-tokens-remaining:
71+
- "60000000"
72+
anthropic-ratelimit-tokens-reset:
73+
- "2026-01-05T20:51:09Z"
74+
cf-cache-status:
75+
- DYNAMIC
76+
request-id:
77+
- req_011CWpthMRT2MXAdJwcBsCJz
78+
strict-transport-security:
79+
- max-age=31536000; includeSubDomains; preload
80+
x-envoy-upstream-service-time:
81+
- "2470"
82+
status:
83+
code: 200
84+
message: OK
85+
version: 1

0 commit comments

Comments
 (0)