005ce566a8
- 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>
64 lines
2.1 KiB
Python
64 lines
2.1 KiB
Python
"""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}"
|