models.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. """
  2. Tool Models - 工具系统核心数据模型
  3. 定义:
  4. 1. ToolResult: 工具执行结果(支持双层记忆管理)
  5. 2. ToolContext: 工具执行上下文(依赖注入)
  6. """
  7. from dataclasses import dataclass, field
  8. from typing import Any, Dict, List, Optional, Protocol
  9. @dataclass
  10. class ToolResult:
  11. """
  12. 工具执行结果
  13. 支持双层记忆管理(参考 Browser-Use 的 ActionResult):
  14. - output: 主要输出,可能很长,可以配置只给 LLM 看一次
  15. - long_term_memory: 简短摘要,永久保存在对话历史中
  16. 这种设计避免了大量临时内容占用 context。
  17. """
  18. # 主要输出(临时内容)
  19. title: str # 简短标题,用于展示
  20. output: str # 主要输出内容
  21. # 记忆管理
  22. long_term_memory: Optional[str] = None # 永久记忆(简短摘要)
  23. include_output_only_once: bool = False # output 是否只给 LLM 看一次
  24. # 元数据
  25. metadata: Dict[str, Any] = field(default_factory=dict)
  26. # 状态标志
  27. truncated: bool = False # 输出是否被截断
  28. error: Optional[str] = None # 错误信息(如果执行失败)
  29. # 附件支持(用于浏览器自动化等场景)
  30. attachments: List[str] = field(default_factory=list) # 文件路径列表
  31. images: List[Dict[str, Any]] = field(default_factory=list) # 图片列表
  32. artifact_refs: List[Dict[str, Any]] = field(default_factory=list) # Validator可解析的标准只读产物引用
  33. # Token追踪(用于工具内部LLM调用)
  34. tool_usage: Optional[Dict[str, Any]] = None # 格式:{"model": "...", "prompt_tokens": 100, "completion_tokens": 50, "cost": 0.0}
  35. def to_llm_message(self, first_time: bool = True) -> str:
  36. """
  37. 转换为给 LLM 的消息
  38. Args:
  39. first_time: 是否第一次展示(影响 include_output_only_once 的行为)
  40. Returns:
  41. 给 LLM 的消息字符串
  42. """
  43. # 如果有错误,优先返回错误
  44. if self.error:
  45. return f"Error: {self.error}"
  46. # 构建消息
  47. parts = []
  48. # 标题
  49. if self.title:
  50. parts.append(f"# {self.title}")
  51. # 主要输出
  52. if first_time or not self.include_output_only_once:
  53. if self.output:
  54. parts.append(self.output)
  55. if self.truncated:
  56. parts.append("(Output truncated)")
  57. # 长期记忆(永远包含)
  58. if self.long_term_memory:
  59. parts.append(f"\nSummary: {self.long_term_memory}")
  60. # 附件信息
  61. if self.attachments:
  62. parts.append(f"\nAttachments: {', '.join(self.attachments)}")
  63. return "\n\n".join(parts)
  64. class ToolContext(Protocol):
  65. """
  66. 工具执行上下文(依赖注入)
  67. 工具函数可以声明需要哪些上下文字段,框架自动注入。
  68. 使用 Protocol 允许不同实现提供不同的上下文字段。
  69. """
  70. # 基础字段(所有工具都可用)
  71. trace_id: str
  72. step_id: str
  73. uid: Optional[str]
  74. # 浏览器相关(Browser-Use 集成)
  75. browser_session: Optional[Any] # BrowserSession 实例
  76. page_url: Optional[str] # 当前页面 URL
  77. file_system: Optional[Any] # FileSystem 实例
  78. sensitive_data: Optional[Dict[str, Any]] # 敏感数据字典
  79. # 其他可扩展字段
  80. context: Optional[Dict[str, Any]] # 额外上下文数据
  81. @dataclass
  82. class ToolContextImpl:
  83. """ToolContext 的默认实现"""
  84. # 基础字段
  85. trace_id: str
  86. step_id: str
  87. uid: Optional[str] = None
  88. # 浏览器相关
  89. browser_session: Optional[Any] = None
  90. page_url: Optional[str] = None
  91. file_system: Optional[Any] = None
  92. sensitive_data: Optional[Dict[str, Any]] = None
  93. # 额外上下文
  94. context: Optional[Dict[str, Any]] = None