Skip to content

Extend v1/messages by introducing token-in/out and returning routed experts #4597

Open
lvhan028 wants to merge 13 commits into
InternLM:mainfrom
lvhan028:worktree-feat+extend-v1-messages
Open

Extend v1/messages by introducing token-in/out and returning routed experts #4597
lvhan028 wants to merge 13 commits into
InternLM:mainfrom
lvhan028:worktree-feat+extend-v1-messages

Conversation

@lvhan028
Copy link
Copy Markdown
Collaborator

Thanks for your contribution and we appreciate it a lot. The following instructions would make your pull request more healthy and more easily receiving feedbacks. If you do not understand some items, don't worry, just make the pull request and seek help from maintainers.

Motivation

Please describe the motivation of this PR and the goal you want to achieve through this PR.

Modification

Please briefly describe what modification is made in this PR.

BC-breaking (Optional)

Does the modification introduce changes that break the backward-compatibility of the downstream repositories?
If so, please describe how it breaks the compatibility and how the downstream projects should modify their code to keep compatibility with this PR.

Use cases (Optional)

If this PR introduces a new feature, it is better to list some use cases here, and update the documentation.

Checklist

  1. Pre-commit or other linting tools are used to fix the potential lint issues.
  2. The modification is covered by complete unit tests. If not, please add more unit tests to ensure the correctness.
  3. If the modification has a dependency on downstream projects of a newer version, this PR should be tested with all supported versions of downstream projects.
  4. The documentation has been modified accordingly, like docstring or example tutorials.

lvhan028 and others added 10 commits May 18, 2026 13:08
…turn_token_ids to MessagesRequest

Add LMDeploy-specific extension fields to the Anthropic /v1/messages
request model so that /generate-style token-ID input and multimodal
image data can be passed alongside the standard Anthropic messages
format.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add validation in the /v1/messages endpoint to enforce priority rules:
- input_ids and image_data are rejected when messages is non-empty
- image_data requires input_ids when messages is empty
- input_ids must not be an empty list

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ng response

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…esponse

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Verify that the /v1/messages endpoint with input_ids and stream=True
produces valid SSE events (message_start, content_block_delta, message_stop).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 19, 2026 03:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the Anthropic-compatible /v1/messages API to accept additional /generate-style inputs and to optionally return richer generation metadata (token IDs and routed experts), with corresponding updates to streaming and tests.

Changes:

  • Extend MessagesRequest/MessagesResponse to include input_ids, image_data, return_token_ids, return_routed_experts, plus response fields output_ids and routed_experts.
  • Update /v1/messages endpoint to validate/route between messages vs input_ids(+image_data) and to populate output_ids/routed_experts in responses.
  • Update Anthropic SSE streaming to optionally emit output_ids and routed_experts; add/extend tests for the new behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/test_lmdeploy/serve/anthropic/test_endpoints.py Adds tests for new request fields and response metadata in both streaming and non-stream modes.
lmdeploy/serve/anthropic/streaming.py Adds optional emission of output_ids in content_block_delta and routed_experts in message_delta.
lmdeploy/serve/anthropic/protocol.py Extends Anthropic request/response models with new optional fields.
lmdeploy/serve/anthropic/endpoints/messages.py Adds validation and routing for input_ids/image_data, wires new flags into streaming and non-stream responses.
lmdeploy/serve/anthropic/adapter.py Passes return_routed_experts into GenerationConfig.
Comments suppressed due to low confidence (2)

lmdeploy/serve/anthropic/endpoints/messages.py:109

  • When input_ids mode is used (messages empty and resolved_input_ids set), tool-calling inputs like tools/tool_choice are silently ignored because no response_parser is built and tools=None is passed into async_engine.generate. It would be clearer to reject tool-calling parameters in input_ids mode (400) or explicitly support them.
        parser_cls = getattr(server_context, 'response_parser_cls', None)
        if request.tools and (parser_cls is None or parser_cls.tool_parser_cls is None):
            return create_error_response(
                HTTPStatus.BAD_REQUEST,
                'Please launch the api_server with --tool-call-parser if you want to use tool calling.')

tests/test_lmdeploy/serve/anthropic/test_endpoints.py:608

  • Despite the docstring, this test never sets return_routed_experts=True and never asserts on routed_experts. As written it only verifies output_ids behavior. Add a request with return_routed_experts=True and assert the response contains the expected routed_experts value (or adjust the docstring/name).
def test_messages_non_stream_with_output_ids_and_routed_experts():
    """When return_token_ids is True, output_ids must be populated with the
    generated token IDs.

    When return_routed_experts is True, routed_experts must be populated from the engine result.
    """
    client = _make_client()
    # Test output_ids when return_token_ids is True
    response = client.post(
        '/v1/messages',
        headers={'anthropic-version': '2023-06-01'},
        json={
            'model': 'fake-model',
            'max_tokens': 16,
            'messages': [{'role': 'user', 'content': 'Hi'}],
            'return_token_ids': True,
        },
    )
    assert response.status_code == 200
    data = response.json()
    # output_ids should be populated from token IDs generated by the fake engine
    assert data.get('output_ids') == [101, 102]

    # Test that output_ids is None when return_token_ids is False (default)
    response2 = client.post(
        '/v1/messages',
        headers={'anthropic-version': '2023-06-01'},
        json={
            'model': 'fake-model',
            'max_tokens': 16,
            'messages': [{'role': 'user', 'content': 'Hi'}],
        },
    )
    assert response2.status_code == 200
    data2 = response2.json()
    assert data2.get('output_ids') is None

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +52 to +56
# Validate input_ids and image_data constraints.
# messages has higher priority. input_ids and image_data are only used when
# messages is empty. image_data requires input_ids.
messages_empty = (request.messages is None
or (isinstance(request.messages, list) and len(request.messages) == 0))
Comment on lines +225 to +227
if return_routed_experts and final_res is not None and hasattr(final_res, 'routed_experts'):
message_delta_data['routed_experts'] = final_res.routed_experts
yield _format_sse('message_delta', message_delta_data)
Comment on lines +536 to +551
def test_messages_non_stream_includes_output_ids_when_return_token_ids():
"""The response should include output_ids in the response-level field."""
client = _make_client()
response = client.post(
'/v1/messages',
headers={'anthropic-version': '2023-06-01'},
json={
'model': 'fake-model',
'max_tokens': 16,
'messages': [{'role': 'user', 'content': 'Hi'}],
},
)
assert response.status_code == 200
data = response.json()
# output_ids is a new optional field; it should be present (possibly None)
assert 'output_ids' in data
Comment on lines +495 to +533
def test_messages_accepts_input_ids_and_image_data():
"""Extended fields input_ids, image_data, return_routed_experts, and
return_token_ids must be accepted by the protocol model."""
from lmdeploy.serve.anthropic.protocol import MessagesRequest

req = MessagesRequest(
model='fake-model',
messages=[],
max_tokens=16,
input_ids=[1, 2, 3],
image_data='https://example.com/img.png',
return_routed_experts=True,
return_token_ids=True,
)
assert req.input_ids == [1, 2, 3]
assert req.image_data == 'https://example.com/img.png'
assert req.return_routed_experts is True
assert req.return_token_ids is True

# Defaults
req2 = MessagesRequest(model='m', messages=[], max_tokens=16)
assert req2.input_ids is None
assert req2.image_data is None
assert req2.return_routed_experts is False
assert req2.return_token_ids is False

# Also verify the endpoint doesn't reject the extended fields via HTTP
client = _make_client()
response = client.post(
'/v1/messages',
headers={'anthropic-version': '2023-06-01'},
json={
'model': 'fake-model',
'max_tokens': 16,
'messages': [],
'input_ids': [1, 2, 3],
},
)
assert response.status_code != 422
@lvhan028 lvhan028 changed the title Worktree feat+extend v1 messages Extend v1/messages by introducing token-in/out and returning routed experts May 19, 2026
lvhan028 and others added 3 commits May 19, 2026 12:34
… response

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants