Repository navigation
Conversation
Streaming paths never called ResponseTerminator.is_terminated() and hard-coded terminated=False in every yielded response, so an agent configured with response_terminators and a streaming model backend never reported termination and skipped the "Please continue." continuation loop that non-streaming step() applies. Mirror the non-streaming behavior in _stream_response, _astream_response and their chunk processors / structured-output branches: check terminators on each completed streamed message, propagate the status to the final streamed response and agent state, and prompt the model to continue until a terminator fires or max_iteration is reached. Add regression tests covering sync/async streaming termination and continuation.
Contributor
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
5 of 7 tasks
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Related Issue
Closes #4399
Description
A
ChatAgentconfigured withresponse_terminatorsand a streaming model backend (model_config_dict={"stream": True}) never consulted its terminators:is_terminated()was never called,agent.terminatedstayedFalse, and every yielded response carriedterminated=False, so the agent never reported completion in stream mode while the identical non-streaming agent terminates on the same model output. Consumers that break their loop onterminated(e.g.camel/societies/workforce/role_playing_worker.py:154-162) can never end their chat via a terminator in this configuration.Root cause: the only terminator call sites were the non-streaming ones —
_step_impl(camel/agents/chat_agent.py:3132-3150),_astep_non_streaming_task(:3440-3458) and_step_get_info(:3959-3972). The streaming chunk processors_process_stream_chunks_with_accumulator/_aprocess_stream_chunks_with_accumulatornever readself.response_terminatorsand hard-codedterminated=Falsein the finalChatAgentResponse(parent of this branch::4868and:5998), and_stream_response/_astream_responsehad no equivalent of the "Please continue." continuation loop that_step_implruns when a terminator reports not-terminated. The constructor docstring (camel/agents/chat_agent.py:423-426) promises the agent "will keep prompting the model until a terminator signals completion" with no streaming carve-out, and the streaming code's own non-streaming fallback branch (via_convert_to_chatagent_response->_step_get_info) already terminates correctly — the gap was only in the chunk-processing paths.Changes (
camel/agents/chat_agent.pyonly):_check_response_terminators, the same terminator pass_step_get_infoperforms (callis_terminated()on the completed message list, first firing terminator wins, updateself.terminated).record_messagesites of the four streaming completion paths —_process_stream_chunks_with_accumulator,_aprocess_stream_chunks_with_accumulator, and the structured-output branches of_stream_response/_astream_response— and propagate the resulting status to the final streamed response instead of the hard-codedFalse. Partial responses keepterminated=False._stream_response/_astream_response, when a completed streamed response does not trigger a terminator, mirror_step_impl: stop with a warning atmax_iteration, otherwise add the "Please continue." user message to memory and request the model again.Out of scope: the streaming info dict keeps its existing schema (
finish_reasons), so it still carries notermination_reasonsentry when a terminator fires; that pre-existing schema difference is the secondary observation noted in the issue.Testing
Reproduction first on unpatched
master(24fde60a) with the four new regression tests added totest/agents/test_chat_agent.py(sync/async termination and sync/async continuation; fully offline viaDummyModel+ chunk stubs, no API key needed):The core assertion failure is
AssertionError: Expected 'mock' to have been called once. Called 0 times.—is_terminated()is never invoked in streaming mode. The issue's repro script also printsBUG PRESENT: terminator fired in non-streaming mode but was never consulted in streaming mode; agent never terminates.on the unpatched tree.After the fix:
and the repro script now reports for the same scripted model output
"Goodbye!":No existing test changes states:
The 4 module failures (
test_tool_calling_async,test_chat_agent_creation_methods,test_chat_agent_stream_with_structured_output,test_chat_agent_async_stream_with_structured_output) need a live OpenAI backend and fail identically on unpatchedmaster. The 3 failures in the widertest/agents/run (test_knowledge_agent.py::test_parse_graph_elements—ModuleNotFoundErrorfor an optional dep,test_role_playing.py::test_role_playing_role_sequence,test_task_agent.py::test_task_planner_agent[model0]) also fail identically on unpatchedmasterin this environment.Lint and type check, run as CI runs them (
.pre-commit-config.yaml):The mypy count is byte-identical to unpatched
masterin this environment (missing optional dependency stubs such asrequests,playwright,nebula3,flask,pptx,sklearn); neither changed file reports an error.What is the purpose of this pull request?
Checklist
pyproject.tomland runuv lock— no dependency changesAI assistance disclosure: this patch was drafted with AI assistance and reviewed by a human; the test output quoted above was produced by running the commands shown against this branch and unpatched
master.