feat(ai): Phase 24 C — Telegram /ai 動態控制 + Redis 狀態管理
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled

新增 ai_control.py:
- /ai status: 所有 Provider 狀態 + 路由模式
- /ai router on/off: 動態切換 AIRouter (覆蓋 env var)
- /ai primary <provider>: 設定主要 Provider
- /ai enable/disable <provider>: 控制 Provider 啟停
- /ai cost: 費用統計
- 白名單: OPENCLAW_TG_USER_WHITELIST 保護

telegram_gateway.py:
- _handle_chat_message 加入 /ai 指令攔截路由
- 白名單未授權返回警告

openclaw.py:
- Redis 狀態覆蓋 env USE_AI_ROUTER (/ai router on/off 生效)
- Redis primary_provider 覆蓋路由決策 (/ai primary 生效)
- Redis disabled provider 過濾 (/ai disable 生效)

Redis Keys:
  ai:control:use_router
  ai:control:primary_provider
  ai:control:disabled:<provider>

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-03 00:34:14 +08:00
parent b4b3a457c5
commit dbe71f82e3
3 changed files with 330 additions and 4 deletions

View File

@@ -924,8 +924,19 @@ class OpenClawService:
# USE_AI_ROUTER=true → 新 AIRouterExecutor 路由
# USE_AI_ROUTER=false → 舊 if/else fallback chain (現狀)
# 回滾: kubectl set env deployment/awoooi-api USE_AI_ROUTER=false
# Phase 24 C: Redis 狀態覆蓋 env var (/ai router on/off)
# =================================================================
if settings.USE_AI_ROUTER:
# Redis 狀態優先 (Phase 24 C — 2026-04-03 ogt)
_use_ai_router = settings.USE_AI_ROUTER
try:
from src.services.ai_control import get_ai_router_enabled
_redis_override = await get_ai_router_enabled()
if _redis_override is not None:
_use_ai_router = _redis_override
except Exception:
pass
if _use_ai_router:
try:
# 2026-04-02 ogt: C2 修復 — 呼叫 AIRouter.route() 智慧路由 (非靜態 order)
# D1 意圖分類路由、D7 隱私保護 (DIAGNOSE/CODE_REVIEW 強制 local) 生效
@@ -937,10 +948,23 @@ class OpenClawService:
decision = await router.route(prompt, alert_context)
# Step 2: 從 RoutingDecision 建立 provider_order (主 + fallback)
# Phase 24 C: Redis primary_provider 覆蓋路由決策
provider_order = [decision.selected_provider.value] + [
p.value for p, _ in decision.fallback_chain
if p.value != decision.selected_provider.value
]
try:
from src.services.ai_control import get_primary_provider, is_provider_disabled
_primary = await get_primary_provider()
if _primary and _primary != decision.selected_provider.value:
# 把 primary 移到首位 (保留原始 fallback)
provider_order = [_primary] + [p for p in provider_order if p != _primary]
# 過濾被停用的 Provider
_filtered = [p for p in provider_order if not await is_provider_disabled(p)]
if _filtered:
provider_order = _filtered
except Exception:
pass
# Step 3: D7 隱私 — DIAGNOSE/CODE_REVIEW 強制 local
require_local = decision.intent in (IntentType.DIAGNOSE, IntentType.CODE_REVIEW)