diff --git a/backend/app/api/endpoints/ai_sessions.py b/backend/app/api/endpoints/ai_sessions.py index b5420787..4ffd7097 100644 --- a/backend/app/api/endpoints/ai_sessions.py +++ b/backend/app/api/endpoints/ai_sessions.py @@ -517,11 +517,18 @@ async def save_task_lane( if session.user_id != current_user.id: raise HTTPException(status_code=403, detail="Not your session") - session.pending_task_lane = { + payload = { "questions": [q.model_dump() for q in body.questions], "actions": [a.model_dump() for a in body.actions], "responses": body.responses, } + + # Guard against oversized payloads (max 256KB serialized) + import json + if len(json.dumps(payload)) > 256 * 1024: + raise HTTPException(status_code=413, detail="Task lane payload too large") + + session.pending_task_lane = payload await db.commit() diff --git a/backend/app/schemas/ai_session.py b/backend/app/schemas/ai_session.py index 23bfd652..fd37fde6 100644 --- a/backend/app/schemas/ai_session.py +++ b/backend/app/schemas/ai_session.py @@ -289,10 +289,11 @@ class ChatMessageResponse(BaseModel): class SaveTaskLaneRequest(BaseModel): """Save the full task lane state (AI items + user responses).""" - questions: list[QuestionItem] = [] - actions: list[ActionItem] = [] + questions: list[QuestionItem] = Field(default_factory=list, max_length=50) + actions: list[ActionItem] = Field(default_factory=list, max_length=50) responses: list[dict[str, Any]] = Field( default_factory=list, + max_length=100, description="User's in-progress task responses with state/value", )