diff --git a/apps/api/src/services/ai_providers/nemotron.py b/apps/api/src/services/ai_providers/nemotron.py index 9140c8b2..c4c63b32 100644 --- a/apps/api/src/services/ai_providers/nemotron.py +++ b/apps/api/src/services/ai_providers/nemotron.py @@ -220,10 +220,21 @@ class NemotronProvider: validation_status = "✅ 驗證通過" if validation_passed and tools else "❌ 驗證失敗" + # 2026-04-09 Claude Sonnet 4.6: 記錄 tool calling 使用的模型和後端 + from src.services.nvidia_provider import OllamaToolProvider + if isinstance(nvidia, OllamaToolProvider): + tool_model = settings.OLLAMA_TOOL_MODEL # e.g. "llama3.1:8b" + tool_backend = "Ollama 本機" + else: + tool_model = "nemotron-mini-4b-instruct" + tool_backend = "NVIDIA 雲端" + payload = { "tools": tools, "validation": validation_status, "latency_ms": latency_ms, + "tool_model": tool_model, + "tool_backend": tool_backend, } logger.info( diff --git a/apps/api/src/services/decision_manager.py b/apps/api/src/services/decision_manager.py index c085a19c..c8b08676 100644 --- a/apps/api/src/services/decision_manager.py +++ b/apps/api/src/services/decision_manager.py @@ -151,6 +151,9 @@ async def _push_decision_to_telegram( nemotron_tools = proposal_data.get("nemotron_tools") nemotron_validation = proposal_data.get("nemotron_validation", "") nemotron_latency_ms = proposal_data.get("nemotron_latency_ms", 0.0) + # 2026-04-09 Claude Sonnet 4.6: Tool Calling 模型/後端 + nemotron_tool_model = proposal_data.get("nemotron_tool_model", "") + nemotron_tool_backend = proposal_data.get("nemotron_tool_backend", "") # 建立 approval_id (使用 incident_id 作為追蹤) # 2026-03-27 ogt: 修復 INC-INC-INC- 重複前綴 bug @@ -173,6 +176,8 @@ async def _push_decision_to_telegram( nemotron_tools=nemotron_tools, nemotron_validation=nemotron_validation, nemotron_latency_ms=nemotron_latency_ms, + nemotron_tool_model=nemotron_tool_model, + nemotron_tool_backend=nemotron_tool_backend, # 2026-04-05 Claude Code: 傳入 incident_id 以啟用 detail/reanalyze/history 按鈕 incident_id=incident.incident_id, ) diff --git a/apps/api/src/services/openclaw.py b/apps/api/src/services/openclaw.py index e56b859a..ff78140a 100644 --- a/apps/api/src/services/openclaw.py +++ b/apps/api/src/services/openclaw.py @@ -1554,6 +1554,8 @@ Focus on: proposal["nemotron_tools"] = nemotron_result.get("tools", []) proposal["nemotron_validation"] = nemotron_result.get("validation", "⏳ 驗證中") proposal["nemotron_latency_ms"] = nemotron_result.get("latency_ms", 0.0) + proposal["nemotron_tool_model"] = nemotron_result.get("tool_model", "") + proposal["nemotron_tool_backend"] = nemotron_result.get("tool_backend", "") logger.info( "nemotron_collaboration_complete", @@ -1600,6 +1602,8 @@ Focus on: proposal["nemotron_tools"] = gemini_fallback_result.get("tools", []) proposal["nemotron_validation"] = gemini_fallback_result.get("validation", "⚠️ Gemini 代理") proposal["nemotron_latency_ms"] = gemini_fallback_result.get("latency_ms", 0.0) + proposal["nemotron_tool_model"] = "gemini-fallback" + proposal["nemotron_tool_backend"] = "Gemini 雲端" return proposal, provider, True diff --git a/apps/api/src/services/telegram_gateway.py b/apps/api/src/services/telegram_gateway.py index 885bb4b1..9988654e 100644 --- a/apps/api/src/services/telegram_gateway.py +++ b/apps/api/src/services/telegram_gateway.py @@ -170,6 +170,8 @@ class TelegramMessage: # 2026-03-31 Claude Code: OpenClaw + Nemotron 雙軌顯示 # ========================================================================== nemotron_enabled: bool = False # 是否啟用 Nemotron 協作 + nemotron_tool_model: str = "" # Tool Calling 模型 (e.g. "llama3.1:8b") + nemotron_tool_backend: str = "" # Tool Calling 後端 (e.g. "Ollama 本機" / "NVIDIA 雲端") nemotron_tools: list[dict] | None = None # Tool Calling 結果 [{"tool": str, "args": dict, "valid": bool}] nemotron_validation: str = "" # "✅ 驗證通過" / "❌ 驗證失敗" / "⏳ 驗證中" nemotron_latency_ms: float = 0.0 # Nemotron 呼叫延遲 (ms) @@ -396,13 +398,13 @@ class TelegramMessage: source_label = "⚙️ 規則匹配" # Nemotron 區塊 + # 2026-04-09 Claude Sonnet 4.6: 顯示 AI 鏈路 — OpenClaw 用哪個模型,Tool Calling 用哪個模型 nemotron_block = "" if self.nemotron_enabled and self.nemotron_tools: tools_lines = [] for t in self.nemotron_tools[:3]: # 最多顯示 3 個 valid_emoji = "✅" if t.get("valid", False) else "❌" tool_name = html.escape(str(t.get("tool", "unknown"))[:20]) - # 2026-04-05 ogt: 格式化 args 為可讀的 key=value,而非 Python dict 字串 args = t.get("args", {}) if isinstance(args, dict) and args: args_str = ", ".join(f"{k}={v}" for k, v in list(args.items())[:2]) @@ -414,14 +416,23 @@ class TelegramMessage: tools_str = "\n".join(tools_lines) validation_display = html.escape(self.nemotron_validation or "⏳ 驗證中") + # Tool Calling 模型/後端標籤 + if self.nemotron_tool_model and self.nemotron_tool_backend: + tool_model_label = f"{html.escape(self.nemotron_tool_model)} ({html.escape(self.nemotron_tool_backend)})" + elif self.nemotron_tool_model: + tool_model_label = f"{html.escape(self.nemotron_tool_model)}" + else: + tool_model_label = "Nemotron" + + latency_line = f"└ 延遲: {self.nemotron_latency_ms:.0f}ms\n" if self.nemotron_latency_ms > 0 else "" + nemotron_block = ( f"━━━━━━━━━━━━━━━━━━━\n" - f"🔧 Nemotron 執行方案\n" + f"🔧 Tool Calling: {tool_model_label}\n" f"{tools_str}\n" f"└ 驗證: {validation_display}\n" + f"{latency_line}" ) - if self.nemotron_latency_ms > 0: - nemotron_block += f"└ 延遲: {self.nemotron_latency_ms:.0f}ms\n" # 2026-04-05 Claude Code: 重設計訊息格式,提升易讀性 # 組裝訊息 @@ -1327,6 +1338,9 @@ class TelegramGateway: nemotron_tools: list[dict] | None = None, nemotron_validation: str = "", nemotron_latency_ms: float = 0.0, + # 2026-04-09 Claude Sonnet 4.6: Tool Calling 模型/後端顯示 + nemotron_tool_model: str = "", + nemotron_tool_backend: str = "", # 2026-04-05 Claude Code: incident_id 用於 detail/reanalyze/history 按鈕 incident_id: str = "", ) -> dict: @@ -1399,6 +1413,9 @@ class TelegramGateway: nemotron_tools=nemotron_tools, nemotron_validation=nemotron_validation, nemotron_latency_ms=nemotron_latency_ms, + # 2026-04-09 Claude Sonnet 4.6: Tool Calling 模型/後端 + nemotron_tool_model=nemotron_tool_model, + nemotron_tool_backend=nemotron_tool_backend, ) # 格式化訊息 — Phase 22: 如果 Nemotron 啟用,使用雙軌格式