mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-13 23:11:40 +00:00
* fix(websearch): restore snippet text in native web_search_tool_result blocks (LIT-5315) The build_web_search_tool_result_block method copied url/title/page_age but hardcoded encrypted_content to empty string, never reading SearchResult.snippet. This left every native block content-free, forcing clients to web_fetch each result to recover evidence—the reported symptom. The Anthropic spec carries page text only in encrypted_content (an opaque server-issued blob we cannot mint), so snippet is emitted as an additive key alongside the spec fields. encrypted_content stays empty rather than holding plaintext, which would assert encryption semantics that don't hold. The anthropic SDK's BaseModel sets extra='allow', so the additive snippet key survives SDK parsing. litellm has no typed model for web_search_result at all, so nothing drops it internally. Turn-2 replay behavior is unaffected: the empty encrypted_content already exists today. Tests: - Updated test_shape_with_results to assert snippet present - Added test_snippet_carried_for_every_result to cover multi-result ordering - Added test_missing_snippet_degrades_to_empty_string for edge case - Mutation check: reverting source-only yields 3 test failures, restored to 117 passed Fixes: LIT-5315 Co-Authored-By: Claude <noreply@anthropic.com> * fix(websearch): make synthesized web_search blocks replayable by native clients Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(websearch): flatten a resultless replayed search block so Bedrock accepts the next turn The flatten added for LIT-5315 bails when the replayed web_search_tool_result carries an empty content list, but that is exactly what the interceptor emits when a search legitimately returns nothing and when a search raises. The block survived into the outbound body, Bedrock rejected the tag, and the conversation died on the following turn just as it did before the flatten existed. An empty content list has no encrypted_content to respect and no evidence to preserve, so it flattens safely, and its paired server_tool_use goes with it. The rendered text now says so explicitly rather than emitting a bare header. Adds the multi-turn replay coverage that existed nowhere: the outbound Bedrock invoke body is asserted free of both block types, parametrized over the results-present and resultless cases, and built from the interceptor's own builder so the fixture cannot drift from what it emits. Resolves LIT-5320 * test(websearch): pin flatten idempotency for the agentic-loop re-entry The agentic loop re-enters the same /v1/messages entry point for its follow-up call and hands it the original client history, so the flatten runs again over already-flattened messages once per iteration. Bedrock always takes that path, since its config reports web search as natively handled and the short-circuit is skipped. A pass that appended the rendered text instead of replacing the block would duplicate the evidence on every iteration and re-ship the unsupported tag, and no existing single-pass test sees it. Mutation checked: keeping the original block alongside the rendered text fails this test on its own. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Yassin Kortam <yassin@berri.ai> |
||
|---|---|---|
| .. | ||
| test_websearch_chat_completion.py | ||
| test_websearch_interception_handler.py | ||
| test_websearch_interception_thinking.py | ||
| test_websearch_native_blocks.py | ||
| test_websearch_responses.py | ||
| test_websearch_short_circuit.py | ||
| test_websearch_streaming_wrap.py | ||
| test_websearch_thinking_constraint.py | ||