feat: trigger prompt reply after opening confirmation
This commit is contained in:
@@ -10,7 +10,11 @@ from uuid import uuid4
|
||||
from loguru import logger
|
||||
from models import AssistantConfig
|
||||
from pipecat.adapters.schemas.function_schema import FunctionSchema
|
||||
from pipecat.frames.frames import OutputTransportMessageUrgentFrame, TTSSpeakFrame
|
||||
from pipecat.frames.frames import (
|
||||
LLMRunFrame,
|
||||
OutputTransportMessageUrgentFrame,
|
||||
TTSSpeakFrame,
|
||||
)
|
||||
from pipecat.processors.aggregators.llm_context import LLMContext
|
||||
from pipecat.processors.frame_processor import FrameProcessor
|
||||
from pipecat.services.llm_service import (
|
||||
@@ -165,6 +169,7 @@ class PromptBrain(BaseBrain):
|
||||
raise RuntimeError("PromptBrain 尚未初始化")
|
||||
opening_message = self._opening_message()
|
||||
opening_actions = self._startup_actions("opening")
|
||||
generate_after_confirmation = opening_message is not None
|
||||
speech = (
|
||||
self._render_greeting(self._cfg).strip()
|
||||
if opening_message is not None
|
||||
@@ -179,7 +184,8 @@ class PromptBrain(BaseBrain):
|
||||
speak=self._speak_opening,
|
||||
set_input_enabled=runtime.set_input_enabled,
|
||||
input_already_blocked=self._opening_input_blocked,
|
||||
release_input_on_success=not bool(opening_actions),
|
||||
# Keep the gate until the automatic first reply is queued.
|
||||
release_input_on_success=False,
|
||||
release_input_on_failure=False,
|
||||
)
|
||||
if not message_result.succeeded:
|
||||
@@ -191,7 +197,13 @@ class PromptBrain(BaseBrain):
|
||||
if opening_actions:
|
||||
result = await self._action_stages.run(
|
||||
self._opening_actions_stage_spec(),
|
||||
set_input_enabled=runtime.set_input_enabled,
|
||||
# The Prompt opening lifecycle owns the input gate when a
|
||||
# confirmation message will trigger an automatic reply.
|
||||
set_input_enabled=(
|
||||
None
|
||||
if generate_after_confirmation
|
||||
else runtime.set_input_enabled
|
||||
),
|
||||
input_already_blocked=self._opening_input_blocked,
|
||||
release_input_on_failure=False,
|
||||
on_outcome=self._publish_opening_outcome,
|
||||
@@ -204,6 +216,11 @@ class PromptBrain(BaseBrain):
|
||||
raise
|
||||
self._opening_finished = True
|
||||
self._opening_input_blocked = False
|
||||
if generate_after_confirmation and not runtime.call_end.ending:
|
||||
logger.debug("Prompt 开场确认完成,触发自动首句")
|
||||
await runtime.queue_frame(LLMRunFrame())
|
||||
if runtime.set_input_enabled is not None:
|
||||
runtime.set_input_enabled(True)
|
||||
|
||||
async def _speak_opening(self, content: str) -> Awaitable[None] | None:
|
||||
if self._output is None:
|
||||
|
||||
@@ -353,7 +353,7 @@ class PromptBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
["preflight_1", "preflight_2"],
|
||||
)
|
||||
|
||||
async def test_opening_stage_starts_speech_and_releases_on_confirmation(self):
|
||||
async def test_opening_stage_triggers_reply_after_confirmation(self):
|
||||
tool = RuntimeTool(
|
||||
id="opening_data",
|
||||
name="加载开场数据",
|
||||
@@ -454,6 +454,10 @@ class PromptBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
await opening_task
|
||||
self.assertEqual(input_states, [False, True])
|
||||
self.assertEqual(called_tool_ids, ["opening_data"])
|
||||
self.assertEqual(
|
||||
sum(isinstance(frame, LLMRunFrame) for frame in queued),
|
||||
1,
|
||||
)
|
||||
self.assertEqual(
|
||||
len(
|
||||
[
|
||||
@@ -469,6 +473,10 @@ class PromptBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
# Replayed client-ready must not execute startup actions twice.
|
||||
await brain.on_client_ready()
|
||||
self.assertEqual(brain._actions.execute.await_count, 1)
|
||||
self.assertEqual(
|
||||
sum(isinstance(frame, LLMRunFrame) for frame in queued),
|
||||
1,
|
||||
)
|
||||
|
||||
async def test_required_opening_failure_keeps_input_blocked_and_ends_call(self):
|
||||
cfg = AssistantConfig(
|
||||
|
||||
Reference in New Issue
Block a user