context.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """
  2. 上下文工具 - 刷新当前执行状态并读取授权协议快照
  3. 提供 get_current_context 工具,让 Agent 可以主动获取:
  4. - 当前计划(GoalTree)
  5. - 焦点提醒
  6. - 协作者状态
  7. 框架也会在特定轮次自动调用此工具进行周期性上下文刷新。
  8. """
  9. import json
  10. from cyber_agent.tools import tool, ToolResult, ToolContext
  11. from cyber_agent.core.agent_mode import policy_from_context
  12. from cyber_agent.core.context_policy import (
  13. ContextPolicyError,
  14. get_authorized_context_snapshot,
  15. require_matching_root_task_anchor,
  16. )
  17. @tool(
  18. description="获取当前执行上下文,包括计划状态、焦点提醒、协作者信息等。当你感到困惑或需要回顾当前任务状态时调用。",
  19. hidden_params=["context"],
  20. groups=["core"],
  21. )
  22. async def get_current_context(
  23. context: ToolContext,
  24. ) -> ToolResult:
  25. """
  26. 获取当前执行上下文
  27. Returns:
  28. ToolResult: 包含 GoalTree、焦点提醒、协作者状态等信息
  29. """
  30. runner = context.get("runner")
  31. goal_tree = context.get("goal_tree")
  32. trace_id = context.get("trace_id")
  33. if not runner:
  34. return ToolResult(
  35. title="❌ 无法获取上下文",
  36. output="Runner 未初始化",
  37. error="Runner not available"
  38. )
  39. # 获取 trace 对象
  40. trace = None
  41. if runner.trace_store and trace_id:
  42. trace = await runner.trace_store.get_trace(trace_id)
  43. # Runner 是工具的必需上下文,统一由它渲染 Goal、通知和 Recursive 摘要。
  44. context_content = runner._build_context_injection(trace, goal_tree)
  45. if not context_content:
  46. context_content = "当前无需要刷新的上下文信息"
  47. return ToolResult(
  48. title="📋 当前执行上下文",
  49. output=context_content,
  50. long_term_memory="已刷新执行上下文",
  51. )
  52. @tool(
  53. description="读取当前 Recursive Trace 已获授权的一份不可变协议上下文引用。",
  54. hidden_params=["context"],
  55. groups=["core"],
  56. )
  57. async def read_context_ref(
  58. ref_id: str,
  59. version: str,
  60. context: ToolContext,
  61. ) -> ToolResult:
  62. """读取当前 Trace本地持有的精确 ContextRef版本。
  63. Agent按需调用;工具重新加载持久化 Trace并校验模式、所有者、树归属和内容哈希,
  64. 不接受任意 Trace ID,也不遍历父级、祖先或兄弟。
  65. """
  66. store = context.get("store")
  67. trace_id = context.get("trace_id")
  68. if not store or not trace_id:
  69. return ToolResult(
  70. title="上下文引用读取失败",
  71. output="",
  72. error="store and trace_id are required",
  73. )
  74. trace = await store.get_trace(trace_id)
  75. if not trace:
  76. return ToolResult(
  77. title="上下文引用读取失败",
  78. output="",
  79. error=f"Trace not found: {trace_id}",
  80. )
  81. policy = policy_from_context(trace.context)
  82. if (
  83. not policy.requires_task_protocol
  84. or trace.agent_type == "validator"
  85. or trace.context.get("created_by_tool") == "validator"
  86. ):
  87. return ToolResult(
  88. title="上下文引用读取失败",
  89. output="",
  90. error="read_context_ref requires a writable Recursive business Agent",
  91. )
  92. root_trace_id = trace.context.get("root_trace_id") or trace.trace_id
  93. root = trace if root_trace_id == trace.trace_id else await store.get_trace(
  94. root_trace_id
  95. )
  96. if not root:
  97. return ToolResult(
  98. title="上下文引用读取失败",
  99. output="",
  100. error=f"Recursive root Trace not found: {root_trace_id}",
  101. )
  102. try:
  103. require_matching_root_task_anchor(root.context, trace.context)
  104. snapshot = get_authorized_context_snapshot(
  105. trace.context,
  106. ref_id=ref_id,
  107. version=version,
  108. root_trace_id=root_trace_id,
  109. uid=trace.uid,
  110. )
  111. except ContextPolicyError as exc:
  112. return ToolResult(
  113. title="上下文引用读取失败",
  114. output="",
  115. error=str(exc),
  116. )
  117. payload = {
  118. "ref_id": snapshot.ref_id,
  119. "version": snapshot.version,
  120. "kind": snapshot.kind,
  121. "summary": snapshot.summary,
  122. "source_trace_id": snapshot.source_trace_id,
  123. "content": snapshot.content,
  124. }
  125. return ToolResult(
  126. title="授权上下文引用",
  127. output=json.dumps(
  128. payload,
  129. ensure_ascii=False,
  130. sort_keys=True,
  131. separators=(",", ":"),
  132. ),
  133. long_term_memory=(
  134. f"已读取 {snapshot.kind} 引用 {snapshot.ref_id}@{snapshot.version[:12]}"
  135. ),
  136. )