feat(chat): add session pinning feature with database migration

- Add `pinned` column to chat_sessions table with default FALSE
- Implement database migration for existing installations using PRAGMA table_info
- Create composite index for pinned + updated_at sorting
- Add pin/unpin API endpoints (PUT/DELETE /sessions/{id}/pin)
- Update session listing to sort by pinned status then updated_at
- Extend ChatSessionsRepository with pin_session method
- Update API documentation to reflect new pinning functionality

The feature allows users to pin important chat sessions to the top of the list. Sessions are sorted with pinned sessions first (by updated_at), followed by regular sessions (by updated_at). Database migration ensures backward compatibility with existing installations.
This commit is contained in:
YueGuobin committed 2026-03-04 23:18:30 +08:00
1 parent f688a2d5c0
commit 4a017b1a7f
5 files changed
+202 -6

No files matched your search

+76
View File
@@ -323,3 +323,79 @@ async def rename_session(
)
return schemas.ChatSession(**session)
@router.put(
"/sessions/{session_id}/pin",
response_model=schemas.ChatSession,
summary="Pin a chat session",
description="Pin a chat session to the top of the list."
)
async def pin_session(
session_id: str,
project: Project = Depends(dep_project),
current_user: schemas.User = Depends(get_current_active_user),
) -> schemas.ChatSession:
"""
Pin a chat session.
"""
# Check if project is opened
if project.status != "opened":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Project must be opened to pin chat sessions. Current status: {project.status}"
)
# Get AgentService for this project
agent_manager = await get_project_agent_manager()
agent_service = await agent_manager.get_agent(str(project.id), project.path)
# Pin session
session = await agent_service.pin_session(session_id, pinned=True)
if not session:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Session '{session_id}' not found"
)
return schemas.ChatSession(**session)
@router.delete(
"/sessions/{session_id}/pin",
response_model=schemas.ChatSession,
summary="Unpin a chat session",
description="Unpin a chat session from the top of the list."
)
async def unpin_session(
session_id: str,
project: Project = Depends(dep_project),
current_user: schemas.User = Depends(get_current_active_user),
) -> schemas.ChatSession:
"""
Unpin a chat session.
"""
# Check if project is opened
if project.status != "opened":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Project must be opened to unpin chat sessions. Current status: {project.status}"
)
# Get AgentService for this project
agent_manager = await get_project_agent_manager()
agent_service = await agent_manager.get_agent(str(project.id), project.path)
# Unpin session
session = await agent_service.pin_session(session_id, pinned=False)
if not session:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Session '{session_id}' not found"
)
return schemas.ChatSession(**session)