-
-
Notifications
You must be signed in to change notification settings - Fork 12.4k
[gpt-oss][2/N] Support input_messages in responsesRequest #26962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
ec420f3
initial commit input_messages
82e94a4
function call round trip
98c41db
restructure so we use system/dev prompt from latest request
2532ed0
test harmony utils
67a5045
unit test
6995d10
clean
89061d4
remove precommit
ac078e2
charlotte comments
b1d2b02
comments
cc0be1d
move
ce12450
Merge branch 'main' into input-messages-2
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,254 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # SPDX-FileCopyrightText: Copyright contributors to the vLLM project | ||
|
|
||
| from openai_harmony import Role | ||
|
|
||
| from vllm.entrypoints.harmony_utils import parse_input_to_harmony_message | ||
|
|
||
|
|
||
| class TestParseInputToHarmonyMessage: | ||
| """Tests for parse_input_to_harmony_message function.""" | ||
|
|
||
| def test_assistant_message_with_tool_calls(self): | ||
| """Test parsing assistant message with tool calls.""" | ||
| chat_msg = { | ||
| "role": "assistant", | ||
| "tool_calls": [ | ||
| { | ||
| "function": { | ||
| "name": "get_weather", | ||
| "arguments": '{"location": "San Francisco"}', | ||
| } | ||
| }, | ||
| { | ||
| "function": { | ||
| "name": "search_web", | ||
| "arguments": '{"query": "latest news"}', | ||
| } | ||
| }, | ||
| ], | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 2 | ||
|
|
||
| # First tool call | ||
| assert messages[0].author.role == Role.ASSISTANT | ||
| assert messages[0].content[0].text == '{"location": "San Francisco"}' | ||
| assert messages[0].channel == "commentary" | ||
| assert messages[0].recipient == "functions.get_weather" | ||
| assert messages[0].content_type == "json" | ||
|
|
||
| # Second tool call | ||
| assert messages[1].author.role == Role.ASSISTANT | ||
| assert messages[1].content[0].text == '{"query": "latest news"}' | ||
| assert messages[1].channel == "commentary" | ||
| assert messages[1].recipient == "functions.search_web" | ||
| assert messages[1].content_type == "json" | ||
|
|
||
| def test_assistant_message_with_empty_tool_call_arguments(self): | ||
| """Test parsing assistant message with tool call having None arguments.""" | ||
| chat_msg = { | ||
| "role": "assistant", | ||
| "tool_calls": [ | ||
| { | ||
| "function": { | ||
| "name": "get_current_time", | ||
| "arguments": None, | ||
| } | ||
| } | ||
| ], | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].content[0].text == "" | ||
| assert messages[0].recipient == "functions.get_current_time" | ||
|
|
||
| def test_tool_message_with_string_content(self): | ||
| """Test parsing tool message with string content.""" | ||
| chat_msg = { | ||
| "role": "tool", | ||
| "name": "get_weather", | ||
| "content": "The weather in San Francisco is sunny, 72°F", | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.TOOL | ||
| assert messages[0].author.name == "functions.get_weather" | ||
| assert ( | ||
| messages[0].content[0].text == "The weather in San Francisco is sunny, 72°F" | ||
| ) | ||
| assert messages[0].channel == "commentary" | ||
|
|
||
| def test_tool_message_with_array_content(self): | ||
| """Test parsing tool message with array content.""" | ||
| chat_msg = { | ||
| "role": "tool", | ||
| "name": "search_results", | ||
| "content": [ | ||
| {"type": "text", "text": "Result 1: "}, | ||
| {"type": "text", "text": "Result 2: "}, | ||
| { | ||
| "type": "image", | ||
| "url": "http://example.com/img.png", | ||
| }, # Should be ignored | ||
| {"type": "text", "text": "Result 3"}, | ||
| ], | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.TOOL | ||
| assert messages[0].content[0].text == "Result 1: Result 2: Result 3" | ||
|
|
||
| def test_tool_message_with_empty_content(self): | ||
| """Test parsing tool message with None content.""" | ||
| chat_msg = { | ||
| "role": "tool", | ||
| "name": "empty_tool", | ||
| "content": None, | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].content[0].text == "" | ||
|
|
||
| def test_system_message(self): | ||
| """Test parsing system message.""" | ||
| chat_msg = { | ||
| "role": "system", | ||
| "content": "You are a helpful assistant", | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| # System messages are converted using Message.from_dict | ||
| # which should preserve the role | ||
| assert messages[0].author.role == Role.SYSTEM | ||
|
|
||
| def test_developer_message(self): | ||
| """Test parsing developer message.""" | ||
| chat_msg = { | ||
| "role": "developer", | ||
| "content": "Use concise language", | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.DEVELOPER | ||
|
|
||
| def test_user_message_with_string_content(self): | ||
| """Test parsing user message with string content.""" | ||
| chat_msg = { | ||
| "role": "user", | ||
| "content": "What's the weather in San Francisco?", | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.USER | ||
| assert messages[0].content[0].text == "What's the weather in San Francisco?" | ||
|
|
||
| def test_user_message_with_array_content(self): | ||
| """Test parsing user message with array content.""" | ||
| chat_msg = { | ||
| "role": "user", | ||
| "content": [ | ||
| {"text": "What's in this image? "}, | ||
| {"text": "Please describe it."}, | ||
| ], | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.USER | ||
| assert len(messages[0].content) == 2 | ||
| assert messages[0].content[0].text == "What's in this image? " | ||
| assert messages[0].content[1].text == "Please describe it." | ||
|
|
||
| def test_assistant_message_with_string_content(self): | ||
| """Test parsing assistant message with string content (no tool calls).""" | ||
| chat_msg = { | ||
| "role": "assistant", | ||
| "content": "Hello! How can I help you today?", | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.ASSISTANT | ||
| assert messages[0].content[0].text == "Hello! How can I help you today?" | ||
|
|
||
| def test_pydantic_model_input(self): | ||
| """Test parsing Pydantic model input (has model_dump method).""" | ||
|
|
||
| class MockPydanticModel: | ||
| def model_dump(self, exclude_none=True): | ||
| return { | ||
| "role": "user", | ||
| "content": "Test message", | ||
| } | ||
|
|
||
| chat_msg = MockPydanticModel() | ||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].author.role == Role.USER | ||
| assert messages[0].content[0].text == "Test message" | ||
|
|
||
| def test_message_with_empty_content(self): | ||
| """Test parsing message with empty string content.""" | ||
| chat_msg = { | ||
| "role": "user", | ||
| "content": "", | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].content[0].text == "" | ||
|
|
||
| def test_tool_call_with_missing_function_fields(self): | ||
| """Test parsing tool call with missing name or arguments.""" | ||
| chat_msg = { | ||
| "role": "assistant", | ||
| "tool_calls": [ | ||
| { | ||
| "function": {} # Missing both name and arguments | ||
| } | ||
| ], | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert messages[0].recipient == "functions." | ||
| assert messages[0].content[0].text == "" | ||
|
|
||
| def test_array_content_with_missing_text(self): | ||
| """Test parsing array content where text field is missing.""" | ||
| chat_msg = { | ||
| "role": "user", | ||
| "content": [ | ||
| {}, # Missing text field | ||
| {"text": "actual text"}, | ||
| ], | ||
| } | ||
|
|
||
| messages = parse_input_to_harmony_message(chat_msg) | ||
|
|
||
| assert len(messages) == 1 | ||
| assert len(messages[0].content) == 2 | ||
| assert messages[0].content[0].text == "" | ||
| assert messages[0].content[1].text == "actual text" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.