Skip to content

feat/220 token counting integration tests#243

Open
mkoushni wants to merge 1 commit into
praxis-proxy:mainfrom
mkoushni:feat/220-token-counting-integration-tests
Open

feat/220 token counting integration tests#243
mkoushni wants to merge 1 commit into
praxis-proxy:mainfrom
mkoushni:feat/220-token-counting-integration-tests

Conversation

@mkoushni

@mkoushni mkoushni commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

test(examples): add token_counting integration tests and example config (#220)

Summary

Adds an end-to-end integration test suite and example configuration for
the token_count filter (merged in #262), covering all five provider
response formats, both streaming and non-streaming delivery, and
response-body passthrough guarantees, as described in
proposal #220.

Rebased onto current main: uses the actual merged filter names
(token_count, token_usage_headers) and header names
(Praxis-Token-Input/Output/Total) rather than the placeholder names
from the original proposal draft (x_token_headers, X-Token-*).


What changed

examples/configs/token-counting.yaml

Rewrote the example pipeline to chain
router → token_usage_headers → token_count → access_log → load_balancer,
matching the filters that actually exist on main. Documents that
response headers are committed before the response body phase, so
token_usage_headers (declared before token_count to run after it
in the reverse response-hook order) has nothing to inject for any of
the currently-supported providers (openai, anthropic, google, bedrock,
azure) — they all extract counts from the response body in
on_response_body, after headers have already been sent. Counts remain
available in filter_metadata for other response-phase filters.

tests/integration/tests/suite/examples/token_counting.rs

12 integration tests covering the provider/mode matrix from proposal
#220 that's actually supported by the merged filter:

Test Provider What is verified
openai_non_streaming_extracts_token_counts OpenAI 200 OK + body passthrough
anthropic_non_streaming_extracts_token_counts Anthropic 200 OK + body passthrough
google_non_streaming_extracts_token_counts Google 200 OK + body passthrough
bedrock_converse_non_streaming_extracts_token_counts Bedrock Converse 200 OK + body passthrough
azure_non_streaming_extracts_token_counts Azure 200 OK + body passthrough
openai_streaming_extracts_token_counts OpenAI 200 OK + SSE body passthrough
anthropic_streaming_split_events_extracts_token_counts Anthropic 200 OK + SSE body passthrough (input/output tokens split across message_start/message_delta)
google_streaming_no_done_sentinel_extracts_token_counts Google 200 OK + SSE body passthrough (no [DONE] sentinel)
non_json_response_body_passes_through_unchanged OpenAI Body byte-for-byte identical; no Praxis-Token-* headers
missing_usage_fields_no_token_headers_injected OpenAI Praxis-Token-* headers absent when no usage
openai_streaming_whitespace_and_comments OpenAI Noisy SSE (keep-alive comments, empty lines, pretty-printed JSON) passes through unchanged
example_config_token_counting_openai OpenAI Example config smoke test — config parses and proxy returns 200

Why Praxis-Token-* headers are never asserted present here:
Response headers are committed before the response body filter phase
begins. token_usage_headers runs its on_response hook in reverse
pipeline order — after token_count.on_response but before
token_count.on_response_body. Every provider covered here extracts
counts from the response body inside on_response_body, at which
point headers have already been sent downstream, so
token_usage_headers never has anything to inject. Header-based
extraction (e.g. a future Bedrock InvokeModel provider using
upstream response headers) is the one case where header injection
would be observable; that provider isn't part of this PR and is
tracked separately.

Wiring

  • tests/.../examples/mod.rs — adds mod token_counting;
  • examples/README.md — adds token-counting.yaml entry

Test plan

  • make lint passes (clippy, nightly fmt, separators, filter-docs)
  • make test passes (full unit + integration + doctest suite)
  • All 12 integration tests pass locally

Related

@mkoushni mkoushni requested review from a team and leseb July 2, 2026 13:05
@mkoushni mkoushni requested a review from shaneutt as a code owner July 2, 2026 13:05
@praxis-bot-app

praxis-bot-app Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR too large: 768 lines added (limit: 750, excludes Cargo files, tests, docs, examples, and benchmarks). Please split into smaller PRs. Add skip/pr-conventions label to override.

leseb
leseb previously requested changes Jul 2, 2026

@leseb leseb left a comment

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.

please wait for #244 so we can run these tests in CI, thanks!

Comment thread tests/integration/tests/suite/examples/token_counting.rs Outdated
@mkoushni mkoushni force-pushed the feat/220-token-counting-integration-tests branch from 7444f6f to a623efd Compare July 6, 2026 12:55
@praxis-bot-app

praxis-bot-app Bot commented Jul 6, 2026

Copy link
Copy Markdown

Missing Signed-off-by: a623efd. All commits require sign-off (via git commit --signoff).

@mkoushni mkoushni force-pushed the feat/220-token-counting-integration-tests branch 2 times, most recently from 22a8a9f to 4d2a19b Compare July 6, 2026 13:02
Comment thread tests/integration/tests/suite/examples/mod.rs Outdated
@leseb leseb dismissed their stale review July 7, 2026 07:56

#244 merged

@praxis-bot praxis-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review: Token Counting Integration Tests (#243)

Adds integration tests and example config for the token counting pipeline. The test matrix is well structured and the SSE/non-streaming coverage across providers is thorough.

Findings

# Severity File Description
1 Critical mod.rs Duplicate mod token_counting; — will not compile
2 Large token_counting.rs Missing negative test: Bedrock InvokeModel with absent upstream token-count headers
3 Medium token_counting.rs Doc comment on test function violates project convention
4 Medium token_counting.rs Separator says "Helpers" — convention requires "Test Utilities"

Comment thread tests/integration/tests/suite/examples/mod.rs
Comment thread tests/integration/tests/suite/examples/token_counting.rs
Comment thread tests/integration/tests/suite/examples/token_counting.rs Outdated
Comment thread tests/integration/tests/suite/examples/token_counting.rs Outdated
@shaneutt shaneutt added this to the v0.1.0 milestone Jul 8, 2026
@shaneutt shaneutt moved this from Next to Review in AI Gateway - Model Serving Jul 8, 2026
@mkoushni mkoushni force-pushed the feat/220-token-counting-integration-tests branch from f1f91a7 to 0d5ae40 Compare July 9, 2026 08:31
@mkoushni mkoushni changed the title Feat/220 token counting integration tests feat/220 token counting integration tests Jul 9, 2026
@mkoushni mkoushni force-pushed the feat/220-token-counting-integration-tests branch from 89d1c76 to 6fae4bc Compare July 9, 2026 15:42
@praxis-bot-app

praxis-bot-app Bot commented Jul 9, 2026

Copy link
Copy Markdown

Unsigned commits: 6fae4bc. Please sign your commits.

…ig (praxis-proxy#220)

Adds the integration test suite and example configuration described in
docs/proposals/00220_token-counting-integration-tests.md.

New files:
- examples/configs/token-counting.yaml — example pipeline chaining
  token_count → x_token_headers → access_log with the ordering note
  that x_token_headers must precede token_count in the filter list.
  Comments explain that X-Token-* header injection is only possible for
  bedrock_invoke_model (counts from upstream response headers); for all
  other providers counts live in FilterContext metadata and access log.
- tests/integration/tests/suite/examples/token_counting.rs — 13 tests
  covering all five provider formats (openai, anthropic, google, bedrock,
  azure), non-streaming and SSE streaming, noisy SSE, non-JSON passthrough,
  missing usage fields, and the example-config smoke test.

Wiring:
- tests/.../examples/mod.rs: add mod token_counting
- examples/README.md: add token-counting.yaml entry

Signed-off-by: mkoushni <mkoushni@redhat.com>
@mkoushni mkoushni force-pushed the feat/220-token-counting-integration-tests branch from 6fae4bc to 46d6f18 Compare July 9, 2026 15:45
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.

6 participants