Make end call tool can be cancelled

This commit is contained in:
Xin Wang
2026-08-12 09:18:40 +08:00
parent fc026e765e
commit d0bb5b3868
15 changed files with 350 additions and 48 deletions

View File

@@ -68,6 +68,7 @@ from services.pipecat.turn_config import (
create_user_turn_strategies,
create_vad_analyzer,
create_vad_params,
is_configured_user_turn_start,
)
from services.pipecat.processors import (
KNOWLEDGE_CONTEXT_MARKER,
@@ -330,6 +331,16 @@ async def run_pipeline(
)
)
input_state = {"enabled": True}
current_enable_interrupt = cfg.enableInterrupt
current_turn_config = dict(cfg.turnConfig)
def is_voice_end_interruption(frame) -> bool:
return (
input_state["enabled"]
and current_enable_interrupt
and is_configured_user_turn_start(frame, current_turn_config)
)
tool_interruption_strategy = ToolInterruptionUserMuteStrategy(
{
tool.function_name: policy_for_tool(tool).execution_mode
@@ -355,7 +366,11 @@ async def run_pipeline(
vad_analyzer=create_vad_analyzer(cfg.turnConfig),
user_mute_strategies=[
CallEndingUserMuteStrategy(
lambda: call_end.ending or not input_state["enabled"]
lambda: (
not call_end.accepts_input or not input_state["enabled"]
),
is_user_interruption=is_voice_end_interruption,
cancel_pending_end=call_end.cancel_pending_end,
),
tool_interruption_strategy,
],
@@ -369,10 +384,11 @@ async def run_pipeline(
assistant_aggregator = PassthroughLLMAssistantAggregator(context)
user_input = UserInputProcessor(
should_ignore_input=lambda: (
call_end.ending
not call_end.accepts_input
or not input_state["enabled"]
or tool_interruption_strategy.is_muted
)
),
cancel_pending_end=call_end.cancel_pending_end,
)
session_update = SessionUpdateProcessor(
brain.on_session_update,
@@ -723,9 +739,6 @@ async def run_pipeline(
**current_voice_services,
},
)
current_enable_interrupt = cfg.enableInterrupt
current_turn_config = dict(cfg.turnConfig)
async def apply_workflow_turn_config(
enable_interrupt: bool,
turn_config: dict[str, Any],
@@ -983,11 +996,12 @@ async def run_realtime_pipeline(
client_tools.set_interrupt_handler(interrupt_for_client_tool_result)
user_input = RealtimeUserInputProcessor(
should_ignore_input=lambda: (
call_end.ending or not input_state["enabled"]
)
not call_end.accepts_input or not input_state["enabled"]
),
cancel_pending_end=call_end.cancel_pending_end,
)
input_gate = RealtimeInputAudioGateProcessor(
lambda: not call_end.ending and input_state["enabled"]
lambda: call_end.accepts_input and input_state["enabled"]
)
dynamic_variables = RealtimeDynamicVariableProcessor(brain, cfg, realtime)