feat: 将项目从nano重命名为beaver并更新相关配置

- 将所有环境变量前缀从NANO_改为BEAVER_
- 更新README.md文档内容,包括项目介绍、组件说明和快速开始指南
- 修改.gitignore文件,添加auth-portal运行时路径排除规则
- 更新app-instance镜像标签从nano/app-instance改为beaver/app-instance
- 增强技能安全检查器,支持工具前缀白名单功能
- 添加技能草稿重新检查安全性API端点
- 扩展证据选择器,收集工具调用名称用于技能学习
- 改进技能合成器,基于实际调用的工具生成工具提示
- 优化路由超时处理机制,增加重试逻辑
- 更新后端架构文档,添加可视化入口和基础概念说明
- 实现在WebSocket消息中传递工具迭代次数信息
This commit is contained in:
2026-05-20 18:01:06 +08:00
parent 3b0af173cc
commit 9d6cde2d23
63 changed files with 4894 additions and 1596 deletions

View File

@ -1437,6 +1437,15 @@ def create_app(
raise HTTPException(status_code=404, detail="Safety report not found")
return report.to_dict()
@app.post("/api/skills/{skill_name}/drafts/{draft_id}/safety")
async def recheck_skill_draft_safety(skill_name: str, draft_id: str, request: Request) -> dict[str, Any]:
loaded = get_agent_service(request).create_loop().boot()
try:
report = loaded.skill_learning_pipeline.check_safety(skill_name, draft_id) # type: ignore[union-attr]
except ValueError as exc:
raise _skill_draft_http_error(exc) from exc
return report.to_dict()
@app.get("/api/skills/{skill_name}/drafts/{draft_id}/eval")
async def get_skill_draft_eval(skill_name: str, draft_id: str, request: Request) -> dict[str, Any]:
loaded = get_agent_service(request).create_loop().boot()
@ -1831,6 +1840,7 @@ def create_app(
"model": _clean_text(payload.get("model")) or None,
"provider_name": _clean_text(payload.get("provider_name")) or None,
"embedding_model": _clean_text(payload.get("embedding_model")) or None,
"max_tool_iterations": _int_or_none(payload.get("max_tool_iterations")),
}
websocket_thinking_enabled = _bool_or_none(payload.get("thinking_enabled"))
if websocket_thinking_enabled is not None:
@ -1844,6 +1854,7 @@ def create_app(
"content": f"Run failed before completion: {exc}",
"session_id": session_id,
"finish_reason": "error",
"tool_iterations": 0,
"metadata": {
"error": str(exc),
"input_metadata": _websocket_input_metadata(payload),
@ -2403,6 +2414,15 @@ def _bool_or_none(value: Any) -> bool | None:
return None
def _int_or_none(value: Any) -> int | None:
if value in (None, ""):
return None
try:
return int(value)
except (TypeError, ValueError):
return None
def _websocket_message_payload(result: Any, *, input_payload: dict[str, Any]) -> dict[str, Any]:
validation_result = getattr(result, "validation_result", None)
task_id = getattr(result, "task_id", None)
@ -2414,6 +2434,7 @@ def _websocket_message_payload(result: Any, *, input_payload: dict[str, Any]) ->
"session_id": getattr(result, "session_id", None),
"run_id": getattr(result, "run_id", None),
"finish_reason": getattr(result, "finish_reason", None),
"tool_iterations": getattr(result, "tool_iterations", 0),
"provider_name": getattr(result, "provider_name", None),
"model": getattr(result, "model", None),
"usage": dict(getattr(result, "usage", {}) or {}),