feat: Provider model_settings 全链路 + 监管节点工具集 + 重型插件注入 + 前端打磨
- Provider model_settings (Provider+Model 级别参数配置): DB JSONB → API → GSM → AgentFactory.resolve → 三节点 agent.run 注入 - 新增 data/toolset/regulatory_toolset/: 监管节点专属工具(query_workflow_status / query_task_list / send_file) - send_file 从 interactive_toolset 迁移至 regulatory_toolset,interactive 仅保留 approval - mcp_helper 合入 GlobalPluginManager dispatch tools - 前端 Provider 弹窗参数设置区加 JSON 编辑器(model_settings) - 前端 Plugin 页面新增"重型插件"Tab(HeavyPluginList 占位) - .gitignore 精简:去除系统默认项,修复 data/ 子目录追踪 - data/toolset/ 与 data/plugin/ 首次纳入版本控制 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
from .query_workflow_status import query_workflow_status
|
||||
from .query_task_list import query_task_list
|
||||
from .send_file import send_file
|
||||
|
||||
__all__ = [
|
||||
"query_workflow_status",
|
||||
"query_task_list",
|
||||
"send_file",
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "监管节点工具集",
|
||||
"version": "0.1.0",
|
||||
"description": "监管节点(regulatory_node)专属能力:查询工作流、查询任务列表、发送文件",
|
||||
"tools": [
|
||||
{
|
||||
"name": "query_workflow_status",
|
||||
"file": "query_workflow_status.py",
|
||||
"is_system": true,
|
||||
"action_scope": ["regulatory_node"],
|
||||
"config_args": {},
|
||||
"category": "system"
|
||||
},
|
||||
{
|
||||
"name": "query_task_list",
|
||||
"file": "query_task_list.py",
|
||||
"is_system": true,
|
||||
"action_scope": ["regulatory_node"],
|
||||
"config_args": {},
|
||||
"category": "system"
|
||||
},
|
||||
{
|
||||
"name": "send_file",
|
||||
"file": "send_file.py",
|
||||
"is_system": true,
|
||||
"action_scope": ["regulatory_node"],
|
||||
"config_args": {},
|
||||
"category": "system"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
"""query_task_list:列出当前用户的所有工作流任务。
|
||||
|
||||
regulatory_node 用以回答"我有哪些任务/正在跑什么"。返回精简后的任务列表,
|
||||
不包含 graph state、context 等大字段。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from kilostar.utils.ray_hook import ray_actor_hook
|
||||
|
||||
|
||||
async def query_task_list(
|
||||
user_id: str,
|
||||
status_filter: Optional[str] = None,
|
||||
limit: int = 20,
|
||||
) -> Dict[str, Any]:
|
||||
"""列出当前用户的工作流任务。
|
||||
|
||||
Args:
|
||||
user_id: 用户 ID(通常由调用方从对话上下文中带入)
|
||||
status_filter: 可选,按状态过滤(pending/running/completed/failed)
|
||||
limit: 最多返回条数,默认 20
|
||||
|
||||
Returns:
|
||||
{
|
||||
"user_id": str,
|
||||
"tasks": [
|
||||
{"trace_id": ..., "title": ..., "status": ..., "command": ..., "created_at": ...}
|
||||
],
|
||||
"total": int
|
||||
}
|
||||
"""
|
||||
pg = ray_actor_hook("postgres_database").postgres_database
|
||||
workflows = await pg.list_workflows.remote(user_id) or []
|
||||
|
||||
tasks: List[Dict[str, Any]] = []
|
||||
for wf in workflows:
|
||||
status = getattr(wf, "status", None)
|
||||
if status_filter and status != status_filter:
|
||||
continue
|
||||
tasks.append(
|
||||
{
|
||||
"trace_id": getattr(wf, "trace_id", None),
|
||||
"title": getattr(wf, "title", None),
|
||||
"status": status,
|
||||
"command": getattr(wf, "command", None),
|
||||
"created_at": str(getattr(wf, "created_at", "")),
|
||||
}
|
||||
)
|
||||
if len(tasks) >= limit:
|
||||
break
|
||||
|
||||
return {
|
||||
"user_id": user_id,
|
||||
"tasks": tasks,
|
||||
"total": len(tasks),
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
"""query_workflow_status:查询某个 trace_id 对应工作流的最近事件。
|
||||
|
||||
regulatory_node 在与用户对话时,可以借此工具回答"我那个任务跑到哪一步了"
|
||||
之类的问题。返回最近 N 条事件 + 当前工作流 status。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from kilostar.utils.ray_hook import ray_actor_hook
|
||||
|
||||
|
||||
async def query_workflow_status(trace_id: str, limit: int = 10) -> Dict[str, Any]:
|
||||
"""查询指定工作流 trace_id 的状态与最近事件。
|
||||
|
||||
Args:
|
||||
trace_id: 工作流追踪 ID
|
||||
limit: 返回最近多少条事件,默认 10
|
||||
|
||||
Returns:
|
||||
{
|
||||
"trace_id": str,
|
||||
"status": str | None, # 工作流当前状态(pending/running/completed/failed)
|
||||
"title": str | None,
|
||||
"recent_events": [ # 最近事件,按时间倒序
|
||||
{"event_type": ..., "level": ..., "message": ..., "node_name": ..., "created_at": ...}
|
||||
]
|
||||
}
|
||||
"""
|
||||
pg = ray_actor_hook("postgres_database").postgres_database
|
||||
|
||||
workflow = await pg.get_workflow.remote(trace_id)
|
||||
events = await pg.query_event_logs.remote(trace_id=trace_id, limit=limit)
|
||||
|
||||
recent: List[Dict[str, Any]] = []
|
||||
for e in events or []:
|
||||
recent.append(
|
||||
{
|
||||
"event_type": getattr(e, "event_type", None),
|
||||
"level": getattr(e, "level", None),
|
||||
"message": getattr(e, "message", None),
|
||||
"node_name": getattr(e, "node_name", None),
|
||||
"created_at": str(getattr(e, "created_at", "")),
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"trace_id": trace_id,
|
||||
"status": getattr(workflow, "status", None) if workflow else None,
|
||||
"title": getattr(workflow, "title", None) if workflow else None,
|
||||
"recent_events": recent,
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
"""send_file:在对话/工作流场景下投递一份文件给用户。
|
||||
|
||||
regulatory_node 直接对话场景下用此工具把生成的文件发给用户:
|
||||
- 工作流场景(带 trace_id):写入 data/artifact/<trace_id>/,前端通过 SSE
|
||||
收到带下载链接的卡片。
|
||||
- 直接对话场景(无 trace_id):退化为把文件内容拼回字符串返回给 agent,
|
||||
让 agent 再以代码块形式吐给用户。
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
from kilostar.utils.ray_hook import ray_actor_hook
|
||||
from kilostar.utils.settings import get_artifact_dir
|
||||
|
||||
|
||||
_SAFE_NAME_RE = re.compile(r"[^A-Za-z0-9._-]+")
|
||||
|
||||
|
||||
def _sanitize_filename(name: str) -> str:
|
||||
name = name.strip().replace("\\", "/").split("/")[-1]
|
||||
name = _SAFE_NAME_RE.sub("_", name)
|
||||
return name or "file"
|
||||
|
||||
|
||||
async def send_file(filename: str, content: str, trace_id: str = "") -> str:
|
||||
"""把 agent 生成的文件作为附件投递给用户。
|
||||
|
||||
Args:
|
||||
filename: 文件名(含扩展名),如 "report.md" / "main.py"
|
||||
content: 文件内容(UTF-8 文本)
|
||||
trace_id: 当前会话/工作流的 trace_id;为空时退化为直接返回内容
|
||||
|
||||
Returns:
|
||||
发送结果说明或文件内容
|
||||
"""
|
||||
if not trace_id:
|
||||
return f"文件 {filename} 内容如下:\n\n```\n{content}\n```"
|
||||
|
||||
safe_name = _sanitize_filename(filename)
|
||||
artifact_id = uuid.uuid4().hex[:12]
|
||||
trace_dir: Path = get_artifact_dir() / trace_id
|
||||
trace_dir.mkdir(parents=True, exist_ok=True)
|
||||
file_path = trace_dir / f"{artifact_id}_{safe_name}"
|
||||
file_path.write_text(content, encoding="utf-8")
|
||||
|
||||
payload = json.dumps(
|
||||
{
|
||||
"type": "file",
|
||||
"filename": safe_name,
|
||||
"artifact_id": artifact_id,
|
||||
"url": f"/api/v1/resource/artifact/{trace_id}/{artifact_id}",
|
||||
"size": len(content.encode("utf-8")),
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
actor_list = ray_actor_hook("global_workflow_manager")
|
||||
await actor_list.global_workflow_manager.put_pending.remote(
|
||||
trace_id, f"__FILE__{payload}"
|
||||
)
|
||||
return f"已发送文件: {safe_name}"
|
||||
Reference in New Issue
Block a user