feat: 工具系统迁移 + 重型插件骨架 + 前端交互增强
- 工具系统从 kilostar/plugin/tool_plugin/ 迁移到 data/toolset/(manifest.json 声明式) - 新增 plugin_runtime 模块:BaseOrganization / GlobalPluginManager / loader / tool_bridge - 新增 org_task + org_task_event 表及 DAO(alembic 0009) - 新增 /api/v1/plugin 路由(submit/status/stream/install/reload) - 新增 data/plugin/example_dept 示例重型插件 - regulatory_node 支持聊天历史上下文注入 - send_file 改为 artifact 存盘 + SSE 推送下载链接 - 前端 WorkflowFileCard 组件 + ToolSettings README 渲染 - utils 整理:合并 access/role_check、standalone_proxy→ray_compat、删除废弃模块 - 项目结构文档移至 docs/STRUCTURE.md 并详细展开 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.responses import StreamingResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
from kilostar.utils.access import Accessor, TokenData
|
||||
from kilostar.utils.ray_hook import ray_actor_hook
|
||||
|
||||
plugin_router = APIRouter(prefix="/api/v1/plugin", tags=["plugin"])
|
||||
|
||||
|
||||
class SubmitRequest(BaseModel):
|
||||
org_name: str
|
||||
task_description: str
|
||||
context: Optional[dict] = None
|
||||
|
||||
|
||||
@plugin_router.post("/submit")
|
||||
async def submit_task(
|
||||
req: SubmitRequest,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
pm = ray_actor_hook("global_plugin_manager").global_plugin_manager
|
||||
plugins = await pm.list_plugins.remote()
|
||||
if req.org_name not in plugins:
|
||||
raise HTTPException(404, f"Plugin '{req.org_name}' not found")
|
||||
|
||||
org = ray_actor_hook(f"org_{req.org_name}").get(f"org_{req.org_name}")
|
||||
ctx = req.context or {}
|
||||
ctx["user"] = token_data.username
|
||||
task_id = await org.submit.remote(req.task_description, ctx)
|
||||
return {"task_id": task_id}
|
||||
|
||||
|
||||
@plugin_router.get("/task/{task_id}")
|
||||
async def get_task_status(
|
||||
task_id: str,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
db = ray_actor_hook("postgres_database").postgres_database
|
||||
task = await db.get_org_task.remote(task_id)
|
||||
if not task:
|
||||
raise HTTPException(404, "Task not found")
|
||||
return task
|
||||
|
||||
|
||||
@plugin_router.get("/task/{task_id}/events")
|
||||
async def get_task_events(
|
||||
task_id: str,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
db = ray_actor_hook("postgres_database").postgres_database
|
||||
events = await db.query_org_events.remote(task_id)
|
||||
return {"events": events}
|
||||
|
||||
|
||||
@plugin_router.get("/task/{task_id}/stream")
|
||||
async def stream_task(
|
||||
task_id: str,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
import asyncio
|
||||
|
||||
org_name = None
|
||||
db = ray_actor_hook("postgres_database").postgres_database
|
||||
task = await db.get_org_task.remote(task_id)
|
||||
if not task:
|
||||
raise HTTPException(404, "Task not found")
|
||||
org_name = task["org_name"]
|
||||
|
||||
org = ray_actor_hook(f"org_{org_name}").get(f"org_{org_name}")
|
||||
|
||||
async def _generate():
|
||||
async for event in await org.stream.remote(task_id):
|
||||
yield f"data: {event}\n\n"
|
||||
|
||||
return StreamingResponse(_generate(), media_type="text/event-stream")
|
||||
|
||||
|
||||
@plugin_router.get("/list")
|
||||
async def list_plugins(
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
pm = ray_actor_hook("global_plugin_manager").global_plugin_manager
|
||||
plugins = await pm.list_plugins.remote()
|
||||
return {"plugins": plugins}
|
||||
|
||||
|
||||
@plugin_router.post("/install")
|
||||
async def install_plugin(
|
||||
name: str,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
pm = ray_actor_hook("global_plugin_manager").global_plugin_manager
|
||||
await pm.install.remote(name)
|
||||
return {"status": "ok", "name": name}
|
||||
|
||||
|
||||
@plugin_router.post("/reload/{name}")
|
||||
async def reload_plugin(
|
||||
name: str,
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
pm = ray_actor_hook("global_plugin_manager").global_plugin_manager
|
||||
await pm.reload.remote(name)
|
||||
return {"status": "ok", "name": name}
|
||||
Reference in New Issue
Block a user