mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-25 08:48:13 +02:00
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:
parent
d256c6005c
commit
0e12c41fc7
76 changed files with 1776 additions and 670 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import re
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from pipecat.frames.frames import (
|
||||
LLMMessagesAppendFrame,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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. "
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue