feat(workflow): add edge-tool routing and realtime runtime

This commit is contained in:
Xin Wang
2026-08-04 22:29:04 +08:00
parent 1902ffc240
commit 59588ba88d
25 changed files with 1952 additions and 107 deletions

View File

@@ -16,6 +16,7 @@ from models import AssistantConfig
from openai import AsyncOpenAI
from PIL import Image
from services.brains import Brain, BrainRuntime, build_brain
from services.brains.base import RealtimeBrainRuntime
from services.conversation_history import ConversationRecorder
from services.pipecat.call_lifecycle import (
CallEndCoordinator,
@@ -73,6 +74,7 @@ from services.pipecat.processors import (
KnowledgeRetrievalProcessor,
PassthroughLLMAssistantAggregator,
RealtimeDynamicVariableProcessor,
RealtimeInputAudioGateProcessor,
RealtimeUserInputProcessor,
SessionUpdateProcessor,
UserInput,
@@ -890,7 +892,32 @@ async def run_realtime_pipeline(
instructions=brain.system_prompt(cfg),
)
input_sample_rate, output_sample_rate = realtime_audio_sample_rates(cfg)
user_input = RealtimeUserInputProcessor()
worker_holder: dict[str, PipelineWorker] = {}
input_state = {"enabled": True}
async def queue_call_end(reason: str) -> None:
worker = worker_holder.get("worker")
if worker is None:
return
logger.info(f"结束 Realtime 通话: reason={reason}")
await worker.queue_frame(
OutputTransportMessageUrgentFrame(
message={"type": "call-ended", "reason": reason}
)
)
await worker.queue_frame(EndFrame())
call_end = CallEndCoordinator(queue_call_end)
client_tools = ClientToolBroker()
client_tools.set_interrupt_handler(realtime.interrupt)
user_input = RealtimeUserInputProcessor(
should_ignore_input=lambda: (
call_end.ending or not input_state["enabled"]
)
)
input_gate = RealtimeInputAudioGateProcessor(
lambda: not call_end.ending and input_state["enabled"]
)
dynamic_variables = RealtimeDynamicVariableProcessor(brain, cfg, realtime)
async def refresh_realtime_instructions() -> None:
@@ -910,14 +937,22 @@ async def run_realtime_pipeline(
channel=channel,
runtime_mode=cfg.runtimeMode,
session_id=cfg.conversation_id or None,
extra=(
WorkflowEngine(cfg.graph).session_metadata()
if cfg.type == "workflow"
else None
),
)
pipeline = Pipeline(
[
transport.input(),
client_tools,
session_update,
user_input,
input_gate,
realtime,
dynamic_variables,
EndCallAfterSpeechProcessor(call_end),
ConversationHistoryProcessor(recorder),
transport.output(),
]
@@ -931,11 +966,28 @@ async def run_realtime_pipeline(
),
enable_rtvi=False,
)
worker_holder["worker"] = worker
def set_input_enabled(enabled: bool) -> None:
input_state["enabled"] = enabled
await brain.setup_realtime(
cfg,
RealtimeBrainRuntime(
realtime=realtime,
queue_frame=worker.queue_frame,
call_end=call_end,
session_id=cfg.conversation_id or "",
client_tools=client_tools,
set_input_enabled=set_input_enabled,
),
)
bind_realtime_pipeline_events(
transport=transport,
worker=worker,
realtime=realtime,
brain=brain,
text_input=user_input,
greeting=greeting,
)