feat(memory): P1 长期记忆升级 —— 异步攒批 Consolidate + 软删 + importance/last_seen #1
@@ -101,16 +101,26 @@ type toolCatalogEntry struct {
|
|||||||
Inject []string `json:"inject"`
|
Inject []string `json:"inject"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// agentTools 动态构建 ReAct 可用的工具集:调 MCP list_tools 自描述目录 → 取 agent_exposed 的工具
|
// agentTools 动态构建 ReAct 可用的工具集:分别向 mcp-go / mcp-py 探 list_tools 自描述目录,
|
||||||
// → 用上报的参数 schema 建 InvokableTool;inject 参数(user_id/session_id/kb/task_id)服务端运行时
|
// 取 agent_exposed 的工具按上报参数 schema 建 InvokableTool;inject 参数(user_id/session_id/
|
||||||
// 绑定、不暴露给模型。新增工具只需在 mcp-go 注册表标 agent,无需改这里(杜绝硬编码)。
|
// kb/task_id)服务端运行时绑定、不暴露给模型。某台 MCP 离线即跳过(降级)。
|
||||||
|
// 新增工具只需在对应 MCP 注册表标 agent,无需改这里(杜绝硬编码)。
|
||||||
func (o *Orchestrator) agentTools(b *board, taskID string, tr *execTracer) []tool.BaseTool {
|
func (o *Orchestrator) agentTools(b *board, taskID string, tr *execTracer) []tool.BaseTool {
|
||||||
if o.tools == nil {
|
if o.tools == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
var out []tool.BaseTool
|
||||||
|
out = append(out, o.discoverTools(contract.ToolSubjectGo, b, taskID, tr)...)
|
||||||
|
out = append(out, o.discoverTools(contract.ToolSubjectPy, b, taskID, tr)...)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// discoverTools 向某台 MCP(subject 前缀决定 go/py)探 list_tools,把 agent_exposed 的工具
|
||||||
|
// 转成 Eino InvokableTool。该 MCP 不可用 / 无应答时返回空(不阻断)。
|
||||||
|
func (o *Orchestrator) discoverTools(subject func(string) string, b *board, taskID string, tr *execTracer) []tool.BaseTool {
|
||||||
cctx, cancel := context.WithTimeout(context.Background(), toolCallTimeout)
|
cctx, cancel := context.WithTimeout(context.Background(), toolCallTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
res, err := o.tools.CallTool(cctx, contract.ToolSubjectGo("list_tools"), &contract.ToolCall{Tool: "list_tools"})
|
res, err := o.tools.CallTool(cctx, subject("list_tools"), &contract.ToolCall{Tool: "list_tools"})
|
||||||
if err != nil || res == nil || !res.OK {
|
if err != nil || res == nil || !res.OK {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -120,7 +130,6 @@ func (o *Orchestrator) agentTools(b *board, taskID string, tr *execTracer) []too
|
|||||||
if json.Unmarshal([]byte(res.Content), &cat) != nil {
|
if json.Unmarshal([]byte(res.Content), &cat) != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// inject 参数名 → 本任务的运行时值(不进模型菜单)。
|
|
||||||
injectVal := map[string]any{"user_id": b.uid, "session_id": b.sid, "task_id": taskID, "kb": b.kb}
|
injectVal := map[string]any{"user_id": b.uid, "session_id": b.sid, "task_id": taskID, "kb": b.kb}
|
||||||
|
|
||||||
var out []tool.BaseTool
|
var out []tool.BaseTool
|
||||||
@@ -144,7 +153,7 @@ func (o *Orchestrator) agentTools(b *board, taskID string, tr *execTracer) []too
|
|||||||
}
|
}
|
||||||
out = append(out, &mcpTool{
|
out = append(out, &mcpTool{
|
||||||
mcpName: e.Name,
|
mcpName: e.Name,
|
||||||
subject: contract.ToolSubjectGo,
|
subject: subject,
|
||||||
caller: o.tools, taskID: taskID, tr: tr,
|
caller: o.tools, taskID: taskID, tr: tr,
|
||||||
bind: bind,
|
bind: bind,
|
||||||
info: &schema.ToolInfo{
|
info: &schema.ToolInfo{
|
||||||
|
|||||||
@@ -25,12 +25,18 @@ log = logging.getLogger("mcp_py")
|
|||||||
SUBJECT_PY_ALL = "sundynix.tools.py.>"
|
SUBJECT_PY_ALL = "sundynix.tools.py.>"
|
||||||
QUEUE_PY = "mcp-py-workers"
|
QUEUE_PY = "mcp-py-workers"
|
||||||
|
|
||||||
# 工具元信息:名称 → (中文名, 作用简述)。list_tools 据此上报给管理端展示。
|
# 工具元信息(与 mcp-go 注册表同形):list_tools 上报给管理端展示 + dispatcher 动态构建自主 agent 工具集。
|
||||||
|
# agent=是否暴露给自主 agent;params=模型可填参数;inject=服务端注入参数(不暴露给模型)。
|
||||||
TOOL_META = {
|
TOOL_META = {
|
||||||
"echo": ("回显", "原样返回入参(调试用)"),
|
"echo": {"cn": "回显", "desc": "原样返回入参(调试用)"},
|
||||||
"run_code": ("代码执行", "静态守卫 + Docker 隔离沙箱运行代码(标准档 256m/10s)"),
|
"run_code": {
|
||||||
"parse_document": ("文档解析", "文件 → 纯文本(MinerU / PaddleOCR)"),
|
"cn": "代码执行",
|
||||||
"secure_sandbox": ("安全沙箱", "更严资源档(128m/5s)的隔离执行,用于高风险代码"),
|
"desc": "在隔离沙箱里执行 Python 代码(静态守卫 + Docker,256m/10s)。用于计算、数据处理、逻辑验证。",
|
||||||
|
"agent": True,
|
||||||
|
"params": [{"name": "code", "type": "string", "desc": "要执行的 Python 代码", "required": True}],
|
||||||
|
},
|
||||||
|
"parse_document": {"cn": "文档解析", "desc": "文件 → 纯文本(MinerU / PaddleOCR)"},
|
||||||
|
"secure_sandbox": {"cn": "安全沙箱", "desc": "更严资源档(128m/5s)的隔离执行,用于高风险代码"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,10 +108,18 @@ class McpGateway:
|
|||||||
return str(args.get("text", ""))
|
return str(args.get("text", ""))
|
||||||
|
|
||||||
async def _list_tools(self, args: dict) -> str:
|
async def _list_tools(self, args: dict) -> str:
|
||||||
"""自省:上报业务工具清单(名称 + 中文名 + 作用),供管理端探活 + 展示。"""
|
"""自省:上报业务工具清单(名称/中文名/作用 + agent 暴露元信息),供管理端展示 + dispatcher 动态发现。"""
|
||||||
tools = [
|
tools = [
|
||||||
{"name": n, "cn": cn, "desc": d}
|
{
|
||||||
for n, (cn, d) in TOOL_META.items()
|
"name": n,
|
||||||
|
"cn": m["cn"],
|
||||||
|
"desc": m["desc"],
|
||||||
|
"agent_exposed": m.get("agent", False),
|
||||||
|
"agent_name": m.get("agent_name", ""),
|
||||||
|
"params": m.get("params", []),
|
||||||
|
"inject": m.get("inject", []),
|
||||||
|
}
|
||||||
|
for n, m in TOOL_META.items()
|
||||||
if n in self._tools # 仅上报真正注册的业务工具(list_tools 自身不计入)
|
if n in self._tools # 仅上报真正注册的业务工具(list_tools 自身不计入)
|
||||||
]
|
]
|
||||||
return json.dumps({"service": "mcp-py", "tools": tools})
|
return json.dumps({"service": "mcp-py", "tools": tools})
|
||||||
|
|||||||
Reference in New Issue
Block a user