Auto-assign as project option (default off)
Some checks failed
Deploy Tracker / deploy (push) Failing after 3s

- Project.auto_assign boolean field (default False)
- create_task only auto-assigns if project.auto_assign=True
- PATCH /projects/{id} accepts auto_assign
- ProjectOut includes auto_assign
This commit is contained in:
markov 2026-02-27 23:55:56 +01:00
parent 93cdd38b96
commit 502b55b5a9
4 changed files with 9 additions and 3 deletions

View File

@ -29,6 +29,7 @@ class ProjectUpdate(BaseModel):
description: str | None = None description: str | None = None
repo_urls: list[str] | None = None repo_urls: list[str] | None = None
status: str | None = None status: str | None = None
auto_assign: bool | None = None
class ProjectMemberAdd(BaseModel): class ProjectMemberAdd(BaseModel):
@ -70,6 +71,7 @@ async def _project_out(p: Project, db: AsyncSession) -> ProjectOut:
status=p.status, status=p.status,
task_counter=p.task_counter, task_counter=p.task_counter,
chat_id=str(chat.id) if chat else None, chat_id=str(chat.id) if chat else None,
auto_assign=p.auto_assign,
) )
@ -126,6 +128,8 @@ async def update_project(project_id: str, req: ProjectUpdate, db: AsyncSession =
project.repo_urls = req.repo_urls project.repo_urls = req.repo_urls
if req.status is not None: if req.status is not None:
project.status = req.status project.status = req.status
if req.auto_assign is not None:
project.auto_assign = req.auto_assign
await db.commit() await db.commit()
return await _project_out(project, db) return await _project_out(project, db)

View File

@ -102,6 +102,7 @@ class ProjectOut(BaseModel):
status: str status: str
task_counter: int task_counter: int
chat_id: str | None = None chat_id: str | None = None
auto_assign: bool = False
class Config: class Config:
from_attributes = True from_attributes = True

View File

@ -282,8 +282,8 @@ async def create_task(
db.add(task) db.add(task)
await db.flush() await db.flush()
# Auto-assign by capabilities if no assignee set # Auto-assign by capabilities if enabled and no assignee set
if not assignee_id and req.labels: if not assignee_id and req.labels and project.auto_assign:
from ..models import AgentConfig, ProjectMember from ..models import AgentConfig, ProjectMember
agents_q = await db.execute( agents_q = await db.execute(
select(Member, AgentConfig) select(Member, AgentConfig)

View File

@ -3,7 +3,7 @@
import uuid import uuid
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from sqlalchemy import ForeignKey, Integer, String, Text, UniqueConstraint from sqlalchemy import Boolean, ForeignKey, Integer, String, Text, UniqueConstraint
from sqlalchemy.dialects.postgresql import ARRAY, UUID from sqlalchemy.dialects.postgresql import ARRAY, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
@ -25,6 +25,7 @@ class Project(Base):
repo_urls: Mapped[list[str]] = mapped_column(ARRAY(String), default=list) repo_urls: Mapped[list[str]] = mapped_column(ARRAY(String), default=list)
status: Mapped[str] = mapped_column(String(20), default=ProjectStatus.ACTIVE) # active | archived status: Mapped[str] = mapped_column(String(20), default=ProjectStatus.ACTIVE) # active | archived
task_counter: Mapped[int] = mapped_column(Integer, default=0) # for sequential task numbers task_counter: Mapped[int] = mapped_column(Integer, default=0) # for sequential task numbers
auto_assign: Mapped[bool] = mapped_column(Boolean, default=False) # auto-assign tasks by labels ↔ capabilities
tasks: Mapped[list["Task"]] = relationship(back_populates="project", cascade="all, delete-orphan") tasks: Mapped[list["Task"]] = relationship(back_populates="project", cascade="all, delete-orphan")
chats: Mapped[list["Chat"]] = relationship(back_populates="project", cascade="all, delete-orphan") chats: Mapped[list["Chat"]] = relationship(back_populates="project", cascade="all, delete-orphan")