chore: remove legacy Chat/Message/TaskAction, clean imports
Some checks failed
Deploy Tracker / deploy (push) Failing after 3s
Some checks failed
Deploy Tracker / deploy (push) Failing after 3s
This commit is contained in:
parent
8b3a9b2148
commit
c5243fad83
@ -11,7 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from ..database import get_db
|
||||
from ..models import Member
|
||||
from ..models.chat import Attachment, Message # Legacy imports
|
||||
from ..models.event import EventAttachment
|
||||
from .schemas import UploadOut
|
||||
|
||||
router = APIRouter(tags=["attachments"])
|
||||
@ -69,7 +69,7 @@ async def download_attachment(
|
||||
):
|
||||
"""Download an attachment by ID."""
|
||||
result = await db.execute(
|
||||
select(Attachment).where(Attachment.id == uuid.UUID(attachment_id))
|
||||
select(EventAttachment).where(EventAttachment.id == uuid.UUID(attachment_id))
|
||||
)
|
||||
att = result.scalar_one_or_none()
|
||||
if not att:
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
"""ORM → Pydantic converters. Single place for all model-to-schema transformations."""
|
||||
|
||||
from ..models import Event, EventAttachment, Member, ProjectFile, Step, Task
|
||||
from ..models.chat import Message, Attachment # Legacy for backward compatibility
|
||||
from ..enums import MemberType
|
||||
from .schemas import (
|
||||
AgentConfigOut,
|
||||
@ -9,7 +8,6 @@ from .schemas import (
|
||||
EventOut,
|
||||
MemberBrief,
|
||||
MemberOut,
|
||||
MessageOut,
|
||||
ProjectFileOut,
|
||||
StepOut,
|
||||
SubtaskBrief,
|
||||
@ -17,13 +15,6 @@ from .schemas import (
|
||||
)
|
||||
|
||||
|
||||
def _resolve_mentions(m: Message) -> list[MemberBrief]:
|
||||
"""Convert stored mention slugs to MemberBrief objects.
|
||||
Uses pre-loaded relationships if available, otherwise returns slug-only briefs."""
|
||||
if not m.mentions:
|
||||
return []
|
||||
# For now: return slug-only briefs (id will be empty until we store mention IDs)
|
||||
return [MemberBrief(id="", slug=slug, name=slug) for slug in m.mentions]
|
||||
|
||||
|
||||
def member_brief(m: Member | None) -> MemberBrief | None:
|
||||
@ -58,7 +49,7 @@ def member_out(m: Member) -> MemberOut:
|
||||
)
|
||||
|
||||
|
||||
def attachment_out(a: Attachment | EventAttachment) -> AttachmentOut:
|
||||
def attachment_out(a: EventAttachment) -> AttachmentOut:
|
||||
return AttachmentOut(
|
||||
id=str(a.id),
|
||||
filename=a.filename,
|
||||
@ -78,24 +69,7 @@ def step_out(s: Step) -> StepOut:
|
||||
)
|
||||
|
||||
|
||||
def message_out(m: Message) -> MessageOut:
|
||||
return MessageOut(
|
||||
id=str(m.id),
|
||||
chat_id=str(m.chat_id) if m.chat_id else None,
|
||||
task_id=str(m.task_id) if m.task_id else None,
|
||||
parent_id=str(m.parent_id) if m.parent_id else None,
|
||||
author_type=m.author_type,
|
||||
author_id=str(m.author_id) if m.author_id else None,
|
||||
author=member_brief(m.author) if m.author else None,
|
||||
content=m.content,
|
||||
thinking=m.thinking,
|
||||
tool_log=m.tool_log,
|
||||
mentions=_resolve_mentions(m),
|
||||
actor=member_brief(m.actor) if hasattr(m, 'actor') and m.actor else None,
|
||||
voice_url=m.voice_url,
|
||||
attachments=[attachment_out(a) for a in (m.attachments or [])],
|
||||
created_at=m.created_at.isoformat() if m.created_at else "",
|
||||
)
|
||||
|
||||
|
||||
|
||||
def task_out(t: Task, project_slug: str = "") -> TaskOut:
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
"""Messages API — unified messages for chats and task comments."""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from ..database import get_db
|
||||
from ..enums import AuthorType, ChatKind
|
||||
from ..models.chat import Message, Chat, Attachment # Legacy imports
|
||||
from .schemas import MessageOut
|
||||
from .converters import message_out
|
||||
|
||||
router = APIRouter(tags=["messages"])
|
||||
|
||||
UPLOAD_DIR = os.environ.get("UPLOAD_DIR", "/data/uploads")
|
||||
|
||||
|
||||
# --- Schemas ---
|
||||
|
||||
class AttachmentInput(BaseModel):
|
||||
"""Uploaded file info from /upload endpoint."""
|
||||
file_id: str # UUID from upload
|
||||
filename: str
|
||||
mime_type: str | None = None
|
||||
size: int = 0
|
||||
storage_name: str # filename on disk
|
||||
|
||||
|
||||
class MessageCreate(BaseModel):
|
||||
chat_id: str | None = None
|
||||
task_id: str | None = None
|
||||
parent_id: str | None = None
|
||||
content: str
|
||||
thinking: str | None = None
|
||||
mentions: list[str] = []
|
||||
voice_url: str | None = None
|
||||
attachments: list[AttachmentInput] = []
|
||||
|
||||
|
||||
# --- Endpoints ---
|
||||
|
||||
@router.get("/messages", response_model=list[MessageOut])
|
||||
async def list_messages(
|
||||
chat_id: Optional[str] = Query(None),
|
||||
task_id: Optional[str] = Query(None),
|
||||
parent_id: Optional[str] = Query(None),
|
||||
limit: int = Query(50, le=200),
|
||||
offset: int = Query(0),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
q = select(Message).options(selectinload(Message.attachments), selectinload(Message.author), selectinload(Message.actor))
|
||||
|
||||
if chat_id:
|
||||
q = q.where(Message.chat_id == uuid.UUID(chat_id))
|
||||
if task_id:
|
||||
q = q.where(Message.task_id == uuid.UUID(task_id))
|
||||
if parent_id:
|
||||
q = q.where(Message.parent_id == uuid.UUID(parent_id))
|
||||
|
||||
# For top-level messages only (no threads), if no parent_id filter
|
||||
if not parent_id and (chat_id or task_id):
|
||||
q = q.where(Message.parent_id.is_(None))
|
||||
|
||||
# Get newest N messages (DESC), then reverse to chronological order
|
||||
q = q.order_by(Message.created_at.desc()).offset(offset).limit(limit)
|
||||
result = await db.execute(q)
|
||||
messages = [message_out(m).model_dump() for m in result.scalars()]
|
||||
messages.reverse()
|
||||
return messages
|
||||
|
||||
|
||||
@router.post("/messages", response_model=MessageOut)
|
||||
async def create_message(req: MessageCreate, request: Request, db: AsyncSession = Depends(get_db)):
|
||||
if not req.chat_id and not req.task_id:
|
||||
raise HTTPException(400, "Either chat_id or task_id must be provided")
|
||||
|
||||
# Resolve author from auth — never trust client-provided author fields
|
||||
member = getattr(request.state, "member", None)
|
||||
if not member:
|
||||
raise HTTPException(401, "Not authenticated")
|
||||
author_id = member.id
|
||||
author_type = member.type
|
||||
|
||||
msg = Message(
|
||||
chat_id=uuid.UUID(req.chat_id) if req.chat_id else None,
|
||||
task_id=uuid.UUID(req.task_id) if req.task_id else None,
|
||||
parent_id=uuid.UUID(req.parent_id) if req.parent_id else None,
|
||||
author_type=author_type,
|
||||
author_id=author_id,
|
||||
content=req.content,
|
||||
thinking=req.thinking,
|
||||
mentions=req.mentions,
|
||||
voice_url=req.voice_url,
|
||||
)
|
||||
db.add(msg)
|
||||
await db.flush() # get msg.id
|
||||
|
||||
# Create attachment records
|
||||
for att_in in req.attachments:
|
||||
att = Attachment(
|
||||
message_id=msg.id,
|
||||
filename=att_in.filename,
|
||||
mime_type=att_in.mime_type,
|
||||
size=att_in.size,
|
||||
storage_path=att_in.storage_name,
|
||||
)
|
||||
db.add(att)
|
||||
|
||||
await db.commit()
|
||||
result2 = await db.execute(
|
||||
select(Message).where(Message.id == msg.id).options(
|
||||
selectinload(Message.attachments),
|
||||
selectinload(Message.author)
|
||||
)
|
||||
)
|
||||
msg = result2.scalar_one()
|
||||
|
||||
author_id = str(msg.author_id) if msg.author_id else None
|
||||
|
||||
# Build response using shared converter
|
||||
msg_data = message_out(msg).model_dump()
|
||||
|
||||
# Broadcast via WebSocket
|
||||
from ..ws.manager import manager
|
||||
from ..models.task import Task
|
||||
|
||||
project_id = None
|
||||
if req.chat_id:
|
||||
chat_result = await db.execute(select(Chat).where(Chat.id == uuid.UUID(req.chat_id)))
|
||||
chat = chat_result.scalar_one_or_none()
|
||||
if chat and chat.project_id:
|
||||
project_id = str(chat.project_id)
|
||||
elif chat and chat.kind == ChatKind.LOBBY:
|
||||
await manager.broadcast_all(
|
||||
{"type": "message.new", "data": msg_data},
|
||||
exclude_member_id=author_id,
|
||||
)
|
||||
return message_out(msg)
|
||||
|
||||
# If no chat_id but task_id — resolve project from task
|
||||
if not project_id and req.task_id:
|
||||
task_result = await db.execute(select(Task).where(Task.id == uuid.UUID(req.task_id)))
|
||||
task = task_result.scalar_one_or_none()
|
||||
if task and task.project_id:
|
||||
project_id = str(task.project_id)
|
||||
|
||||
if project_id:
|
||||
await manager.broadcast_message(project_id, msg_data, author_id=author_id)
|
||||
else:
|
||||
await manager.broadcast_all(
|
||||
{"type": "message.new", "data": msg_data},
|
||||
exclude_member_id=author_id,
|
||||
)
|
||||
|
||||
return message_out(msg)
|
||||
|
||||
|
||||
@router.get("/messages/{message_id}/replies", response_model=list[MessageOut])
|
||||
async def list_replies(message_id: str, db: AsyncSession = Depends(get_db)):
|
||||
"""Get thread replies for a message."""
|
||||
result = await db.execute(
|
||||
select(Message)
|
||||
.where(Message.parent_id == uuid.UUID(message_id))
|
||||
.options(selectinload(Message.attachments), selectinload(Message.author))
|
||||
.order_by(Message.created_at)
|
||||
)
|
||||
return [message_out(m) for m in result.scalars()]
|
||||
@ -9,9 +9,8 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from ..database import get_db
|
||||
from ..enums import ChatKind, MemberRole, ProjectStatus
|
||||
from ..enums import MemberRole, ProjectStatus
|
||||
from ..models import Project, Member, ProjectMember
|
||||
from ..models.chat import Chat # Legacy import
|
||||
from ..ws.manager import manager
|
||||
from .schemas import ProjectOut
|
||||
|
||||
@ -60,10 +59,6 @@ async def _get_project(project_id: str, db: AsyncSession) -> Project:
|
||||
|
||||
|
||||
async def _project_out(p: Project, db: AsyncSession) -> ProjectOut:
|
||||
chat_result = await db.execute(
|
||||
select(Chat).where(Chat.project_id == p.id, Chat.kind == ChatKind.PROJECT)
|
||||
)
|
||||
chat = chat_result.scalar_one_or_none()
|
||||
return ProjectOut(
|
||||
id=str(p.id),
|
||||
name=p.name,
|
||||
@ -72,7 +67,6 @@ async def _project_out(p: Project, db: AsyncSession) -> ProjectOut:
|
||||
repo_urls=p.repo_urls or [],
|
||||
status=p.status,
|
||||
task_counter=p.task_counter,
|
||||
chat_id=str(chat.id) if chat else None,
|
||||
auto_assign=p.auto_assign,
|
||||
)
|
||||
|
||||
@ -103,11 +97,6 @@ async def create_project(req: ProjectCreate, db: AsyncSession = Depends(get_db))
|
||||
repo_urls=req.repo_urls,
|
||||
)
|
||||
db.add(project)
|
||||
await db.flush()
|
||||
|
||||
chat = Chat(project_id=project.id, kind=ChatKind.PROJECT)
|
||||
db.add(chat)
|
||||
|
||||
await db.commit()
|
||||
|
||||
out = await _project_out(project, db)
|
||||
|
||||
@ -62,22 +62,6 @@ class SubtaskBrief(BaseModel):
|
||||
assignee: MemberBrief | None = None
|
||||
|
||||
|
||||
class MessageOut(BaseModel):
|
||||
id: str
|
||||
chat_id: str | None = None
|
||||
task_id: str | None = None
|
||||
parent_id: str | None = None
|
||||
author_type: str
|
||||
author_id: str | None = None
|
||||
author: MemberBrief | None = None
|
||||
content: str
|
||||
thinking: str | None = None
|
||||
tool_log: list[dict] | None = None
|
||||
mentions: list[MemberBrief] = []
|
||||
actor: MemberBrief | None = None
|
||||
voice_url: str | None = None
|
||||
attachments: list[AttachmentOut] = []
|
||||
created_at: str
|
||||
|
||||
|
||||
class EventOut(BaseModel):
|
||||
@ -142,7 +126,6 @@ class ProjectOut(BaseModel):
|
||||
repo_urls: list[str] = []
|
||||
status: str
|
||||
task_counter: int
|
||||
chat_id: str | None = None
|
||||
auto_assign: bool = False
|
||||
|
||||
class Config:
|
||||
|
||||
@ -12,13 +12,12 @@ from sqlalchemy.orm import selectinload, joinedload
|
||||
|
||||
from ..database import get_db
|
||||
from ..enums import (
|
||||
AuthorType, ChatKind, MemberType, TaskLinkType, TaskPriority, TaskStatus, TaskType, WSEventType,
|
||||
AuthorType, MemberType, TaskLinkType, TaskPriority, TaskStatus, TaskType, WSEventType,
|
||||
)
|
||||
from ..models import Task, Step, Project, Member, TaskLink, Event
|
||||
from ..models.chat import Message, Chat # Legacy imports
|
||||
from .auth import get_current_member
|
||||
from .schemas import TaskOut, MessageOut, MemberBrief
|
||||
from .converters import task_out, message_out, member_brief
|
||||
from .schemas import TaskOut, MemberBrief
|
||||
from .converters import task_out, member_brief
|
||||
|
||||
router = APIRouter(tags=["tasks"])
|
||||
|
||||
|
||||
@ -169,15 +169,14 @@ app.add_middleware(
|
||||
)
|
||||
|
||||
# Routers
|
||||
from .api import auth, members, projects, tasks, messages, events, steps, attachments, project_files, labels # noqa: E402
|
||||
from .api import auth, members, projects, tasks, events, steps, attachments, project_files, labels # noqa: E402
|
||||
from .ws.handler import router as ws_router # noqa: E402
|
||||
|
||||
app.include_router(auth.router, prefix="/api/v1")
|
||||
app.include_router(members.router, prefix="/api/v1")
|
||||
app.include_router(projects.router, prefix="/api/v1")
|
||||
app.include_router(tasks.router, prefix="/api/v1")
|
||||
app.include_router(messages.router, prefix="/api/v1") # Backward compatibility
|
||||
app.include_router(events.router, prefix="/api/v1") # New events API
|
||||
app.include_router(events.router, prefix="/api/v1") # Events API (replaces messages)
|
||||
app.include_router(steps.router, prefix="/api/v1")
|
||||
app.include_router(attachments.router, prefix="/api/v1")
|
||||
app.include_router(project_files.router, prefix="/api/v1")
|
||||
|
||||
@ -32,10 +32,6 @@ class AuthMethod(StrEnum):
|
||||
TOKEN = "token"
|
||||
|
||||
|
||||
class ChatKind(StrEnum):
|
||||
LOBBY = "lobby"
|
||||
PROJECT = "project"
|
||||
|
||||
|
||||
class ListenMode(StrEnum):
|
||||
ALL = "all"
|
||||
|
||||
@ -1,78 +0,0 @@
|
||||
"""Chat and Message models — unified message for chats and task comments."""
|
||||
|
||||
import uuid
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey, Integer, JSON, String, Text
|
||||
from sqlalchemy.dialects.postgresql import ARRAY, UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from ..enums import ChatKind
|
||||
from .base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .member import Member
|
||||
from .project import Project
|
||||
|
||||
|
||||
class Chat(Base):
|
||||
"""Chat room — lobby, project, or custom."""
|
||||
__tablename__ = "chats"
|
||||
|
||||
project_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id"))
|
||||
kind: Mapped[str] = mapped_column(String(20), default=ChatKind.PROJECT) # lobby | project
|
||||
|
||||
project: Mapped["Project | None"] = relationship(back_populates="chats")
|
||||
messages: Mapped[list["Message"]] = relationship(
|
||||
back_populates="chat", cascade="all, delete-orphan",
|
||||
foreign_keys="Message.chat_id"
|
||||
)
|
||||
|
||||
|
||||
class Message(Base):
|
||||
"""Unified message — works for chat messages AND task comments."""
|
||||
__tablename__ = "messages"
|
||||
|
||||
# Context: one of chat_id or task_id must be set
|
||||
chat_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("chats.id"))
|
||||
task_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("tasks.id", ondelete="CASCADE"))
|
||||
|
||||
# Thread support
|
||||
parent_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("messages.id"))
|
||||
|
||||
# Author
|
||||
author_type: Mapped[str] = mapped_column(String(20), nullable=False) # human | agent | system
|
||||
author_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("members.id"), nullable=True)
|
||||
|
||||
# Actor — who initiated the action (for system messages: who created/moved/assigned the task)
|
||||
actor_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("members.id"), nullable=True)
|
||||
|
||||
# Tool log — JSON array of tool calls [{name, args, result, error?}]
|
||||
tool_log: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
|
||||
# Content
|
||||
content: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
thinking: Mapped[str | None] = mapped_column(Text, nullable=True) # LLM reasoning/thinking block
|
||||
mentions: Mapped[list[str]] = mapped_column(ARRAY(String), default=list)
|
||||
voice_url: Mapped[str | None] = mapped_column(String(500))
|
||||
|
||||
# Relationships
|
||||
chat: Mapped["Chat | None"] = relationship(back_populates="messages", foreign_keys=[chat_id])
|
||||
author: Mapped["Member"] = relationship(foreign_keys=[author_id])
|
||||
actor: Mapped["Member | None"] = relationship(foreign_keys=[actor_id])
|
||||
attachments: Mapped[list["Attachment"]] = relationship(back_populates="message", cascade="all, delete-orphan")
|
||||
replies: Mapped[list["Message"]] = relationship(back_populates="parent")
|
||||
parent: Mapped["Message | None"] = relationship(back_populates="replies", remote_side="Message.id")
|
||||
|
||||
|
||||
class Attachment(Base):
|
||||
"""File attachment on a message."""
|
||||
__tablename__ = "attachments"
|
||||
|
||||
message_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("messages.id"), nullable=False)
|
||||
filename: Mapped[str] = mapped_column(String(500), nullable=False)
|
||||
mime_type: Mapped[str | None] = mapped_column(String(100))
|
||||
size: Mapped[int] = mapped_column(Integer, default=0) # bytes
|
||||
storage_path: Mapped[str] = mapped_column(String(1000), nullable=False)
|
||||
|
||||
message: Mapped["Message"] = relationship(back_populates="attachments")
|
||||
@ -12,7 +12,6 @@ from .base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .task import Task
|
||||
from .chat import Chat
|
||||
from .member import Member
|
||||
|
||||
|
||||
@ -28,7 +27,6 @@ class Project(Base):
|
||||
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")
|
||||
chats: Mapped[list["Chat"]] = relationship(back_populates="project", cascade="all, delete-orphan")
|
||||
members: Mapped[list["ProjectMember"]] = relationship(back_populates="project", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
|
||||
@ -9,12 +9,11 @@ from sqlalchemy.orm import selectinload
|
||||
|
||||
from ..database import async_session
|
||||
from ..enums import (
|
||||
AuthMethod, ChatKind, ListenMode, MemberRole, MemberStatus, MemberType,
|
||||
AuthMethod, ListenMode, MemberRole, MemberStatus, MemberType,
|
||||
ProjectStatus, WSEventType,
|
||||
)
|
||||
from ..models import Member, AgentConfig, Project, ProjectMember, Task, Event
|
||||
from ..models.chat import Chat, Message # Legacy imports
|
||||
from ..api.schemas import MessageOut, MemberBrief
|
||||
from ..api.schemas import MemberBrief
|
||||
from .manager import ConnectedClient, manager
|
||||
|
||||
logger = logging.getLogger("tracker.ws")
|
||||
@ -31,26 +30,7 @@ def _to_member_brief(member: Member) -> MemberBrief:
|
||||
)
|
||||
|
||||
|
||||
def _to_message_out(msg: Message, author: Member | None = None) -> MessageOut:
|
||||
# mentions stored as member IDs in DB
|
||||
mention_briefs = [MemberBrief(id=mid, slug="", name="") for mid in (msg.mentions or [])]
|
||||
return MessageOut(
|
||||
id=str(msg.id),
|
||||
chat_id=str(msg.chat_id) if msg.chat_id else None,
|
||||
task_id=str(msg.task_id) if msg.task_id else None,
|
||||
parent_id=str(msg.parent_id) if msg.parent_id else None,
|
||||
author_type=msg.author_type,
|
||||
author_id=str(msg.author_id) if msg.author_id else None,
|
||||
author=_to_member_brief(author) if author else None,
|
||||
content=msg.content,
|
||||
thinking=msg.thinking,
|
||||
tool_log=msg.tool_log,
|
||||
mentions=mention_briefs,
|
||||
actor=_to_member_brief(msg.actor) if hasattr(msg, 'actor') and msg.actor else None,
|
||||
voice_url=msg.voice_url,
|
||||
attachments=[],
|
||||
created_at=msg.created_at.isoformat() if msg.created_at else "",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@router.websocket("/ws")
|
||||
@ -334,14 +314,8 @@ async def _handle_chat_send(session_id: str, data: dict):
|
||||
if project_id:
|
||||
resolved_project_id = uuid.UUID(project_id)
|
||||
elif chat_id:
|
||||
# Legacy: resolve project_id from chat_id
|
||||
chat_result = await db.execute(select(Chat).where(Chat.id == uuid.UUID(chat_id)))
|
||||
chat = chat_result.scalar_one_or_none()
|
||||
if chat and chat.project_id:
|
||||
resolved_project_id = chat.project_id
|
||||
elif chat and chat.kind == ChatKind.LOBBY:
|
||||
# Skip lobby for now - Events need project_id
|
||||
await client.ws.send_json({"type": WSEventType.ERROR, "message": "Lobby chat not supported yet"})
|
||||
# Legacy chat_id support removed - use project_id instead
|
||||
await client.ws.send_json({"type": WSEventType.ERROR, "message": "chat_id deprecated, use project_id"})
|
||||
return
|
||||
elif task_id:
|
||||
# Task comment
|
||||
@ -420,14 +394,8 @@ async def _handle_agent_stream(session_id: str, event_type: str, data: dict):
|
||||
chat_id = data.get("chat_id")
|
||||
task_id = data.get("task_id")
|
||||
|
||||
if not project_id and (chat_id or task_id):
|
||||
if not project_id and task_id:
|
||||
async with async_session() as db:
|
||||
if chat_id:
|
||||
chat_result = await db.execute(select(Chat).where(Chat.id == uuid.UUID(chat_id)))
|
||||
chat = chat_result.scalar_one_or_none()
|
||||
if chat and chat.project_id:
|
||||
project_id = str(chat.project_id)
|
||||
elif task_id:
|
||||
from ..models import Task
|
||||
task_result = await db.execute(select(Task).where(Task.id == uuid.UUID(task_id)))
|
||||
task = task_result.scalar_one_or_none()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user