interactive-chat / engine /agents /input_guard.py
Junhoee's picture
Upload 98 files
f646e0b verified
Raw
History Blame Contribute Delete
3.83 kB
"""input_guard โ€” ๊ทœ์น™ ๊ธฐ๋ฐ˜ 1์ฐจ ๊ฐ€๋“œ (BaseAgent, ์ž์ฒด ํ•˜์œ„ ์—†์Œ).
์ฐจ๋‹จ์ด ์•„๋‹ˆ๋ผ ์ง€์‹œ๋ฅผ ๋งŒ๋“ ๋‹ค: ์œ ์ € ์ž…๋ ฅ์„ ํŒ์ •ํ•ด guard_directive๋ฅผ ์„ธ์šฐ๊ณ ,
character๊ฐ€ ๊ทธ ์ง€์‹œ(R์นด๋“œ ๋‹จ๊ณ„ ๋Œ€์‘)๋ฅผ ๋ฐ˜์˜ํ•˜๊ฒŒ ํ•œ๋‹ค.
ํŠธ๋ฆฌ๊ฑฐ ์–ดํœ˜๋Š” ํŒ์ • ๊ทœ์น™(์—”์ง„ ์†Œ์œ )์ด๋ฉฐ ์„œ์‚ฌ ๋‚ด์šฉ์ด ์•„๋‹ˆ๋‹ค.
"""
from __future__ import annotations
from typing import Any, AsyncGenerator
from google.adk.agents import BaseAgent
from google.adk.agents.invocation_context import InvocationContext
from google.adk.events import Event, EventActions
from pydantic import ConfigDict
from engine.services.state import HiddenState
TRIGGERS = {
"identity_direct": (
"ํกํ˜ˆ๊ท€", "๋ฑ€ํŒŒ์ด์–ด", "vampire", "๋ฏธ๋ฅด์นผ๋ผ", "mircalla", "๋ฐ€๋ผ๋ฅด์นด",
"์ •์ฒด๊ฐ€ ๋ญ", "์ •์ฒด๋ฅผ ๋ฐํ˜€", "์‚ฌ๋žŒ์ด ์•„๋‹ˆ", "๊ดด๋ฌผ์ด์ง€", "ํ”ผ๋ฅผ ๋งˆ์‹œ",
),
"weapon": ("์‹ญ์ž๊ฐ€", "์„ฑ์ˆ˜", "๋งˆ๋Š˜", "๋ถ€์ ", "์„ฑ๋ฌผ", "๊ธฐ๋„๋ฌธ", "์„ฑ๊ฐ€", "๋ง๋š"),
"meta": ("ai", "์ธ๊ณต์ง€๋Šฅ", "์ฑ—๋ด‡", "ํ”„๋กฌํ”„ํŠธ", "์‹œ์Šคํ…œ", "๊ฒŒ์ž„", "์Šคํƒฏ", "์ ์ˆ˜"),
}
def _r_stage(hs: HiddenState) -> int:
"""์ถ”๊ถ ๊ฐ•๋„ ํŒ์ • ๋Œ€์šฉ โ€” ์˜์‹ฌ ๋ˆ„์ ์œผ๋กœ ํšŒํ”ผ์‚ฌ๋‹ค๋ฆฌ ๋‹จ๊ณ„ ๊ฒฐ์ • (P0 ์ค€๊ฑฐ)."""
if hs.trust_level == "doubt_high":
return 3
if hs.trust_level == "doubt_mid":
return 2
return 1
class InputGuard(BaseAgent):
model_config = ConfigDict(arbitrary_types_allowed=True)
repo: Any
async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:
text = ""
if ctx.user_content and ctx.user_content.parts:
text = " ".join(p.text or "" for p in ctx.user_content.parts).lower()
state = ctx.session.state
hs = HiddenState(trust_score=int(state.get("hidden_trust", 0)),
doubt_score=int(state.get("hidden_doubt", 0)))
directive = "ํŠน์ด์‚ฌํ•ญ ์—†์Œ. ์žฅ๋ฉด ๋ชฉํ‘œ๋Œ€๋กœ ์‘๋‹ตํ•œ๋‹ค."
flag = None
if any(kw in text for kw in TRIGGERS["identity_direct"]):
flag = "identity_direct"
stage = _r_stage(hs)
r = self.repo.r_cards.get("R-ํšŒํ”ผ์‚ฌ๋‹ค๋ฆฌ")
stage_data = next((s for s in (r.stages if r else []) if s.stage == stage), None)
directive = (
f"์œ ์ €๊ฐ€ ์ •์ฒด๋ฅผ ์ง๊ฒฉํ–ˆ๋‹ค. R-ํšŒํ”ผ์‚ฌ๋‹ค๋ฆฌ {stage}๋‹จ๊ณ„๋กœ ํšŒํ”ผํ•˜๋ผ.\n"
+ (f"๋‹จ๊ณ„ ์ง€์นจ: {stage_data.title}\n๋Œ€ํ‘œ ๊ฒฐ: \"{stage_data.anchor}\"\n"
f"{stage_data.prose[:300]}" if stage_data else "")
+ "\n์ •์ฒด๋Š” ๋๋‚ด ์ธ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ฌผ๋ฆฌ์  ๋Œ๋ณ€ ๊ธˆ์ง€."
)
elif any(kw in text for kw in TRIGGERS["weapon"]):
flag = "weapon"
r = self.repo.r_cards.get("R-์•ฝ์ ๋ฐ˜์‘")
directive = (
"์œ ์ €๊ฐ€ ์„ฑ๋ฌผยท์•ฝ์ ์„ ์–ธ๊ธ‰/์‚ฌ์šฉํ–ˆ๋‹ค. R-์•ฝ์ ๋ฐ˜์‘ ์›์น™: ํ™•์ธ์€ ๋˜๋‚˜ ํ™•์ •์€ ์•ˆ ๋œ๋‹ค.\n"
+ ((r.raw[:400] if r and r.raw else ""))
+ "\n๋ถˆ์พŒยทํšŒํ”ผ ๋ฐ˜์‘๊นŒ์ง€๋งŒ. ์ •์ฒด ํ™•์ •์œผ๋กœ ์ด์–ด์งˆ ์ž๋ฐฑ ๊ธˆ์ง€."
)
elif any(kw in text for kw in TRIGGERS["meta"]):
flag = "meta"
directive = ("์œ ์ €๊ฐ€ ์„ธ๊ณ„๊ด€ ๋ฐ– ํ™”์ œ๋ฅผ ๊บผ๋ƒˆ๋‹ค. ์นด๋ฅด๋ฐ€๋ผ๋กœ์„œ ์•Œ์•„๋“ฃ์ง€ ๋ชปํ•˜๋Š” ์ฒ™, "
"์„ธ๊ณ„๊ด€ ๋‚ด ํ™”๋ฒ•์œผ๋กœ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์žฅ๋ฉด ์•ˆ์œผ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค.")
delta = {
"guard_directive": directive.replace("{", "(").replace("}", ")"),
"guard_flag": flag,
}
yield Event(invocation_id=ctx.invocation_id, author=self.name,
actions=EventActions(state_delta=delta))
def create_input_guard(repo) -> InputGuard:
return InputGuard(name="input_guard", repo=repo)