feat(api): track previous in_progress_at during task status transitions
This commit is contained in:
@@ -2137,8 +2137,10 @@ async def _apply_non_lead_agent_task_rules(
|
|||||||
raise _blocked_task_error(blocked_ids)
|
raise _blocked_task_error(blocked_ids)
|
||||||
if status_value == "inbox":
|
if status_value == "inbox":
|
||||||
update.task.assigned_agent_id = None
|
update.task.assigned_agent_id = None
|
||||||
|
update.task.previous_in_progress_at = update.task.in_progress_at
|
||||||
update.task.in_progress_at = None
|
update.task.in_progress_at = None
|
||||||
elif status_value == "review":
|
elif status_value == "review":
|
||||||
|
update.task.previous_in_progress_at = update.task.in_progress_at
|
||||||
update.task.assigned_agent_id = None
|
update.task.assigned_agent_id = None
|
||||||
update.task.in_progress_at = None
|
update.task.in_progress_at = None
|
||||||
else:
|
else:
|
||||||
@@ -2199,8 +2201,12 @@ async def _apply_admin_task_rules(
|
|||||||
if "status" in update.updates:
|
if "status" in update.updates:
|
||||||
status_value = _required_status_value(update.updates["status"])
|
status_value = _required_status_value(update.updates["status"])
|
||||||
if status_value == "inbox":
|
if status_value == "inbox":
|
||||||
|
update.task.previous_in_progress_at = update.task.in_progress_at
|
||||||
update.task.assigned_agent_id = None
|
update.task.assigned_agent_id = None
|
||||||
update.task.in_progress_at = None
|
update.task.in_progress_at = None
|
||||||
|
elif status_value == "review":
|
||||||
|
update.task.previous_in_progress_at = update.task.in_progress_at
|
||||||
|
update.task.in_progress_at = None
|
||||||
elif status_value == "in_progress":
|
elif status_value == "in_progress":
|
||||||
update.task.in_progress_at = utcnow()
|
update.task.in_progress_at = utcnow()
|
||||||
|
|
||||||
@@ -2353,8 +2359,8 @@ async def _finalize_updated_task(
|
|||||||
comment_text = (update.comment or "").strip()
|
comment_text = (update.comment or "").strip()
|
||||||
review_comment_author = update.task.assigned_agent_id or update.previous_assigned
|
review_comment_author = update.task.assigned_agent_id or update.previous_assigned
|
||||||
review_comment_since = (
|
review_comment_since = (
|
||||||
update.task.in_progress_at
|
update.task.previous_in_progress_at
|
||||||
if update.task.in_progress_at is not None
|
if update.task.previous_in_progress_at is not None
|
||||||
else update.previous_in_progress_at
|
else update.previous_in_progress_at
|
||||||
)
|
)
|
||||||
if not comment_text and not await has_valid_recent_comment(
|
if not comment_text and not await has_valid_recent_comment(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class Task(TenantScoped, table=True):
|
|||||||
priority: str = Field(default="medium", index=True)
|
priority: str = Field(default="medium", index=True)
|
||||||
due_at: datetime | None = None
|
due_at: datetime | None = None
|
||||||
in_progress_at: datetime | None = None
|
in_progress_at: datetime | None = None
|
||||||
|
previous_in_progress_at: datetime | None = None
|
||||||
|
|
||||||
created_by_user_id: UUID | None = Field(
|
created_by_user_id: UUID | None = Field(
|
||||||
default=None,
|
default=None,
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
"""Track prior in_progress_at during status transitions.
|
||||||
|
|
||||||
|
Revision ID: a2f6c9d4b7e8
|
||||||
|
Revises: 4c1f5e2a7b9d
|
||||||
|
Create Date: 2026-02-15 00:00:00.000000
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "a2f6c9d4b7e8"
|
||||||
|
down_revision = "4c1f5e2a7b9d"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Add previous_in_progress_at column to tasks."""
|
||||||
|
op.add_column(
|
||||||
|
"tasks",
|
||||||
|
sa.Column("previous_in_progress_at", sa.DateTime(), nullable=True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Drop previous_in_progress_at column from tasks."""
|
||||||
|
op.drop_column("tasks", "previous_in_progress_at")
|
||||||
@@ -340,6 +340,7 @@ async def test_non_lead_agent_moves_task_to_review_and_task_unassigns() -> None:
|
|||||||
gateway_id = uuid4()
|
gateway_id = uuid4()
|
||||||
worker_id = uuid4()
|
worker_id = uuid4()
|
||||||
task_id = uuid4()
|
task_id = uuid4()
|
||||||
|
in_progress_at = utcnow()
|
||||||
|
|
||||||
session.add(Organization(id=org_id, name="org"))
|
session.add(Organization(id=org_id, name="org"))
|
||||||
session.add(
|
session.add(
|
||||||
@@ -377,7 +378,7 @@ async def test_non_lead_agent_moves_task_to_review_and_task_unassigns() -> None:
|
|||||||
description="",
|
description="",
|
||||||
status="in_progress",
|
status="in_progress",
|
||||||
assigned_agent_id=worker_id,
|
assigned_agent_id=worker_id,
|
||||||
in_progress_at=utcnow(),
|
in_progress_at=in_progress_at,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
@@ -397,6 +398,12 @@ async def test_non_lead_agent_moves_task_to_review_and_task_unassigns() -> None:
|
|||||||
assert updated.status == "review"
|
assert updated.status == "review"
|
||||||
assert updated.assigned_agent_id is None
|
assert updated.assigned_agent_id is None
|
||||||
assert updated.in_progress_at is None
|
assert updated.in_progress_at is None
|
||||||
|
|
||||||
|
refreshed_task = (
|
||||||
|
(await session.exec(select(Task).where(col(Task.id) == task_id))).first()
|
||||||
|
)
|
||||||
|
assert refreshed_task is not None
|
||||||
|
assert refreshed_task.previous_in_progress_at == in_progress_at
|
||||||
finally:
|
finally:
|
||||||
await engine.dispose()
|
await engine.dispose()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user