Re-inject turn completion instructions after LLM context reset
When filter_incomplete_user_turns is enabled and an LLMMessagesUpdateFrame replaces the context via set_messages(), the turn completion instructions system message was lost. This caused the LLM to stop emitting turn completion markers. Re-inject the instructions after set_messages() to fix this.
This commit is contained in:
1
changelog/3888.fixed.md
Normal file
1
changelog/3888.fixed.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
- Fixed turn completion instructions being lost when `LLMMessagesUpdateFrame` replaces the LLM context. When `filter_incomplete_user_turns` is enabled, the turn completion system message is now re-injected after context replacement.
|
||||||
@@ -642,6 +642,9 @@ class LLMUserAggregator(LLMContextAggregator):
|
|||||||
|
|
||||||
async def _handle_llm_messages_update(self, frame: LLMMessagesUpdateFrame):
|
async def _handle_llm_messages_update(self, frame: LLMMessagesUpdateFrame):
|
||||||
self.set_messages(frame.messages)
|
self.set_messages(frame.messages)
|
||||||
|
if self._params.filter_incomplete_user_turns:
|
||||||
|
config = self._params.user_turn_completion_config or UserTurnCompletionConfig()
|
||||||
|
self._context.add_message({"role": "system", "content": config.completion_instructions})
|
||||||
if frame.run_llm:
|
if frame.run_llm:
|
||||||
await self.push_context_frame()
|
await self.push_context_frame()
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ from pipecat.turns.user_mute import (
|
|||||||
MuteUntilFirstBotCompleteUserMuteStrategy,
|
MuteUntilFirstBotCompleteUserMuteStrategy,
|
||||||
)
|
)
|
||||||
from pipecat.turns.user_stop import SpeechTimeoutUserTurnStopStrategy
|
from pipecat.turns.user_stop import SpeechTimeoutUserTurnStopStrategy
|
||||||
|
from pipecat.turns.user_turn_completion_mixin import UserTurnCompletionConfig
|
||||||
from pipecat.turns.user_turn_strategies import UserTurnStrategies
|
from pipecat.turns.user_turn_strategies import UserTurnStrategies
|
||||||
|
|
||||||
USER_TURN_STOP_TIMEOUT = 0.2
|
USER_TURN_STOP_TIMEOUT = 0.2
|
||||||
@@ -155,6 +156,28 @@ class TestLLMUserAggregator(unittest.IsolatedAsyncioTestCase):
|
|||||||
)
|
)
|
||||||
assert context.messages[0]["content"] == "Hi there!"
|
assert context.messages[0]["content"] == "Hi there!"
|
||||||
|
|
||||||
|
async def test_llm_messages_update_reinjects_turn_completion_instructions(self):
|
||||||
|
context = LLMContext()
|
||||||
|
params = LLMUserAggregatorParams(filter_incomplete_user_turns=True)
|
||||||
|
pipeline = Pipeline([LLMUserAggregator(context, params=params)])
|
||||||
|
|
||||||
|
new_messages = [
|
||||||
|
{"role": "system", "content": "You are a helpful assistant."},
|
||||||
|
{"role": "user", "content": "Hello!"},
|
||||||
|
]
|
||||||
|
frames_to_send = [LLMMessagesUpdateFrame(messages=new_messages)]
|
||||||
|
await run_test(
|
||||||
|
pipeline,
|
||||||
|
frames_to_send=frames_to_send,
|
||||||
|
)
|
||||||
|
config = UserTurnCompletionConfig()
|
||||||
|
# The context should contain the new messages plus the re-injected instructions
|
||||||
|
assert len(context.messages) == 3
|
||||||
|
assert context.messages[0]["content"] == "You are a helpful assistant."
|
||||||
|
assert context.messages[1]["content"] == "Hello!"
|
||||||
|
assert context.messages[2]["role"] == "system"
|
||||||
|
assert context.messages[2]["content"] == config.completion_instructions
|
||||||
|
|
||||||
async def test_default_user_turn_strategies(self):
|
async def test_default_user_turn_strategies(self):
|
||||||
context = LLMContext()
|
context = LLMContext()
|
||||||
user_aggregator = LLMUserAggregator(
|
user_aggregator = LLMUserAggregator(
|
||||||
|
|||||||
Reference in New Issue
Block a user