Skip to content

fix(anthropic_stream_events): bound streaming tool-call state (max_tool_blocks) - #862

Open
leseb wants to merge 1 commit into
praxis-proxy:mainfrom
leseb:leseb/validate-issue-412
Open

fix(anthropic_stream_events): bound streaming tool-call state (max_tool_blocks)#862
leseb wants to merge 1 commit into
praxis-proxy:mainfrom
leseb:leseb/validate-issue-412

Conversation

@leseb

@leseb leseb commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

The anthropic_stream_events filter stored two ctx.filter_metadata entries per unique streaming tool-call index and never released them, so a backend that streams an unbounded number of distinct tool-call indices could grow per-response memory without limit (DoS). This adds a max_tool_blocks cap (default 10,000; zero rejected at config build) that counts tool-call content blocks as they open and fails the stream closed before opening a block beyond the cap, keeping per-response memory bounded. Scope is the Anthropic filter only.

Related issue

Closes #412

Validation

  • Unit tests — cargo test -p praxis-ai-apis -- max_tool_blocks (parse custom cap, reject zero, fail closed past cap)
  • Integration or functional tests — cargo test -p praxis-tests-integration -- streaming_tool_calls (self-validating pair: within-cap completes with message_stop; over-cap aborts before message_stop)
  • make lint (also ran make build, clean)

Checklist

  • I reviewed every changed line and can explain the change.
  • New capabilities include an example config and functional example test.
  • User-facing behavior and generated documentation are updated.
  • Performance-sensitive changes include appropriate benchmark or load-test evidence. (N/A — memory-bound safety cap, not a throughput change.)
  • Commits are signed and include a Signed-off-by trailer.

Breaking changes

None. max_tool_blocks defaults to 10,000, so existing configs are unaffected; operators may lower it to tighten the bound or raise it for workloads with many concurrent tool calls.

…x_tool_blocks

The filter stored two ctx.filter_metadata entries per unique streaming
tool-call index and never released them, so a backend that streams an
unbounded number of distinct tool-call indices could grow per-response
memory without limit (DoS).

Add a max_tool_blocks cap (default 10,000; zero is rejected at config
build). The filter counts tool-call content blocks as they open and fails
the stream closed before opening a block beyond the cap, so per-response
memory stays bounded.

Scope is the Anthropic filter only. Adds unit tests, a self-validating
integration test pair (within-cap completes with message_stop; over-cap
aborts before message_stop), the example-config knob, and regenerated
filter docs.

Signed-off-by: Sébastien Han <seb@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Streaming tool-call state grows without an aggregate limit

1 participant