feat: CEO plan preview & confirm before company execution
- Add POST /companies/{id}/plan endpoint for stateless CEO plan preview (no DB write)
- execute()/execute_stream() accept optional confirmed ceo_plan to skip re-planning
- Frontend: plan preview dialog in CompanyBuilder to review/tweak analysis, dept goals & deliverables before running; previewCompanyPlan API with extended timeout
- Grant file_write tool to CEO/CTO presets; add echarts dependency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,9 @@ class DepartmentAdd(BaseModel):
|
||||
|
||||
class ExecuteRequest(BaseModel):
|
||||
project_description: str = Field(..., min_length=1, description="公司级项目目标")
|
||||
ceo_plan: Optional[Dict[str, Any]] = Field(
|
||||
None, description="已确认的 CEO 计划;提供时跳过二次规划,直接据此执行"
|
||||
)
|
||||
|
||||
|
||||
# ─── Endpoints ───
|
||||
@@ -365,6 +368,24 @@ def remove_department(
|
||||
# ─── 项目执行 ───
|
||||
|
||||
|
||||
@router.post("/{company_id}/plan")
|
||||
async def plan_company(
|
||||
company_id: str,
|
||||
body: ExecuteRequest,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""仅生成 CEO 计划供预览/确认,不派发部门、不落库。"""
|
||||
company = db.query(Company).filter(Company.id == company_id).first()
|
||||
if not company:
|
||||
raise HTTPException(status_code=404, detail="公司不存在")
|
||||
orchestrator = CompanyOrchestrator(db, company_id, current_user.id)
|
||||
try:
|
||||
return await orchestrator.preview_plan(body.project_description)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/{company_id}/execute")
|
||||
async def execute_company(
|
||||
company_id: str,
|
||||
@@ -378,7 +399,7 @@ async def execute_company(
|
||||
raise HTTPException(status_code=404, detail="公司不存在")
|
||||
orchestrator = CompanyOrchestrator(db, company_id, current_user.id)
|
||||
try:
|
||||
result = await orchestrator.execute(body.project_description)
|
||||
result = await orchestrator.execute(body.project_description, ceo_plan=body.ceo_plan)
|
||||
return result
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
@@ -400,7 +421,7 @@ async def execute_company_stream(
|
||||
|
||||
async def event_stream():
|
||||
try:
|
||||
async for event in orchestrator.execute_stream(body.project_description):
|
||||
async for event in orchestrator.execute_stream(body.project_description, ceo_plan=body.ceo_plan):
|
||||
yield f"data: {json.dumps(event, ensure_ascii=False)}\n\n"
|
||||
except Exception as e:
|
||||
yield f"data: {json.dumps({'type': 'error', 'message': str(e)}, ensure_ascii=False)}\n\n"
|
||||
|
||||
Reference in New Issue
Block a user