Skip to content

fix(anthropic): stream tag duplication, 529 mapping, image fetch hardening - #3907

Merged
crazywoola merged 1 commit into
langgenius:mainfrom
hpiclaranet:fix/anthropic-stream-errors-image-fetch-033
Sep 24, 2026
Merged

crazywoola merged 1 commit into
langgenius:mainfrom
hpiclaranet:fix/anthropic-stream-errors-image-fetch-033

Conversation

@hpiclaranet

Copy link
Copy Markdown
Contributor

Summary

Supersedes #3757 (closed by the maintainer on 2026-09-20) and #3721. Rebased onto current main (4a9e83b6), squashed to a single commit; version 0.3.33 (main carries 0.3.32 via #3887; #3788/#3725 propose 0.3.31/0.3.32). The llm.py changes merge cleanly on top of the Fable 5.1/SDK modernization (#3811), the model-type fix (#3843), the icon/deps refresh (#3850) and the structure-output fix (#3887). Full anthropic suite: 125 passed, 15 skipped. Addresses the maintainer's review on #3757: fresh version, Release Notes calling out the image-fetch restrictions, and URL-based image input verification.

Three reliability fixes in the Anthropic provider, each confirmed by code-path analysis of the streaming state machine and the installed anthropic SDK (0.120.0 at analysis time; the plugin now locks 1.4.0 via #3850 and the full suite was re-verified with SDK 1.4.0):

  1. Duplicate closing think tag in streams — when a thinking block was followed directly by a tool_use block, the input_json_delta events matched none of the block-type branches, so current_block_type stayed "thinking". The block transition had already emitted the closing tag once, and the MessageStopEvent handler emitted it a second time, corrupting the thought text Dify stores. Tool-use deltas now mark the block as "tool_use".
  2. HTTP 529 misclassified as a client error — anthropic.OverloadedError is a direct subclass of APIStatusError (not InternalServerError), so it fell through the APIError catch-all into InvokeBadRequestError. It is now mapped to InvokeServerUnavailableError (server-side capacity, retryable). The mapping entry is ordered before the catch-all, which is what the SDK's first-match lookup requires.
  3. Unbounded image URL fetch — requests.get(data) had no timeout (a hung URL could block the worker indefinitely), no size cap, accepted any URL scheme, and followed redirects. It now uses a (5s connect, 15s read) timeout, streamed reads bounded to a 10 MB cap (early rejection via Content-Length or during iter_content, so a hostile server cannot push unbounded bytes into the process), http(s)-only URLs (surrounding whitespace tolerated), and no redirect following with explicit 3xx rejection (a 3xx with an image-like body is rejected, not consumed).

Release Notes

  • Fixed duplicated "thinking" end markers in streamed agent responses when Claude calls a tool directly after thinking
  • Fixed Anthropic 529 (overloaded) errors being shown as user errors; they are now treated as transient server issues
  • Hardened URL-based image input: downloads are now capped at 10 MB and HTTP redirects are rejected (image URLs that previously relied on 3xx redirects must now supply the direct resource URL or use data URIs); enforced bounded timeouts (5s connect / 15s read) and http(s)-only schemes

Change Type

  • Documentation / non-plugin change
  • Non-LLM plugin (tools, extensions, datasource, etc.)
  • LLM plugin

Screenshots / Videos

Not applicable — streaming state machine, error mapping, and fetch hardening, covered by unit tests.

LLM Plugin Checklist

Areas affected by this change (check all that apply)
  • Message flow (system messages, user ↔ assistant turn-taking)
  • Tool interaction flow (multi-round usage, Agent App and Agent Node)
  • Multimodal input (images, PDFs, audio, video, etc.)
  • Multimodal output (images, audio, video, etc.)
  • Structured output (JSON, XML, etc.)
  • Token consumption metrics
  • Other LLM functionality (reasoning, grounding, prompt caching, etc.)
  • New models / model parameter fixes

Version

Testing

  • Local deployment — clean uv venv aligned with manifest.yaml, pyproject.toml, and uv.lock: full anthropic suite 125 passed, 15 skipped on the rebased head (d2975895, main 4a9e83b6, SDK 1.4.0) — 20 tests in test_stream_and_hardening.py, including two new URL-based image input-path tests: test_image_url_input_reaches_request_content (a direct URL image is fetched and reaches the request as base64) and test_image_url_that_previously_redirected_rejected_at_input_path (a redirecting URL fails fast at the input path with a clear error). The bug-target tests fail against the pre-fix code (verified by checking out the base commit): duplicate-tag, 529 mapping, timeout/no-redirect/stream kwargs, whitespace stripping, 3xx-with-valid-body, Content-Length cap, oversized body. ruff check shows zero new findings vs baseline.
  • SaaS (cloud.dify.ai)

Known limitations (pre-existing, out of scope here):

  • The fetch hardening does not restrict private-network hostnames (multi-tenant deployments should apply network-level egress controls); no upstream allowlist exists in this plugin's credential schema.
  • 503/504 mapping: ServiceUnavailableError/DeadlineExceededError are not explicitly mapped in this PR (pre-existing gap; generic 5xx map to InternalServerError, which is already mapped). With the SDK now at 1.4.0 (chore(plugins): refresh verified icons and dependencies, fix CI #3850) those classes exist, so a 503/504 would be surfaced as a client error until explicitly mapped — out of scope here.
  • The redacted/omitted-thinking delta branch in the stream handler does not match the SDK event model (verified against 0.120, 1.3.0 and 1.4.0 — no redacted delta variant; pre-existing; encrypted thinking is intentionally not rendered).

…ening

- Tool-use deltas now mark the block as "tool_use", fixing duplicate
  closing think tags when a thinking block is followed directly by a
  tool_use block in streams.
- Map anthropic.OverloadedError (HTTP 529) to InvokeServerUnavailableError
  (retryable), ordered before the generic APIError catch-all.
- Harden image URL fetching: (5s, 15s) timeout, 10 MB streamed cap with
  early Content-Length rejection, http(s)-only schemes, redirects rejected.
- Add URL-based image input-path tests: a direct URL image is fetched and
  reaches the request as base64; a redirecting URL fails fast at the input
  path with a clear user-visible error.

Rebased onto main (4a9e83b); version 0.3.33 (main carries 0.3.32 via langgenius#3887);
verified with Anthropic SDK 1.4.0 (langgenius#3850).
@crazywoola
crazywoola deployed to models/anthropic September 24, 2026 02:58 — with GitHub Actions Active
@crazywoola
crazywoola enabled auto-merge (squash) September 24, 2026 03:01
@crazywoola
crazywoola merged commit 99eca04 into langgenius:main Sep 24, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
models/anthropic — d2975895 Deployed Sep 24, 2026 by crazywoola via test (models/anthropic) #2787
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.

2 participants