Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/app/services/ai/ai_execution_policy.py

125 lines
5.2 KiB
Python

"""
سیاست اجرای دستیار AI — حالت تحلیلگر، نظارت انسانی، خودکار.
جدا از exploration_mode (عمق تحلیل agent).
"""
from __future__ import annotations
from typing import Optional
from app.services.ai.ai_exploration_service import (
EXPLORATION_MODE_AUTO,
EXPLORATION_MODE_EXPLORE,
)
from app.services.ai.ai_tool_index import get_tool_index
from app.services.ai.ai_write_guard import get_risk_level, is_write_function
EXECUTION_MODE_ANALYZER = "analyzer"
EXECUTION_MODE_SUPERVISED = "supervised"
EXECUTION_MODE_AUTONOMOUS = "autonomous"
VALID_EXECUTION_MODES = frozenset({
EXECUTION_MODE_ANALYZER,
EXECUTION_MODE_SUPERVISED,
EXECUTION_MODE_AUTONOMOUS,
})
DEFAULT_EXECUTION_MODE = EXECUTION_MODE_ANALYZER
# عملیات پرریسک — حتی در حالت خودکار نیاز به تأیید صریح دارند.
# منبع حقیقت: Tool Manifest.always_confirm (با risk_level=high روی خود Tool)
HIGH_RISK_ALWAYS_APPROVE = get_tool_index().always_confirm_names
EXECUTION_MODE_LABELS_FA = {
EXECUTION_MODE_ANALYZER: "تحلیلگر",
EXECUTION_MODE_SUPERVISED: "با تأیید من",
EXECUTION_MODE_AUTONOMOUS: "خودکار",
}
EXECUTION_MODE_DESCRIPTIONS_FA = {
EXECUTION_MODE_ANALYZER: "فقط خواندن و تحلیل داده‌ها — بدون تغییر در سیستم",
EXECUTION_MODE_SUPERVISED: "هر تغییر قبل از اجرا نیاز به تأیید شما دارد",
EXECUTION_MODE_AUTONOMOUS: "اجرای مستقیم تغییرات؛ عملیات پرریسک همچنان تأیید می‌خواهند",
}
def resolve_execution_mode(value: Optional[str]) -> str:
mode = (value or DEFAULT_EXECUTION_MODE).strip().lower()
if mode not in VALID_EXECUTION_MODES:
return DEFAULT_EXECUTION_MODE
return mode
def exposes_write_tools(execution_mode: str) -> bool:
return resolve_execution_mode(execution_mode) != EXECUTION_MODE_ANALYZER
def exploration_mode_for_execution(execution_mode: str) -> str:
"""پیش‌فرض exploration بر اساس سیاست اجرا."""
if resolve_execution_mode(execution_mode) == EXECUTION_MODE_ANALYZER:
return EXPLORATION_MODE_EXPLORE
return EXPLORATION_MODE_AUTO
def execution_mode_prompt_block(execution_mode: str) -> str:
mode = resolve_execution_mode(execution_mode)
if mode == EXECUTION_MODE_ANALYZER:
return (
"\n\n[حالت اجرا: تحلیلگر]\n"
"شما در حالت مشاوره‌ای و فقط-خواندنی هستید.\n"
"- فقط از ابزارهای خواندنی برای تحلیل داده‌های کسب‌وکار استفاده کنید.\n"
"- هیچ ابزار نوشتنی (ایجاد، ویرایش، حذف) فراخوانی نکنید.\n"
"- اگر کاربر درخواست تغییر داده کرد، توضیح دهید که در این حالت امکان ثبت تغییر نیست "
"و پیشنهاد کنید حالت «با تأیید من» یا «خودکار» را انتخاب کند."
)
if mode == EXECUTION_MODE_SUPERVISED:
return (
"\n\n[حالت اجرا: با تأیید من]\n"
"قبل از هر عملیات نوشتنی (ایجاد، ویرایش، حذف)، سیستم از کاربر تأیید می‌گیرد.\n"
"خلاصهٔ عملیات پیشنهادی را شفاف بیان کنید و منتظر تأیید کاربر بمانید."
)
return (
"\n\n[حالت اجرا: خودکار]\n"
"می‌توانید عملیات نوشتنی معمولی را مستقیم اجرا کنید.\n"
"عملیات پرریسک (حذف، workflow، export و …) همچنان نیاز به تأیید کاربر دارند.\n"
"پس از هر تغییر، خلاصهٔ اقدام انجام‌شده را گزارش دهید."
)
def is_high_risk_write(function_name: str, registry=None) -> bool:
if registry is not None:
fn = registry.get_function(function_name)
if fn is not None:
if bool(getattr(fn, "always_confirm", False)):
return True
return get_risk_level(function_name, registry) == "high"
if function_name in HIGH_RISK_ALWAYS_APPROVE:
return True
return get_risk_level(function_name, registry) == "high"
def should_block_write_in_analyzer(execution_mode: str, function_name: str, registry=None) -> bool:
if resolve_execution_mode(execution_mode) != EXECUTION_MODE_ANALYZER:
return False
return is_write_function(function_name, registry)
def should_require_write_approval(
execution_mode: str,
function_name: str,
*,
approve_writes: bool,
registry=None,
) -> bool:
"""آیا قبل از اجرا باید APPROVAL_REQUIRED برگردد؟"""
if not is_write_function(function_name, registry):
return False
mode = resolve_execution_mode(execution_mode)
if mode == EXECUTION_MODE_ANALYZER:
return False
if mode == EXECUTION_MODE_SUPERVISED:
return not approve_writes
# autonomous — فقط پرریسک
if is_high_risk_write(function_name, registry):
return not approve_writes
return False