Files
multiAgentTry/backend/app/routers/meetings.py
Claude Code 1719d1f1f9 重构 API 路由并新增工作流编排功能
后端:
- 重构 agents, heartbeats, locks, meetings, resources, roles, workflows 路由
- 新增 orchestrator 和 providers 路由
- 新增 CLI 调用器和流程编排服务
- 添加日志配置和依赖项

前端:
- 更新 AgentsPage、SettingsPage、WorkflowPage 页面
- 扩展 api.ts 新增 API 接口

其他:
- 清理测试 agent 数据文件
- 新增示例工作流和项目审计报告

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 16:36:25 +08:00

261 lines
8.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
会议管理 API 路由
接入 MeetingScheduler栅栏同步+ MeetingRecorder会议记录
"""
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import List, Optional
from dataclasses import asdict
from datetime import datetime
from ..services.meeting_scheduler import get_meeting_scheduler
from ..services.meeting_recorder import get_meeting_recorder
router = APIRouter()
class MeetingCreate(BaseModel):
title: str
agenda: Optional[str] = ""
meeting_type: Optional[str] = "design_review"
attendees: List[str] = []
steps: Optional[List[str]] = None
class MeetingWaitRequest(BaseModel):
agent_id: str
timeout: Optional[int] = 300
class DiscussionRequest(BaseModel):
agent_id: str
agent_name: Optional[str] = ""
content: str
step: Optional[str] = ""
class ProgressRequest(BaseModel):
step: str
class FinishRequest(BaseModel):
consensus: Optional[str] = ""
def _meeting_to_dict(meeting) -> dict:
"""将 MeetingInfo 转为前端友好的 dict"""
return {
"meeting_id": meeting.meeting_id,
"title": meeting.title,
"date": meeting.date,
"status": meeting.status,
"attendees": meeting.attendees,
"steps": [
{"step_id": s.step_id, "label": s.label, "status": s.status}
for s in meeting.steps
],
"discussions": [
{
"agent_id": d.agent_id,
"agent_name": d.agent_name,
"content": d.content,
"timestamp": d.timestamp,
"step": d.step
}
for d in meeting.discussions
],
"progress_summary": meeting.progress_summary,
"consensus": meeting.consensus,
"created_at": meeting.created_at,
"ended_at": meeting.ended_at
}
@router.get("")
@router.get("/")
async def list_meetings(date: Optional[str] = None):
"""获取会议列表(默认今天)"""
recorder = get_meeting_recorder()
meetings = await recorder.list_meetings(date)
return {"meetings": [_meeting_to_dict(m) for m in meetings]}
@router.get("/today")
async def list_today_meetings():
"""获取今日会议"""
recorder = get_meeting_recorder()
meetings = await recorder.list_meetings()
return {"meetings": [_meeting_to_dict(m) for m in meetings]}
@router.post("/")
async def create_meeting(meeting: MeetingCreate):
"""创建新会议(同时创建调度记录和会议记录)"""
recorder = get_meeting_recorder()
scheduler = get_meeting_scheduler()
meeting_id = f"meeting-{int(datetime.now().timestamp())}"
# 在调度器中创建(用于栅栏同步)
await scheduler.create_meeting(
meeting_id=meeting_id,
title=meeting.title,
expected_attendees=meeting.attendees
)
# 在记录器中创建(用于记录内容)
meeting_info = await recorder.create_meeting(
meeting_id=meeting_id,
title=meeting.title,
attendees=meeting.attendees,
steps=meeting.steps
)
return _meeting_to_dict(meeting_info)
@router.post("/create")
async def create_meeting_alt(meeting: MeetingCreate):
"""创建会议 API前端使用的端点与 POST / 相同)"""
return await create_meeting(meeting)
@router.get("/{meeting_id}")
async def get_meeting(meeting_id: str, date: Optional[str] = None):
"""获取会议详情"""
recorder = get_meeting_recorder()
meeting_info = await recorder.get_meeting(meeting_id, date)
if not meeting_info:
raise HTTPException(status_code=404, detail="Meeting not found")
return _meeting_to_dict(meeting_info)
@router.get("/{meeting_id}/queue")
async def get_meeting_queue(meeting_id: str):
"""获取会议等待队列"""
scheduler = get_meeting_scheduler()
queue = await scheduler.get_queue(meeting_id)
if not queue:
raise HTTPException(status_code=404, detail="Meeting queue not found")
return {
"meeting_id": queue.meeting_id,
"title": queue.title,
"status": queue.status,
"expected_attendees": queue.expected_attendees,
"arrived_attendees": queue.arrived_attendees,
"missing_attendees": queue.missing_attendees,
"progress": queue.progress,
"is_ready": queue.is_ready
}
@router.post("/{meeting_id}/wait")
async def wait_for_meeting(meeting_id: str, request: MeetingWaitRequest):
"""栅栏同步等待(阻塞直到所有参会者到齐或超时)"""
scheduler = get_meeting_scheduler()
status = await scheduler.wait_for_meeting(
agent_id=request.agent_id,
meeting_id=meeting_id,
timeout=request.timeout or 300
)
return {"meeting_id": meeting_id, "status": status}
@router.post("/{meeting_id}/end")
async def end_meeting(meeting_id: str):
"""结束会议(调度层)"""
scheduler = get_meeting_scheduler()
success = await scheduler.end_meeting(meeting_id)
if not success:
raise HTTPException(status_code=404, detail="Meeting not found")
return {"success": True, "meeting_id": meeting_id}
@router.post("/{meeting_id}/join")
async def join_meeting(meeting_id: str, data: dict):
"""Agent 加入会议"""
agent_id = data.get("agent_id", "")
scheduler = get_meeting_scheduler()
await scheduler.add_attendee(meeting_id, agent_id)
return {"success": True, "meeting_id": meeting_id, "agent_id": agent_id}
@router.post("/{meeting_id}/discuss")
async def add_discussion(meeting_id: str, data: DiscussionRequest):
"""添加讨论内容"""
recorder = get_meeting_recorder()
await recorder.add_discussion(
meeting_id=meeting_id,
agent_id=data.agent_id,
agent_name=data.agent_name or data.agent_id,
content=data.content,
step=data.step or ""
)
return {"success": True, "meeting_id": meeting_id}
@router.post("/{meeting_id}/finish")
async def finish_meeting(meeting_id: str, data: FinishRequest):
"""完成会议(记录层 - 保存共识并标记完成)"""
recorder = get_meeting_recorder()
success = await recorder.end_meeting(
meeting_id=meeting_id,
consensus=data.consensus or ""
)
if not success:
raise HTTPException(status_code=404, detail="Meeting not found")
# 同时结束调度
scheduler = get_meeting_scheduler()
await scheduler.end_meeting(meeting_id)
return {"success": True, "meeting_id": meeting_id}
@router.post("/{meeting_id}/progress")
async def update_progress(meeting_id: str, data: ProgressRequest):
"""更新会议进度"""
recorder = get_meeting_recorder()
await recorder.update_progress(
meeting_id=meeting_id,
step_label=data.step
)
return {"success": True, "meeting_id": meeting_id}
@router.post("/record/create")
async def create_meeting_record(data: dict):
"""创建会议记录(前端使用的端点)"""
recorder = get_meeting_recorder()
meeting_id = data.get("meeting_id", f"meeting-{int(datetime.now().timestamp())}")
meeting_info = await recorder.create_meeting(
meeting_id=meeting_id,
title=data.get("title", "未命名会议"),
attendees=data.get("attendees", []),
steps=data.get("steps", [])
)
# 同时在调度器中注册
scheduler = get_meeting_scheduler()
await scheduler.create_meeting(
meeting_id=meeting_id,
title=data.get("title", "未命名会议"),
expected_attendees=data.get("attendees", [])
)
return _meeting_to_dict(meeting_info)
@router.post("/record/{meeting_id}/discussion")
async def add_meeting_discussion(meeting_id: str, data: dict):
"""添加会议讨论(前端使用的端点)"""
recorder = get_meeting_recorder()
await recorder.add_discussion(
meeting_id=meeting_id,
agent_id=data.get("agent_id", ""),
agent_name=data.get("agent_name", data.get("agent_id", "")),
content=data.get("content", ""),
step=data.get("step", "")
)
return {"success": True, "meeting_id": meeting_id, "discussion": data}