feat: add deterministic message interaction stages
This commit is contained in:
@@ -2,8 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
from models import AssistantConfig
|
||||
from pipecat.flows import ContextStrategy, ContextStrategyConfig, NodeConfig
|
||||
from pipecat.frames.frames import LLMUpdateSettingsFrame
|
||||
@@ -108,7 +106,6 @@ class WorkflowAgentStage:
|
||||
node_id: str,
|
||||
*,
|
||||
functions: list,
|
||||
greeting_context_message: dict[str, str] | None,
|
||||
leading_messages: list[dict[str, str]] | None = None,
|
||||
) -> NodeConfig:
|
||||
data = self._engine.data(node_id)
|
||||
@@ -119,11 +116,6 @@ class WorkflowAgentStage:
|
||||
if data.get("contextPolicy") == "fresh"
|
||||
else ContextStrategy.APPEND
|
||||
)
|
||||
greeting_messages = (
|
||||
[deepcopy(greeting_context_message)]
|
||||
if strategy == ContextStrategy.RESET and greeting_context_message
|
||||
else []
|
||||
)
|
||||
fixed_reply_messages = (
|
||||
[{"role": "assistant", "content": entry_speech}]
|
||||
if entry_mode == "fixed_speech" and entry_speech
|
||||
@@ -133,7 +125,6 @@ class WorkflowAgentStage:
|
||||
"name": node_id,
|
||||
"role_message": self.role_message(node_id),
|
||||
"task_messages": [
|
||||
*greeting_messages,
|
||||
*(leading_messages or []),
|
||||
*fixed_reply_messages,
|
||||
],
|
||||
|
||||
@@ -15,6 +15,7 @@ class WorkflowStatus(StrEnum):
|
||||
ROUTING = "routing"
|
||||
RUNNING_AGENT = "running_agent"
|
||||
RUNNING_ACTION = "running_action"
|
||||
RUNNING_MESSAGE = "running_message"
|
||||
HANDOFF = "handoff"
|
||||
ENDED = "ended"
|
||||
|
||||
|
||||
@@ -5,65 +5,15 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from pipecat.frames.frames import OutputTransportMessageUrgentFrame, TTSSpeakFrame
|
||||
from pipecat.frames.frames import OutputTransportMessageUrgentFrame
|
||||
from pipecat.utils.time import time_now_iso8601
|
||||
|
||||
from services.brains.base import BrainRuntime
|
||||
from services.runtime_variables import DynamicVariableStore
|
||||
from services.fixed_speech import FixedSpeechOutput
|
||||
|
||||
|
||||
class WorkflowOutput:
|
||||
class WorkflowOutput(FixedSpeechOutput):
|
||||
"""Publish debug events and fixed speech without duplicating persistence."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
store: DynamicVariableStore,
|
||||
runtime: BrainRuntime,
|
||||
) -> None:
|
||||
self._store = store
|
||||
self._runtime = runtime
|
||||
self._client_ready = False
|
||||
self._pending_transcripts: list[dict[str, Any]] = []
|
||||
|
||||
async def mark_client_ready(self) -> None:
|
||||
self._client_ready = True
|
||||
pending = self._pending_transcripts
|
||||
self._pending_transcripts = []
|
||||
for message in pending:
|
||||
await self.emit(message)
|
||||
|
||||
async def speak(
|
||||
self,
|
||||
text: str,
|
||||
*,
|
||||
source: str,
|
||||
node_id: str | None = None,
|
||||
) -> None:
|
||||
"""Record, display and synthesize one Workflow-owned utterance."""
|
||||
content = text.strip()
|
||||
if not content:
|
||||
return
|
||||
self._store.record("agent", content)
|
||||
transcript = {
|
||||
"type": "transcript",
|
||||
"role": "assistant",
|
||||
"content": content,
|
||||
"timestamp": time_now_iso8601(),
|
||||
"source": source,
|
||||
**({"nodeId": node_id} if node_id else {}),
|
||||
}
|
||||
if self._client_ready:
|
||||
await self.emit(transcript)
|
||||
else:
|
||||
self._pending_transcripts.append(transcript)
|
||||
|
||||
track_speech = getattr(self._runtime.call_end, "track_speech", None)
|
||||
if callable(track_speech):
|
||||
track_speech()
|
||||
await self._runtime.queue_frame(
|
||||
TTSSpeakFrame(content, append_to_context=False)
|
||||
)
|
||||
|
||||
async def emit_node_active(self, node_id: str | None) -> None:
|
||||
if node_id:
|
||||
await self.emit({"type": "node-active", "nodeId": node_id})
|
||||
|
||||
Reference in New Issue
Block a user