feat: enhance memory API responses with limits and update UI components for memory limit handling

This commit is contained in:
Anish Sarkar 2026-05-20 03:17:05 +05:30
parent fa6d7c60bf
commit 73043a0756
9 changed files with 132 additions and 51 deletions

View file

@ -8,7 +8,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.db import User, get_async_session
from app.services.memory import (
MemoryRead,
MemoryScope,
memory_limits,
read_memory,
reset_memory,
save_memory,
@ -18,10 +20,6 @@ from app.users import current_active_user
router = APIRouter()
class MemoryRead(BaseModel):
memory_md: str
class MemoryUpdate(BaseModel):
memory_md: str
@ -36,7 +34,7 @@ async def get_user_memory(
target_id=user.id,
session=session,
)
return MemoryRead(memory_md=memory_md)
return MemoryRead(memory_md=memory_md, limits=memory_limits())
@router.put("/users/me/memory", response_model=MemoryRead)
@ -53,7 +51,7 @@ async def update_user_memory(
)
if result.status == "error":
raise HTTPException(status_code=400, detail=result.message)
return MemoryRead(memory_md=result.memory_md)
return MemoryRead(memory_md=result.memory_md, limits=memory_limits())
@router.post("/users/me/memory/reset", response_model=MemoryRead)
@ -68,4 +66,4 @@ async def reset_user_memory(
)
if result.status == "error":
raise HTTPException(status_code=400, detail=result.message)
return MemoryRead(memory_md=result.memory_md)
return MemoryRead(memory_md=result.memory_md, limits=memory_limits())

View file

@ -8,7 +8,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.db import User, get_async_session
from app.services.memory import (
MemoryRead,
MemoryScope,
memory_limits,
read_memory,
reset_memory,
save_memory,
@ -19,15 +21,11 @@ from app.utils.rbac import check_search_space_access
router = APIRouter()
class TeamMemoryRead(BaseModel):
memory_md: str
class TeamMemoryUpdate(BaseModel):
memory_md: str
@router.get("/searchspaces/{search_space_id}/memory", response_model=TeamMemoryRead)
@router.get("/searchspaces/{search_space_id}/memory", response_model=MemoryRead)
async def get_team_memory(
search_space_id: int,
session: AsyncSession = Depends(get_async_session),
@ -39,10 +37,10 @@ async def get_team_memory(
target_id=search_space_id,
session=session,
)
return TeamMemoryRead(memory_md=memory_md)
return MemoryRead(memory_md=memory_md, limits=memory_limits())
@router.put("/searchspaces/{search_space_id}/memory", response_model=TeamMemoryRead)
@router.put("/searchspaces/{search_space_id}/memory", response_model=MemoryRead)
async def update_team_memory(
search_space_id: int,
body: TeamMemoryUpdate,
@ -58,10 +56,10 @@ async def update_team_memory(
)
if result.status == "error":
raise HTTPException(status_code=400, detail=result.message)
return TeamMemoryRead(memory_md=result.memory_md)
return MemoryRead(memory_md=result.memory_md, limits=memory_limits())
@router.post("/searchspaces/{search_space_id}/memory/reset", response_model=TeamMemoryRead)
@router.post("/searchspaces/{search_space_id}/memory/reset", response_model=MemoryRead)
async def reset_team_memory(
search_space_id: int,
session: AsyncSession = Depends(get_async_session),
@ -75,4 +73,4 @@ async def reset_team_memory(
)
if result.status == "error":
raise HTTPException(status_code=400, detail=result.message)
return TeamMemoryRead(memory_md=result.memory_md)
return MemoryRead(memory_md=result.memory_md, limits=memory_limits())

View file

@ -1,9 +1,11 @@
"""First-class memory service for user and team markdown memory."""
from .schemas import MemoryLimits, MemoryRead
from .service import (
MemoryScope,
SaveResult,
extract_and_save,
memory_limits,
read_memory,
reset_memory,
save_memory,
@ -18,9 +20,12 @@ from .validation import (
__all__ = [
"MEMORY_HARD_LIMIT",
"MEMORY_SOFT_LIMIT",
"MemoryLimits",
"MemoryRead",
"MemoryScope",
"SaveResult",
"extract_and_save",
"memory_limits",
"read_memory",
"reset_memory",
"save_memory",

View file

@ -1,4 +1,4 @@
"""Structured output schemas for memory extraction."""
"""Schemas for memory API responses and structured extraction."""
from __future__ import annotations
@ -7,6 +7,20 @@ from typing import Literal
from pydantic import BaseModel, Field
class MemoryLimits(BaseModel):
"""Canonical memory size limits exposed to clients."""
soft: int
hard: int
class MemoryRead(BaseModel):
"""Memory document payload returned by user and team memory APIs."""
memory_md: str
limits: MemoryLimits
class MemoryExtractionDecision(BaseModel):
"""Structured extraction result; avoids string sentinel parsing."""

View file

@ -9,7 +9,6 @@ from typing import Any, Literal
from uuid import UUID
from langchain_core.messages import HumanMessage
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@ -19,9 +18,10 @@ from app.services.memory.prompts import (
USER_MEMORY_EXTRACT_PROMPT,
)
from app.services.memory.rewrite import forced_rewrite
from app.services.memory.schemas import MemoryExtractionDecision
from app.services.memory.schemas import MemoryExtractionDecision, MemoryLimits
from app.services.memory.validation import (
MEMORY_HARD_LIMIT,
MEMORY_SOFT_LIMIT,
soft_limit_warning,
strip_preamble_to_first_heading,
validate_bullet_format,
@ -68,8 +68,8 @@ class SaveResult:
return data
class MemoryRead(BaseModel):
memory_md: str
def memory_limits() -> MemoryLimits:
return MemoryLimits(soft=MEMORY_SOFT_LIMIT, hard=MEMORY_HARD_LIMIT)
def _normalize_scope(scope: MemoryScope | str) -> MemoryScope: