fix(ai): SuggestedAction enum 擴充 + Pydantic fallback 防護
根本原因: NemoTron 輸出 "investigate" → Pydantic 只接受 4 個值 → 爆炸 → openclaw_analysis_parse_failed → analysis_result=None → 全部 fallback 卡片顯示「待分析」 修復: 1. SuggestedAction enum 新增 INVESTIGATE/OBSERVE/APPLY_HPA/TUNE_RESOURCES (prompt.py 列了 6 個,enum 只有 4 個,prompt/model 不同步是根源) 2. normalize_suggested_action validator: uppercase + 別名映射 + 未知值 fallback NO_ACTION 確保任何 LLM 輸出都不會讓 Pydantic 爆炸導致 analysis_result = None Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,11 +19,19 @@ class SuggestedAction(str, Enum):
|
||||
AI 建議操作類型
|
||||
|
||||
必須與 executor.OperationType 對應
|
||||
|
||||
2026-04-17 ogt + Claude Sonnet 4.6: 新增 INVESTIGATE/APPLY_HPA/TUNE_RESOURCES
|
||||
根本原因: prompts.py 列了 6 個值,但 enum 只有 4 個
|
||||
→ NemoTron 輸出 "investigate" → Pydantic 爆炸 → analysis_result = None → 全部 fallback
|
||||
"""
|
||||
RESTART_DEPLOYMENT = "RESTART_DEPLOYMENT"
|
||||
DELETE_POD = "DELETE_POD"
|
||||
SCALE_DEPLOYMENT = "SCALE_DEPLOYMENT"
|
||||
NO_ACTION = "NO_ACTION" # 無需處理
|
||||
APPLY_HPA = "APPLY_HPA"
|
||||
TUNE_RESOURCES = "TUNE_RESOURCES"
|
||||
INVESTIGATE = "INVESTIGATE" # 調查診斷,不下執行指令
|
||||
OBSERVE = "OBSERVE" # 觀察等待
|
||||
NO_ACTION = "NO_ACTION" # 無需處理
|
||||
|
||||
|
||||
class AIRiskLevel(str, Enum):
|
||||
@@ -86,6 +94,7 @@ class OpenClawDecision(BaseModel):
|
||||
...,
|
||||
description="建議執行的操作類型",
|
||||
)
|
||||
|
||||
target_resource: str = Field(
|
||||
...,
|
||||
description="目標資源名稱 (e.g., 'harbor', 'grafana')",
|
||||
@@ -192,9 +201,31 @@ class OpenClawDecision(BaseModel):
|
||||
@field_validator("suggested_action", mode="before")
|
||||
@classmethod
|
||||
def normalize_suggested_action(cls, v):
|
||||
"""正規化 suggested_action"""
|
||||
"""
|
||||
正規化 suggested_action:大小寫 + 別名映射 + 未知值 fallback
|
||||
|
||||
2026-04-17 ogt + Claude Sonnet 4.6(亞太):
|
||||
根本原因: NemoTron 輸出 "investigate"(小寫) → Pydantic 拒絕 → analysis_result = None
|
||||
舊版只做 uppercase,未知值仍爆 → 修復為: 先 uppercase,再別名映射,最後 fallback NO_ACTION
|
||||
"""
|
||||
if isinstance(v, str):
|
||||
return v.upper().replace("-", "_").replace(" ", "_")
|
||||
normalized = v.upper().replace("-", "_").replace(" ", "_")
|
||||
# 別名映射 (LLM 可能輸出非正式名稱)
|
||||
alias_map = {
|
||||
"DIAGNOSE": "INVESTIGATE",
|
||||
"DEBUG": "INVESTIGATE",
|
||||
"MONITOR": "OBSERVE",
|
||||
"WATCH": "OBSERVE",
|
||||
"TUNE": "TUNE_RESOURCES",
|
||||
"HPA": "APPLY_HPA",
|
||||
}
|
||||
normalized = alias_map.get(normalized, normalized)
|
||||
# 未知值 fallback NO_ACTION,絕不讓 Pydantic 爆炸導致 analysis_result = None
|
||||
try:
|
||||
SuggestedAction(normalized)
|
||||
return normalized
|
||||
except ValueError:
|
||||
return "NO_ACTION"
|
||||
return v
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user