|
@@ -0,0 +1,204 @@
|
|
|
|
|
+"""
|
|
|
|
|
+人设树常量点检索工具 - 根据人设名称提取所有常量点
|
|
|
|
|
+
|
|
|
|
|
+用于 Agent 执行时自主提取人设树中的常量点。
|
|
|
|
|
+"""
|
|
|
|
|
+
|
|
|
|
|
+import json
|
|
|
|
|
+from pathlib import Path
|
|
|
|
|
+from typing import Any, Dict, List
|
|
|
|
|
+
|
|
|
|
|
+from agent.tools import tool, ToolResult
|
|
|
|
|
+
|
|
|
|
|
+# 人设数据基础路径
|
|
|
|
|
+PERSONA_DATA_BASE_PATH = Path(__file__).parent.parent / "data"
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _extract_constant_points(tree_data: Dict[str, Any], dimension: str, path_prefix: str = "") -> List[Dict[str, Any]]:
|
|
|
|
|
+ """
|
|
|
|
|
+ 递归提取树中所有常量点
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ tree_data: 树节点数据
|
|
|
|
|
+ dimension: 维度类型(形式/实质/意图)
|
|
|
|
|
+ path_prefix: 当前路径前缀
|
|
|
|
|
+
|
|
|
|
|
+ Returns:
|
|
|
|
|
+ 常量点列表
|
|
|
|
|
+ """
|
|
|
|
|
+ constant_points = []
|
|
|
|
|
+
|
|
|
|
|
+ for node_name, node_data in tree_data.items():
|
|
|
|
|
+ # 跳过元数据字段
|
|
|
|
|
+ if node_name.startswith("_"):
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ # 构建当前节点的路径
|
|
|
|
|
+ current_path = f"{path_prefix}>{node_name}" if path_prefix else node_name
|
|
|
|
|
+
|
|
|
|
|
+ # 检查是否为常量点:_type 为 "ID" 且 _is_constant 为 true
|
|
|
|
|
+ if isinstance(node_data, dict):
|
|
|
|
|
+ node_type = node_data.get("_type")
|
|
|
|
|
+ is_constant = node_data.get("_is_constant", False)
|
|
|
|
|
+
|
|
|
|
|
+ if node_type == "ID" and is_constant:
|
|
|
|
|
+ constant_points.append({
|
|
|
|
|
+ "点名称": node_name,
|
|
|
|
|
+ "维度": dimension,
|
|
|
|
|
+ "路径": current_path,
|
|
|
|
|
+ "权重": node_data.get("_persona_weight_score", 0),
|
|
|
|
|
+ "帖子数量": node_data.get("_post_count", 0)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ # 递归处理子节点
|
|
|
|
|
+ if "children" in node_data:
|
|
|
|
|
+ child_points = _extract_constant_points(
|
|
|
|
|
+ node_data["children"],
|
|
|
|
|
+ dimension,
|
|
|
|
|
+ current_path
|
|
|
|
|
+ )
|
|
|
|
|
+ constant_points.extend(child_points)
|
|
|
|
|
+
|
|
|
|
|
+ return constant_points
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _load_persona_tree(persona_name: str) -> Dict[str, List[Dict[str, Any]]]:
|
|
|
|
|
+ """
|
|
|
|
|
+ 加载人设树数据并提取所有常量点
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ persona_name: 人设名称,如 "家有大志"
|
|
|
|
|
+
|
|
|
|
|
+ Returns:
|
|
|
|
|
+ 包含三个维度常量点的字典
|
|
|
|
|
+ """
|
|
|
|
|
+ persona_dir = PERSONA_DATA_BASE_PATH / persona_name / "tree"
|
|
|
|
|
+
|
|
|
|
|
+ if not persona_dir.exists():
|
|
|
|
|
+ return {
|
|
|
|
|
+ "found": False,
|
|
|
|
|
+ "persona_name": persona_name,
|
|
|
|
|
+ "error": f"人设目录不存在: {persona_dir}"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tree_files = {
|
|
|
|
|
+ "形式": persona_dir / "形式_point_tree_how.json",
|
|
|
|
|
+ "实质": persona_dir / "实质_point_tree_how.json",
|
|
|
|
|
+ "意图": persona_dir / "意图_point_tree_how.json"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ all_constant_points = {
|
|
|
|
|
+ "形式": [],
|
|
|
|
|
+ "实质": [],
|
|
|
|
|
+ "意图": []
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ missing_files = []
|
|
|
|
|
+
|
|
|
|
|
+ for dimension, tree_file in tree_files.items():
|
|
|
|
|
+ if not tree_file.exists():
|
|
|
|
|
+ missing_files.append(f"{dimension}_point_tree_how.json")
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ with open(tree_file, 'r', encoding='utf-8') as f:
|
|
|
|
|
+ tree_data = json.load(f)
|
|
|
|
|
+
|
|
|
|
|
+ # 提取该维度的所有常量点
|
|
|
|
|
+ constant_points = _extract_constant_points(tree_data, dimension)
|
|
|
|
|
+ all_constant_points[dimension] = constant_points
|
|
|
|
|
+
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ return {
|
|
|
|
|
+ "found": False,
|
|
|
|
|
+ "persona_name": persona_name,
|
|
|
|
|
+ "error": f"读取文件 {tree_file.name} 失败: {str(e)}"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if missing_files:
|
|
|
|
|
+ return {
|
|
|
|
|
+ "found": False,
|
|
|
|
|
+ "persona_name": persona_name,
|
|
|
|
|
+ "error": f"缺失文件: {', '.join(missing_files)}"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ "found": True,
|
|
|
|
|
+ "persona_name": persona_name,
|
|
|
|
|
+ "constant_points": all_constant_points
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@tool(
|
|
|
|
|
+ description="根据人设名称检索该人设树中的所有常量点(_is_constant=true的点)。",
|
|
|
|
|
+ display={
|
|
|
|
|
+ "zh": {
|
|
|
|
|
+ "name": "人设常量点检索",
|
|
|
|
|
+ "params": {
|
|
|
|
|
+ "persona_name": "人设名称(如:家有大志)",
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+)
|
|
|
|
|
+async def search_person_tree_constants(persona_name: str) -> ToolResult:
|
|
|
|
|
+ """
|
|
|
|
|
+ 根据人设名称检索该人设树中的所有常量点。
|
|
|
|
|
+
|
|
|
|
|
+ 常量点是指人设树中 _type 为 "ID" 且 _is_constant 为 true 的节点。
|
|
|
|
|
+ 这些点代表了该人设的核心特征和固定属性。
|
|
|
|
|
+
|
|
|
|
|
+ Args:
|
|
|
|
|
+ persona_name: 人设名称,如 "家有大志"
|
|
|
|
|
+
|
|
|
|
|
+ Returns:
|
|
|
|
|
+ ToolResult: 包含三个维度(形式、实质、意图)的常量点列表
|
|
|
|
|
+ """
|
|
|
|
|
+ if not persona_name:
|
|
|
|
|
+ return ToolResult(
|
|
|
|
|
+ title="人设常量点检索失败",
|
|
|
|
|
+ output="",
|
|
|
|
|
+ error="请提供人设名称",
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ result = _load_persona_tree(persona_name)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ return ToolResult(
|
|
|
|
|
+ title="人设常量点检索失败",
|
|
|
|
|
+ output="",
|
|
|
|
|
+ error=f"检索异常: {str(e)}",
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ if not result.get("found"):
|
|
|
|
|
+ return ToolResult(
|
|
|
|
|
+ title="人设常量点检索失败",
|
|
|
|
|
+ output="",
|
|
|
|
|
+ error=result.get("error", "未知错误"),
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ constant_points = result["constant_points"]
|
|
|
|
|
+
|
|
|
|
|
+ # 统计信息
|
|
|
|
|
+ total_count = sum(len(points) for points in constant_points.values())
|
|
|
|
|
+
|
|
|
|
|
+ # 格式化输出
|
|
|
|
|
+ output_data = {
|
|
|
|
|
+ "人设名称": persona_name,
|
|
|
|
|
+ "常量点总数": total_count,
|
|
|
|
|
+ "形式常量点": constant_points["形式"],
|
|
|
|
|
+ "实质常量点": constant_points["实质"],
|
|
|
|
|
+ "意图常量点": constant_points["意图"],
|
|
|
|
|
+ "统计": {
|
|
|
|
|
+ "形式点数": len(constant_points["形式"]),
|
|
|
|
|
+ "实质点数": len(constant_points["实质"]),
|
|
|
|
|
+ "意图点数": len(constant_points["意图"])
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ output = json.dumps(output_data, ensure_ascii=False, indent=2)
|
|
|
|
|
+
|
|
|
|
|
+ return ToolResult(
|
|
|
|
|
+ title=f"人设常量点检索 - {persona_name}",
|
|
|
|
|
+ output=output,
|
|
|
|
|
+ long_term_memory=f"检索到 {total_count} 个常量点(形式:{len(constant_points['形式'])},实质:{len(constant_points['实质'])},意图:{len(constant_points['意图'])})",
|
|
|
|
|
+ )
|