Compare commits
1 Commits
12c91b7c25
...
5a353f9582
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a353f9582 |
@@ -13,7 +13,6 @@ dependencies = [
|
|||||||
"google-cloud-firestore>=2.23.0",
|
"google-cloud-firestore>=2.23.0",
|
||||||
"pydantic-settings[yaml]>=2.13.1",
|
"pydantic-settings[yaml]>=2.13.1",
|
||||||
"google-auth>=2.34.0",
|
"google-auth>=2.34.0",
|
||||||
"google-genai>=1.64.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ from va_agent.config import settings
|
|||||||
from va_agent.dynamic_instruction import provide_dynamic_instruction
|
from va_agent.dynamic_instruction import provide_dynamic_instruction
|
||||||
from va_agent.notifications import NotificationService
|
from va_agent.notifications import NotificationService
|
||||||
from va_agent.session import FirestoreSessionService
|
from va_agent.session import FirestoreSessionService
|
||||||
from va_agent.governance import GovernancePlugin
|
|
||||||
|
|
||||||
# MCP Toolset for RAG knowledge search
|
# MCP Toolset for RAG knowledge search
|
||||||
toolset = McpToolset(
|
toolset = McpToolset(
|
||||||
@@ -23,7 +22,6 @@ toolset = McpToolset(
|
|||||||
header_provider=auth_headers_provider,
|
header_provider=auth_headers_provider,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Shared Firestore client for session service and notifications
|
# Shared Firestore client for session service and notifications
|
||||||
firestore_db = AsyncClient(database=settings.firestore_db)
|
firestore_db = AsyncClient(database=settings.firestore_db)
|
||||||
|
|
||||||
@@ -42,7 +40,6 @@ notification_service = NotificationService(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Agent with static and dynamic instructions
|
# Agent with static and dynamic instructions
|
||||||
governance = GovernancePlugin()
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
model=settings.agent_model,
|
model=settings.agent_model,
|
||||||
name=settings.agent_name,
|
name=settings.agent_name,
|
||||||
@@ -50,9 +47,8 @@ agent = Agent(
|
|||||||
role="user",
|
role="user",
|
||||||
parts=[Part(text=settings.agent_instructions)],
|
parts=[Part(text=settings.agent_instructions)],
|
||||||
),
|
),
|
||||||
instruction=settings.agent_instructions,
|
instruction=partial(provide_dynamic_instruction, notification_service),
|
||||||
tools=[toolset],
|
tools=[toolset],
|
||||||
after_model_callback=governance.after_model_callback,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
"""GovernancePlugin: Guardrails for VAia, the virtual assistant for VA."""
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
|
|
||||||
from google.adk.agents.callback_context import CallbackContext
|
|
||||||
from google.adk.models import LlmResponse
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
FORBIDDEN_EMOJIS = [
|
|
||||||
"🥵","🔪","🎰","🎲","🃏","😤","🤬","😡","😠","🩸","🧨","🪓","☠️","💀",
|
|
||||||
"💣","🔫","👗","💦","🍑","🍆","👄","👅","🫦","💩","⚖️","⚔️","✝️","🕍",
|
|
||||||
"🕌","⛪","🍻","🍸","🥃","🍷","🍺","🚬","👹","👺","👿","😈","🤡","🧙",
|
|
||||||
"🧙♀️", "🧙♂️", "🧛", "🧛♀️", "🧛♂️", "🔞","🧿","💊", "💏"
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class GovernancePlugin:
|
|
||||||
"""Guardrail executor for VAia requests as a Agent engine callbacks."""
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
"""Initialize guardrail model (structured output), prompt and emojis patterns."""
|
|
||||||
self._combined_pattern = self._get_combined_pattern()
|
|
||||||
|
|
||||||
def _get_combined_pattern(self):
|
|
||||||
person_pattern = r"(?:🧑|👩|👨)"
|
|
||||||
tone_pattern = r"[\U0001F3FB-\U0001F3FF]?"
|
|
||||||
|
|
||||||
# Unique pattern that combines all forbidden emojis, including complex ones with skin tones
|
|
||||||
combined_pattern = re.compile(
|
|
||||||
rf"{person_pattern}{tone_pattern}\u200d❤️?\u200d💋\u200d{person_pattern}{tone_pattern}" # kiss
|
|
||||||
rf"|{person_pattern}{tone_pattern}\u200d❤️?\u200d{person_pattern}{tone_pattern}" # lovers
|
|
||||||
rf"|🖕{tone_pattern}" # middle finger with all skin tone variations
|
|
||||||
rf"|{'|'.join(map(re.escape, sorted(FORBIDDEN_EMOJIS, key=len, reverse=True)))}" # simple emojis
|
|
||||||
rf"|\u200d|\uFE0F" # residual ZWJ and variation selectors
|
|
||||||
)
|
|
||||||
return combined_pattern
|
|
||||||
|
|
||||||
def _remove_emojis(self, text: str) -> tuple[str, list[str]]:
|
|
||||||
removed = self._combined_pattern.findall(text)
|
|
||||||
text = self._combined_pattern.sub("", text)
|
|
||||||
return text.strip(), removed
|
|
||||||
|
|
||||||
|
|
||||||
def after_model_callback(
|
|
||||||
self,
|
|
||||||
callback_context: CallbackContext | None = None,
|
|
||||||
llm_response: LlmResponse | None = None,
|
|
||||||
) -> None:
|
|
||||||
"""Guardrail post-processing.
|
|
||||||
|
|
||||||
Remove forbidden emojis from the model response.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
text_out = ""
|
|
||||||
if llm_response and llm_response.content:
|
|
||||||
content = llm_response.content
|
|
||||||
parts = getattr(content, "parts", None)
|
|
||||||
if parts:
|
|
||||||
part = parts[0]
|
|
||||||
text_value = getattr(part, "text", "")
|
|
||||||
if isinstance(text_value, str):
|
|
||||||
text_out = text_value
|
|
||||||
|
|
||||||
if text_out:
|
|
||||||
new_text, deleted = self._remove_emojis(text_out)
|
|
||||||
if llm_response and llm_response.content and llm_response.content.parts:
|
|
||||||
llm_response.content.parts[0].text = new_text
|
|
||||||
if deleted:
|
|
||||||
if callback_context:
|
|
||||||
callback_context.state["removed_emojis"] = deleted
|
|
||||||
logger.warning(
|
|
||||||
"Removed forbidden emojis from response: %s",
|
|
||||||
deleted,
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Error in after_model_callback")
|
|
||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -1924,7 +1924,6 @@ dependencies = [
|
|||||||
{ name = "google-adk" },
|
{ name = "google-adk" },
|
||||||
{ name = "google-auth" },
|
{ name = "google-auth" },
|
||||||
{ name = "google-cloud-firestore" },
|
{ name = "google-cloud-firestore" },
|
||||||
{ name = "google-genai" },
|
|
||||||
{ name = "pydantic-settings", extra = ["yaml"] },
|
{ name = "pydantic-settings", extra = ["yaml"] },
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1942,7 +1941,6 @@ requires-dist = [
|
|||||||
{ name = "google-adk", specifier = ">=1.14.1" },
|
{ name = "google-adk", specifier = ">=1.14.1" },
|
||||||
{ name = "google-auth", specifier = ">=2.34.0" },
|
{ name = "google-auth", specifier = ">=2.34.0" },
|
||||||
{ name = "google-cloud-firestore", specifier = ">=2.23.0" },
|
{ name = "google-cloud-firestore", specifier = ">=2.23.0" },
|
||||||
{ name = "google-genai", specifier = ">=1.64.0" },
|
|
||||||
{ name = "pydantic-settings", extras = ["yaml"], specifier = ">=2.13.1" },
|
{ name = "pydantic-settings", extras = ["yaml"], specifier = ">=2.13.1" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user