"""Timeline agent — tool definitions for project milestone CRUD.""" from __future__ import annotations from typing import Any from langchain_core.tools import tool from app.core.ws_context import execute_on_client @tool async def list_timelines(project_id: str = "") -> str: """List timelines. Provide project_id to scope to a specific project.""" result = await execute_on_client( action="select", table="timelines", filters={"projectId": project_id or None}, ) rows = result.get("rows", []) if not rows: return "No timelines found." lines = [f"- {r['title']} (date: {r['date']}, id: {r['id']})" for r in rows] return f"Found {len(rows)} timeline(s):\n" + "\n".join(lines) @tool async def create_timeline( project_id: str, title: str, date: int, is_ai_suggested: int = 0, is_approved: int = 0, ) -> str: """Create a project timeline (milestone). project_id: REQUIRED UUID of the parent project title: descriptive name for the milestone date: Unix timestamp in milliseconds is_ai_suggested: 1 if proactively suggested, 0 if user-requested is_approved: 0 until the user confirms """ result = await execute_on_client( action="insert", table="timelines", data={ "projectId": project_id, "title": title, "date": date, "isAiSuggested": is_ai_suggested, "isApproved": is_approved, }, ) row = result["row"] return f"Timeline created: '{row['title']}' (id: {row['id']}, date: {row['date']})" @tool async def update_timeline( timeline_id: str, title: str = "", date: int = -1, is_approved: int = -1, ) -> str: """Update a timeline. Only pass fields that should change. timeline_id: UUID of the timeline (required) date: -1 means unchanged; any other value sets the new date (ms timestamp) is_approved: -1 means unchanged; 0 or 1 sets the approval state """ updates: dict[str, Any] = {} if title: updates["title"] = title if date != -1: updates["date"] = date if is_approved != -1: updates["isApproved"] = is_approved result = await execute_on_client( action="update", table="timelines", data={"id": timeline_id, "updates": updates}, ) row = result["row"] return f"Timeline updated: '{row['title']}' (id: {row['id']})" @tool async def delete_timeline(timeline_id: str) -> str: """Delete a timeline permanently by its UUID.""" await execute_on_client(action="delete", table="timelines", data={"id": timeline_id}) return f"Timeline {timeline_id} deleted."