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 啟用,使用雙軌格式