feat: add voice guardrails (focus, custom input/output, deterministic… - #980
feat: add voice guardrails (focus, custom input/output, deterministic…#980raghvendradhakar wants to merge 1 commit into
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThe change adds Focus and custom guardrails for Breeze Buddy voice agents. It introduces deterministic and model-based evaluation, per-generation coordination, input and response gating, tool protection, configuration validation, model options, and comprehensive tests. ChangesGuardrail contracts and detection
Evaluation and response gating
Agent pipeline and tool integration
Estimated code review effort: 5 (Critical) | ~120 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (9)
tests/test_voice_deterministic_guardrails.py (1)
84-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the invalid-Luhn case on the output direction.
Lines 84 and 85 are parametrized with
direction="input". Payment-card detection runs only on the output direction, so these two cases pass even if the Luhn check is removed. Add an output-direction assertion for the Luhn-invalid number. This makes the negative case actually exercise_contains_payment_card.♻️ Proposed additional test
`@pytest.mark.parametrize`( "candidate", [ "Use order number 4242424242424241.", "My phone number is 9876543210.", ], ) def test_luhn_invalid_numbers_are_not_blocked_on_output(candidate): result = evaluate_deterministic_guardrails( direction="output", candidate=candidate, ) assert result.blocked is False🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_voice_deterministic_guardrails.py` around lines 84 - 85, Extend the tests around the existing invalid-number parametrization to also evaluate these candidates with direction="output", ensuring the invalid-Luhn case exercises _contains_payment_card. Preserve the expected unblocked assertion for both candidates and keep the existing input-direction coverage unchanged.app/ai/voice/agents/breeze_buddy/guardrails/evaluator.py (1)
136-153: 🩺 Stability & Availability | 🔵 TrivialAdd a metric for fail-closed guardrail evaluations.
The evaluator blocks content when the provider fails or exceeds
_GUARDRAIL_TIMEOUT_SECONDS. A provider outage therefore converts normal answers into the fixed redirect message for every sentence. The warning log is the only signal today. Emit a counter or Langfuse event keyed onevaluation_failedanddirection, and alert on a sustained rate. This lets operators detect a degraded guard model before callers report repeated redirects.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/ai/voice/agents/breeze_buddy/guardrails/evaluator.py` around lines 136 - 153, The fail-closed path in the guardrail evaluator needs an operational metric in addition to its warning log. Update the exception handling that returns GuardrailVerdict with evaluation_failed=True to emit a counter or Langfuse event labeled by evaluation_failed and direction, preserving the existing block verdict and redirect behavior.tests/test_voice_custom_guardrails.py (1)
602-609: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for the blocked path of the MCP guardrail wrapper.
This test covers only the no-op case, where no coordinator exists. No test asserts that
_guardrail_wrap_mcp_handlerreturns the blocked envelope and skips the wrapped handler when the input guardrail blocks the turn. That path prevents an external MCP side effect, so it is the security-relevant branch.test_input_block_prevents_tool_side_effectexercisesblocked_tool_resultdirectly, not the MCP wrapper.♻️ Proposed additional test
async def test_mcp_handler_is_blocked_after_input_guardrail_block(): evaluator = _Evaluator(input_decision=GuardrailDecision.BLOCK) coordinator = GuardrailCoordinator( evaluator=evaluator, input_config=_config(), output_config=None, ) coordinator.begin_turn(_context()) calls = [] async def _handler(args, flow_manager): calls.append(args) return {"status": "ok"} class _Bot: guardrail_coordinator = coordinator wrapped = _guardrail_wrap_mcp_handler(_handler, _Bot(), "lookup") assert wrapped is not _handler result = await wrapped({"id": "1"}, None) assert calls == [] assert result == { "status": "error", "data": "Tool execution was blocked by the input guardrail.", }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_voice_custom_guardrails.py` around lines 602 - 609, Add a test alongside test_mcp_handler_is_unchanged_without_input_guardrail that configures a GuardrailCoordinator with an input decision of GuardrailDecision.BLOCK, wraps a handler with _guardrail_wrap_mcp_handler, and awaits it. Assert the wrapped handler is not called, and verify the result matches the blocked MCP envelope with status "error" and the expected input-guardrail message.app/ai/voice/agents/breeze_buddy/template/context.py (1)
551-557: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDrop the redundant coordinator lookup.
blocked_tool_resultcallsget_input_guardrail_coordinatoritself and returnsNonewhen no coordinator is active. The outer check duplicates that lookup.♻️ Proposed simplification
- if get_input_guardrail_coordinator(bot_instance) is not None: - blocked = await blocked_tool_result( - bot_instance, - function_name or handler_func.__name__, - ) - if blocked is not None: - return blocked + blocked = await blocked_tool_result( + bot_instance, + function_name or handler_func.__name__, + ) + if blocked is not None: + return blockedRemove the now-unused
get_input_guardrail_coordinatorimport at Line 20 if no other call site remains in this file.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/ai/voice/agents/breeze_buddy/template/context.py` around lines 551 - 557, Remove the outer get_input_guardrail_coordinator check around blocked_tool_result in the affected handler flow, call blocked_tool_result directly, and preserve the existing return when it yields a non-None result. Remove the get_input_guardrail_coordinator import if no other references remain in the file.app/ai/voice/agents/breeze_buddy/processors/custom_guardrails.py (2)
280-290: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMerge the identical
EndFrameand interruption branches.Both branches run
_cancel_output_work(),_reset_response(), and push the frame. Combine them into oneisinstance(frame, (InterruptionFrame, CancelFrame, EndFrame))check.♻️ Proposed simplification
- if isinstance(frame, (InterruptionFrame, CancelFrame)): - await self._cancel_output_work() - self._reset_response() - await self.push_frame(frame, direction) - return - - if isinstance(frame, EndFrame): + if isinstance(frame, (InterruptionFrame, CancelFrame, EndFrame)): await self._cancel_output_work() self._reset_response() await self.push_frame(frame, direction) return🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/ai/voice/agents/breeze_buddy/processors/custom_guardrails.py` around lines 280 - 290, Merge the separate EndFrame branch into the existing interruption check in the frame-processing method by testing InterruptionFrame, CancelFrame, and EndFrame together. Preserve the shared _cancel_output_work(), _reset_response(), push_frame(), and return behavior.
110-155: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winUse Pipecat task helpers for guardrail output tasks.
GuardrailResponseGateProcessorcreates evaluation and sentence-delivery tasks withasyncio.create_task()and tracks them manually. UseFrameProcessor.create_task()/cancel_task()so the pipeline task manager owns these tasks and includes them in teardown diagnostics.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/ai/voice/agents/breeze_buddy/processors/custom_guardrails.py` around lines 110 - 155, Update GuardrailResponseGateProcessor’s output-task management in _queue_delivery and the evaluation task creation paths to use the inherited FrameProcessor.create_task() helper instead of asyncio.create_task(), and cancel them through cancel_task() in _cancel_output_work. Remove the manual _background_tasks tracking and related bookkeeping while preserving ordered delivery, response-id checks, and teardown behavior.tests/test_daily_initial_context.py (1)
66-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the complete seeded message list.
The assertions check only
messages[0]andmessages[1], which are both role messages. A regression that seeds the messages twice, drops the task messages, or reorders role and task messages would still pass. Assert the full list so the seeding contract fromapp/ai/voice/agents/breeze_buddy/agent/__init__.pyLines 1179-1189 is pinned.💚 Proposed stronger assertion
async def initialize(_node: Any) -> None: events.append("initialize_flow") assert agent.context is not None messages = cast(list[dict[str, Any]], agent.context.get_messages()) - assert messages[0]["content"] == FOCUS_GUARDRAIL_SYSTEM_PROMPT - assert messages[1]["content"] == "Confirm the COD order." + assert messages == [ + {"role": "system", "content": FOCUS_GUARDRAIL_SYSTEM_PROMPT}, + {"role": "system", "content": "Confirm the COD order."}, + {"role": "assistant", "content": "Hello"}, + {"role": "system", "content": "Verify the order details."}, + ]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_daily_initial_context.py` around lines 66 - 71, Update the initialize test callback to assert the complete messages list returned by agent.context.get_messages(), including every seeded role and task message in the exact order defined by the Breeze Buddy agent seeding contract. Replace the partial messages[0]/messages[1] checks while preserving the existing context assertion.app/ai/voice/agents/breeze_buddy/agent/pipeline.py (1)
277-281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the
focus_enabledpredicate into one helper. The same three-part expressionbool(configurations and configurations.guardrails and configurations.guardrails.focus.enabled)is written in three files. Focus is a security control, so all three sites must agree. A future schema change (for example, makingguardrails.focusoptional) would need three coordinated edits, and one missed site would silently disable or enable the policy in part of the pipeline. Addis_focus_enabled(configurations) -> booltoapp/ai/voice/agents/breeze_buddy/template/focus_guardrail.pyand call it from each site.
app/ai/voice/agents/breeze_buddy/agent/pipeline.py#L277-L281: replace the inline expression withfocus_enabled = is_focus_enabled(configurations)and add the import next to the existinginject_focus_guardrailimport at Lines 59-61.app/ai/voice/agents/breeze_buddy/agent/flow.py#L198-L202: replace the inline expression withfocus_enabled = is_focus_enabled(configurations)and add the import next to the existinginject_focus_guardrailimport at Lines 13-15.app/ai/voice/agents/breeze_buddy/agent/__init__.py#L1173-L1177: replace the inline expression withfocus_enabled = is_focus_enabled(self.configurations)and import the helper fromtemplate/focus_guardrail.py.♻️ Proposed helper
# app/ai/voice/agents/breeze_buddy/template/focus_guardrail.py def is_focus_enabled(configurations: Any) -> bool: """Return whether the platform Focus policy applies to this template.""" guardrails = getattr(configurations, "guardrails", None) focus = getattr(guardrails, "focus", None) return bool(focus and focus.enabled)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/ai/voice/agents/breeze_buddy/agent/pipeline.py` around lines 277 - 281, Add is_focus_enabled(configurations) to focus_guardrail.py, safely checking optional guardrails and focus values while returning their enabled state. In app/ai/voice/agents/breeze_buddy/agent/pipeline.py lines 277-281, replace the inline predicate and import the helper; make the same replacement and import in agent/flow.py lines 198-202, and in agent/__init__.py lines 1173-1177 use self.configurations and import the helper.app/ai/voice/agents/breeze_buddy/template/utils.py (1)
115-140: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReuse the shared guardrail check.
has_enabled_custom_guardrails(configurations)matches this predicate inapp/ai/voice/agents/breeze_buddy/guardrails/evaluator.py. Importing and reusing it avoids duplicate enablement logic and keeps the realtime-template validation aligned with the evaluator.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/ai/voice/agents/breeze_buddy/template/utils.py` around lines 115 - 140, The realtime validation currently duplicates the custom guardrail enablement predicate. Import and use has_enabled_custom_guardrails(configurations) in place of the local guardrails/custom_guardrail_enabled logic, while preserving the existing ValueError behavior and message in the realtime configuration validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/ai/voice/agents/breeze_buddy/agent/__init__.py`:
- Around line 1359-1367: Update the guardrail coordinator initialization in the
surrounding generation flow to explicitly implement fail-open behavior: catch
failures from build_guardrail_coordinator, record the error with track_error
using the existing errors collection, log the failed guardrail model or
configuration when available, and leave guardrail_coordinator as None so
generation continues.
- Around line 1178-1193: The Focus-enabled initialization block in the agent
setup should not call self.context.set_messages before FlowManager.initialize.
Remove the initial_messages construction and pre-seeding around self.context,
allowing flow_manager.initialize(initial_node_config) to install the
role_messages and task_messages once without duplication.
In `@app/ai/voice/agents/breeze_buddy/template/field_reference.json`:
- Line 42: Update the guardrails field description in the template reference to
document that realtime LLM templates cannot enable guardrails.input or
guardrails.output because validate_template_compat rejects them, while
guardrails.focus remains allowed. Keep the existing behavior and example
unchanged.
---
Nitpick comments:
In `@app/ai/voice/agents/breeze_buddy/agent/pipeline.py`:
- Around line 277-281: Add is_focus_enabled(configurations) to
focus_guardrail.py, safely checking optional guardrails and focus values while
returning their enabled state. In
app/ai/voice/agents/breeze_buddy/agent/pipeline.py lines 277-281, replace the
inline predicate and import the helper; make the same replacement and import in
agent/flow.py lines 198-202, and in agent/__init__.py lines 1173-1177 use
self.configurations and import the helper.
In `@app/ai/voice/agents/breeze_buddy/guardrails/evaluator.py`:
- Around line 136-153: The fail-closed path in the guardrail evaluator needs an
operational metric in addition to its warning log. Update the exception handling
that returns GuardrailVerdict with evaluation_failed=True to emit a counter or
Langfuse event labeled by evaluation_failed and direction, preserving the
existing block verdict and redirect behavior.
In `@app/ai/voice/agents/breeze_buddy/processors/custom_guardrails.py`:
- Around line 280-290: Merge the separate EndFrame branch into the existing
interruption check in the frame-processing method by testing InterruptionFrame,
CancelFrame, and EndFrame together. Preserve the shared _cancel_output_work(),
_reset_response(), push_frame(), and return behavior.
- Around line 110-155: Update GuardrailResponseGateProcessor’s output-task
management in _queue_delivery and the evaluation task creation paths to use the
inherited FrameProcessor.create_task() helper instead of asyncio.create_task(),
and cancel them through cancel_task() in _cancel_output_work. Remove the manual
_background_tasks tracking and related bookkeeping while preserving ordered
delivery, response-id checks, and teardown behavior.
In `@app/ai/voice/agents/breeze_buddy/template/context.py`:
- Around line 551-557: Remove the outer get_input_guardrail_coordinator check
around blocked_tool_result in the affected handler flow, call
blocked_tool_result directly, and preserve the existing return when it yields a
non-None result. Remove the get_input_guardrail_coordinator import if no other
references remain in the file.
In `@app/ai/voice/agents/breeze_buddy/template/utils.py`:
- Around line 115-140: The realtime validation currently duplicates the custom
guardrail enablement predicate. Import and use
has_enabled_custom_guardrails(configurations) in place of the local
guardrails/custom_guardrail_enabled logic, while preserving the existing
ValueError behavior and message in the realtime configuration validation.
In `@tests/test_daily_initial_context.py`:
- Around line 66-71: Update the initialize test callback to assert the complete
messages list returned by agent.context.get_messages(), including every seeded
role and task message in the exact order defined by the Breeze Buddy agent
seeding contract. Replace the partial messages[0]/messages[1] checks while
preserving the existing context assertion.
In `@tests/test_voice_custom_guardrails.py`:
- Around line 602-609: Add a test alongside
test_mcp_handler_is_unchanged_without_input_guardrail that configures a
GuardrailCoordinator with an input decision of GuardrailDecision.BLOCK, wraps a
handler with _guardrail_wrap_mcp_handler, and awaits it. Assert the wrapped
handler is not called, and verify the result matches the blocked MCP envelope
with status "error" and the expected input-guardrail message.
In `@tests/test_voice_deterministic_guardrails.py`:
- Around line 84-85: Extend the tests around the existing invalid-number
parametrization to also evaluate these candidates with direction="output",
ensuring the invalid-Luhn case exercises _contains_payment_card. Preserve the
expected unblocked assertion for both candidates and keep the existing
input-direction coverage unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 627de68d-00cb-4832-9540-89db19cb08c5
📒 Files selected for processing (22)
app/ai/voice/agents/breeze_buddy/agent/__init__.pyapp/ai/voice/agents/breeze_buddy/agent/flow.pyapp/ai/voice/agents/breeze_buddy/agent/pipeline.pyapp/ai/voice/agents/breeze_buddy/guardrails/__init__.pyapp/ai/voice/agents/breeze_buddy/guardrails/deterministic.pyapp/ai/voice/agents/breeze_buddy/guardrails/evaluator.pyapp/ai/voice/agents/breeze_buddy/guardrails/models.pyapp/ai/voice/agents/breeze_buddy/guardrails/tool_gate.pyapp/ai/voice/agents/breeze_buddy/mcp/__init__.pyapp/ai/voice/agents/breeze_buddy/processors/__init__.pyapp/ai/voice/agents/breeze_buddy/processors/custom_guardrails.pyapp/ai/voice/agents/breeze_buddy/template/context.pyapp/ai/voice/agents/breeze_buddy/template/field_reference.jsonapp/ai/voice/agents/breeze_buddy/template/focus_guardrail.pyapp/ai/voice/agents/breeze_buddy/template/global_function.pyapp/ai/voice/agents/breeze_buddy/template/types.pyapp/ai/voice/agents/breeze_buddy/template/utils.pyapp/api/routers/breeze_buddy/playground/handlers.pytests/test_daily_initial_context.pytests/test_voice_custom_guardrails.pytests/test_voice_deterministic_guardrails.pytests/test_voice_focus_guardrail.py
There was a problem hiding this comment.
Pull request overview
Adds a three-layer “voice guardrails” system to the Breeze Buddy standard voice pipeline: a platform-owned Focus prompt policy, deterministic local detectors for high-confidence violations, and optional customer-authored semantic input/output guardrails evaluated via a platform-routed model and enforced before tools/TTS.
Changes:
- Introduces template schema + prompt injection for Focus guardrail, and seeds the initial LLM context earlier to close a pre-FlowManager timing window.
- Adds deterministic detectors (prompt-injection, secrets, payment cards) plus a per-turn coordinator that runs semantic guardrail evaluation in parallel and fails closed.
- Inserts new pipeline processors to gate user turns, tool side effects (global functions / transition handlers / MCP tools), and sentence-level output to TTS; exposes guardrail model options to the playground UI and adds comprehensive tests.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_voice_focus_guardrail.py | Verifies Focus guardrail schema round-trip and idempotent prompt injection + initial-node ordering. |
| tests/test_voice_deterministic_guardrails.py | Tests deterministic detectors and verifies definite blocks bypass semantic model calls. |
| tests/test_voice_custom_guardrails.py | End-to-end contract tests for custom input/output guardrails, tool gating, and pipeline topology. |
| tests/test_daily_initial_context.py | Ensures Daily greeting/init ordering is preserved while Focus context is seeded earlier when enabled. |
| app/api/routers/breeze_buddy/playground/handlers.py | Exposes sanitized guardrail model catalog to playground configuration options. |
| app/ai/voice/agents/breeze_buddy/template/utils.py | Adds realtime-LLM compatibility rejection for custom input/output guardrails. |
| app/ai/voice/agents/breeze_buddy/template/types.py | Adds guardrails to template configuration schema (Focus + optional input/output guardrails) with validation. |
| app/ai/voice/agents/breeze_buddy/template/global_function.py | Wraps global function execution to block tool side effects when input guardrails block the turn. |
| app/ai/voice/agents/breeze_buddy/template/focus_guardrail.py | Implements platform Focus guardrail system prompt + injection helper. |
| app/ai/voice/agents/breeze_buddy/template/field_reference.json | Documents new guardrails configuration field with examples. |
| app/ai/voice/agents/breeze_buddy/template/context.py | Blocks transition-handler side effects when the input guardrail blocks the current turn. |
| app/ai/voice/agents/breeze_buddy/processors/custom_guardrails.py | Adds InputGuardrailProcessor and GuardrailResponseGateProcessor (sentence-level pre-TTS gating). |
| app/ai/voice/agents/breeze_buddy/processors/init.py | Exports the new guardrail processors for pipeline wiring. |
| app/ai/voice/agents/breeze_buddy/mcp/init.py | Wraps MCP tool handlers with input-guardrail side-effect barrier. |
| app/ai/voice/agents/breeze_buddy/guardrails/tool_gate.py | Shared “wait for input verdict before side effects” helper returning a blocked-tool envelope. |
| app/ai/voice/agents/breeze_buddy/guardrails/models.py | Defines the backend-owned guardrail model catalog + sanitized options output. |
| app/ai/voice/agents/breeze_buddy/guardrails/evaluator.py | Implements semantic guardrail evaluator (tool-based decision) and per-turn coordinator with deterministic short-circuit + redaction. |
| app/ai/voice/agents/breeze_buddy/guardrails/deterministic.py | Implements fast local detectors for prompt injection, secrets, and output payment cards (Luhn). |
| app/ai/voice/agents/breeze_buddy/guardrails/init.py | Adds package initializer with explicit import-cycle avoidance note. |
| app/ai/voice/agents/breeze_buddy/agent/pipeline.py | Seeds Focus prompt in initial LLMContext, inserts guardrail processors around the main LLM, and rejects custom guardrails in realtime mode. |
| app/ai/voice/agents/breeze_buddy/agent/flow.py | Injects Focus guardrail into initial node role messages ahead of other template messages. |
| app/ai/voice/agents/breeze_buddy/agent/init.py | Builds/stops guardrail coordinator per generation, and seeds initial context directly (Focus-enabled) before FlowManager init. |
9935732 to
8d4151b
Compare
8d4151b to
d1b9507
Compare
|
Adds three template-level guardrails to the Breeze Buddy voice agent: a prompt-only "Focus" policy injected into the initial LLM context, plus optional customer-authored input and output guardrails evaluated by a platform-pinned Azure model behind fast local regex/Luhn checks. Two new pipeline processors sit around the main LLM — one holds each finalized caller turn until the check passes (blocked turns skip KB retrieval, the LLM and tools, and get a fixed redirect), the other gates completed assistant sentences before TTS. Blocked caller text is swapped for an opaque marker in live LLM history and restored only when the persisted transcript is built at call end; custom guardrails are rejected on realtime LLM templates and are not enforced on the DAILY_STREAM chat path. 1 new issue found. Walkthrough complete — 1 posted, 0 declined. |
d1b9507 to
e5ddee7
Compare
| self._delivery_tail = None | ||
|
|
||
| async def _drain_output_work(self) -> None: | ||
| """Wait for ordered verdicts and downstream sentence delivery.""" |
There was a problem hiding this comment.
check if pipecat provide any gaurdail mechanisms / gaurdrail processors
There was a problem hiding this comment.
Checked against our pinned pipecat-ai==1.1.0. Pipecat provides generic primitives such as GatedLLMContextAggregator, GatedAggregator, and FunctionFilter, but no built-in semantic guardrail/moderation processor.
66e2af5 to
21d5225
Compare
21d5225 to
f557506
Compare
This change adds three complementary guardrail controls to the Breeze Buddy voice pipeline:
Focus guardrail — a platform-owned system instruction that reinforces the active agent’s trusted goal, prevents prompt disclosure, and redirects unrelated requests. It does not make an additional model call.
Custom input guardrail — a customer-authored rule evaluated against each finalized caller turn. High-confidence attacks are blocked locally; other decisions run through a platform-routed classifier in parallel with the main LLM.
Custom output guardrail — a separate customer-authored rule evaluated against each complete assistant sentence before it reaches TTS.
Summary by CodeRabbit
New Features
Bug Fixes
DOC
https://github.com/juspay/clairvoyance/pull/980/changes#diff-7a2871dda7327227137da51c16c5d5f95c2c4ff4a5aff9ba0419062155a18a6b
NOTE