Source code for pipecat_flows.adapters
#
# Copyright (c) 2024-2026, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
"""LLM adapter for normalizing function and message formats.
This module provides the LLMAdapter class that normalizes interactions between
the flow manager and Pipecat's universal LLMContext. It handles:
- Function name extraction from FlowsFunctionSchema
- Function formatting into ToolsSchema for LLMSetToolsFrame
- Summary message formatting
- Summary generation via out-of-band LLM inference
"""
from typing import Any
from loguru import logger
from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.adapters.schemas.tools_schema import ToolsSchema
from pipecat.processors.aggregators.llm_context import (
NOT_GIVEN,
LLMContext,
LLMContextMessage,
NotGiven,
)
from pipecat_flows.types import FlowsFunctionSchema
[docs]
class LLMAdapter:
"""Adapter for normalizing function and message formats.
Normalizes interactions between the flow manager and Pipecat's universal
LLMContext. Functions must be provided as FlowsFunctionSchema or
FunctionSchema objects.
"""
[docs]
def format_functions(
self,
functions: list[FunctionSchema | FlowsFunctionSchema],
) -> ToolsSchema | NotGiven:
"""Format functions into a ToolsSchema for use in LLMSetToolsFrame.
Args:
functions: List of function definitions (schema objects).
Returns:
ToolsSchema containing the functions, or NOT_GIVEN if no functions.
"""
if not functions:
return NOT_GIVEN
# Convert to standard FunctionSchema objects for the ToolsSchema
standard_functions = []
for func in functions:
if isinstance(func, FlowsFunctionSchema):
# Extract just the FunctionSchema part for the LLM
standard_functions.append(
FunctionSchema(
name=func.name,
description=func.description,
properties=func.properties,
required=func.required,
)
)
elif isinstance(func, FunctionSchema):
# Already a standard FunctionSchema
standard_functions.append(func)
if not standard_functions:
return NOT_GIVEN
return ToolsSchema(standard_tools=standard_functions)
[docs]
def format_summary_message(self, summary: str) -> dict:
"""Format a summary as a developer message.
Summary messages use the LLMContextMessage format (OpenAI-style),
as summarization triggers an LLMMessagesUpdateFrame.
Args:
summary: The generated summary text.
Returns:
A developer message containing the summary.
"""
return {"role": "developer", "content": f"Here's a summary of the conversation:\n{summary}"}
[docs]
async def generate_summary(
self, llm: Any, summary_prompt: str, context: LLMContext
) -> str | None:
"""Generate a summary by running a direct one-shot, out-of-band inference with the LLM.
Args:
llm: LLM service instance containing client/credentials.
summary_prompt: Prompt text to guide summary generation.
context: Context object containing conversation history for the summary.
Returns:
Generated summary text, or None if generation fails.
"""
try:
messages = context.get_messages()
prompt_messages: list[LLMContextMessage] = [
{
"role": "developer",
"content": f"Conversation history: {messages}",
},
]
summary_context = LLMContext(messages=prompt_messages)
return await llm.run_inference(summary_context, system_instruction=summary_prompt)
except Exception as e:
logger.error(f"Summary generation failed: {e}", exc_info=True)
return None