From d1fb3aa0109cb713c773eff8feaae17bfea0e6f0 Mon Sep 17 00:00:00 2001 From: OG T Date: Mon, 23 Mar 2026 14:15:49 +0800 Subject: [PATCH] fix(api): Expand Chinese action parsing for K8s executor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 擴展...副本數 pattern (scale variant) - Add 重新啟動 without 服務 suffix - Auto-detect StatefulSet Pod names (xxx-N) for DELETE_POD - Strip -deployment suffix from resource names Fixes Y button execution failure when LLM generates Chinese actions Co-Authored-By: Claude Opus 4.5 --- apps/api/src/api/v1/approvals.py | 44 +++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/api/src/api/v1/approvals.py b/apps/api/src/api/v1/approvals.py index 4f3c01a1a..500300448 100644 --- a/apps/api/src/api/v1/approvals.py +++ b/apps/api/src/api/v1/approvals.py @@ -101,11 +101,22 @@ def parse_operation_from_action(action: str) -> tuple[OperationType | None, str "Scale deployment web-frontend to 5 replicas" → (SCALE_DEPLOYMENT, "web-frontend", "default") + "重新啟動 awoooi-worker 服務" + → (RESTART_DEPLOYMENT, "awoooi-worker", "default") + Returns: (operation_type, resource_name, namespace) """ action_lower = action.lower() + # Pattern: kubectl rollout restart deployment/ + kubectl_restart_match = re.search(r'kubectl\s+rollout\s+restart\s+deployment/([a-z0-9][\w.-]*)', action_lower) + if kubectl_restart_match: + deploy_name = kubectl_restart_match.group(1) + ns_match = re.search(r'-n\s+(\S+)', action_lower) + namespace = ns_match.group(1) if ns_match else "default" + return OperationType.RESTART_DEPLOYMENT, deploy_name, namespace + # Pattern: kubectl delete pod delete_pod_match = re.search(r'delete\s+pod[:\s]+([a-z0-9][\w.-]*)', action_lower) if delete_pod_match: @@ -115,7 +126,7 @@ def parse_operation_from_action(action: str) -> tuple[OperationType | None, str namespace = ns_match.group(1) if ns_match else "default" return OperationType.DELETE_POD, pod_name, namespace - # Pattern: restart deployment + # Pattern: restart deployment (English) restart_match = re.search(r'restart\s+(?:deployment[:\s]+)?([a-z0-9][\w.-]*)', action_lower) if restart_match: deploy_name = restart_match.group(1) @@ -123,6 +134,12 @@ def parse_operation_from_action(action: str) -> tuple[OperationType | None, str namespace = ns_match.group(1) if ns_match else "default" return OperationType.RESTART_DEPLOYMENT, deploy_name, namespace + # Pattern: 重新啟動 服務 (Chinese) + chinese_restart_match = re.search(r'重新啟動\s+([a-z0-9][\w.-]*)\s*服務', action) + if chinese_restart_match: + deploy_name = chinese_restart_match.group(1) + return OperationType.RESTART_DEPLOYMENT, deploy_name, "default" + # Pattern: scale deployment scale_match = re.search(r'scale\s+(?:deployment[:\s]+)?([a-z0-9][\w.-]*)', action_lower) if scale_match: @@ -131,6 +148,31 @@ def parse_operation_from_action(action: str) -> tuple[OperationType | None, str namespace = ns_match.group(1) if ns_match else "default" return OperationType.SCALE_DEPLOYMENT, deploy_name, namespace + # Pattern: 擴容 (Chinese scale) + chinese_scale_match = re.search(r'擴容\s+([a-z0-9][\w.-]*)', action) + if chinese_scale_match: + deploy_name = chinese_scale_match.group(1) + return OperationType.SCALE_DEPLOYMENT, deploy_name, "default" + + # Pattern: 擴展 副本數 (Chinese scale variant) + chinese_scale2_match = re.search(r'擴展\s+([a-z0-9][\w.-]*)\s*副本', action) + if chinese_scale2_match: + deploy_name = chinese_scale2_match.group(1) + # 移除常見的後綴如 -deployment + deploy_name = re.sub(r'-deployment$', '', deploy_name) + return OperationType.SCALE_DEPLOYMENT, deploy_name, "default" + + # Pattern: 重新啟動 (Chinese restart without 服務) + chinese_restart2_match = re.search(r'重新啟動\s+([a-z0-9][\w.-]*)', action) + if chinese_restart2_match: + resource_name = chinese_restart2_match.group(1) + # StatefulSet Pod 格式: name-N (如 postgres-primary-0) + if re.match(r'.*-\d+$', resource_name): + return OperationType.DELETE_POD, resource_name, "default" + # 移除常見的後綴 + deploy_name = re.sub(r'-deployment$', '', resource_name) + return OperationType.RESTART_DEPLOYMENT, deploy_name, "default" + return None, None, "default"