Browse Source

Fix compatibility issues and add model_api tool export

zhangyitian 17 hours ago
parent
commit
5ed8381111
4 changed files with 726 additions and 210 deletions
  1. 638 197
      agent/core/runner.py
  2. 82 12
      agent/tools/builtin/knowledge.py
  3. 4 0
      agent/trace/compaction.py
  4. 2 1
      examples/create/tool/__init__.py

File diff suppressed because it is too large
+ 638 - 197
agent/core/runner.py


+ 82 - 12
agent/tools/builtin/knowledge.py

@@ -6,17 +6,90 @@
 
 import os
 import logging
+import subprocess
 import httpx
+from dataclasses import dataclass
 from typing import List, Dict, Optional, Any
 from agent.tools import tool, ToolResult, ToolContext
+from agent.core.prompts import build_reflect_prompt, COMPLETION_REFLECT_PROMPT
 
 logger = logging.getLogger(__name__)
 
-# KnowHub Server API 地址
-KNOWHUB_API = os.getenv("KNOWHUB_API", "http://43.106.118.91:9999")
+# KnowHub Server API 地址(去除末尾斜杠)
+KNOWHUB_API = os.getenv("KNOWHUB_API", "http://localhost:8000").rstrip("/")
 
 
-@tool(hidden_params=["context"])
+# ===== 知识管理配置 =====
+
+@dataclass
+class KnowledgeConfig:
+    """知识提取与注入的配置"""
+
+    # 压缩时提取(消息量超阈值触发压缩时,在 Level 1 过滤前用完整 history 反思)
+    enable_extraction: bool = True         # 是否在压缩触发时提取知识
+    reflect_prompt: str = ""               # 自定义反思 prompt;空则使用默认,见 agent/core/prompts/knowledge.py:REFLECT_PROMPT
+
+    # agent运行完成后提取(不代表任务完成,agent 可能中途退出等待人工评估)
+    enable_completion_extraction: bool = True      # 是否在运行完成后提取知识
+    completion_reflect_prompt: str = ""            # 自定义复盘 prompt;空则使用默认,见 agent/core/prompts/knowledge.py:COMPLETION_REFLECT_PROMPT
+
+    # 知识注入(agent切换当前工作的goal时,自动注入相关知识)
+    enable_injection: bool = True          # 是否在 focus goal 时自动注入相关知识
+
+    # 默认字段(保存/搜索时自动注入)
+    owner: str = ""                            # 所有者(空则尝试从 git config user.email 获取,再空则用 agent:{agent_id})
+    default_tags: Optional[Dict[str, str]] = None      # 默认 tags(会与工具调用参数合并)
+    default_scopes: Optional[List[str]] = None         # 默认 scopes(空则用 ["org:cybertogether"])
+    default_search_types: Optional[List[str]] = None   # 默认搜索类型过滤
+    default_search_owner: str = ""                     # 默认搜索 owner 过滤(空则不过滤,支持多个owner用逗号分隔,如 "user1@example.com,user2@example.com")
+
+    def get_reflect_prompt(self) -> str:
+        """压缩时反思 prompt"""
+        return self.reflect_prompt if self.reflect_prompt else build_reflect_prompt()
+
+    def get_completion_reflect_prompt(self) -> str:
+        """任务完成后复盘 prompt"""
+        return self.completion_reflect_prompt if self.completion_reflect_prompt else COMPLETION_REFLECT_PROMPT
+
+    @property
+    def resolved_owner(self) -> str:
+        """解析后的 owner(优先级:配置 > git email > 'agent')
+
+        供 inject_params key path 使用:knowledge_config.resolved_owner
+        """
+        if self.owner:
+            return self.owner
+
+        # 尝试从 git config 获取
+        try:
+            result = subprocess.run(
+                ["git", "config", "user.email"],
+                capture_output=True,
+                text=True,
+                timeout=2,
+            )
+            if result.returncode == 0 and result.stdout.strip():
+                return result.stdout.strip()
+        except Exception:
+            pass
+
+        return "agent"
+
+    def get_owner(self, agent_id: str = "agent") -> str:
+        """获取 owner(优先级:配置 > git email > agent:{agent_id})"""
+        owner = self.resolved_owner
+        if owner == "agent" and agent_id != "agent":
+            return f"agent:{agent_id}"
+        return owner
+
+
+@tool(
+    hidden_params=["context"],
+    inject_params={
+        "types": {"mode": "default", "key": "knowledge_config.default_search_types"},
+        "owner": {"mode": "default", "key": "knowledge_config.default_search_owner"},
+    }
+)
 async def knowledge_search(
     query: str,
     top_k: int = 5,
@@ -33,7 +106,7 @@ async def knowledge_search(
         top_k: 返回数量(默认 5)
         min_score: 最低评分过滤(默认 3)
         types: 按类型过滤(user_profile/strategy/tool/usecase/definition/plan)
-        owner: 按所有者过滤(可选)
+        owner: 按所有者过滤(可选,支持多个owner用逗号分隔的字符串,如 "user1@example.com,user2@example.com"
         context: 工具上下文
 
     Returns:
@@ -72,8 +145,8 @@ async def knowledge_search(
             eval_data = item.get("eval", {})
             score = eval_data.get("score", 3)
             output_lines.append(f"\n### {idx}. [{item['id']}] (⭐ {score})")
-            output_lines.append(f"**任务**: {item['task'][:150]}...")
-            output_lines.append(f"**内容**: {item['content'][:200]}...")
+            output_lines.append(f"**任务**: {item['task']}")
+            output_lines.append(f"**内容**: {item['content']}")
 
         return ToolResult(
             title="✅ 知识检索成功",
@@ -98,12 +171,9 @@ async def knowledge_search(
 @tool(
     hidden_params=["context", "owner"],
     inject_params={
-        "owner": lambda ctx: ctx.get("knowledge_config", {}).get("owner") if ctx else None,
-        "tags": lambda ctx, args: {
-            **ctx.get("knowledge_config", {}).get("default_tags", {}),
-            **(args.get("tags") or {})
-        } if ctx else args.get("tags"),
-        "scopes": lambda ctx, args: (args.get("scopes") or []) + (ctx.get("knowledge_config", {}).get("default_scopes") or []) if ctx else args.get("scopes"),
+        "owner": {"mode": "default", "key": "knowledge_config.resolved_owner"},
+        "tags": {"mode": "merge", "key": "knowledge_config.default_tags"},
+        "scopes": {"mode": "merge", "key": "knowledge_config.default_scopes"},
     }
 )
 async def knowledge_save(

+ 4 - 0
agent/trace/compaction.py

@@ -208,6 +208,10 @@ def compress_completed_goals(
     return result
 
 
+# 兼容别名
+filter_by_goal_status = compress_completed_goals
+
+
 # ===== Token 估算 =====
 
 def estimate_tokens(messages: List[Dict[str, Any]]) -> int:

+ 2 - 1
examples/create/tool/__init__.py

@@ -4,5 +4,6 @@ Create 示例的自定义工具
 
 from examples.create.tool.topic_search_image import topic_search_image
 from examples.create.tool.topic_search_video import topic_search_video
+from examples.create.tool.model_api import list_models, deploy_model, inference
 
-__all__ = ["topic_search_image", "topic_search_video"]
+__all__ = ["topic_search_image", "topic_search_video", "list_models", "deploy_model", "inference"]

Some files were not shown because too many files changed in this diff