Skip to content

fix(runner): pydantic-ai 2.13.0 — restore WebSearch runs broken by Anthropic pause_turn - #322

Merged
ryw merged 2 commits into
mainfrom
fix/pydantic-ai-2x-pause-turn
Jul 20, 2026
Merged

fix(runner): pydantic-ai 2.13.0 — restore WebSearch runs broken by Anthropic pause_turn#322
ryw merged 2 commits into
mainfrom
fix/pydantic-ai-2x-pause-turn

Conversation

@ryw

@ryw ryw commented Jul 20, 2026

Copy link
Copy Markdown
Member

What

Two fixes from investigating Kevin's report (competitor-monitoring-digest failing every scheduled run since Thu 7/16, and agent-update submissions erroring):

1. Upgrade pydantic-ai 1.102.0 → 2.13.0 (fixes the failing runs)

Every run of the WebSearch-capability agent has died since 7/16 with:

400 web_search tool use with id srvtoolu_… was found without a corresponding web_search_tool_result block

Anthropic now routinely ends long server-tool turns with stop_reason=pause_turn; pydantic-ai 1.x replays the paused history malformed (pydantic-ai#2600). The fix (pydantic-ai#6303, merged 7/15, first released in v2.10.0) continues paused turns and merges the segments; it was never backported to 1.x. The same failure hit once on 7/9 and became deterministic on 7/16 — consistent with an Anthropic-side ramp, not a TAS deploy (no runner changes since 7/8).

Wrapper adaptations for the 2.x API (small — late-1.x already used the v2-style names):

  • Agent(history_processors=…) removed → scaledown compressor attaches via the ProcessHistory capability
  • Agent(instrument=…) removed → spec instrument: true maps to the Instrumentation capability
  • [mcp] extra no longer exists — MCP client deps ship by default

2. Surface CAP status/body on agent-change dispatch failures

The REST/MCP path collapsed all CAP failures to (http), which is why Kevin's update-submission error was undiagnosable remotely. Now returns HTTP <status>: <body ≤300 chars>, matching what the chat UI already shows. (This does not fix his submission failure — root cause is upstream at CAP, still being pinned down — but makes the next failure self-describing.)

Verification

  • pytest tests/test_run_pydantic_build_agent.py — 10 passed on 2.13.0 (8 existing unchanged + 2 new capability-path tests)
  • Live smoke: basic haiku run streams deltas/steps/usage correctly
  • Live smoke: 6-web-search single-turn run on claude-sonnet-5 (the exact failing shape) completes on 2.13.0
  • cd web && npx vitest run — 196 passed

Follow-up (not in this PR)

  • v2 ships a real Thinking capability — the wrapper still ignores spec Thinking: entries (competitor-monitoring-digest declares one)
  • Live per-step token usage streams 0s on v2 (final totals correct) — ctx.usage timing changed

🤖 Generated with Claude Code

ryw and others added 2 commits July 20, 2026 09:56
…andling

WebSearch-capability runs on Claude have failed since 2026-07-16 with a 400:
"web_search tool use ... without a corresponding web_search_tool_result
block". Anthropic now routinely pauses long server-tool turns
(stop_reason=pause_turn); pydantic-ai 1.102.0 replays the paused history
malformed (pydantic/pydantic-ai#2600). 2.10.0+ continues paused turns and
merges the segments (pydantic/pydantic-ai#6303).

Wrapper changes for the 2.x API:
- Agent(history_processors=...) is gone: scaledown now attaches via the
  ProcessHistory capability.
- Agent(instrument=...) is gone: spec instrument:true maps to the
  Instrumentation capability.
- pydantic-ai 2.x has no [mcp] extra; the MCP client ships by default.

Verified: unit tests pass unchanged apart from the two new capability
tests; live smoke runs (basic haiku run + a 6-search WebSearch run on
claude-sonnet-5, the exact failing shape) complete on 2.13.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The REST/MCP agent-change path collapsed every Tembo CAP failure to
"Tembo Coding Agent rejected the request (http)", hiding the upstream
status and error body. Include them (body capped at 300 chars) so a
failing dispatch is diagnosable from the caller's error alone — the
chat UI already shows the same detail via formatCapError. Logging the
body remains forbidden (#44); this only returns it to the caller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
// the body that #44 forbids — it can echo the submitted prompt.
const detail =
res.error.kind === "http"
? `HTTP ${res.error.status}: ${res.error.body.slice(0, 300) || "(no body)"}`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One wrinkle: requestAgentChangeSystem() reuses this path for learning batches, and the scheduler logs res.error on failure. If CAP echoes the submitted prompt in the body, this return value now writes that body to server logs. Consider keeping the body only for request-backed API/MCP responses and returning a sanitized detail for the system/learning path.

Comment thread api/Dockerfile
RUN python3 -m venv "${PYDANTIC_AI_VENV}" && \
"${PYDANTIC_AI_VENV}/bin/pip" install --no-cache-dir \
'pydantic-ai[mcp]==1.102.0' pyyaml==6.0.2 composio==0.13.1 \
'pydantic-ai==2.13.0' pyyaml==6.0.2 composio==0.13.1 \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v2 bump also changes streamed tool-result events from .result to .part (event.tool_call_id carries the id). make_stream_handler() still reads FunctionToolResultEvent.result, so under 2.x live progress can mark successful function tool returns as ok: false until the final captured steps arrive. The version bump should include that handler migration so live run steps don't show false failures.

@ryw
ryw merged commit 0b77a8f into main Jul 20, 2026
10 checks passed
@ryw
ryw deleted the fix/pydantic-ai-2x-pause-turn branch July 20, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant