- Add app/core/deep_agent.py with Home and Floating supervisor graphs using LangGraph create_react_agent (hierarchical pattern) - Strip ChatAgent classes from all 4 agent files, keep @tool functions - Rewrite output_formatter.py for event-based (token/tool_end/mutations) stream - Update device_ws.py to use run_home_stream/run_floating_stream - Rewrite chat.py REST route to use run_home - Add update_core_memory tool to both supervisors - Add langgraph>=0.3.0 to requirements.txt - Remove orchestrator.py, execution_plan.py, agent_registry.py, plans.py - Remove PlanAction, PlanStep, ExecutionPlan, execution_mode from schemas - Update all affected tests to match new API - Remove 6 deprecated test files for deleted modules - Clean up stale docstrings referencing removed orchestrator
93 lines
2.6 KiB
Python
93 lines
2.6 KiB
Python
"""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."
|
|
|
|
|
|
|