tool_logging.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. """工具调用日志的通用封装。"""
  2. from __future__ import annotations
  3. import json
  4. from typing import Any, Dict
  5. from .log_capture import log, log_fold
  6. def _pretty_json_if_possible(text: str) -> str:
  7. """如果文本是合法 JSON,则返回带缩进的可读格式;否则原样返回。"""
  8. raw = (text or "").strip()
  9. if not raw:
  10. return text
  11. if not (raw.startswith("{") or raw.startswith("[")):
  12. return text
  13. try:
  14. parsed = json.loads(raw)
  15. except Exception:
  16. return text
  17. return json.dumps(parsed, ensure_ascii=False, indent=2)
  18. def format_tool_result_for_log(result: Any) -> str:
  19. """将 ToolResult 或普通字符串格式化为可写入日志的文本(避免过长 metadata 刷屏)。"""
  20. if result is None:
  21. return ""
  22. if isinstance(result, str):
  23. s = result
  24. return s if len(s) <= 8000 else s[:8000] + "\n...(truncated)"
  25. title = getattr(result, "title", "") or ""
  26. output = getattr(result, "output", None) or ""
  27. err = getattr(result, "error", None)
  28. truncated = output if len(output) <= 6000 else output[:6000] + "\n...(truncated)"
  29. payload: Dict[str, Any] = {"title": title, "output": truncated}
  30. if err:
  31. payload["error"] = err
  32. md = getattr(result, "metadata", None)
  33. if isinstance(md, dict) and md:
  34. payload["metadata_keys"] = list(md.keys())
  35. return json.dumps(payload, ensure_ascii=False)
  36. def log_tool_call(tool_name: str, params: Dict[str, Any], result: str) -> None:
  37. """以折叠块结构化输出工具调用参数与返回内容。"""
  38. with log_fold(f"🔧 {tool_name}"):
  39. with log_fold("📥 调用参数"):
  40. log(json.dumps(params, ensure_ascii=False, indent=2))
  41. with log_fold("📤 返回内容"):
  42. log(_pretty_json_if_possible(result))