From c1fd50f28cd05fabe6b6434ca35f475e368a9073 Mon Sep 17 00:00:00 2001 From: markov Date: Sat, 28 Feb 2026 00:47:09 +0100 Subject: [PATCH] Labels on AgentConfig + auto-assign by labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AgentConfig.labels ARRAY(String) field - Auto-assign matches task labels ↔ agent labels (not capabilities) - labels in AgentConfigOut, auth.ok, config.updated --- src/tracker/api/converters.py | 1 + src/tracker/api/members.py | 5 +++++ src/tracker/api/schemas.py | 1 + src/tracker/api/tasks.py | 4 ++-- src/tracker/models/member.py | 1 + src/tracker/ws/handler.py | 1 + 6 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tracker/api/converters.py b/src/tracker/api/converters.py index 5f61fe7..82efdd7 100644 --- a/src/tracker/api/converters.py +++ b/src/tracker/api/converters.py @@ -35,6 +35,7 @@ def member_out(m: Member) -> MemberOut: if m.agent_config: agent_cfg = AgentConfigOut( capabilities=m.agent_config.capabilities or [], + labels=m.agent_config.labels or [], chat_listen=m.agent_config.chat_listen, task_listen=m.agent_config.task_listen, prompt=m.agent_config.prompt, diff --git a/src/tracker/api/members.py b/src/tracker/api/members.py index 3b5255a..dd91bf3 100644 --- a/src/tracker/api/members.py +++ b/src/tracker/api/members.py @@ -23,6 +23,7 @@ router = APIRouter(tags=["members"]) class AgentConfigSchema(BaseModel): capabilities: list[str] = [] + labels: list[str] = [] chat_listen: str = ListenMode.MENTIONS task_listen: str = ListenMode.MENTIONS prompt: str | None = None @@ -130,6 +131,7 @@ async def create_member(req: MemberCreate, db: AsyncSession = Depends(get_db)): if req.agent_config: agent_cfg = AgentConfigOut( capabilities=req.agent_config.capabilities, + labels=req.agent_config.labels, chat_listen=req.agent_config.chat_listen, task_listen=req.agent_config.task_listen, prompt=req.agent_config.prompt, @@ -167,6 +169,8 @@ async def update_member(member_id: str, req: MemberUpdate, db: AsyncSession = De ac = req.agent_config if ac.capabilities is not None: member.agent_config.capabilities = ac.capabilities + if ac.labels is not None: + member.agent_config.labels = ac.labels if ac.chat_listen is not None: member.agent_config.chat_listen = ac.chat_listen if ac.task_listen is not None: @@ -195,6 +199,7 @@ async def update_member(member_id: str, req: MemberUpdate, db: AsyncSession = De "task_listen": ac.task_listen, "max_concurrent_tasks": ac.max_concurrent_tasks, "capabilities": ac.capabilities or [], + "labels": ac.labels or [], }, }) diff --git a/src/tracker/api/schemas.py b/src/tracker/api/schemas.py index 03040dd..54d0dc0 100644 --- a/src/tracker/api/schemas.py +++ b/src/tracker/api/schemas.py @@ -82,6 +82,7 @@ class MessageOut(BaseModel): class AgentConfigOut(BaseModel): capabilities: list[str] = [] + labels: list[str] = [] chat_listen: str task_listen: str prompt: str | None = None diff --git a/src/tracker/api/tasks.py b/src/tracker/api/tasks.py index dbd3a1d..53ecfd3 100644 --- a/src/tracker/api/tasks.py +++ b/src/tracker/api/tasks.py @@ -308,8 +308,8 @@ async def create_task( ) ) for agent, config in agents_q: - caps = config.capabilities or [] - if any(label in caps for label in req.labels): + agent_labels = config.labels or [] + if any(label in agent_labels for label in req.labels): task.assignee_id = agent.id task.watcher_ids = [agent.id] break diff --git a/src/tracker/models/member.py b/src/tracker/models/member.py index 4cdcbe2..cf634df 100644 --- a/src/tracker/models/member.py +++ b/src/tracker/models/member.py @@ -44,6 +44,7 @@ class AgentConfig(Base): UUID(as_uuid=True), ForeignKey("members.id"), nullable=False, unique=True ) capabilities: Mapped[list[str]] = mapped_column(ARRAY(String), default=list) + labels: Mapped[list[str]] = mapped_column(ARRAY(String), default=list) # for auto-assign matching chat_listen: Mapped[str] = mapped_column(String(20), default=ListenMode.MENTIONS) # all | mentions | none task_listen: Mapped[str] = mapped_column(String(20), default=ListenMode.MENTIONS) # all | mentions | none prompt: Mapped[str | None] = mapped_column(Text) diff --git a/src/tracker/ws/handler.py b/src/tracker/ws/handler.py index e259ca7..ca0eaff 100644 --- a/src/tracker/ws/handler.py +++ b/src/tracker/ws/handler.py @@ -265,6 +265,7 @@ async def _authenticate(ws: WebSocket, token: str, on_behalf_of: str | None = No "task_listen": ac.task_listen, "max_concurrent_tasks": ac.max_concurrent_tasks, "capabilities": ac.capabilities or [], + "labels": ac.labels or [], } await ws.send_json({