6d658b4f4d
- 工具系统从 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>
109 lines
3.2 KiB
Python
109 lines
3.2 KiB
Python
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}
|