Add a LLMMessagesTransformFrame to facilitate programmatically editing context in a frame-based way.
The previous approach required the caller to directly grab a reference to the context object, grab a "snapshot" of its messages *at that point in time*, transform the messages, and then push an `LLMMessagesUpdateFrame` with the transformed messages. This approach can lead to problems: what if there had already been a change to the context queued in the pipeline? The transformed messages would simply overwrite it without consideration.
This commit is contained in:
@@ -22,6 +22,7 @@ from pipecat.frames.frames import (
|
||||
LLMFullResponseEndFrame,
|
||||
LLMFullResponseStartFrame,
|
||||
LLMMessagesAppendFrame,
|
||||
LLMMessagesTransformFrame,
|
||||
LLMMessagesUpdateFrame,
|
||||
LLMRunFrame,
|
||||
LLMTextFrame,
|
||||
@@ -180,6 +181,56 @@ class TestLLMUserAggregator(unittest.IsolatedAsyncioTestCase):
|
||||
assert context.messages[0]["content"] == "You are a helpful assistant."
|
||||
assert context.messages[1]["content"] == "Hello!"
|
||||
|
||||
async def test_llm_messages_transform(self):
|
||||
context = LLMContext()
|
||||
# Set up initial messages
|
||||
context.set_messages(
|
||||
[
|
||||
{"role": "user", "content": "Hello"},
|
||||
{"role": "assistant", "content": "Hi there!"},
|
||||
{"role": "user", "content": "How are you?"},
|
||||
]
|
||||
)
|
||||
|
||||
pipeline = Pipeline([LLMUserAggregator(context)])
|
||||
|
||||
# Transform that keeps only user messages
|
||||
def keep_user_messages(messages):
|
||||
return [m for m in messages if m["role"] == "user"]
|
||||
|
||||
frames_to_send = [LLMMessagesTransformFrame(transform=keep_user_messages)]
|
||||
expected_down_frames = [
|
||||
SpeechControlParamsFrame # no LLMContextFrame expected, run_llm defaults to False
|
||||
]
|
||||
await run_test(
|
||||
pipeline,
|
||||
frames_to_send=frames_to_send,
|
||||
expected_down_frames=expected_down_frames,
|
||||
)
|
||||
assert len(context.messages) == 2
|
||||
assert context.messages[0]["content"] == "Hello"
|
||||
assert context.messages[1]["content"] == "How are you?"
|
||||
|
||||
async def test_llm_messages_transform_run(self):
|
||||
context = LLMContext()
|
||||
# Set up initial messages
|
||||
context.set_messages([{"role": "user", "content": "Hello"}])
|
||||
|
||||
pipeline = Pipeline([LLMUserAggregator(context)])
|
||||
|
||||
# Transform that modifies the content
|
||||
def uppercase_content(messages):
|
||||
return [{"role": m["role"], "content": m["content"].upper()} for m in messages]
|
||||
|
||||
frames_to_send = [LLMMessagesTransformFrame(transform=uppercase_content, run_llm=True)]
|
||||
expected_down_frames = [SpeechControlParamsFrame, LLMContextFrame]
|
||||
await run_test(
|
||||
pipeline,
|
||||
frames_to_send=frames_to_send,
|
||||
expected_down_frames=expected_down_frames,
|
||||
)
|
||||
assert context.messages[0]["content"] == "HELLO"
|
||||
|
||||
async def test_default_user_turn_strategies(self):
|
||||
context = LLMContext()
|
||||
user_aggregator = LLMUserAggregator(
|
||||
|
||||
Reference in New Issue
Block a user