Files
wehub-resource-sync 7ce4c8e27e
pre-commit / pre-run-check (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:55:37 +08:00

860 lines
30 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import json
from collections.abc import Sequence
import pytest
from openai_harmony import (
Conversation,
Message,
RenderConversationConfig,
Role,
)
from transformers import AutoTokenizer
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
from vllm.entrypoints.openai.engine.protocol import FunctionCall
from vllm.entrypoints.openai.parser.harmony_utils import (
get_encoding,
)
from vllm.parser.harmony import HarmonyParser
from vllm.parser.parser_manager import ParserManager
REASONING_MODEL_NAME = "openai/gpt-oss-20b"
@pytest.fixture(scope="module")
def gpt_oss_tokenizer():
return AutoTokenizer.from_pretrained(REASONING_MODEL_NAME)
@pytest.fixture
def harmony_parser(gpt_oss_tokenizer):
parser_cls = ParserManager.get_parser(
tool_parser_name="openai",
reasoning_parser_name="openai_gptoss",
enable_auto_tools=True,
model_name=REASONING_MODEL_NAME,
is_harmony=True,
)
assert parser_cls is HarmonyParser
return parser_cls(gpt_oss_tokenizer)
@pytest.fixture
def chat_request():
return ChatCompletionRequest(
model="openai/gpt-oss-20b",
messages=[{"role": "user", "content": "Hello"}],
)
@pytest.fixture
def malformed_msgs_str() -> list[str]:
return [
"<|channel|>analysis<|message|>thinking<|end|>",
"<|start|>assistant<|channel|>commentary<|message|>thinking<|end|>",
'<|start|>assistant<|channel|>final {"answer": "hi"}<|return|>',
]
def encode_output(harmony_str: str) -> list[int]:
return get_encoding().encode(harmony_str, allowed_special="all")
def assistant(content: str, channel: str) -> Message:
return Message.from_role_and_content(Role.ASSISTANT, content).with_channel(channel)
def tool_call(
recipient: str,
content: str,
channel: str = "commentary",
content_type: str | None = "json",
) -> Message:
message = assistant(content, channel).with_recipient(recipient)
return message if content_type is None else message.with_content_type(content_type)
def get_model_output_tokens(
prompt_messages: Sequence[Message],
response_messages: Sequence[Message],
) -> list[int]:
enc = get_encoding()
# Keep analysis messages when synthesizing model-output-only token sequences
# for parser tests; the default render path drops them after a later final turn.
config = RenderConversationConfig(auto_drop_analysis=False)
prompt_ids = enc.render_conversation_for_completion(
Conversation.from_messages(list(prompt_messages)),
Role.ASSISTANT,
config=config,
)
full_ids = enc.render_conversation(
Conversation.from_messages([*prompt_messages, *response_messages]),
config=config,
)
assert full_ids[: len(prompt_ids)] == prompt_ids
return full_ids[len(prompt_ids) :]
def get_text(msg: Message) -> str:
return msg.content[0].text if msg.content else ""
def tool_call_tuples(tool_calls: list[FunctionCall] | None) -> list[tuple[str, str]]:
return [] if tool_calls is None else [(tc.name, tc.arguments) for tc in tool_calls]
def tool_call_headers(delta_message) -> list:
if delta_message is None or not delta_message.tool_calls:
return []
return [
tool_call
for tool_call in delta_message.tool_calls
if tool_call.function and tool_call.function.name
]
def tool_call_payloads(delta_message) -> list:
if delta_message is None or not delta_message.tool_calls:
return []
return [
tool_call
for tool_call in delta_message.tool_calls
if tool_call.function and tool_call.function.arguments
]
def tool_call_entries(delta_message) -> list[tuple[int, str | None, str | None]]:
if delta_message is None or not delta_message.tool_calls:
return []
return [
(
tool_call.index,
tool_call.function.name if tool_call.function else None,
tool_call.function.arguments if tool_call.function else None,
)
for tool_call in delta_message.tool_calls
]
def assert_parser_is_reset(harmony_parser: HarmonyParser):
assert harmony_parser._parser is None
assert harmony_parser._num_processed_messages == 0
assert harmony_parser._current_message_tokens == []
class TestFlush:
def test_flush(self, harmony_parser):
harmony_parser.process_chunk(
encode_output("<|channel|>analysis<|message|>Think")
)
flushed_segments = harmony_parser.flush()
assert flushed_segments is not None
assert len(flushed_segments) == 1
flushed = flushed_segments[0]
assert flushed is not None
assert flushed.channel == "analysis"
assert flushed.recipient is None
assert flushed.delta == ""
assert flushed.completed_message is not None
assert get_text(flushed.completed_message) == "Think"
assert_parser_is_reset(harmony_parser)
def test_flush_recovers_invalid_output(self, harmony_parser, malformed_msgs_str):
for msg_str in malformed_msgs_str[:-1]:
chunk = harmony_parser.process_chunk(encode_output(msg_str))
assert "".join(segment.delta for segment in chunk.segments) == "thinking"
last_msg_str = malformed_msgs_str[-1]
harmony_parser.process_chunk(encode_output(last_msg_str))
flushed_segments = harmony_parser.flush()
assert len(flushed_segments) == 2
delta_segment = flushed_segments[0]
message_segment = flushed_segments[1]
assert delta_segment.channel == "final"
assert delta_segment.recipient is None
assert delta_segment.delta == last_msg_str
assert message_segment.channel == "final"
assert message_segment.recipient is None
assert get_text(message_segment.completed_message) == last_msg_str
assert_parser_is_reset(harmony_parser)
class TestParse:
# Rendered conversation outputs.
def test_reasoning_only(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "Why?")]
response = [assistant("This is reasoning", "analysis")]
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert reasoning == "This is reasoning"
assert content is None
assert tool_calls is None
def test_content_only(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "Hello")]
response = [assistant("This is a test", "final")]
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert reasoning is None
assert content == "This is a test"
assert tool_calls is None
def test_reasoning_and_content(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "What is 2+2?")]
response = [
assistant("I should think first.", "analysis"),
assistant("The answer is 4.", "final"),
]
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert reasoning == "I should think first."
assert content == "The answer is 4."
assert tool_calls is None
@pytest.mark.parametrize(
"tool_args",
[
'{"location": "Tokyo"}',
'{\n"location": "Tokyo"\n}',
],
)
@pytest.mark.parametrize("tool_channel", ["commentary", "analysis"])
def test_single_tool_call(
self, harmony_parser, chat_request, tool_args, tool_channel
):
prompt = [
Message.from_role_and_content(Role.USER, "What is the weather in Tokyo?")
]
response = [tool_call("functions.get_current_weather", tool_args, tool_channel)]
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert reasoning is None
assert content is None
assert tool_call_tuples(tool_calls) == [
("get_current_weather", json.dumps({"location": "Tokyo"}))
]
def test_multiple_tool_calls_varied_formats(self, harmony_parser, chat_request):
prompt = [
Message.from_role_and_content(
Role.USER, "What is the weather in Tokyo based on where I'm at?"
)
]
response = [
tool_call("functions.get_current_weather", '{"location": "Tokyo"}'),
tool_call("functions.get_user_location", '{"location": "Tokyo"}'),
tool_call(
"functions.no_content_type",
'{"location": "Tokyo"}',
content_type=None,
),
tool_call("functions.not_json_no_content_type", "foo", content_type=None),
tool_call("functions.empty_args", "{}"),
tool_call("functions.no_args", ""),
]
_, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert content is None
assert tool_call_tuples(tool_calls) == [
("get_current_weather", json.dumps({"location": "Tokyo"})),
("get_user_location", json.dumps({"location": "Tokyo"})),
("no_content_type", json.dumps({"location": "Tokyo"})),
("not_json_no_content_type", "foo"),
("empty_args", json.dumps({})),
("no_args", ""),
]
def test_tool_call_bare_recipient(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "Weather?")]
response = [tool_call("get_current_weather", '{"location": "Tokyo"}')]
_, _, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert tool_call_tuples(tool_calls) == [
("get_current_weather", json.dumps({"location": "Tokyo"}))
]
def test_multiple_tool_calls_bare_recipients(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "Use both tools.")]
response = [
tool_call("get_current_weather", '{"location": "Tokyo"}'),
tool_call("get_user_location", "{}"),
]
_, _, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert tool_call_tuples(tool_calls) == [
("get_current_weather", json.dumps({"location": "Tokyo"})),
("get_user_location", json.dumps({})),
]
def test_assistant_recipient_not_tool(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "Hello")]
response = [
tool_call("assistant", "Some tool response", content_type=None),
assistant("Here is the answer", "final"),
]
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert reasoning is None
assert content == "Here is the answer"
assert tool_calls is None
def test_tool_call_dotted_name(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "Compute 2+3")]
response = [tool_call("math.sum", '{"a": 2, "b": 3}')]
_, _, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert tool_call_tuples(tool_calls) == [
("math.sum", json.dumps({"a": 2, "b": 3}))
]
def test_tool_calls_with_final_content(self, harmony_parser, chat_request):
prompt = [Message.from_role_and_content(Role.USER, "What is the weather?")]
response = [
assistant("User asked about the weather.", "analysis"),
tool_call("functions.get_current_weather", '{"location": "Tokyo"}'),
assistant("This tool call will get the weather.", "final"),
]
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=get_model_output_tokens(prompt, response),
)
assert reasoning == "User asked about the weather."
assert content == "This tool call will get the weather."
assert tool_call_tuples(tool_calls) == [
("get_current_weather", json.dumps({"location": "Tokyo"}))
]
# Raw/truncated Harmony output streams.
def test_interrupted_first_message(self, harmony_parser, chat_request):
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=encode_output(
"<|channel|>final<|message|>I'm in the middle of answering"
),
)
assert reasoning is None
assert content == "I'm in the middle of answering"
assert tool_calls is None
assert_parser_is_reset(harmony_parser)
def test_interrupted_reasoning_first_message(self, harmony_parser, chat_request):
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=encode_output(
"<|channel|>analysis<|message|>I'm in the middle of thinking"
),
)
assert reasoning == "I'm in the middle of thinking"
assert content is None
assert tool_calls is None
assert_parser_is_reset(harmony_parser)
def test_truncated_output(self, harmony_parser, chat_request):
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=encode_output(
"<|channel|>analysis<|message|>I'm thinking.<|end|>"
"<|start|>assistant<|channel|>final<|message|>"
"I'm in the middle of answering"
),
)
assert reasoning == "I'm thinking."
assert content == "I'm in the middle of answering"
assert tool_calls is None
assert_parser_is_reset(harmony_parser)
def test_malformed_msgs_recovers_raw_content(
self, harmony_parser, chat_request, malformed_msgs_str
):
combined_output = "".join(malformed_msgs_str)
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=encode_output(combined_output),
)
assert reasoning == "thinking"
assert content == "thinking\n" + malformed_msgs_str[-1]
assert tool_calls is None
assert_parser_is_reset(harmony_parser)
@pytest.mark.parametrize(
("harmony_str", "expected_content"),
[
(
"<|channel|>commentary<|message|>I'll search for that",
"I'll search for that",
),
(
"<|channel|>commentary<|message|>Let me look that up.<|end|>"
"<|start|>assistant<|channel|>final<|message|>The answer is 42.<|end|>",
"Let me look that up.\nThe answer is 42.",
),
],
)
def test_commentary_preambles(
self,
harmony_parser,
chat_request,
harmony_str,
expected_content,
):
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=encode_output(harmony_str),
)
assert reasoning is None
assert content == expected_content
assert tool_calls is None
def test_commentary_with_recipient_excluded(self, harmony_parser, chat_request):
reasoning, content, tool_calls = harmony_parser.parse(
"",
chat_request,
model_output_token_ids=encode_output(
"<|channel|>commentary"
"<|message|>Let me check the weather.<|end|>"
"<|start|>assistant to=functions.get_weather"
"<|channel|>commentary"
'<|message|>{"location": "SF"}<|end|>'
),
)
assert reasoning is None
assert content == "Let me check the weather."
assert tool_call_tuples(tool_calls) == [
("get_weather", json.dumps({"location": "SF"}))
]
class TestParseDelta:
def test_basic(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
first_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output("<|channel|>analysis<|message|>Thinking"),
request=chat_request,
finished=False,
)
second_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|end|><|start|>assistant<|channel|>final<|message|>Answer"
),
request=chat_request,
finished=True,
)
assert first_delta is not None
assert first_delta.reasoning == "Thinking"
assert first_delta.content is None
assert second_delta is not None
assert second_delta.content == "Answer"
assert second_delta.reasoning is None
assert_parser_is_reset(parser)
def test_multi_token(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output("<|channel|>final<|message|>Hello, world!"),
request=chat_request,
finished=False,
)
assert delta is not None
assert delta.content == "Hello, world!"
assert delta.reasoning is None
assert not delta.tool_calls
def test_malformed_msgs_recovers_raw_content(
self, gpt_oss_tokenizer, chat_request, malformed_msgs_str
):
parser = HarmonyParser(gpt_oss_tokenizer)
for msg_str in malformed_msgs_str[:-1]:
delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(msg_str),
request=chat_request,
finished=False,
)
assert delta.reasoning or delta.content == "thinking"
assert not delta.tool_calls
last_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(malformed_msgs_str[-1]),
request=chat_request,
finished=True,
)
assert last_delta is not None
assert last_delta.content == malformed_msgs_str[-1]
assert last_delta.reasoning is None
assert not last_delta.tool_calls
assert_parser_is_reset(parser)
@pytest.mark.parametrize("tool_channel", ["commentary", "analysis"])
def test_tool_call_split_across_deltas(
self, gpt_oss_tokenizer, chat_request, tool_channel
):
parser = HarmonyParser(gpt_oss_tokenizer)
first_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Thinking<|end|>"
f"<|start|>assistant to=functions.get_weather<|channel|>{tool_channel}"
'<|constrain|>json<|message|>{"location": '
),
request=chat_request,
finished=False,
)
second_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output('"Paris"}<|call|>'),
request=chat_request,
finished=False,
)
assert first_delta is not None
assert first_delta.reasoning == "Thinking"
assert first_delta.content is None
assert tool_call_entries(first_delta) == [
(0, "get_weather", '{"location": '),
]
assert second_delta is not None
assert second_delta.reasoning is None
assert second_delta.content is None
assert tool_call_entries(second_delta) == [(0, None, '"Paris"}')]
def test_commentary_preamble_streaming(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>commentary<|message|>I'll search for that"
),
request=chat_request,
finished=False,
)
assert delta is not None
assert delta.content == "I'll search for that"
assert delta.reasoning is None
assert not delta.tool_calls
def test_multiple_choices(self, gpt_oss_tokenizer, chat_request):
parser_a = HarmonyParser(gpt_oss_tokenizer)
parser_b = HarmonyParser(gpt_oss_tokenizer)
delta_a = parser_a.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Check weather<|end|>"
"<|start|>assistant to=functions.get_weather<|channel|>commentary"
'<|constrain|>json<|message|>{"location": "Paris"}'
),
request=chat_request,
finished=False,
)
delta_b = parser_b.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Check time<|end|>"
"<|start|>assistant to=functions.get_time<|channel|>commentary"
'<|constrain|>json<|message|>{"timezone": "UTC"}'
),
request=chat_request,
finished=False,
)
assert [tool.function.name for tool in tool_call_headers(delta_a)] == [
"get_weather"
]
assert [tool.function.name for tool in tool_call_headers(delta_b)] == [
"get_time"
]
assert {tool.index for tool in delta_a.tool_calls} == {0}
assert {tool.index for tool in delta_b.tool_calls} == {0}
def test_dotted_function_name(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Compute this<|end|>"
"<|start|>assistant to=math.sum<|channel|>commentary"
'<|constrain|>json<|message|>{"a": 2, "b": 3}'
),
request=chat_request,
finished=False,
)
assert delta is not None
assert [tool.function.name for tool in tool_call_headers(delta)] == ["math.sum"]
assert {tool.index for tool in delta.tool_calls} == {0}
@pytest.mark.parametrize("recipient", ["assistant", "browser"])
def test_builtin_recipient_skipped(
self,
gpt_oss_tokenizer,
chat_request,
recipient,
):
parser = HarmonyParser(gpt_oss_tokenizer)
prompt = [Message.from_role_and_content(Role.USER, "Hello")]
response = [tool_call(recipient, "Ignore this", content_type=None)]
delta = parser.parse_delta(
delta_text="",
delta_token_ids=get_model_output_tokens(prompt, response),
request=chat_request,
finished=False,
)
assert delta is None
def test_cross_channel_with_tool(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Reasoning about query...<|end|>"
"<|start|>assistant to=functions.search<|channel|>commentary"
'<|constrain|>json<|message|>{"query": "vllm"}<|call|>'
"<|start|>assistant<|channel|>final<|message|>Done"
),
request=chat_request,
finished=False,
)
assert delta is not None
assert delta.reasoning == "Reasoning about query..."
assert delta.content == "Done"
assert tool_call_entries(delta) == [(0, "search", '{"query": "vllm"}')]
def test_tool_index_across_calls(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
first_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Thinking<|end|>"
"<|start|>assistant to=functions.get_weather<|channel|>commentary"
'<|constrain|>json<|message|>{"location": "Paris"}<|call|>'
),
request=chat_request,
finished=False,
)
second_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|start|>assistant to=functions.get_time<|channel|>commentary"
'<|constrain|>json<|message|>{"timezone": "UTC"}<|call|>'
),
request=chat_request,
finished=False,
)
assert [tool.index for tool in tool_call_headers(first_delta)] == [0]
assert [tool.index for tool in tool_call_headers(second_delta)] == [1]
assert [tool.function.name for tool in tool_call_headers(second_delta)] == [
"get_time"
]
def test_multi_tool_interleaved(self, gpt_oss_tokenizer, chat_request):
parser = HarmonyParser(gpt_oss_tokenizer)
first_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"<|channel|>analysis<|message|>Plan<|end|>"
"<|start|>assistant to=functions.tool_a<|channel|>commentary"
'<|constrain|>json<|message|>{"a": 1}<|call|>'
"<|start|>assistant to=functions.tool_b<|channel|>commentary"
'<|constrain|>json<|message|>{"b": '
),
request=chat_request,
finished=False,
)
second_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output("2"),
request=chat_request,
finished=False,
)
third_delta = parser.parse_delta(
delta_text="",
delta_token_ids=encode_output(
"}<|call|><|start|>assistant<|channel|>final<|message|>Done<|end|>"
"<|start|>assistant to=functions.tool_c<|channel|>commentary"
'<|constrain|>json<|message|>{"c": 3}'
),
request=chat_request,
finished=False,
)
assert tool_call_entries(first_delta) == [
(0, "tool_a", '{"a": 1}'),
(1, "tool_b", '{"b": '),
]
assert [tool.index for tool in tool_call_headers(first_delta)] == [0, 1]
assert second_delta is not None
assert tool_call_entries(second_delta) == [(1, None, "2")]
assert [tool.index for tool in tool_call_payloads(second_delta)] == [1]
assert third_delta is not None
assert third_delta.content == "Done"
assert tool_call_entries(third_delta) == [
(1, None, "}"),
(2, "tool_c", '{"c": 3}'),
]
assert [tool.index for tool in tool_call_headers(third_delta)] == [2]
class TestProcessChunk:
def test_empty(self, harmony_parser):
result = harmony_parser.process_chunk([])
assert result.segments == []
assert result.reasoning_token_count == 0
def test_single_channel(self, harmony_parser):
result = harmony_parser.process_chunk(
encode_output("<|channel|>final<|message|>Hello")
)
assert [
(s.channel, s.recipient, s.delta) for s in result.segments if s.delta
] == [("final", None, "Hello")]
def test_constrained_output_segment_recipient_normalized(self, harmony_parser):
result = harmony_parser.process_chunk(
encode_output(
'<|channel|>final <|constrain|>json<|message|>{"result":true}<|end|>'
)
)
content_segments = [segment for segment in result.segments if segment.delta]
assert all(segment.channel == "final" for segment in content_segments)
assert all(segment.recipient is None for segment in content_segments)
assert (
"".join(segment.delta for segment in content_segments) == '{"result":true}'
)
completed_messages = [
segment.completed_message
for segment in result.segments
if segment.completed_message is not None
]
assert len(completed_messages) == 1
assert completed_messages[0].recipient is None
def test_cross_channel(self, harmony_parser):
result = harmony_parser.process_chunk(
encode_output(
"<|channel|>analysis<|message|>Think<|end|>"
"<|start|>assistant<|channel|>final<|message|>Answer"
)
)
assert [
(s.channel, s.recipient, s.delta) for s in result.segments if s.delta
] == [
("analysis", None, "Think"),
("final", None, "Answer"),
]
def test_multi_boundary(self, harmony_parser):
result = harmony_parser.process_chunk(
encode_output(
"<|channel|>analysis<|message|>One<|end|>"
"<|start|>assistant<|channel|>final<|message|>Two<|end|>"
)
)
boundary_segments = [
segment
for segment in result.segments
if segment.completed_message is not None
]
assert [
(segment.completed_message.channel, get_text(segment.completed_message))
for segment in boundary_segments
] == [
("analysis", "One"),
("final", "Two"),
]