chore: bump pipecat version and fix tests (#263)

* chore: bump pipecat version and fix tests

* chore: add github workflow to run tests

* fix: install reqirements.dev.txt in test script

* fix: fix api-test action

* feat: add integration test

* test: add integration tests

* test: add test for function call mute strategy
This commit is contained in:
Abhishek 2026-05-04 21:35:37 +05:30 committed by GitHub
parent d256c6005c
commit 0e12c41fc7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 1776 additions and 670 deletions

View file

@ -1,9 +1,11 @@
from .base import BaseFileSystem
from .minio import MinioFileSystem
from .null import NullFileSystem
from .s3 import S3FileSystem
__all__ = [
"BaseFileSystem",
"S3FileSystem",
"MinioFileSystem",
"NullFileSystem",
]

View file

@ -0,0 +1,50 @@
from typing import Any, BinaryIO, Dict, NoReturn, Optional
from .base import BaseFileSystem
class NullFileSystem(BaseFileSystem):
"""No-op filesystem used when storage is not configured (e.g. tests).
Every operation raises so that any test that exercises storage fails
loudly instead of silently succeeding against a stub.
"""
def _fail(self, op: str) -> NoReturn:
raise RuntimeError(
f"NullFileSystem.{op} called — storage is not configured. "
"Set ENVIRONMENT to a non-test value or inject a real filesystem fixture."
)
async def acreate_file(self, file_path: str, content: BinaryIO) -> bool:
self._fail("acreate_file")
async def aupload_file(self, local_path: str, destination_path: str) -> bool:
self._fail("aupload_file")
async def aget_signed_url(
self,
file_path: str,
expiration: int = 3600,
force_inline: bool = False,
use_internal_endpoint: bool = False,
) -> Optional[str]:
self._fail("aget_signed_url")
async def aget_file_metadata(self, file_path: str) -> Optional[Dict[str, Any]]:
self._fail("aget_file_metadata")
async def aget_presigned_put_url(
self,
file_path: str,
expiration: int = 900,
content_type: str = "text/csv",
max_size: int = 10_485_760,
) -> Optional[str]:
self._fail("aget_presigned_put_url")
async def adownload_file(self, source_path: str, local_path: str) -> bool:
self._fail("adownload_file")
async def acopy_file(self, source_path: str, destination_path: str) -> bool:
self._fail("acopy_file")

View file

@ -9,7 +9,6 @@ import asyncio
from typing import Dict, Set
from loguru import logger
from pipecat.audio.utils import mix_audio
from pipecat.frames.frames import (
Frame,

View file

@ -3,6 +3,10 @@
from typing import Any, Dict
from loguru import logger
from pipecat.pipeline.pipeline import Pipeline
from pipecat.processors.aggregators.llm_response_universal import (
LLMContextAggregatorPair,
)
from api.db.db_client import DBClient
from api.services.looptalk.audio_streamer import get_or_create_audio_streamer
@ -23,10 +27,6 @@ from api.services.pipecat.service_factory import (
from api.services.workflow.dto import ReactFlowDTO
from api.services.workflow.pipecat_engine import PipecatEngine
from api.services.workflow.workflow import WorkflowGraph
from pipecat.pipeline.pipeline import Pipeline
from pipecat.processors.aggregators.llm_response_universal import (
LLMContextAggregatorPair,
)
class LoopTalkPipelineBuilder:

View file

@ -7,7 +7,6 @@
"""Internal frame serializer for agent-to-agent communication."""
from loguru import logger
from pipecat.frames.frames import (
Frame,
InputAudioRawFrame,

View file

@ -11,8 +11,6 @@ import time
from typing import Dict, Optional, Tuple
from loguru import logger
from api.services.looptalk.internal_serializer import InternalFrameSerializer
from pipecat.frames.frames import (
CancelFrame,
EndFrame,
@ -29,6 +27,8 @@ from pipecat.transports.base_input import BaseInputTransport
from pipecat.transports.base_output import BaseOutputTransport
from pipecat.transports.base_transport import BaseTransport, TransportParams
from api.services.looptalk.internal_serializer import InternalFrameSerializer
class InternalInputTransport(BaseInputTransport):
"""Input side of internal transport for agent-to-agent communication."""

View file

@ -6,6 +6,8 @@ from pathlib import Path
from typing import Any, Dict, Optional
from loguru import logger
from pipecat.pipeline.task import PipelineTask
from pipecat.utils.run_context import set_current_run_id
from api.db.db_client import DBClient
from api.services.looptalk.internal_transport import (
@ -13,8 +15,6 @@ from api.services.looptalk.internal_transport import (
InternalTransportManager,
)
from api.services.pipecat.transport_setup import create_internal_transport
from pipecat.pipeline.task import PipelineTask
from pipecat.utils.run_context import set_current_run_id
from .core.pipeline_builder import LoopTalkPipelineBuilder
from .core.recording_manager import RecordingManager

View file

@ -188,7 +188,12 @@ def register_event_handlers(
await engine.llm.queue_frame(LLMContextFrame(engine.context))
else:
logger.debug("Playing text greeting via TTS")
await task.queue_frame(TTSSpeakFrame(greeting_value))
# append_to_context=True so the assistant aggregator commits
# the greeting to the LLM context once TTS finishes; without
# it the LLM would re-greet on its first generation.
await task.queue_frame(
TTSSpeakFrame(greeting_value, append_to_context=True)
)
else:
logger.debug(
"Both pipeline_started and client_connected received - triggering initial LLM generation"

View file

@ -429,7 +429,6 @@ async def _run_pipeline(
engine.set_audio_config(audio_config)
assistant_params = LLMAssistantAggregatorParams(
expect_stripped_words=True,
correct_aggregation_callback=engine.create_aggregation_correction_callback(),
)

View file

@ -21,9 +21,8 @@ from fastapi import (
status,
)
from fastapi.websockets import WebSocketState
from scipy.io import wavfile
from pipecat.audio.turn.smart_turn.local_smart_turn_v2 import LocalSmartTurnAnalyzerV2
from scipy.io import wavfile
LOG_LEVEL = (
logging.DEBUG

View file

@ -20,7 +20,6 @@ from typing import Any, Dict, Optional
import numpy as np
import websockets
from loguru import logger
from pipecat.audio.turn.smart_turn.base_smart_turn import (
BaseSmartTurn,
SmartTurnTimeoutException,

View file

@ -2,6 +2,7 @@ from loguru import logger
from api.constants import (
ENABLE_AWS_S3,
ENVIRONMENT,
MINIO_ACCESS_KEY,
MINIO_BUCKET,
MINIO_ENDPOINT,
@ -11,9 +12,9 @@ from api.constants import (
S3_BUCKET,
S3_REGION,
)
from api.enums import StorageBackend
from api.enums import Environment, StorageBackend
from .filesystem import BaseFileSystem, MinioFileSystem, S3FileSystem
from .filesystem import BaseFileSystem, MinioFileSystem, NullFileSystem, S3FileSystem
def get_storage_for_backend(backend: str) -> BaseFileSystem:
@ -73,12 +74,18 @@ def get_current_storage_backend() -> StorageBackend:
return StorageBackend.get_current_backend()
# Create a single storage instance at module load time
_backend = StorageBackend.get_current_backend()
logger.info(
f"Initializing storage backend: {_backend.name} (value: {_backend.value}, ENABLE_AWS_S3={ENABLE_AWS_S3})"
)
storage_fs = get_storage_for_backend(_backend.value)
# Create a single storage instance at module load time.
# In the test environment we skip the real backend so import doesn't require
# MinIO/S3 to be reachable; tests that need storage must inject a real fs.
if ENVIRONMENT == Environment.TEST.value:
logger.info("ENVIRONMENT=test — using NullFileSystem (no storage backend)")
storage_fs: BaseFileSystem = NullFileSystem()
else:
_backend = StorageBackend.get_current_backend()
logger.info(
f"Initializing storage backend: {_backend.name} (value: {_backend.value}, ENABLE_AWS_S3={ENABLE_AWS_S3})"
)
storage_fs = get_storage_for_backend(_backend.value)
# For backward compatibility, keep get_storage() function

View file

@ -6,7 +6,6 @@ This module contains the business logic for Asterisk ARI call operations.
from typing import Any, Dict
from loguru import logger
from pipecat.serializers.call_strategies import HangupStrategy, TransferStrategy

View file

@ -1,15 +1,15 @@
"""ARI (Asterisk) transport factory."""
from fastapi import WebSocket
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import AsteriskFrameSerializer
from .strategies import ARIBridgeSwapStrategy, ARIHangupStrategy

View file

@ -8,6 +8,7 @@ import json
from fastapi import APIRouter, Request
from loguru import logger
from pipecat.utils.run_context import set_current_run_id
from api.db import db_client
from api.services.telephony.factory import get_telephony_provider_for_run
@ -15,7 +16,6 @@ from api.services.telephony.status_processor import (
StatusCallbackRequest,
_process_status_update,
)
from pipecat.utils.run_context import set_current_run_id
router = APIRouter()

View file

@ -3,9 +3,9 @@
from typing import Any, Dict
from loguru import logger
from pipecat.serializers.call_strategies import HangupStrategy
from api.services.telephony.providers.cloudonix.provider import CLOUDONIX_API_BASE_URL
from pipecat.serializers.call_strategies import HangupStrategy
class CloudonixHangupStrategy(HangupStrategy):

View file

@ -1,15 +1,15 @@
"""Cloudonix transport factory."""
from fastapi import WebSocket
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import CloudonixFrameSerializer
from .strategies import CloudonixHangupStrategy

View file

@ -9,6 +9,7 @@ from typing import Optional
from fastapi import APIRouter, Header, Request
from loguru import logger
from pipecat.utils.run_context import set_current_run_id
from starlette.responses import HTMLResponse
from api.db import db_client
@ -18,7 +19,6 @@ from api.services.telephony.status_processor import (
_process_status_update,
)
from api.utils.common import get_backend_endpoints
from pipecat.utils.run_context import set_current_run_id
router = APIRouter()

View file

@ -1,15 +1,15 @@
"""Plivo transport factory."""
from fastapi import WebSocket
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import PlivoFrameSerializer

View file

@ -8,6 +8,7 @@ import json
from fastapi import APIRouter, Request
from loguru import logger
from pipecat.utils.run_context import set_current_run_id
from api.db import db_client
from api.services.telephony.factory import get_telephony_provider_for_run
@ -16,7 +17,6 @@ from api.services.telephony.status_processor import (
StatusCallbackRequest,
_process_status_update,
)
from pipecat.utils.run_context import set_current_run_id
router = APIRouter()

View file

@ -1,15 +1,15 @@
"""Telnyx transport factory."""
from fastapi import WebSocket
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import TelnyxFrameSerializer

View file

@ -9,6 +9,7 @@ from typing import Optional
from fastapi import APIRouter, Header, Request
from loguru import logger
from pipecat.utils.run_context import set_current_run_id
from starlette.responses import HTMLResponse
from api.db import db_client
@ -18,7 +19,6 @@ from api.services.telephony.status_processor import (
_process_status_update,
)
from api.utils.common import get_backend_endpoints
from pipecat.utils.run_context import set_current_run_id
router = APIRouter()

View file

@ -8,7 +8,6 @@ from typing import Any, Dict
import aiohttp
from loguru import logger
from pipecat.serializers.call_strategies import HangupStrategy, TransferStrategy

View file

@ -1,15 +1,15 @@
"""Twilio transport factory."""
from fastapi import WebSocket
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import TwilioFrameSerializer
from .strategies import TwilioConferenceStrategy, TwilioHangupStrategy

View file

@ -10,6 +10,7 @@ from typing import Optional
from fastapi import APIRouter, Header, Request
from loguru import logger
from pipecat.utils.run_context import set_current_run_id
from starlette.responses import HTMLResponse
from api.db import db_client
@ -24,7 +25,6 @@ from api.utils.common import get_backend_endpoints
from api.utils.telephony_helper import (
parse_webhook_request,
)
from pipecat.utils.run_context import set_current_run_id
router = APIRouter()

View file

@ -7,15 +7,15 @@ Vobiz uses Plivo-compatible WebSocket protocol:
from fastapi import WebSocket
from loguru import logger
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import VobizFrameSerializer

View file

@ -9,6 +9,7 @@ from typing import Optional
from fastapi import APIRouter, Request
from loguru import logger
from pipecat.utils.run_context import set_current_run_id
from api.db import db_client
from api.services.telephony.factory import get_telephony_provider_for_run
@ -16,7 +17,6 @@ from api.services.telephony.status_processor import (
StatusCallbackRequest,
_process_status_update,
)
from pipecat.utils.run_context import set_current_run_id
router = APIRouter()

View file

@ -1,13 +1,14 @@
"""Vonage transport factory."""
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from pipecat.transports.websocket.fastapi import (
FastAPIWebsocketParams,
FastAPIWebsocketTransport,
)
from api.services.pipecat.audio_config import AudioConfig
from api.services.pipecat.audio_mixer import build_audio_out_mixer
from api.services.telephony.factory import load_credentials_for_transport
from .serializers import VonageFrameSerializer

View file

@ -1,14 +1,12 @@
"""Utility module for applying disposition code mapping."""
from typing import Optional
from loguru import logger
from api.db import db_client
from api.enums import OrganizationConfigurationKey
async def apply_disposition_mapping(value: str, organization_id: Optional[int]) -> str:
async def apply_disposition_mapping(value: str, organization_id: int | None) -> str:
"""Apply disposition code mapping if configured.
Args:
@ -46,32 +44,3 @@ async def apply_disposition_mapping(value: str, organization_id: Optional[int])
except Exception as e:
logger.error(f"Error applying disposition mapping: {e}")
return value
async def get_organization_id_from_workflow_run(
workflow_run_id: Optional[int],
) -> Optional[int]:
"""Get organization_id from workflow_run_id through the model relationships.
Args:
workflow_run_id: The workflow run ID
Returns:
The organization ID if found, otherwise None
"""
if not workflow_run_id:
return None
try:
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
if not workflow_run or not workflow_run.workflow:
return None
workflow = workflow_run.workflow
if not workflow.user:
return None
return workflow.user.selected_organization_id
except Exception as e:
logger.error(f"Error getting organization_id from workflow_run: {e}")
return None

View file

@ -1,11 +1,5 @@
from typing import TYPE_CHECKING, Awaitable, Callable, Optional, Union
from api.services.pipecat.audio_playback import play_audio
from api.services.workflow.disposition_mapper import (
apply_disposition_mapping,
get_organization_id_from_workflow_run,
)
from api.services.workflow.workflow import Node, WorkflowGraph
from pipecat.adapters.schemas.tools_schema import ToolsSchema
from pipecat.frames.frames import (
BotStartedSpeakingFrame,
@ -21,6 +15,11 @@ from pipecat.services.llm_service import FunctionCallParams
from pipecat.services.settings import LLMSettings
from pipecat.utils.enums import EndTaskReason
from api.db import db_client
from api.services.pipecat.audio_playback import play_audio
from api.services.workflow.disposition_mapper import apply_disposition_mapping
from api.services.workflow.workflow import Node, WorkflowGraph
if TYPE_CHECKING:
from pipecat.frames.frames import Frame
from pipecat.services.anthropic.llm import AnthropicLLMService
@ -114,6 +113,9 @@ class PipecatEngine:
# Custom tool manager (initialized in initialize())
self._custom_tool_manager: Optional[CustomToolManager] = None
# Cached organization ID (resolved lazily from workflow run)
self._organization_id: Optional[int] = None
# Embeddings configuration (passed from run_pipeline.py)
self._embeddings_api_key: Optional[str] = embeddings_api_key
self._embeddings_model: Optional[str] = embeddings_model
@ -141,10 +143,13 @@ class PipecatEngine:
async def _get_organization_id(self) -> Optional[int]:
"""Get and cache the organization ID from workflow run."""
if self._custom_tool_manager:
return await self._custom_tool_manager.get_organization_id()
# Fallback for when manager is not yet initialized
return await get_organization_id_from_workflow_run(self._workflow_run_id)
if self._organization_id is None:
self._organization_id = (
await db_client.get_organization_id_by_workflow_run_id(
self._workflow_run_id
)
)
return self._organization_id
def _get_otel_context(self):
"""Extract the OTel Context from the task's TracingContext.
@ -324,11 +329,7 @@ class PipecatEngine:
)
# Register function with LLM
self.llm.register_function(
name,
transition_func,
cancel_on_interruption=False,
)
self.llm.register_function(name, transition_func)
async def _register_knowledge_base_function(
self, document_uuids: list[str]

View file

@ -14,7 +14,6 @@ import re
from typing import TYPE_CHECKING
from loguru import logger
from pipecat.frames.frames import (
LLMMessagesAppendFrame,
)

View file

@ -6,8 +6,6 @@ from typing import TYPE_CHECKING, Optional
from loguru import logger
from opentelemetry import trace
from api.services.pipecat.tracing_config import ensure_tracing
from pipecat.frames.frames import LLMContextSummaryRequestFrame
from pipecat.utils.context.llm_context_summarization import (
LLMContextSummarizationUtil,
@ -15,6 +13,8 @@ from pipecat.utils.context.llm_context_summarization import (
)
from pipecat.utils.tracing.service_attributes import add_llm_span_attributes
from api.services.pipecat.tracing_config import ensure_tracing
if TYPE_CHECKING:
from api.services.workflow.pipecat_engine import PipecatEngine

View file

@ -13,21 +13,6 @@ import uuid
from typing import TYPE_CHECKING, Any, Dict, List, Optional
from loguru import logger
from api.db import db_client
from api.enums import ToolCategory, WorkflowRunMode
from api.services.pipecat.audio_playback import play_audio, play_audio_loop
from api.services.telephony.call_transfer_manager import get_call_transfer_manager
from api.services.telephony.factory import get_telephony_provider
from api.services.telephony.transfer_event_protocol import TransferContext
from api.services.workflow.disposition_mapper import (
get_organization_id_from_workflow_run,
)
from api.services.workflow.tools.calculator import get_calculator_tools, safe_calculator
from api.services.workflow.tools.custom_tool import (
execute_http_tool,
tool_to_function_schema,
)
from pipecat.adapters.schemas.function_schema import FunctionSchema
from pipecat.frames.frames import (
FunctionCallResultProperties,
@ -36,6 +21,18 @@ from pipecat.frames.frames import (
from pipecat.services.llm_service import FunctionCallParams
from pipecat.utils.enums import EndTaskReason
from api.db import db_client
from api.enums import ToolCategory, WorkflowRunMode
from api.services.pipecat.audio_playback import play_audio, play_audio_loop
from api.services.telephony.call_transfer_manager import get_call_transfer_manager
from api.services.telephony.factory import get_telephony_provider
from api.services.telephony.transfer_event_protocol import TransferContext
from api.services.workflow.tools.calculator import get_calculator_tools, safe_calculator
from api.services.workflow.tools.custom_tool import (
execute_http_tool,
tool_to_function_schema,
)
if TYPE_CHECKING:
from api.services.workflow.pipecat_engine import PipecatEngine
@ -75,7 +72,6 @@ class CustomToolManager:
def __init__(self, engine: "PipecatEngine") -> None:
self._engine = engine
self._organization_id: Optional[int] = None
async def _play_config_message(
self, config: dict, *, append_to_context: bool = False
@ -122,12 +118,8 @@ class CustomToolManager:
return False
async def get_organization_id(self) -> Optional[int]:
"""Get and cache the organization ID from workflow run."""
if self._organization_id is None:
self._organization_id = await get_organization_id_from_workflow_run(
self._engine._workflow_run_id
)
return self._organization_id
"""Get the organization ID from the engine (shared cache)."""
return await self._engine._get_organization_id()
async def get_tool_schemas(self, tool_uuids: list[str]) -> list[FunctionSchema]:
"""Fetch custom tools and convert them to function schemas.
@ -215,13 +207,10 @@ class CustomToolManager:
function_name = schema["function"]["name"]
# Create and register the handler
handler, timeout_secs, cancel_on_interruption = self._create_handler(
tool, function_name
)
handler, timeout_secs = self._create_handler(tool, function_name)
self._engine.llm.register_function(
function_name,
handler,
cancel_on_interruption=cancel_on_interruption,
timeout_secs=timeout_secs,
)
@ -244,19 +233,16 @@ class CustomToolManager:
Async handler function for the tool
"""
timeout_secs: Optional[float] = None
cancel_on_interruption = True
if tool.category == ToolCategory.END_CALL.value:
cancel_on_interruption = False
handler = self._create_end_call_handler(tool, function_name)
elif tool.category == ToolCategory.TRANSFER_CALL.value:
timeout_secs = 120.0
cancel_on_interruption = False
handler = self._create_transfer_call_handler(tool, function_name)
else:
handler = self._create_http_tool_handler(tool, function_name)
return handler, timeout_secs, cancel_on_interruption
return handler, timeout_secs
def _register_calculator_handler(self) -> None:
"""Register the built-in calculator function with the LLM."""
@ -335,7 +321,7 @@ class CustomToolManager:
tool=tool,
arguments=function_call_params.arguments,
call_context_vars=self._engine._call_context_vars,
organization_id=self._organization_id,
organization_id=await self.get_organization_id(),
)
await function_call_params.result_callback(result)

View file

@ -5,12 +5,12 @@ from typing import TYPE_CHECKING, Any, List
from loguru import logger
from opentelemetry import trace
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.utils.tracing.service_attributes import add_llm_span_attributes
from api.services.gen_ai.json_parser import parse_llm_json
from api.services.pipecat.tracing_config import ensure_tracing
from api.services.workflow.dto import ExtractionVariableDTO
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.utils.tracing.service_attributes import add_llm_span_attributes
if TYPE_CHECKING:
from api.services.workflow.pipecat_engine import PipecatEngine

View file

@ -4,6 +4,7 @@ import json
from typing import Any
from loguru import logger
from pipecat.processors.aggregators.llm_context import LLMContext
from api.db.models import WorkflowRunModel
from api.services.gen_ai.json_parser import parse_llm_json
@ -26,7 +27,6 @@ from api.services.workflow.qa.tracing import (
setup_langfuse_parent_context,
)
from api.utils.template_renderer import render_template
from pipecat.processors.aggregators.llm_context import LLMContext
async def _run_llm_inference(

View file

@ -3,6 +3,7 @@
from typing import Any
from loguru import logger
from pipecat.processors.aggregators.llm_context import LLMContext
from api.db import db_client
from api.db.models import WorkflowRunModel
@ -10,7 +11,6 @@ from api.services.pipecat.service_factory import create_llm_service_from_provide
from api.services.workflow.dto import NodeType, QANodeData
from api.services.workflow.qa.llm_config import resolve_llm_config
from api.services.workflow.qa.tracing import create_node_summary_trace
from pipecat.processors.aggregators.llm_context import LLMContext
NODE_SUMMARY_SYSTEM_PROMPT = (
"You are analyzing a voice AI agent script. This is only a part of a larger script. "

View file

@ -78,7 +78,6 @@ def add_qa_span_to_trace(
return
try:
from opentelemetry import trace as otel_trace
from pipecat.utils.tracing.service_attributes import add_llm_span_attributes
tracer = otel_trace.get_tracer("pipecat")
@ -122,9 +121,9 @@ def create_node_summary_trace(
try:
from opentelemetry import trace as otel_trace
from opentelemetry.context import Context
from pipecat.utils.tracing.service_attributes import add_llm_span_attributes
from api.services.pipecat.tracing_config import ensure_tracing
from pipecat.utils.tracing.service_attributes import add_llm_span_attributes
if not ensure_tracing():
return None