Merge pull request #1451 from pipecat-ai/set-tool-choice-from-context-aggregator

Set tool choice from context aggregator
This commit is contained in:
Filipi da Silva Fuchter
2025-03-26 09:12:26 -03:00
committed by GitHub
3 changed files with 24 additions and 1 deletions

View File

@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added a new frame, `LLMSetToolChoiceFrame`, which provides a mechanism
for modifying the `tool_choice` in the context.
- Added support in `DailyTransport` for updating remote participants' - Added support in `DailyTransport` for updating remote participants'
`canReceive` permission via the `update_remote_participants()` method, by `canReceive` permission via the `update_remote_participants()` method, by
bumping the daily-python dependency to >= 0.16.0. bumping the daily-python dependency to >= 0.16.0.

View File

@@ -363,6 +363,13 @@ class LLMSetToolsFrame(DataFrame):
tools: List[dict] tools: List[dict]
@dataclass
class LLMSetToolChoiceFrame(DataFrame):
"""A frame containing a tool choice for an LLM to use for function calling."""
tool_choice: Literal["none", "auto", "required"] | dict
@dataclass @dataclass
class LLMEnablePromptCachingFrame(DataFrame): class LLMEnablePromptCachingFrame(DataFrame):
"""A frame to enable/disable prompt caching in certain LLMs.""" """A frame to enable/disable prompt caching in certain LLMs."""

View File

@@ -6,7 +6,7 @@
import asyncio import asyncio
from abc import abstractmethod from abc import abstractmethod
from typing import Dict, List, Set from typing import Dict, List, Literal, Set
from loguru import logger from loguru import logger
@@ -26,6 +26,7 @@ from pipecat.frames.frames import (
LLMMessagesAppendFrame, LLMMessagesAppendFrame,
LLMMessagesFrame, LLMMessagesFrame,
LLMMessagesUpdateFrame, LLMMessagesUpdateFrame,
LLMSetToolChoiceFrame,
LLMSetToolsFrame, LLMSetToolsFrame,
LLMTextFrame, LLMTextFrame,
OpenAILLMContextAssistantTimestampFrame, OpenAILLMContextAssistantTimestampFrame,
@@ -140,6 +141,11 @@ class BaseLLMResponseAggregator(FrameProcessor):
"""Set LLM tools to be used in the current conversation.""" """Set LLM tools to be used in the current conversation."""
pass pass
@abstractmethod
def set_tool_choice(self, tool_choice):
"""Set the tool choice. This should modify the LLM context."""
pass
@abstractmethod @abstractmethod
def reset(self): def reset(self):
"""Reset the internals of this aggregator. This should not modify the """Reset the internals of this aggregator. This should not modify the
@@ -204,6 +210,9 @@ class LLMContextResponseAggregator(BaseLLMResponseAggregator):
def set_tools(self, tools: List): def set_tools(self, tools: List):
self._context.set_tools(tools) self._context.set_tools(tools)
def set_tool_choice(self, tool_choice: Literal["none", "auto", "required"] | dict):
self._context.set_tool_choice(tool_choice)
def reset(self): def reset(self):
self._aggregation = "" self._aggregation = ""
@@ -274,6 +283,8 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
self.set_messages(frame.messages) self.set_messages(frame.messages)
elif isinstance(frame, LLMSetToolsFrame): elif isinstance(frame, LLMSetToolsFrame):
self.set_tools(frame.tools) self.set_tools(frame.tools)
elif isinstance(frame, LLMSetToolChoiceFrame):
self.set_tool_choice(frame.tool_choice)
else: else:
await self.push_frame(frame, direction) await self.push_frame(frame, direction)
@@ -415,6 +426,8 @@ class LLMAssistantContextAggregator(LLMContextResponseAggregator):
self.set_messages(frame.messages) self.set_messages(frame.messages)
elif isinstance(frame, LLMSetToolsFrame): elif isinstance(frame, LLMSetToolsFrame):
self.set_tools(frame.tools) self.set_tools(frame.tools)
elif isinstance(frame, LLMSetToolChoiceFrame):
self.set_tool_choice(frame.tool_choice)
elif isinstance(frame, FunctionCallInProgressFrame): elif isinstance(frame, FunctionCallInProgressFrame):
await self._handle_function_call_in_progress(frame) await self._handle_function_call_in_progress(frame)
elif isinstance(frame, FunctionCallResultFrame): elif isinstance(frame, FunctionCallResultFrame):