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:
+46
-6
@@ -26,6 +26,40 @@ from kilostar.core.individual.regulatory_node.template import (
|
||||
|
||||
chat_router = APIRouter(prefix="/api/v1/chat", tags=["chat"])
|
||||
|
||||
# 单次注入历史的最大轮数(user+assistant 算一轮),防止 token 爆炸。
|
||||
_HISTORY_MAX_TURNS = 20
|
||||
|
||||
|
||||
def _build_message_history(rows) -> list:
|
||||
"""把 DB 中的 ChatHistoryMessage 列表转成 pydantic-ai message_history 格式。
|
||||
|
||||
历史按时间升序,截取末尾最多 _HISTORY_MAX_TURNS*2 条;user 消息映射为
|
||||
``ModelRequest(parts=[UserPromptPart])``,assistant(``regulatory_node``)映射为
|
||||
``ModelResponse(parts=[TextPart])``。其它 owner 跳过。
|
||||
"""
|
||||
from pydantic_ai.messages import (
|
||||
ModelRequest, ModelResponse, UserPromptPart, TextPart,
|
||||
)
|
||||
|
||||
trimmed = rows[-(_HISTORY_MAX_TURNS * 2):]
|
||||
history: list = []
|
||||
for row in trimmed:
|
||||
owner = row.message_owner
|
||||
text = row.message
|
||||
if not text:
|
||||
continue
|
||||
if owner == "user":
|
||||
history.append(ModelRequest(parts=[UserPromptPart(content=text)]))
|
||||
elif owner == "regulatory_node":
|
||||
history.append(ModelResponse(parts=[TextPart(content=text)]))
|
||||
return history
|
||||
|
||||
|
||||
async def _load_message_history(chat_id: str) -> list:
|
||||
postgres_database = ray_actor_hook("postgres_database").postgres_database
|
||||
rows = await postgres_database.list_chat_messages.remote(chat_id=chat_id)
|
||||
return _build_message_history(rows or [])
|
||||
|
||||
|
||||
def _extract_reply(resp: MessageResponse | None) -> str | None:
|
||||
"""从 RegulatoryNode.working 的输出里取出对用户的回复文本。
|
||||
@@ -39,7 +73,7 @@ def _extract_reply(resp: MessageResponse | None) -> str | None:
|
||||
|
||||
|
||||
async def _ask_regulatory(
|
||||
*, user_id: str, chat_id: str, message: str
|
||||
*, user_id: str, chat_id: str, message: str, message_history: list | None = None
|
||||
) -> str | None:
|
||||
"""统一封装 chat 入口对 RegulatoryNode 的调用。"""
|
||||
regulatory_node = ray_actor_hook("regulatory_node").regulatory_node
|
||||
@@ -49,7 +83,9 @@ async def _ask_regulatory(
|
||||
platform_id=chat_id,
|
||||
message=message,
|
||||
)
|
||||
resp: MessageResponse | None = await regulatory_node.working.remote(payload)
|
||||
resp: MessageResponse | None = await regulatory_node.working.remote(
|
||||
payload, message_history
|
||||
)
|
||||
return _extract_reply(resp)
|
||||
|
||||
|
||||
@@ -120,7 +156,8 @@ async def send_chat_message(
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
postgres_database = ray_actor_hook("postgres_database").postgres_database
|
||||
# 存用户消息
|
||||
# 先取历史(不含当前输入),再写入用户消息,避免历史里出现重复
|
||||
message_history = await _load_message_history(chat_id)
|
||||
await postgres_database.add_chat_message.remote(
|
||||
chat_id=chat_id, message=request.message, message_owner="user"
|
||||
)
|
||||
@@ -130,6 +167,7 @@ async def send_chat_message(
|
||||
user_id=token_data.user_id,
|
||||
chat_id=chat_id,
|
||||
message=request.message,
|
||||
message_history=message_history,
|
||||
)
|
||||
|
||||
# 存回复
|
||||
@@ -164,10 +202,12 @@ async def stream_chat_message(
|
||||
token_data: TokenData = Depends(Accessor.get_current_user),
|
||||
):
|
||||
"""SSE 流式聊天端点:standalone 模式下逐 token 流式输出;distributed 模式 fallback 到整段回复。"""
|
||||
from kilostar.utils.standalone_proxy import _STANDALONE
|
||||
from kilostar.utils.ray_compat import _STANDALONE
|
||||
|
||||
postgres_database = ray_actor_hook("postgres_database").postgres_database
|
||||
|
||||
message_history = await _load_message_history(chat_id)
|
||||
|
||||
await postgres_database.add_chat_message.remote(
|
||||
chat_id=chat_id, message=request_body.message, message_owner="user"
|
||||
)
|
||||
@@ -183,7 +223,7 @@ async def stream_chat_message(
|
||||
|
||||
if not _STANDALONE:
|
||||
async def fallback_generator():
|
||||
resp = await regulatory_node.working.remote(payload)
|
||||
resp = await regulatory_node.working.remote(payload, message_history)
|
||||
full_response = resp.reply_message if resp else ""
|
||||
if full_response:
|
||||
await postgres_database.add_chat_message.remote(
|
||||
@@ -195,7 +235,7 @@ async def stream_chat_message(
|
||||
return StreamingResponse(fallback_generator(), media_type="text/event-stream")
|
||||
|
||||
token_queue = asyncio.Queue()
|
||||
stream_task = regulatory_node.stream_working.remote(payload, token_queue)
|
||||
stream_task = regulatory_node.stream_working.remote(payload, token_queue, message_history)
|
||||
|
||||
async def event_generator():
|
||||
full_response = ""
|
||||
|
||||
Reference in New Issue
Block a user