feat(telegram): ADR-019 Phase 3 - feature-flagged agent dispatch for cmd:X
All checks were successful
CD Pipeline / deploy (push) Successful in 2m47s
All checks were successful
CD Pipeline / deploy (push) Successful in 2m47s
ADR-019 Phase 3:在 handle_cmd 入口插入 agent dispatch hook,將白名單 cmd 翻成 NL question 交 OpenClaw agent 處理。Agent 自動透過 Phase 2 的 check_data_freshness tool probe 資料缺口,缺資料時主動詢問用戶,避免靜默產出空白結果。 新增: - 環境變數 OPENCLAW_AGENT_DISPATCH (預設 0)、OPENCLAW_AGENT_DISPATCH_CMDS (逗號分隔) - _CMD_TO_NL 翻譯字典:sales / top / vendor 三 cmd 起步 - _agent_dispatch_cmd() helper:feature flag + 白名單 + agent 呼叫 + 失敗 fallback 設計考量: - 預設 OFF,零 prod regression 風險 - Agent 失敗自動回原 handler,不卡用戶 - 灰度路徑:先在 staging 開 OPENCLAW_AGENT_DISPATCH=1 + CMDS=sales 觀察一週 - 21 cmd 不需要全部翻譯,只翻譯有「資料缺口可能性」或「參數需確認」的 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -119,6 +119,20 @@ _ALLOW_PRIVATE_WITHOUT_WHITELIST = (
|
||||
in {'1', 'true', 'yes', 'on'}
|
||||
)
|
||||
|
||||
# ADR-019 Phase 3: Feature-flagged agent dispatch
|
||||
# 預設 OFF;啟用步驟:
|
||||
# export OPENCLAW_AGENT_DISPATCH=1
|
||||
# export OPENCLAW_AGENT_DISPATCH_CMDS=sales,top,vendor (逗號分隔白名單)
|
||||
# 啟用後白名單內 cmd 改走 OpenClaw NL agent,agent 自決查資料/詢問用戶/答覆
|
||||
_OPENCLAW_AGENT_DISPATCH_ENABLED = (
|
||||
os.getenv('OPENCLAW_AGENT_DISPATCH', '0').strip().lower()
|
||||
in {'1', 'true', 'yes', 'on'}
|
||||
)
|
||||
_AGENT_DISPATCH_CMDS = {
|
||||
c.strip() for c in os.getenv('OPENCLAW_AGENT_DISPATCH_CMDS', '').split(',')
|
||||
if c.strip()
|
||||
}
|
||||
|
||||
# ── fail-closed 統一授權檢查 ───────────────────────────────────
|
||||
# 規則(任一滿足即通過,否則一律拒絕):
|
||||
# 1. group/supergroup 且 chat_id == ALLOWED_GROUP
|
||||
@@ -4530,10 +4544,46 @@ def openclaw_answer(question: str):
|
||||
|
||||
|
||||
# ── 指令處理 ──────────────────────────────────────────────────
|
||||
_CMD_TO_NL = {
|
||||
'sales': lambda a: f"請查 {a or '今日'} 的業績數字(包含營收、訂單數、毛利率)",
|
||||
'top': lambda a: f"請列出 {a or '今日'} 的 TOP10 熱銷商品",
|
||||
'vendor': lambda a: f"請列出 {a or '今日'} 的 TOP10 熱銷廠商",
|
||||
}
|
||||
|
||||
|
||||
def _agent_dispatch_cmd(cmd, arg, chat_id, reply_to) -> bool:
|
||||
"""ADR-019 Phase 3: Feature-flagged. 將白名單 cmd 翻成 NL question 交 agent 處理。
|
||||
|
||||
Agent 自動 probe 資料新鮮度(透過 Phase 2 的 check_data_freshness tool),缺資料時
|
||||
主動詢問用戶。回 True 表示已交 agent 處理,handle_cmd 不再走原 dispatch。
|
||||
回 False 表示維持原行為(含 feature flag 關閉、cmd 不在白名單、agent 失敗等)。
|
||||
"""
|
||||
if not _OPENCLAW_AGENT_DISPATCH_ENABLED:
|
||||
return False
|
||||
if cmd not in _AGENT_DISPATCH_CMDS:
|
||||
return False
|
||||
if cmd not in _CMD_TO_NL:
|
||||
return False # 翻譯規則尚未建立 → 安全降級
|
||||
|
||||
nl_question = _CMD_TO_NL[cmd](arg)
|
||||
try:
|
||||
sys_log.info(f"[AgentDispatch] cmd:{cmd}:{arg or ''} → NL: {nl_question}")
|
||||
txt, kb = openclaw_answer(nl_question)
|
||||
send_message(chat_id, txt, reply_to, keyboard=kb)
|
||||
return True
|
||||
except Exception as e:
|
||||
sys_log.error(f"[AgentDispatch] cmd:{cmd} agent failed, fallback to direct handler: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def handle_cmd(cmd, arg, chat_id, reply_to):
|
||||
ld = latest_date() or datetime.now(TAIPEI_TZ).strftime('%Y/%m/%d')
|
||||
target = normalize_date(arg) if arg else ld
|
||||
|
||||
# ADR-019 Phase 3: agent dispatch hook(feature flag 預設 OFF)
|
||||
if _agent_dispatch_cmd(cmd, arg, chat_id, reply_to):
|
||||
return
|
||||
|
||||
def _send_mcp_text_result(title: str, data, empty_message: str) -> bool:
|
||||
"""相容新版 MCP 文字回傳;已處理則回 True,舊 dict 格式則回 False。"""
|
||||
if isinstance(data, str):
|
||||
|
||||
Reference in New Issue
Block a user