feat: 完善企业场景多线路由与执行稳定性
补齐平台模板与场景 DSL、预算控制、执行看板和企业场景脚本,增强 Windows 启动/迁移与前端代理和聊天会话记忆,修复执行创建阶段 500 与异步链路排障体验。 Made-with: Cursor
This commit is contained in:
@@ -38,6 +38,114 @@ class ExecutionLogResponse(BaseModel):
|
||||
from_attributes = True
|
||||
|
||||
|
||||
def _has_execution_permission(db: Session, execution: Execution, current_user: User) -> bool:
|
||||
if getattr(current_user, "role", None) == "admin":
|
||||
return True
|
||||
if execution.workflow_id:
|
||||
workflow = db.query(Workflow).filter(Workflow.id == execution.workflow_id).first()
|
||||
return bool(workflow and workflow.user_id == current_user.id)
|
||||
if execution.agent_id:
|
||||
agent = db.query(Agent).filter(Agent.id == execution.agent_id).first()
|
||||
return bool(agent and (agent.user_id == current_user.id or agent.status in ["published", "running"]))
|
||||
return False
|
||||
|
||||
|
||||
@router.get("/executions/{execution_id}/chain")
|
||||
async def get_execution_chain(
|
||||
execution_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""获取父子执行链路(当前执行 + 递归子执行)。"""
|
||||
root = db.query(Execution).filter(Execution.id == execution_id).first()
|
||||
if not root:
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
if not _has_execution_permission(db, root, current_user):
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
all_execs = db.query(Execution).all()
|
||||
by_parent: Dict[Optional[str], List[Execution]] = {}
|
||||
for e in all_execs:
|
||||
by_parent.setdefault(e.parent_execution_id, []).append(e)
|
||||
|
||||
def _build_tree(e: Execution) -> Dict[str, Any]:
|
||||
children = by_parent.get(e.id, [])
|
||||
children.sort(key=lambda x: x.created_at or datetime.min)
|
||||
return {
|
||||
"id": e.id,
|
||||
"status": e.status,
|
||||
"workflow_id": e.workflow_id,
|
||||
"agent_id": e.agent_id,
|
||||
"depth": e.depth,
|
||||
"parent_execution_id": e.parent_execution_id,
|
||||
"execution_time": e.execution_time,
|
||||
"created_at": e.created_at.isoformat() if e.created_at else None,
|
||||
"children": [_build_tree(c) for c in children],
|
||||
}
|
||||
|
||||
return _build_tree(root)
|
||||
|
||||
|
||||
@router.get("/executions/{execution_id}/chain/summary")
|
||||
async def get_execution_chain_summary(
|
||||
execution_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""获取父子执行链路汇总(节点数、成功失败数、总耗时)。"""
|
||||
root = db.query(Execution).filter(Execution.id == execution_id).first()
|
||||
if not root:
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
if not _has_execution_permission(db, root, current_user):
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
all_execs = db.query(Execution).all()
|
||||
by_parent: Dict[Optional[str], List[Execution]] = {}
|
||||
by_id: Dict[str, Execution] = {}
|
||||
for e in all_execs:
|
||||
by_parent.setdefault(e.parent_execution_id, []).append(e)
|
||||
by_id[e.id] = e
|
||||
|
||||
stack = [root.id]
|
||||
chain_ids: List[str] = []
|
||||
while stack:
|
||||
cur = stack.pop()
|
||||
chain_ids.append(cur)
|
||||
for c in by_parent.get(cur, []):
|
||||
stack.append(c.id)
|
||||
|
||||
chain_execs = [by_id[i] for i in chain_ids if i in by_id]
|
||||
status_count: Dict[str, int] = {
|
||||
"pending": 0,
|
||||
"running": 0,
|
||||
"completed": 0,
|
||||
"failed": 0,
|
||||
"awaiting_approval": 0,
|
||||
}
|
||||
total_time = 0
|
||||
for e in chain_execs:
|
||||
st = (e.status or "").lower()
|
||||
if st in status_count:
|
||||
status_count[st] += 1
|
||||
if isinstance(e.execution_time, int):
|
||||
total_time += e.execution_time
|
||||
|
||||
max_depth = 0
|
||||
for e in chain_execs:
|
||||
try:
|
||||
max_depth = max(max_depth, int(e.depth or 0))
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
|
||||
return {
|
||||
"root_execution_id": root.id,
|
||||
"total_executions": len(chain_execs),
|
||||
"status_count": status_count,
|
||||
"total_execution_time_ms": total_time,
|
||||
"max_depth": max_depth,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/executions/{execution_id}", response_model=List[ExecutionLogResponse])
|
||||
async def get_execution_logs(
|
||||
execution_id: str,
|
||||
@@ -58,17 +166,7 @@ async def get_execution_logs(
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
# 验证权限:检查workflow或agent的所有权
|
||||
has_permission = False
|
||||
if execution.workflow_id:
|
||||
workflow = db.query(Workflow).filter(Workflow.id == execution.workflow_id).first()
|
||||
if workflow and workflow.user_id == current_user.id:
|
||||
has_permission = True
|
||||
elif execution.agent_id:
|
||||
agent = db.query(Agent).filter(Agent.id == execution.agent_id).first()
|
||||
if agent and (agent.user_id == current_user.id or agent.status in ["published", "running"]):
|
||||
has_permission = True
|
||||
|
||||
if not has_permission:
|
||||
if not _has_execution_permission(db, execution, current_user):
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
# 构建查询
|
||||
@@ -104,17 +202,7 @@ async def get_execution_log_summary(
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
# 验证权限:检查workflow或agent的所有权
|
||||
has_permission = False
|
||||
if execution.workflow_id:
|
||||
workflow = db.query(Workflow).filter(Workflow.id == execution.workflow_id).first()
|
||||
if workflow and workflow.user_id == current_user.id:
|
||||
has_permission = True
|
||||
elif execution.agent_id:
|
||||
agent = db.query(Agent).filter(Agent.id == execution.agent_id).first()
|
||||
if agent and (agent.user_id == current_user.id or agent.status in ["published", "running"]):
|
||||
has_permission = True
|
||||
|
||||
if not has_permission:
|
||||
if not _has_execution_permission(db, execution, current_user):
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
# 统计各级别日志数量
|
||||
@@ -184,17 +272,7 @@ async def get_execution_performance(
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
# 验证权限:检查workflow或agent的所有权
|
||||
has_permission = False
|
||||
if execution.workflow_id:
|
||||
workflow = db.query(Workflow).filter(Workflow.id == execution.workflow_id).first()
|
||||
if workflow and workflow.user_id == current_user.id:
|
||||
has_permission = True
|
||||
elif execution.agent_id:
|
||||
agent = db.query(Agent).filter(Agent.id == execution.agent_id).first()
|
||||
if agent and (agent.user_id == current_user.id or agent.status in ["published", "running"]):
|
||||
has_permission = True
|
||||
|
||||
if not has_permission:
|
||||
if not _has_execution_permission(db, execution, current_user):
|
||||
raise NotFoundError("执行记录", execution_id)
|
||||
|
||||
from sqlalchemy import func
|
||||
|
||||
Reference in New Issue
Block a user