|
|
@@ -1,5 +1,5 @@
|
|
|
"""
|
|
|
-上下文工具 - 获取当前执行上下文
|
|
|
+上下文工具 - 刷新当前执行状态并读取授权协议快照
|
|
|
|
|
|
提供 get_current_context 工具,让 Agent 可以主动获取:
|
|
|
- 当前计划(GoalTree)
|
|
|
@@ -9,7 +9,15 @@
|
|
|
框架也会在特定轮次自动调用此工具进行周期性上下文刷新。
|
|
|
"""
|
|
|
|
|
|
+import json
|
|
|
+
|
|
|
from cyber_agent.tools import tool, ToolResult, ToolContext
|
|
|
+from cyber_agent.core.agent_mode import policy_from_context
|
|
|
+from cyber_agent.core.context_policy import (
|
|
|
+ ContextPolicyError,
|
|
|
+ get_authorized_context_snapshot,
|
|
|
+ require_matching_root_task_anchor,
|
|
|
+)
|
|
|
|
|
|
|
|
|
@tool(
|
|
|
@@ -42,38 +50,8 @@ async def get_current_context(
|
|
|
if runner.trace_store and trace_id:
|
|
|
trace = await runner.trace_store.get_trace(trace_id)
|
|
|
|
|
|
- # 构建上下文内容(复用 runner 的 _build_context_injection 方法)
|
|
|
- if hasattr(runner, '_build_context_injection'):
|
|
|
- context_content = runner._build_context_injection(trace, goal_tree)
|
|
|
- else:
|
|
|
- # Fallback:只返回 GoalTree
|
|
|
- if goal_tree and goal_tree.goals:
|
|
|
- context_content = f"## Current Plan\n\n{goal_tree.to_prompt()}"
|
|
|
- else:
|
|
|
- context_content = "暂无计划信息"
|
|
|
-
|
|
|
- # Fallback 也检查 IM 通知
|
|
|
- im_config = trace.context.get("im_config") if trace else None
|
|
|
- if im_config:
|
|
|
- contact_id = im_config.get("contact_id")
|
|
|
- chat_id = im_config.get("chat_id")
|
|
|
- if contact_id and chat_id:
|
|
|
- try:
|
|
|
- from cyber_agent.tools.builtin.im import chat as im_chat
|
|
|
- notification = im_chat._notifications.get((contact_id, chat_id))
|
|
|
- if notification:
|
|
|
- count = notification.get("count", 0)
|
|
|
- senders = notification.get("from", [])
|
|
|
- senders_str = ", ".join(senders)
|
|
|
- context_content += (
|
|
|
- f"\n\n## IM 消息通知\n\n"
|
|
|
- f"你有 {count} 条新消息,来自: {senders_str}\n"
|
|
|
- f"使用 `im_receive_messages(contact_id=\"{contact_id}\", chat_id=\"{chat_id}\")` 查看消息内容。"
|
|
|
- )
|
|
|
- else:
|
|
|
- context_content += "\n\n## IM 消息通知\n\n暂无新消息"
|
|
|
- except (ImportError, AttributeError):
|
|
|
- pass
|
|
|
+ # Runner 是工具的必需上下文,统一由它渲染 Goal、通知和 Recursive 摘要。
|
|
|
+ context_content = runner._build_context_injection(trace, goal_tree)
|
|
|
|
|
|
if not context_content:
|
|
|
context_content = "当前无需要刷新的上下文信息"
|
|
|
@@ -83,3 +61,91 @@ async def get_current_context(
|
|
|
output=context_content,
|
|
|
long_term_memory="已刷新执行上下文",
|
|
|
)
|
|
|
+
|
|
|
+
|
|
|
+@tool(
|
|
|
+ description="读取当前 Recursive Trace 已获授权的一份不可变协议上下文引用。",
|
|
|
+ hidden_params=["context"],
|
|
|
+ groups=["core"],
|
|
|
+)
|
|
|
+async def read_context_ref(
|
|
|
+ ref_id: str,
|
|
|
+ version: str,
|
|
|
+ context: ToolContext,
|
|
|
+) -> ToolResult:
|
|
|
+ """读取当前 Trace本地持有的精确 ContextRef版本。
|
|
|
+
|
|
|
+ Agent按需调用;工具重新加载持久化 Trace并校验模式、所有者、树归属和内容哈希,
|
|
|
+ 不接受任意 Trace ID,也不遍历父级、祖先或兄弟。
|
|
|
+ """
|
|
|
+ store = context.get("store")
|
|
|
+ trace_id = context.get("trace_id")
|
|
|
+ if not store or not trace_id:
|
|
|
+ return ToolResult(
|
|
|
+ title="上下文引用读取失败",
|
|
|
+ output="",
|
|
|
+ error="store and trace_id are required",
|
|
|
+ )
|
|
|
+ trace = await store.get_trace(trace_id)
|
|
|
+ if not trace:
|
|
|
+ return ToolResult(
|
|
|
+ title="上下文引用读取失败",
|
|
|
+ output="",
|
|
|
+ error=f"Trace not found: {trace_id}",
|
|
|
+ )
|
|
|
+ policy = policy_from_context(trace.context)
|
|
|
+ if (
|
|
|
+ not policy.requires_task_protocol
|
|
|
+ or trace.agent_type == "validator"
|
|
|
+ or trace.context.get("created_by_tool") == "validator"
|
|
|
+ ):
|
|
|
+ return ToolResult(
|
|
|
+ title="上下文引用读取失败",
|
|
|
+ output="",
|
|
|
+ error="read_context_ref is only available to Recursive revision 2 business Agents",
|
|
|
+ )
|
|
|
+ root_trace_id = trace.context.get("root_trace_id") or trace.trace_id
|
|
|
+ root = trace if root_trace_id == trace.trace_id else await store.get_trace(
|
|
|
+ root_trace_id
|
|
|
+ )
|
|
|
+ if not root:
|
|
|
+ return ToolResult(
|
|
|
+ title="上下文引用读取失败",
|
|
|
+ output="",
|
|
|
+ error=f"Recursive root Trace not found: {root_trace_id}",
|
|
|
+ )
|
|
|
+ try:
|
|
|
+ require_matching_root_task_anchor(root.context, trace.context)
|
|
|
+ snapshot = get_authorized_context_snapshot(
|
|
|
+ trace.context,
|
|
|
+ ref_id=ref_id,
|
|
|
+ version=version,
|
|
|
+ root_trace_id=root_trace_id,
|
|
|
+ uid=trace.uid,
|
|
|
+ )
|
|
|
+ except ContextPolicyError as exc:
|
|
|
+ return ToolResult(
|
|
|
+ title="上下文引用读取失败",
|
|
|
+ output="",
|
|
|
+ error=str(exc),
|
|
|
+ )
|
|
|
+ payload = {
|
|
|
+ "ref_id": snapshot.ref_id,
|
|
|
+ "version": snapshot.version,
|
|
|
+ "kind": snapshot.kind,
|
|
|
+ "summary": snapshot.summary,
|
|
|
+ "source_trace_id": snapshot.source_trace_id,
|
|
|
+ "content": snapshot.content,
|
|
|
+ }
|
|
|
+ return ToolResult(
|
|
|
+ title="授权上下文引用",
|
|
|
+ output=json.dumps(
|
|
|
+ payload,
|
|
|
+ ensure_ascii=False,
|
|
|
+ sort_keys=True,
|
|
|
+ separators=(",", ":"),
|
|
|
+ ),
|
|
|
+ long_term_memory=(
|
|
|
+ f"已读取 {snapshot.kind} 引用 {snapshot.ref_id}@{snapshot.version[:12]}"
|
|
|
+ ),
|
|
|
+ )
|