Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/app/services/ai/ai_constants.py
2026-08-21 14:14:21 +00:00

263 lines
11 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
ثابت‌های مشترک سرویس AI (تک‌API).
"""
from __future__ import annotations
# مدل مجازی «خودکار» — در کاتالوگ DB نیست؛ runtime resolve می‌شود.
AUTO_MODEL_CODE = "auto"
# انواع عملیات برای routing مدل auto
AI_OPERATION_CHAT = "chat"
AI_OPERATION_TITLE = "title"
AI_OPERATION_HISTORY_SUMMARY = "history_summary"
AI_OPERATION_THOUGHT = "thought_synthesis"
AI_OPERATION_SUBAGENT = "subagent"
AI_OPERATION_MEMORY_CURATE = "memory_curate"
LIGHT_AI_OPERATIONS: frozenset[str] = frozenset({
AI_OPERATION_TITLE,
AI_OPERATION_HISTORY_SUMMARY,
AI_OPERATION_THOUGHT,
AI_OPERATION_MEMORY_CURATE,
})
# timeout ارتباط با AI Provider (ثانیه)
AI_PROVIDER_TIMEOUT_SEC = 120.0
AI_PROVIDER_STREAM_TIMEOUT_SEC = 180.0
# حداکثر نوبت LLM ↔ tool در یک پاسخ (پیش‌فرض)
MAX_AGENT_ITERATIONS = 8
# تعداد iteration بر اساس پیچیدگی سوال
QUERY_COMPLEXITY_ITERATIONS: dict[str, int] = {
"simple": 3, # سوال ساده — پرس‌وجوی تک‌ابزار
"medium": 6, # سوال متوسط — چند ابزار یا تحلیل
"complex": 12, # سوال پیچیده — گزارش چندمرحله‌ای
}
# حداکثر ابزار ارسالی به مدل در هر درخواست (پس از intent filter)
MAX_TOOLS_PER_REQUEST = 48
# حالت خودکار/با تأیید: کاتالوگ کامل تا سقف ایمنی ارائه‌دهنده؛
# ابزارهای نوشتنی هرگز به‌خاطر ranking حذف نمی‌شوند.
MAX_TOOLS_AUTONOMOUS = 128
# سقف مطلق Discovery — Consumer نمی‌تواند کل کاتالوگ نامحدود را بخواهد.
DISCOVERY_HARD_MAX = 256
# Progressive schema loading: construction/dedup always on.
# Sending a smaller initial schema set than Discovery K is eval/opt-in.
# Production Discovery K stays 48/128.
PROGRESSIVE_SCHEMA_LOADING = False
PROGRESSIVE_SCHEMA_INITIAL_K = 15
# Adaptive Top-K after ranking. Production stays fixed 48/128 until rollout.
ADAPTIVE_DISCOVERY_K = False
# Independent canary percent: 0, 5, 10, 25, 50, 100. Does not turn the global flag on.
ADAPTIVE_K_ROLLOUT_PERCENT = 0
ADAPTIVE_K_CANARY_SALT = "adaptive-k-v1"
# Do not promote from Gold alone; need this many live discovery requests per arm.
ADAPTIVE_K_MIN_LIVE_SAMPLES = 500
# Hybrid lexical+semantic add-on. Default ranker stays keyword/intent.
HYBRID_TOOL_DISCOVERY = False
# Derived inverted index → candidate N → existing ranker.
# False = not 100%. Percent canary is independent. Set False + percent 0, or
# HESABIX_INDEXED_CANDIDATE_KILL=1, to stop canary without touching Adaptive K.
INDEXED_CANDIDATE_RETRIEVAL = False
# First live canary. Allowed: 0, 5, 10, 25, 50, 100. Does not enable Adaptive K.
INDEXED_CANDIDATE_ROLLOUT_PERCENT = 5
INDEXED_CANDIDATE_CANARY_SALT = "indexed-retrieval-v1"
INDEXED_CANDIDATE_MIN_LIVE_SAMPLES = 500
INDEXED_CANDIDATE_KILL_SWITCH = False
# Default N is eval-calibrated; Gold sweep overwrites if a smaller N hits 99%.
CANDIDATE_RETRIEVAL_N = 100
# Canary: empty / weak / inconsistent index → full authorized ranker, never fail open.
INDEXED_CANDIDATE_FALLBACK = True
# Channel names forced to control without killing the whole canary. Empty = none.
# Runtime: HESABIX_INDEXED_CANDIDATE_CHANNEL_HOLD=ticket,crm
INDEXED_CANDIDATE_CHANNEL_HOLD: tuple = ()
# Optional ANN candidate generator. Never replaces keyword retrieval.
VECTOR_CANDIDATE_RETRIEVAL = False
# Refuse O(N) hashed-ngram scan above this authorized-set size.
VECTOR_BRUTE_FORCE_MAX = 512
# off | eval | canary | majority | full — never bypasses PROGRESSIVE_SCHEMA_LOADING.
PROGRESSIVE_ROLLOUT_STAGE = "off"
PROGRESSIVE_CANARY_PERCENT = 5
MAX_DISCOVERY_RETRIES = 1
# سقف همزمانی ابزارهای read-only در یک نوبت (writeها همیشه سریال‌اند)
MAX_PARALLEL_READ_TOOLS = 4
# سقف subagent موقت (AGT-06) — فقط چت درون‌برنامه
MAX_SUBAGENTS_PER_PARENT = 2
MAX_SUBAGENT_ITERATIONS = 4
SUBAGENT_TIMEOUT_SEC = 90.0
# providerهایی که tool_choice اجباری را به API می‌فرستند
PROVIDERS_WITH_FORCED_TOOLS = frozenset({"openai", "anthropic"})
# بافر SSE برای Last-Event-ID — حافظه + Redis در صورت فعال بودن
SSE_EVENT_BUFFER_MAX = 400
SSE_EVENT_BUFFER_TTL_SEC = 15 * 60
SSE_EVENT_REDIS_KEY_PREFIX = "hesabix:ai:sse:"
SSE_SCHEMA_VERSION = 1
# اگر producer روی این worker نباشد، RUNNING تازه یعنی هنوز زنده است
LIVE_RUN_STALE_SEC = 180
# کلاینت اگر به این مدت heartbeat نبیند استریم را fail می‌کند
SSE_CLIENT_STALL_SEC = 20
# محدودیت پیام‌ها برای context
MAX_HISTORY_MESSAGES = 40
MAX_SINGLE_MESSAGE_CHARS = 12_000
MAX_SYSTEM_PROMPT_CHARS = 32_000
# دروازهٔ CI برای suite طلایی آفلاین (بدون فراخوانی مدل زنده)
MIN_OFFLINE_EVAL_PASS_RATE = 100
# بودجهٔ تخمینی توکن ورودی (قبل از ارسال به مدل)
CONTEXT_INPUT_TOKEN_BUDGET = 28_000
CONTEXT_SUMMARIZE_THRESHOLD_RATIO = 0.72
CONTEXT_KEEP_RECENT_MESSAGES = 24
CONTEXT_KEEP_HEAD_MESSAGES = 4
# حافظه بلندمدت — فاصلهٔ به‌روزرسانی خودکار (پیام کاربر)
# منسوخ: یادگیری regex دیگر در مسیر production صدا زده نمی‌شود.
AUTO_SUMMARIZE_USER_MESSAGE_INTERVAL = 6
MAX_MEMORY_FEEDBACK_UPDATES_PER_DAY = 8
MAX_LLM_SUMMARIZE_PER_USER_DAY = 24
MAX_LLM_MEMORY_CURATE_PER_USER_DAY = 80
MEMORY_CURATE_MAX_OPS = 4
MEMORY_CURATE_MIN_CONFIDENCE = 0.55
MEMORY_CURATE_MAX_TOKENS = 500
MEMORY_ALWAYS_KIND_CHAR_BUDGET = 2200
MEMORY_RECALL_KIND_CHAR_BUDGET = 1400
MEMORY_RECALL_MAX_ITEMS = 12
# سقف صفحه‌بندی ابزارهای لیست (هم‌تراز QueryInfo.le=100)
AI_LIST_TAKE_MAX = 100
AI_LIST_TAKE_DEFAULT = 50
# حداکثر طول JSON نتیجه tool در پیام role=tool
MAX_TOOL_RESULT_JSON_CHARS = 6_000
# سقف ردیف در envelope ارسالی به مدل (بقیه در summary.total)
MAX_TOOL_RESULT_RECORDS = 15
# کش بینش کسب‌وکار در prompt (ثانیه)
INSIGHTS_CACHE_TTL_SEC = 300
# حداکثر انتظار برای RAG/embedding در ساخت prompt (ثانیه)
KNOWLEDGE_LOAD_TIMEOUT_SEC = 2.5
# TTL کش نتیجه tool در session (ثانیه) — فقط ابزارهای read-only
TOOL_CACHE_TTL_SEC = 60
# حداکثر تعداد رکورد کش per session
TOOL_CACHE_MAX_ENTRIES = 200
# حداقل طول سوال برای فعال‌سازی planning step
PLANNING_STEP_MIN_CHARS = 30
# Retry LLM
MAX_LLM_RETRIES = 3
# حافظه item-based (v2)
MAX_MEMORY_ITEMS_PER_USER = 200
MAX_MEMORY_ITEM_CONTENT_CHARS = 2048
MEMORY_AUTO_APPROVE_CATEGORIES = frozenset({"fact", "term", "preference"})
MEMORY_KINDS = frozenset({
"instruction",
"identity",
"preference",
"context",
"goal",
"constraint",
})
MEMORY_ALWAYS_KINDS = frozenset({"instruction", "identity", "preference", "constraint"})
MEMORY_RECALL_KINDS = frozenset({"context", "goal"})
MEMORY_CURATOR_AUTO_KINDS = frozenset({
"identity",
"preference",
"context",
"goal",
"constraint",
})
# Exploration mode
EXPLORATION_COMPLEXITY_ITERATIONS: dict[str, int] = {
"simple": 4,
"medium": 8,
"complex": 15,
}
EXPLORATION_LLM_THOUGHT_MIN_TOOLS = 2
# ---- بودجهٔ یکپارچهٔ مراحل استدلال (Agent Budget) ----
# سقف چندبعدی برای کنترل «سقف مراحل استدلال»: علاوه بر تعداد نوبت‌ها،
# بودجهٔ توکن کل و سقف زمان دیوار (wall-clock) نیز اعمال می‌شود.
# سقف توکن مصرفی کل (ورودی+خروجی) در یک پاسخ، بر اساس پیچیدگی سوال.
QUERY_COMPLEXITY_TOKEN_BUDGET: dict[str, int] = {
"simple": 24_000,
"medium": 80_000,
"complex": 220_000,
}
# سقف زمان دیوار (ثانیه) برای کل حلقهٔ agent، بر اساس پیچیدگی سوال.
QUERY_COMPLEXITY_WALL_CLOCK_SEC: dict[str, float] = {
"simple": 45.0,
"medium": 120.0,
"complex": 300.0,
}
# توقف زودهنگام: اگر این تعداد نوبت متوالی «بی‌حاصل» (خطا یا بدون دادهٔ جدید)
# رخ دهد، حلقه پیش از رسیدن به سقف متوقف می‌شود.
MAX_UNPRODUCTIVE_ROUNDS = 2
# ---- تمدید پویا بودجه agent (ارزیابی هدف + ضد loop) ----
# وقتی ارزیابی میانی نشان دهد هدف محقق نشده، بودجه تا این حد تمدید می‌شود.
AGENT_BUDGET_EXTENSIONS_MAX = 2
AGENT_BUDGET_EXTENSION_ITERATIONS = 2
AGENT_BUDGET_ABSOLUTE_MAX_ITERATIONS = 15
# بیش از این تکرار همان tool+args با نتیجهٔ موفق → تشخیص loop و توقف تمدید
AGENT_MAX_IDENTICAL_TOOL_REPEATS = 1
# تکرار همان فراخوانی وقتی نتیجه خطا/خالی است؛ سومی حلقه محسوب می‌شود
AGENT_MAX_IDENTICAL_TOOL_FAILURES = 2
# ---- کنترل استدلال درون‌مدلی (reasoning effort) ----
# سطوح مجاز تلاش استدلال برای مدل‌های reasoning (OpenAI o-series/gpt-5 و Anthropic).
REASONING_EFFORT_LEVELS: frozenset[str] = frozenset(
{"minimal", "low", "medium", "high"}
)
# نگاشت سطح تلاش به بودجهٔ توکن تفکر (thinking) برای Anthropic extended thinking.
ANTHROPIC_THINKING_BUDGET_TOKENS: dict[str, int] = {
"minimal": 1_024,
"low": 4_000,
"medium": 10_000,
"high": 24_000,
}
# انتخاب خودکار سطح تلاش استدلال بر اساس پیچیدگی سوال (وقتی مدل reasoning است
# ولی سطح صریحی تنظیم نشده باشد).
REASONING_EFFORT_BY_COMPLEXITY: dict[str, str] = {
"simple": "low",
"medium": "medium",
"complex": "high",
}
# حداکثر انتظار برای هر loader زمینهٔ prompt (ثانیه)
PROMPT_LOADER_TIMEOUT_SEC = 4.0
# حداکثر انتظار برای نوبت اضطراری «سنتز اجباری» (بدون ابزار) وقتی حلقه با
# شواهد explored/thought اما بدون پاسخ متنی تمام شده است (Phase 1).
FORCED_SYNTHESIS_TIMEOUT_SEC = 25.0
# حداقل طول پاسخ متنی برای «کافی بودن» بدون فراخوانی ابزار (agent loop)
SUBSTANTIVE_TEXT_MIN_CHARS = 160
# پاسخ کوتاه‌تر از این — ممکن است یک نوبت دیگر مجاز باشد
TEXT_ANSWER_SHORT_THRESHOLD_CHARS = 80
# ---- Prompt Caching (Provider-level) ----
# فعال‌سازی cache_control (Anthropic) و prompt_cache_key (OpenAI)
PROMPT_CACHE_ENABLED = True
# حداقل توکن تخمینی prefix ثابت برای فعال‌سازی (Anthropic Sonnet ≈1024)
PROMPT_CACHE_MIN_STATIC_TOKENS = 1024
# TTL Anthropic: "5m" (پیش‌فرض) یا "1h"
ANTHROPIC_PROMPT_CACHE_TTL = "5m"
# OpenAI extended retention: "in_memory" (پیش‌فرض) یا "24h"
OPENAI_PROMPT_CACHE_RETENTION = "in_memory"