-
Notifications
You must be signed in to change notification settings - Fork 302
write chunks in TextParserStreamer #3025
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
base: master
Are you sure you want to change the base?
write chunks in TextParserStreamer #3025
Conversation
There was a problem hiding this 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 refactors the TextParserStreamer to return incremental delta messages in the write() callback instead of accumulated messages, while still maintaining accumulated message access via get_parsed_message(). The key changes update the reasoning parser implementation to properly handle delta messages and modify the concatenation logic in the streamer.
- Modified
TextParserStreamerto write delta messages instead of accumulated messages - Updated
ReasoningIncrementalParserto populate message fields for incremental output - Added
concatenate_json_containers()helper function for message accumulation
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tests/python_tests/test_parsers.py | Updated tests to use get_parsed_message() for assertions and removed manual message accumulation in custom streamers |
| src/cpp/src/text_streamer.cpp | Added concatenate_json_containers() function and modified write() to return delta messages while maintaining internal accumulation |
| src/cpp/src/parsers.cpp | Refactored ReasoningIncrementalParser to populate content field in delta messages and removed keep_original_content logic from helper methods |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/cpp/src/text_streamer.cpp
Outdated
| void concatenate_json_containers(JsonContainer& from, const JsonContainer& to, std::vector<std::string> keys_to_concatenate) { | ||
| for (const auto& key : keys_to_concatenate) { | ||
| if (to.contains(key) && from.contains(key)) { | ||
| // If both are strings, concatenate | ||
| if (to[key].is_string() && from[key].is_string()) { | ||
| to[key] = to[key].get_string() + from[key].get_string(); |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter order is reversed: from should be const and to should be mutable. Currently, modifications are applied to to (line 152) but the function signature suggests from is the destination. Either swap the parameter names or reverse their constness to match the intended behavior.
9b7cd5c to
a41f0d0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
tests/python_tests/test_parsers.py:1
- Assignment to
reason_strloses previously accumulated reasoning content. The variable should be appended to, not replaced, to preserve partial reasoning text from previous chunks.
# Copyright (C) 2023-2025 Intel Corporation
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # When parser is called from streamer, it is expected that content is accumulated inside streamer. | ||
| # Here we are calling parser manually therefore we need to accumulate content manually. | ||
| msg['content'] += subword | ||
| print(msg) |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statement should be removed before merging to production code.
| print(msg) |
| return write(m_pimpl->m_parsed_message); | ||
|
|
||
| // std::cout << msg["content"].get_string() << std::endl; | ||
| // std::cout << msg["reasoning_content"].get_string() << std::endl; |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out debug statements should be removed before merging.
| // std::cout << msg["reasoning_content"].get_string() << std::endl; |
| // if (!message.contains("reasoning_content")) { | ||
| message["reasoning_content"] = ""; | ||
| } | ||
| if (!message.contains("content")) { | ||
| // } | ||
| // if (!message.contains("content")) { | ||
| message["content"] = ""; | ||
| } | ||
| // } |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out conditional checks should be removed. If unconditional initialization is the intended behavior, the comments add unnecessary clutter.
|
|
||
| if (!m_keep_original_content) { | ||
| delta_text = std::string(txt_chunk.substr(close_idx + m_close_tag.size())); | ||
| // Despite the fact that we put txt_chung to delta_text it's correct. |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'txt_chung' to 'txt_chunk'.
| // Despite the fact that we put txt_chung to delta_text it's correct. | |
| // Despite the fact that we put txt_chunk to delta_text it's correct. |
| delta_text.clear(); | ||
| } |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] When think tag is not yet opened and accumulating in cache, delta_text is cleared. This means no delta content is returned to the user during this phase. Consider adding a comment explaining this behavior is intentional to avoid confusion.
| delta_text.clear(); | |
| } | |
| // Intentionally clear delta_text: no delta content is returned to the user during this phase | |
| // (we are waiting for the <think> tag to be fully detected in the cache). | |
| delta_text.clear(); |
d71fc3f to
4017fb5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Keep potential partial close tag in cache | ||
| m_text_cache = std::string(txt_chunk.substr(txt_chunk.size() - num_chars_to_keep)); | ||
| reason_str.append(txt_chunk.substr(0, txt_chunk.size() - num_chars_to_keep)); | ||
| reason_str = txt_chunk.substr(0, txt_chunk.size() - num_chars_to_keep); |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assignment instead of append changes semantics. Previously accumulated reasoning content in reason_str will be lost. This should use reason_str.append() or += to maintain accumulated content, or the accumulated content should be preserved through a different mechanism.
| } else { | ||
| // No partial close tag, accumulate all text | ||
| reason_str.append(txt_chunk); | ||
| reason_str = txt_chunk; |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assignment instead of append discards previously accumulated reasoning content. This should use reason_str.append() or += to maintain accumulated content from previous calls.
|
|
||
| }; | ||
|
|
||
| void concatenate_json_containers(const JsonContainer& from, JsonContainer& to, std::vector<std::string> keys_to_concatenate) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to have it as the json container method.
| /** | ||
| * @brief Ensure required fields exist in the message container. | ||
| */ | ||
| void ensure_message_fields(JsonContainer& message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is either not needed or has to be renamed.
| // Iterate over all parsers and apply them to the message | ||
| for (auto& parser: m_pimpl->m_parsers) { | ||
| message = parser->parse(m_pimpl->m_parsed_message, message, flushed_tokens); | ||
| message = parser->parse(msg, message, flushed_tokens); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicated names: msg and message
| reason_str = std::move(message["reasoning_content"].get_string()); | ||
| } | ||
| std::string txt_chunk = m_text_cache + delta_text; | ||
| std::string reason_str = message.contains("reasoning_content") ? std::move(message["reasoning_content"].get_string()) : ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| std::string reason_str = message.contains("reasoning_content") ? std::move(message["reasoning_content"].get_string()) : ""; |
Description
Return DeltaMessage in incremental
TextStreamerParserinstead of accumualated msg. But accumulated is still available viaget_parsed_message()CVS-CVS-176146
Fixes #(issue)
Checklist: