Skip to content

[TRTLLM-17263][refactor] Move the Anthropic serving modules into serve/api/anthropic - #21518

Draft
JunyiXu-nv wants to merge 14 commits into
NVIDIA:mainfrom
JunyiXu-nv:dev-junyix-feat-serve-anthropic-package-move
Draft

JunyiXu-nv wants to merge 14 commits into
NVIDIA:mainfrom
JunyiXu-nv:dev-junyix-feat-serve-anthropic-package-move

Conversation

@JunyiXu-nv

@JunyiXu-nv JunyiXu-nv commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #21448 ([TRTLLM-17261][refactor] Add the trtllm-serve router skeleton and move /health, /version and /v1/models into ops.system), which is itself stacked on #21406 ([TRTLLM-17261][test] Add route, middleware-order and shim-identity snapshots and a CPU test seam for trtllm-serve): the first commits below belong to those PRs and disappear from this diff when they merge; this PR's own change is the last 2 commits.

@coderabbitai summary

Description

This PR moves the three Anthropic Messages modules next to the servers, tensorrt_llm/serve/anthropic_adapter.py, anthropic_protocol.py and anthropic_batches.py, whole into the endpoint package tensorrt_llm/serve/api/anthropic/ (adapter.py, protocol.py, batches.py), deletes the old paths and rewrites every import of them in the repository. It also adds tests/unittest/serve/api/anthropic/test_messages_behavior.py, which pins what the aggregated and the disaggregated server answer on the Anthropic routes today, so that the follow-up PR that converges the two servers' Anthropic handling into one serving class can show it keeps every answer.

Part of the trtllm-serve refactor (epic TRTLLM-17056), task TRTLLM-17263 "Typed return contract and Anthropic convergence". It builds on #21448 (the tensorrt_llm/serve/api/ package) and on #21406 ([TRTLLM-17261][test] Add route, middleware-order and shim-identity snapshots and a CPU test seam for trtllm-serve), whose server factory and fake generators the new tests use.

Behavior

No behavior change. The three modules move byte-identical apart from their import lines (the pure-move check below compares every definition), and the new test_messages_behavior.py pins both servers' Anthropic answers with the served model (server-model) and the requested model (client-model) named differently, including a stream without chunks, the one case where the two servers report different model names today (the aggregated server its served name, the disaggregated one the client's). The follow-up PR must keep that file unchanged and green.

Moves

Pure-move check
## Move spec

```yaml
file_moves:
- from: tensorrt_llm/serve/anthropic_adapter.py
  to: tensorrt_llm/serve/api/anthropic/adapter.py
  group: A
  shim: false
- from: tensorrt_llm/serve/anthropic_protocol.py
  to: tensorrt_llm/serve/api/anthropic/protocol.py
  group: A
  shim: false
- from: tensorrt_llm/serve/anthropic_batches.py
  to: tensorrt_llm/serve/api/anthropic/batches.py
  group: A
  shim: false
rewrite_internal_imports: true

Pure-move check: base d3aacdd, head 147c114, tools 517fc468330a

Symbol From To Result
AnthropicRequestError tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
AnthropicResponseError tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
AnthropicStreamReframer tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
STOP_REASON_MAP tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
STREAM_PING_INTERVAL_S tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_ANTHROPIC_BILLING_SYSTEM_BLOCK tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_KEEP_ALL_THINKING_KWARGS tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_OUTPUT_FORMAT_SCHEMA_NAME tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_ToolCallStream tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_convert_messages tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_convert_tool_choice tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_convert_tools tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_image_part tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_is_anthropic_billing_system_block tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_iter_openai_sse_lines tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_map_stop_result tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_system_text_parts tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_thinking_retention_kwargs tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_tool_result_text tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
_with_ticks tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
anthropic_error_response tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
convert_anthropic_count_tokens_request tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
convert_anthropic_request tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
convert_chat_response tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
convert_usage tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
map_stop_reason tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
reframe_openai_stream tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
thinking_signature tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/api/anthropic/adapter.py verbatim
AnthropicBatchStore tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
BATCH_CONCURRENCY_ENV tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
BATCH_TTL tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
BatchItemOutcome tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
BatchItemRunner tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
BatchStoreFullError tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
DEFAULT_BATCH_CONCURRENCY tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
DEFAULT_MAX_RETAINED_BATCHES tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
MAX_RETAINED_BATCHES_ENV tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
_BatchRecord tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
_ItemResult tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
_int_env tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
_now tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
_rfc3339 tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
results_to_jsonl tensorrt_llm/serve/anthropic_batches.py tensorrt_llm/serve/api/anthropic/batches.py verbatim
ANTHROPIC_BATCH_MAX_REQUESTS tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBaseModel tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBatchDeleteResponse tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBatchList tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBatchProcessingStatus tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBatchRequestCounts tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBatchRequestItem tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicBatchResultType tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicContentBlockDeltaEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicContentBlockStartEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicContentBlockStopEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicContentBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicContentDelta tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicCountTokensRequest tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicCountTokensResponse tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicCreateBatchRequest tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicErrorEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicErrorResponse tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicErrorType tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicError tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicImageBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicImageSource tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicInputJsonDelta tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessageBatch tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessageDeltaEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessageDelta tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessageStartEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessageStopEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessage tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessagesRequest tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicMessagesResponse tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicPingEvent tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicRedactedThinkingBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicSignatureDelta tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicStopReason tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicTextBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicTextDelta tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingAdaptive tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingConfig tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingDelta tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingDisabled tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingDisplay tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicThinkingEnabled tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicToolChoice tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicToolResultBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicToolUseBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicTool tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicUnknownBlock tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
AnthropicUsage tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
SCHEMA_CLIENT_TOOL_TYPE_PREFIXES tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
SERVER_TOOL_TYPE_PREFIXES tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
_CONTENT_BLOCK_MODELS tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
_CUSTOM_ID_PATTERN tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
_KNOWN_CONTENT_BLOCK_TYPES tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
_content_block_tag tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
anthropic_sse tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim
current_timestamp tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/api/anthropic/protocol.py verbatim

101 definitions moved verbatim; 0 differences; 3 files moved; shim exports 0 names


</details>

Old import paths: the three modules are deleted with no compatibility shim. The decision behind it: a shim is kept only where code outside this repository is known to import the old path, and none imports these three (see Coordination below). Every importer in the repository now imports the new path (the test that imports the private `_CONTENT_BLOCK_MODELS` and the two function-level imports in `tests/unittest/llmapi/apps/test_kimi_serve_extensions.py` included). For the release notes, "old path → new path":

- `tensorrt_llm.serve.anthropic_adapter` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_protocol` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_batches` → `tensorrt_llm.serve.api.anthropic.batches`

and the 77 public names they hold:

- `tensorrt_llm.serve.anthropic_adapter.STOP_REASON_MAP` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.AnthropicRequestError` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.AnthropicResponseError` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.anthropic_error_response` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.convert_anthropic_request` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.convert_anthropic_count_tokens_request` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.map_stop_reason` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.convert_usage` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.thinking_signature` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.convert_chat_response` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.AnthropicStreamReframer` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.STREAM_PING_INTERVAL_S` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_adapter.reframe_openai_stream` → `tensorrt_llm.serve.api.anthropic.adapter`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBaseModel` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicTextBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicImageSource` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicImageBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicToolUseBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicToolResultBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicRedactedThinkingBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicUnknownBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicContentBlock` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessage` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.SERVER_TOOL_TYPE_PREFIXES` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.SCHEMA_CLIENT_TOOL_TYPE_PREFIXES` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicTool` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicToolChoice` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingDisplay` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingEnabled` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingAdaptive` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingDisabled` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingConfig` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessagesRequest` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicCountTokensRequest` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicStopReason` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicUsage` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessagesResponse` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicCountTokensResponse` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBatchProcessingStatus` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBatchResultType` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.ANTHROPIC_BATCH_MAX_REQUESTS` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBatchRequestCounts` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBatchRequestItem` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicCreateBatchRequest` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessageBatch` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBatchList` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicBatchDeleteResponse` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicErrorType` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicError` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicErrorResponse` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessageStartEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicContentBlockStartEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicTextDelta` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicInputJsonDelta` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicThinkingDelta` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicSignatureDelta` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicContentDelta` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicContentBlockDeltaEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicContentBlockStopEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessageDelta` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessageDeltaEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicMessageStopEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicPingEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.AnthropicErrorEvent` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.anthropic_sse` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_protocol.current_timestamp` → `tensorrt_llm.serve.api.anthropic.protocol`
- `tensorrt_llm.serve.anthropic_batches.BATCH_CONCURRENCY_ENV` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.DEFAULT_BATCH_CONCURRENCY` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.BATCH_TTL` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.MAX_RETAINED_BATCHES_ENV` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.DEFAULT_MAX_RETAINED_BATCHES` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.BatchItemOutcome` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.BatchItemRunner` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.BatchStoreFullError` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.AnthropicBatchStore` → `tensorrt_llm.serve.api.anthropic.batches`
- `tensorrt_llm.serve.anthropic_batches.results_to_jsonl` → `tensorrt_llm.serve.api.anthropic.batches`

History: `git log --follow tensorrt_llm/serve/api/anthropic/adapter.py` (and `protocol.py`, `batches.py`) follows each file back to #18289, and `git blame -C -C <new path>` attributes every line to its original commit.

Commit structure of this PR's own change: the first commit is the generated move (the three files copied, the old paths deleted, every import rewritten; the formatters then re-sorted the rewritten import lines), the second commit holds the hand edits (`tensorrt_llm/serve/api/anthropic/__init__.py`, the module import alias `import tensorrt_llm.serve.api.anthropic.adapter as adapter` in `test_anthropic_adapter.py`, the new test package and `test_messages_behavior.py`). Review the move on the first commit; `main` squash-merges, so the split is for review only. The move is regenerated on the latest `main` right before merge.

Coordination (every open PR re-checked on 2026-11-03: 1 183 open PRs, the file lists of the 25 PRs the API caps at 100 files paged separately). PRs that edit the three moved modules and re-apply on the new paths after this merges: #19605, #20936, #21049, #21059, #21062, #21107, #21449. PRs that add an import of an old path and would break on merge, since no shim is kept: #20739, #21195, #21388 - whichever of them and this PR lands second retargets to `tensorrt_llm.serve.api.anthropic.<module>`. PRs that edit only the five test files whose imports change here (at most a conflict in an import block): #20865, #21155, #21392, #21445, #21479, #21498, #21515 (the fifth file, `tests/unittest/llmapi/apps/test_kimi_serve_extensions.py`, was checked against all 1 204 open PRs on 2026-11-04: #21498 is the only other PR that edits it). The diffs of #17056, #21012, #21262, #21039, #21038 and #17541 cannot be fetched through the API and were not checked. Outside the repository, a GitHub code search for `tensorrt_llm.serve.anthropic_adapter`, `.anthropic_protocol` and `.anthropic_batches` finds only this repository and one fork that carries copies of these files, so no compatibility shim is kept. The move is regenerated on the latest `main` right before it merges.

### CI bookkeeping

- Multi-GPU table: none (the three moved modules are not in it; the servers whose import lines change already are)
- CODEOWNERS: none (no forwarding line: the old paths are deleted, not shimmed; `/tensorrt_llm/serve` keeps owning the new package)
- legacy-files.txt: none (the moved modules were ruff-formatted before and stay so); derived configs unchanged; `ruff-legacy-baseline.json`: none (no entry for the moved modules)
- Test lists: none new. `tests/unittest/serve/api/anthropic/test_messages_behavior.py` carries `pytest.mark.cpu_only` and is collected by the existing `unittest/serve` entry of `tests/integration/test_lists/test-db/l0_cpu.yml` (stages CPU-Generic-x86-1/-2, CPU-Generic-arm-2); the five edited test files are already registered
- mypy: none (the package marker holds no code; moved code joins type checking when its package graduates)

Follow-up: "One Anthropic Messages serving class for the aggregated and disaggregated servers" (number once open) adds the serving classes and the router to this package, moves the eight Anthropic routes off `OpenAIServer` and keeps `test_messages_behavior.py` unchanged.

## Test Coverage

Run from the worktree against this branch (CPU only, no GPU on the host):

- `pytest -m cpu_only tests/unittest/serve/api/anthropic/test_messages_behavior.py -q`: 18 passed, 0 skipped (the count the follow-up PR must reproduce). The same 18 tests pass on the base commit (#21448's head), with the production code before the move: the move changed no answer.
- `pytest -m cpu_only tests/unittest/llmapi/apps/test_anthropic_routes.py tests/unittest/llmapi/apps/test_anthropic_adapter.py tests/unittest/llmapi/apps/test_anthropic_batches.py tests/unittest/llmapi/apps/test_chat_template_kwargs_guard.py -q`: 251 passed (only their imports changed)
- `tests/unittest/llmapi/apps/test_kimi_serve_extensions.py` (`cpu_only`; its two function-level imports of the moved modules are rewritten): passes, run with `LLM_MODELS_ROOT` set together with the four files above
- `pytest -m cpu_only tests/unittest/serve tests/unittest/llmapi/apps/test_render_callers.py tests/unittest/llmapi/apps/test_context_length_error.py tests/unittest/disaggregated -q`: 1587 passed, 1 skipped, 2 xfailed, 144 deselected; one failure, `tests/unittest/disaggregated/test_disagg_cluster_manager_worker.py::test_cluster_worker_heartbeat[etcd]`, is pytest-timeout's 20 s limit firing while the host ran at load 23 (32 cores shared with other test runs); the same file passed in both runs of the `unittest/disaggregated` entry below and touches nothing this PR changes. Re-run in isolation afterwards, the file passes. The OpenEngine lifecycle file named in the next item also passes 14/14 on this branch when re-run alone, while on the base commit's tree, run right before it under the same load, two of its variants hit the same 90 s budgets: the timeouts are the host's, not this change's
- `LLM_MODELS_ROOT=... PYTHONPATH=tests python3 -m test_common.serve.cpu_tests` (every serve CPU test, one pytest process per test-db entry): all 66 entries green except `unittest/grpc/openengine/test_frontend_lifecycle.py`, where one of the fourteen `test_frontend_group_cleanup` variants (a different one on each of two runs) hit its 90 s readiness timeout under host load 20-30; the OpenEngine process tree imports only `serve/_frontend_processes.py` and `serve/_perf_metrics_config.py` from `tensorrt_llm/serve`, never the moved modules. The `unittest/serve` entry, which collects the new test file, passed with 130 tests; the route snapshot, the middleware-order snapshot and the shim identity table are unchanged (this PR adds no row)
- `pytest tests/unittest/api_stability -q`: 98 passed (`test_serve_api.py` and `test_serve_cli.py` included, which the CPU stage does not run)
- `LLM_MODELS_ROOT=... pytest -rs tests/unittest/llmapi/apps/test_harmony_parsing.py tests/unittest/llmapi/apps/test_harmony_channel_validation.py`: 79 passed, 0 skipped, no test skipped as "not importable" (`openai_server.py`'s imports changed)
- Pure-move check on the head commit: `101 definitions moved verbatim; 0 differences; 3 files moved; shim exports 0 names` (output above)
- `pre-commit run --files <every changed file>` twice: no hook modifies a file on either run; `python scripts/legacy_utils.py lint-precommit tensorrt_llm/serve/openai_server.py tensorrt_llm/serve/openai_disagg_server.py` passes
- `git ls-files tensorrt_llm/serve/anthropic_adapter.py tensorrt_llm/serve/anthropic_protocol.py tensorrt_llm/serve/anthropic_batches.py` prints nothing; `git grep -n -E "serve[./]anthropic_(adapter|protocol|batches)" -- tensorrt_llm/ tests/ examples/ scripts/ docs/ triton_backend/` prints nothing (no import, module import or string reference to an old path remains)
- No test patches a name of the three modules through an old module path; the two `monkeypatch.setattr(adapter, "STREAM_PING_INTERVAL_S", ...)` sites of `test_anthropic_adapter.py` go through the retargeted module alias and still intercept (their ping-interval tests pass)
- Left to CI (GPU): `test_e2e.py::test_anthropic_messages` (`l0_h100.yml`) and the single-GPU disaggregated block of `l0_a10.yml`, whose servers import the moved modules

## PR Checklist

Please review the following before submitting your PR:
- PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
- PR Follows [TRT-LLM CODING GUIDELINES](https://github.com/NVIDIA/TensorRT-LLM/blob/main/CODING_GUIDELINES.md) to the best of your knowledge.
- Test cases are provided for new code paths (see [test instructions](https://github.com/NVIDIA/TensorRT-LLM/tree/main/tests#1-how-does-the-ci-work))
- If PR introduces API changes, an appropriate PR label is added - either `api-compatible` or `api-breaking`. For `api-breaking`, include `BREAKING` in the PR title.
- Any new dependencies have been scanned for license and vulnerabilities
- [CODEOWNERS](https://github.com/NVIDIA/TensorRT-LLM/blob/main/.github/CODEOWNERS) updated if ownership changes
- Documentation updated as needed
- Update [tava architecture diagram](https://github.com/NVIDIA/TensorRT-LLM/blob/main/.github/tava_architecture_diagram.md) if there is a significant design change in PR.
- The reviewers assigned automatically/manually are appropriate for the PR.


- [x] Please check this after reviewing the above items as appropriate for this PR.

## GitHub Bot Help

To see a list of available CI bot commands, please comment `/bot help`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

…apshots and a CPU test seam for trtllm-serve

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
… baselines at the merge base

The route reference is generated from the live apps; the object.__new__
baseline and the gRPC import allowance record what exists on main today
and only shrink.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…n the snapshot matrix

An attached frontend of a multi-frontend server registers ten launcher
forwarding routes before the local table; seven share a method and path
with local handlers and three use a path parameter that matches every
batch id, so registration order decides which handler serves them. The
new configuration records all of it, a live invariant pins the
forwarding-before-local order independently of the reference, and the
route-class failure message now says why the msgpack route class matters.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
- AGENTS.md: the CPU test command sets LLM_MODELS_ROOT, which the runner
  requires, and the stage-mapping note says the mapper matches list-entry
  text, so a file listed through its directory maps by the directory.
- check_contracts matches each from-import as <module>.<name>, so
  'from pkg import sub' and 'from .. import sub' count as imports of the
  submodule; new test for both forms and for the allowance entry.
- The VisualGen /v1/models test asserts the 200 status.
- The AGENTS.md command check also recognizes commands that start with
  LLM_MODELS_ROOT=.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…on the current main

The disaggregated frontend now registers its routes with KvHintsRoute
(NVIDIA#20269), which strips kv_hints from request bodies unless the server
trusts its ingress. Regenerate the route reference: the six
disaggregated configurations record KvHintsRoute where they recorded
APIRoute; their route sets and order are unchanged.

The route-class invariant, which a regenerated reference cannot hide,
now requires KvHintsRoute on every API route of the disaggregated
frontend and APIRoute on the coordinator app. Dropping the KV-hint
policy from the frontend fails it even after a regeneration, and both
apps still reject the aggregated server's msgpack route class.

The object.__new__ baseline records the sites on main at the merge base:
test_kv_hints.py builds one server that way (NVIDIA#20269), and
test_harmony_parsing.py no longer builds any (NVIDIA#21176).

The harmony parsing tests are now registered as a whole file (NVIDIA#21411),
so the node-id entry that the CPU-selection test used as its example is
gone. The node-id check now runs select_entries on a one-entry list of
its own, so it no longer depends on which node-id entries l0_cpu.yml
holds.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…ail on silent regressions

The route snapshot now requires every configuration other than the three
invalid ones to build, so a configuration that starts failing at construction
cannot pass through a regenerated reference. The object.__new__ ratchet
resolves 'from ... import <server class> as <name>' aliases and records each
baseline site as its enclosing function or class plus the server class, so
swapping one site for another in the same file no longer passes. The baseline
keeps the same 52 sites in the same 26 files.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…lm/serve/_base/msgspec_route.py

Generated move: _msgpack_decoder, _MsgspecRequest and _MsgspecRoute leave
tensorrt_llm/serve/openai_server.py byte for byte; the module imports
_MsgspecRoute back for its app router and keeps no re-export (the three
names are private). The two disaggregated test importers now import the
new module. OpenAIServer.health, .version and .get_model are removed
here and replaced by the system router added in the following commits.

tensorrt_llm/serve/_base/msgspec_route.py joins legacy-files.txt (its
code comes from a legacy-formatted file), and the generated lint configs
are regenerated with scripts/legacy_utils.py gen-configs.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…ve the system endpoints through it

New structure: tensorrt_llm/serve/_base/ (shared serving infrastructure)
and tensorrt_llm/serve/api/ (endpoint packages, one router plus one
serving class each; the package __init__ imports nothing so routers load
lazily, by role). serve/_base/routing.py provides make_router(), which
always uses the msgpack-decoding route class, and attach_routers(),
which imports and attaches only the routers whose RouterSpec matches the
server role.

The first endpoint package, serve/api/ops/system/, serves /health,
/version and /v1/models for every role. OpenAIServer builds a
SystemServing with the injected _health_probe (today's probe body,
SIGINT side effect included) and attaches the routers before the role
dispatch; the 12 add_api_route lines for the three paths leave the four
role tables. Same routes, methods, route classes, bodies and
conflict-relevant order: the recorded route reference is unchanged.

The layering tests gain the new packages' contracts, the route-snapshot
failure message points new endpoints at the router pattern, and the
serve agent docs describe where a new endpoint goes.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…w serve packages

tensorrt_llm/serve/_base/ and tensorrt_llm/serve/api/ops/ join the
multi-GPU trigger list: the msgpack route class decodes the
disaggregated frontend's worker requests, and /health is the
disaggregated readiness probe, so changes under these directories keep
running the multi-GPU stages that exercise that path.

The three new modules join the strict mypy file set, and the type-check
pre-commit hook now also triggers on changes under tensorrt_llm/serve/
and tensorrt_llm/commands/serve_cli/, so edits to typed serving modules
get local type checking; the hook still checks only the declared file
set.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
… tests that build routes by hand

Two multi-frontend tests build an OpenAIServer without its constructor
and call register_routes() themselves. Since /health, /version and
/v1/models are attached through the system router by the constructor,
those tests no longer saw the three routes: one asserted that /version
stays local on an attached frontend (404), the other reported the three
per-frontend-safe entries as removed. Both helpers now set the serving
object and attach the routers before the hand registration, in the
constructor's order, and the route enumeration walks included routers,
which FastAPI 0.139 keeps as objects without a path in app.routes.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…n the OpenEngine metrics test

The HTTP-enablement case builds a real OpenAIServer through its
constructor and looked for /prometheus/metrics by reading .path off
every entry of app.routes. Since the constructor attaches the system
router, FastAPI 0.139 keeps an included-router object there that has no
.path, and the child process failed with AttributeError. The test now
matches a GET /prometheus/metrics request against the routes with the
public route-matching API, which works on both ends of the pinned
FastAPI range.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…d name

The check that endpoint packages under tensorrt_llm/serve/api do not
import each other read the package off the from-module alone, so
`from tensorrt_llm.serve import api` inside an endpoint package passed
and `from tensorrt_llm.serve.api.ops import system` inside ops/system
failed. It now reads the package off <module>.<name> per imported name,
as the layering contracts do, and a synthetic-edge test pins both forms.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
…ve/api/anthropic

Move tensorrt_llm/serve/anthropic_adapter.py, anthropic_protocol.py and
anthropic_batches.py whole into tensorrt_llm/serve/api/anthropic/ as
adapter.py, protocol.py and batches.py, and rewrite every import of them
in the repository. The old paths are deleted without a compatibility
shim: no code outside the repository imports them.

Generated change: the three files are copied byte for byte apart from
their import lines; the importers change only in their import lines.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>
… mark the new package

Add tensorrt_llm/serve/api/anthropic/__init__.py, retarget the two module
imports of the adapter in test_anthropic_adapter.py to the new path, and add
tests/unittest/serve/api/anthropic/test_messages_behavior.py: characterization
tests of what the aggregated and the disaggregated server answer on the
Anthropic routes today (success, streaming, a stream without chunks, rejected
requests, context length, upstream errors, unexpected errors, engine failures,
an unconvertible chat response, and the aggregated Message Batches), with the
served model and the requested model named differently so that each server's
own answer is pinned. The follow-up PR that gives both servers one Anthropic
Messages serving class must keep this file unchanged and green.

Signed-off-by: JunyiXu-nv <219237550+JunyiXu-nv@users.noreply.github.com>

This branch has not been deployed

No deployments
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