Merge pull request #923 from SuanmoSuanyangTechnology/feat/enduser-info-apikey

feat(memory): add V1 memory config management endpoints and memory read/write API
This commit is contained in:
Ke Sun
2026-04-17 21:03:10 +08:00
committed by GitHub
9 changed files with 1198 additions and 221 deletions

View File

@@ -4,7 +4,17 @@
认证方式: API Key
"""
from fastapi import APIRouter
from . import app_api_controller, rag_api_knowledge_controller, rag_api_document_controller, rag_api_file_controller, rag_api_chunk_controller, memory_api_controller, end_user_api_controller
from . import (
app_api_controller,
end_user_api_controller,
memory_api_controller,
memory_config_api_controller,
rag_api_chunk_controller,
rag_api_document_controller,
rag_api_file_controller,
rag_api_knowledge_controller,
)
# 创建 V1 API 路由器
service_router = APIRouter()
@@ -17,5 +27,6 @@ service_router.include_router(rag_api_file_controller.router)
service_router.include_router(rag_api_chunk_controller.router)
service_router.include_router(memory_api_controller.router)
service_router.include_router(end_user_api_controller.router)
service_router.include_router(memory_config_api_controller.router)
__all__ = ["service_router"]

View File

@@ -5,6 +5,7 @@ import uuid
from fastapi import APIRouter, Body, Depends, Request
from sqlalchemy.orm import Session
from app.controllers import user_memory_controllers
from app.core.api_key_auth import require_api_key
from app.core.error_codes import BizCode
from app.core.exceptions import BusinessException
@@ -14,13 +15,31 @@ from app.core.response_utils import success
from app.db import get_db
from app.repositories.end_user_repository import EndUserRepository
from app.schemas.api_key_schema import ApiKeyAuth
from app.schemas.end_user_info_schema import EndUserInfoUpdate
from app.schemas.memory_api_schema import CreateEndUserRequest, CreateEndUserResponse
from app.services import api_key_service
from app.services.memory_config_service import MemoryConfigService
router = APIRouter(prefix="/end_user", tags=["V1 - End User API"])
logger = get_business_logger()
def _get_current_user(api_key_auth: ApiKeyAuth, db: Session):
"""Build a current_user object from API key auth
Args:
api_key_auth: Validated API key auth info
db: Database session
Returns:
User object with current_workspace_id set
"""
api_key = api_key_service.ApiKeyService.get_api_key(db, api_key_auth.api_key_id, api_key_auth.workspace_id)
current_user = api_key.creator
current_user.current_workspace_id = api_key_auth.workspace_id
return current_user
@router.post("/create")
@require_api_key(scopes=["memory"])
@check_end_user_quota
@@ -39,6 +58,7 @@ async def create_end_user(
Optionally accepts a memory_config_id to connect the end user to a specific
memory configuration. If not provided, falls back to the workspace default config.
Optionally accepts an app_id to bind the end user to a specific app.
"""
body = await request.json()
payload = CreateEndUserRequest(**body)
@@ -73,14 +93,26 @@ async def create_end_user(
else:
logger.warning(f"No default memory config found for workspace: {workspace_id}")
# Resolve app_id: explicit from payload, otherwise None
app_id = None
if payload.app_id:
try:
app_id = uuid.UUID(payload.app_id)
except ValueError:
raise BusinessException(
f"Invalid app_id format: {payload.app_id}",
BizCode.INVALID_PARAMETER
)
end_user_repo = EndUserRepository(db)
end_user = end_user_repo.get_or_create_end_user_with_config(
app_id=api_key_auth.resource_id,
app_id=app_id,
workspace_id=workspace_id,
other_id=payload.other_id,
memory_config_id=memory_config_id,
other_name=payload.other_name,
)
end_user.other_name = payload.other_name
logger.info(f"End user ready: {end_user.id}")
result = {
@@ -92,3 +124,50 @@ async def create_end_user(
}
return success(data=CreateEndUserResponse(**result).model_dump(), msg="End user created successfully")
@router.get("/info")
@require_api_key(scopes=["memory"])
async def get_end_user_info(
request: Request,
end_user_id: str,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Get end user info.
Retrieves the info record (aliases, meta_data, etc.) for the specified end user.
Delegates to the manager-side controller for shared logic.
"""
current_user = _get_current_user(api_key_auth, db)
return await user_memory_controllers.get_end_user_info(
end_user_id=end_user_id,
current_user=current_user,
db=db,
)
@router.post("/info/update")
@require_api_key(scopes=["memory"])
async def update_end_user_info(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
):
"""
Update end user info.
Updates the info record (other_name, aliases, meta_data) for the specified end user.
Delegates to the manager-side controller for shared logic.
"""
body = await request.json()
payload = EndUserInfoUpdate(**body)
current_user = _get_current_user(api_key_auth, db)
return await user_memory_controllers.update_end_user_info(
info_update=payload,
current_user=current_user,
db=db,
)

View File

@@ -1,5 +1,8 @@
"""Memory 服务接口 - 基于 API Key 认证"""
from fastapi import APIRouter, Body, Depends, Query, Request
from sqlalchemy.orm import Session
from app.core.api_key_auth import require_api_key
from app.core.logging_config import get_business_logger
from app.core.quota_stub import check_end_user_quota
@@ -7,48 +10,74 @@ from app.core.response_utils import success
from app.db import get_db
from app.schemas.api_key_schema import ApiKeyAuth
from app.schemas.memory_api_schema import (
CreateEndUserRequest,
CreateEndUserResponse,
ListConfigsResponse,
MemoryReadRequest,
MemoryReadResponse,
MemoryReadSyncResponse,
MemoryWriteRequest,
MemoryWriteResponse,
MemoryWriteSyncResponse,
)
from app.services.memory_api_service import MemoryAPIService
from fastapi import APIRouter, Body, Depends, Request
from sqlalchemy.orm import Session
router = APIRouter(prefix="/memory", tags=["V1 - Memory API"])
logger = get_business_logger()
def _sanitize_task_result(result: dict) -> dict:
"""Make Celery task result JSON-serializable.
Converts UUID and other non-serializable values to strings.
Args:
result: Raw task result dict from task_service
Returns:
JSON-safe dict
"""
import uuid as _uuid
from datetime import datetime
def _convert(obj):
if isinstance(obj, dict):
return {k: _convert(v) for k, v in obj.items()}
if isinstance(obj, list):
return [_convert(i) for i in obj]
if isinstance(obj, _uuid.UUID):
return str(obj)
if isinstance(obj, datetime):
return obj.isoformat()
return obj
return _convert(result)
@router.get("")
async def get_memory_info():
"""获取记忆服务信息(占位)"""
return success(data={}, msg="Memory API - Coming Soon")
@router.post("/write_api_service")
@router.post("/write")
@require_api_key(scopes=["memory"])
async def write_memory_api_service(
async def write_memory(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(..., description="Message content"),
):
"""
Write memory to storage.
Stores memory content for the specified end user using the Memory API Service.
Submit a memory write task.
Validates the end user, then dispatches the write to a Celery background task
with per-user fair locking. Returns a task_id for status polling.
"""
body = await request.json()
payload = MemoryWriteRequest(**body)
logger.info(f"Memory write request - end_user_id: {payload.end_user_id}, workspace_id: {api_key_auth.workspace_id}")
memory_api_service = MemoryAPIService(db)
result = await memory_api_service.write_memory(
result = memory_api_service.write_memory(
workspace_id=api_key_auth.workspace_id,
end_user_id=payload.end_user_id,
message=payload.message,
@@ -56,31 +85,53 @@ async def write_memory_api_service(
storage_type=payload.storage_type,
user_rag_memory_id=payload.user_rag_memory_id,
)
logger.info(f"Memory write successful for end_user: {payload.end_user_id}")
return success(data=MemoryWriteResponse(**result).model_dump(), msg="Memory written successfully")
logger.info(f"Memory write task submitted: task_id={result['task_id']}, end_user_id: {payload.end_user_id}")
return success(data=MemoryWriteResponse(**result).model_dump(), msg="Memory write task submitted")
@router.post("/read_api_service")
@router.get("/write/status")
@require_api_key(scopes=["memory"])
async def read_memory_api_service(
async def get_write_task_status(
request: Request,
task_id: str = Query(..., description="Celery task ID"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Check the status of a memory write task.
Returns the current status and result (if completed) of a previously submitted write task.
"""
logger.info(f"Write task status check - task_id: {task_id}")
from app.services.task_service import get_task_memory_write_result
result = get_task_memory_write_result(task_id)
return success(data=_sanitize_task_result(result), msg="Task status retrieved")
@router.post("/read")
@require_api_key(scopes=["memory"])
async def read_memory(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(..., description="Query message"),
):
"""
Read memory from storage.
Queries and retrieves memories for the specified end user with context-aware responses.
Submit a memory read task.
Validates the end user, then dispatches the read to a Celery background task.
Returns a task_id for status polling.
"""
body = await request.json()
payload = MemoryReadRequest(**body)
logger.info(f"Memory read request - end_user_id: {payload.end_user_id}")
memory_api_service = MemoryAPIService(db)
result = await memory_api_service.read_memory(
result = memory_api_service.read_memory(
workspace_id=api_key_auth.workspace_id,
end_user_id=payload.end_user_id,
message=payload.message,
@@ -89,59 +140,95 @@ async def read_memory_api_service(
storage_type=payload.storage_type,
user_rag_memory_id=payload.user_rag_memory_id,
)
logger.info(f"Memory read successful for end_user: {payload.end_user_id}")
return success(data=MemoryReadResponse(**result).model_dump(), msg="Memory read successfully")
logger.info(f"Memory read task submitted: task_id={result['task_id']}, end_user_id: {payload.end_user_id}")
return success(data=MemoryReadResponse(**result).model_dump(), msg="Memory read task submitted")
@router.get("/configs")
@router.get("/read/status")
@require_api_key(scopes=["memory"])
async def list_memory_configs(
async def get_read_task_status(
request: Request,
task_id: str = Query(..., description="Celery task ID"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
List all memory configs for the workspace.
Returns all available memory configurations associated with the authorized workspace.
Check the status of a memory read task.
Returns the current status and result (if completed) of a previously submitted read task.
"""
logger.info(f"List configs request - workspace_id: {api_key_auth.workspace_id}")
logger.info(f"Read task status check - task_id: {task_id}")
memory_api_service = MemoryAPIService(db)
from app.services.task_service import get_task_memory_read_result
result = get_task_memory_read_result(task_id)
result = memory_api_service.list_memory_configs(
workspace_id=api_key_auth.workspace_id,
)
logger.info(f"Listed {result['total']} configs for workspace: {api_key_auth.workspace_id}")
return success(data=ListConfigsResponse(**result).model_dump(), msg="Configs listed successfully")
return success(data=_sanitize_task_result(result), msg="Task status retrieved")
@router.post("/end_users")
@router.post("/write/sync")
@require_api_key(scopes=["memory"])
@check_end_user_quota
async def create_end_user(
async def write_memory_sync(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(..., description="Message content"),
):
"""
Create an end user.
Creates a new end user for the authorized workspace.
If an end user with the same other_id already exists, returns the existing one.
Write memory synchronously.
Blocks until the write completes and returns the result directly.
For async processing with task polling, use /write instead.
"""
body = await request.json()
payload = CreateEndUserRequest(**body)
logger.info(f"Create end user request - other_id: {payload.other_id}, workspace_id: {api_key_auth.workspace_id}")
payload = MemoryWriteRequest(**body)
logger.info(f"Memory write (sync) request - end_user_id: {payload.end_user_id}")
memory_api_service = MemoryAPIService(db)
result = memory_api_service.create_end_user(
result = await memory_api_service.write_memory_sync(
workspace_id=api_key_auth.workspace_id,
other_id=payload.other_id,
end_user_id=payload.end_user_id,
message=payload.message,
config_id=payload.config_id,
storage_type=payload.storage_type,
user_rag_memory_id=payload.user_rag_memory_id,
)
logger.info(f"End user ready: {result['id']}")
return success(data=CreateEndUserResponse(**result).model_dump(), msg="End user created successfully")
logger.info(f"Memory write (sync) successful for end_user: {payload.end_user_id}")
return success(data=MemoryWriteSyncResponse(**result).model_dump(), msg="Memory written successfully")
@router.post("/read/sync")
@require_api_key(scopes=["memory"])
async def read_memory_sync(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(..., description="Query message"),
):
"""
Read memory synchronously.
Blocks until the read completes and returns the answer directly.
For async processing with task polling, use /read instead.
"""
body = await request.json()
payload = MemoryReadRequest(**body)
logger.info(f"Memory read (sync) request - end_user_id: {payload.end_user_id}")
memory_api_service = MemoryAPIService(db)
result = await memory_api_service.read_memory_sync(
workspace_id=api_key_auth.workspace_id,
end_user_id=payload.end_user_id,
message=payload.message,
search_switch=payload.search_switch,
config_id=payload.config_id,
storage_type=payload.storage_type,
user_rag_memory_id=payload.user_rag_memory_id,
)
logger.info(f"Memory read (sync) successful for end_user: {payload.end_user_id}")
return success(data=MemoryReadSyncResponse(**result).model_dump(), msg="Memory read successfully")

View File

@@ -0,0 +1,491 @@
"""Memory Config 服务接口 - 基于 API Key 认证"""
from typing import Optional
import uuid
from fastapi import APIRouter, Body, Depends, Header, Query, Request
from fastapi.encoders import jsonable_encoder
from sqlalchemy.orm import Session
from app.controllers import memory_storage_controller
from app.controllers import memory_forget_controller
from app.controllers import ontology_controller
from app.controllers import emotion_config_controller
from app.controllers import memory_reflection_controller
from app.schemas.memory_storage_schema import ForgettingConfigUpdateRequest
from app.controllers.emotion_config_controller import EmotionConfigUpdate
from app.schemas.memory_reflection_schemas import Memory_Reflection
from app.core.api_key_auth import require_api_key
from app.core.error_codes import BizCode
from app.core.exceptions import BusinessException
from app.core.logging_config import get_business_logger
from app.core.response_utils import success
from app.db import get_db
from app.repositories.memory_config_repository import MemoryConfigRepository
from app.schemas.api_key_schema import ApiKeyAuth
from app.schemas.memory_api_schema import (
ConfigUpdateExtractedRequest,
ConfigUpdateRequest,
ListConfigsResponse,
ConfigCreateRequest,
ConfigUpdateForgettingRequest,
EmotionConfigUpdateRequest,
ReflectionConfigUpdateRequest,
)
from app.schemas.memory_storage_schema import (
ConfigUpdate,
ConfigUpdateExtracted,
ConfigParamsCreate,
)
from app.services import api_key_service
from app.services.memory_api_service import MemoryAPIService
from app.utils.config_utils import resolve_config_id
router = APIRouter(prefix="/memory_config", tags=["V1 - Memory Config API"])
logger = get_business_logger()
def _get_current_user(api_key_auth: ApiKeyAuth, db: Session):
"""Build a current_user object from API key auth
Args:
api_key_auth: Validated API key auth info
db: Database session
Returns:
User object with current_workspace_id set
"""
api_key = api_key_service.ApiKeyService.get_api_key(db, api_key_auth.api_key_id, api_key_auth.workspace_id)
current_user = api_key.creator
current_user.current_workspace_id = api_key_auth.workspace_id
return current_user
def _verify_config_ownership(config_id:str, workspace_id:uuid.UUID, db:Session):
"""Verify that the config belongs to the workspace.
Args:
config_id: The ID of the config to verify
workspace_id: The workspace ID tocheck against
db: Database session for querying
Raises:
BusinessException: If the config does not exist or does not belong to the workspace
"""
try:
resolved_id = resolve_config_id(config_id, db)
except ValueError as e:
raise BusinessException(
message=f"Invalid config_id: {e}",
code=BizCode.INVALID_PARAMETER,
)
config = MemoryConfigRepository.get_by_id(db, resolved_id)
if not config or config.workspace_id != workspace_id:
raise BusinessException(
message="Config not found or access denied",
code=BizCode.MEMORY_CONFIG_NOT_FOUND,
)
# @router.get("/configs")
# @require_api_key(scopes=["memory"])
# async def list_memory_configs(
# request: Request,
# api_key_auth: ApiKeyAuth = None,
# db: Session = Depends(get_db),
# ):
# """
# List all memory configs for the workspace.
# Returns all available memory configurations associated with the authorized workspace.
# """
# logger.info(f"List configs request - workspace_id: {api_key_auth.workspace_id}")
# memory_api_service = MemoryAPIService(db)
# result = memory_api_service.list_memory_configs(
# workspace_id=api_key_auth.workspace_id,
# )
# logger.info(f"Listed {result['total']} configs for workspace: {api_key_auth.workspace_id}")
# return success(data=ListConfigsResponse(**result).model_dump(), msg="Configs listed successfully")
@router.get("/read_all_config")
@require_api_key(scopes=["memory"])
async def read_all_config(
request:Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
List all memory configs with full details (enhanced version).
Returns complete config fields for the authorized workspace.
No config_id ownership check needed — results are filtered by workspace.
"""
logger.info(f"V1 get all configs (full) - workspace: {api_key_auth.workspace_id}")
current_user = _get_current_user(api_key_auth, db)
return memory_storage_controller.read_all_config(
current_user=current_user,
db=db,
)
@router.get("/scenes/simple")
@require_api_key(scopes=["memory"])
async def get_ontology_scenes(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Get available ontology scenes for the workspace.
Returns a simple list of scene_id and scene_name for dropdown selection.
Used before creating a memory config to choose which ontology scene to associate.
"""
logger.info(f"V1 get scenes - workspace: {api_key_auth.workspace_id}")
current_user = _get_current_user(api_key_auth, db)
return await ontology_controller.get_scenes_simple(
db=db,
current_user=current_user,
)
@router.get("/read_config_extracted")
@require_api_key(scopes=["memory"])
async def read_config_extracted(
request: Request,
config_id: str = Query(..., description="config_id"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Get extraction engine config details for a specific config.
Only configs belonging to the authorized workspace can be queried.
"""
logger.info(f"V1 read extracted config - config_id: {config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
return memory_storage_controller.read_config_extracted(
config_id = config_id,
current_user = current_user,
db = db,
)
@router.get("/read_config_forgetting")
@require_api_key(scopes=["memory"])
async def read_config_forgetting(
request: Request,
config_id: str = Query(..., description="config_id"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Get forgetting settings for a specific memory config.
Only configs belonging to the authorized workspace can be queried.
"""
logger.info(f"V1 read forgetting config - config_id: {config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
result = await memory_forget_controller.read_forgetting_config(
config_id = config_id,
current_user = current_user,
db = db,
)
return jsonable_encoder(result)
@router.get("/read_config_emotion")
@require_api_key(scopes=["memory"])
async def read_config_emotion(
request: Request,
config_id: str = Query(..., description="config_id"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Get emotion engine config details for a specific config.
Only configs belonging to the authorized workspace can be queried.
"""
logger.info(f"V1 read emotion config - config_id: {config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
return jsonable_encoder(emotion_config_controller.get_emotion_config(
config_id=config_id,
db=db,
current_user=current_user,
))
@router.get("/read_config_reflection")
@require_api_key(scopes=["memory"])
async def read_config_reflection(
request: Request,
config_id: str = Query(..., description="config_id"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Get reflection engine config details for a specific config.
Only configs belonging to the authorized workspace can be queried.
"""
logger.info(f"V1 read reflection config - config_id: {config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
return jsonable_encoder(await memory_reflection_controller.start_reflection_configs(
config_id=config_id,
current_user=current_user,
db=db,
))
@router.post("/create_config")
@require_api_key(scopes=["memory"])
async def create_memory_config(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
x_language_type: Optional[str] = Header(None, alias="X-Language-Type"),
):
"""
Create a new memory config for the workspace.
The config will be associated with the workspace of the API Key.
config_name is required, other fields are optional.
"""
body = await request.json()
payload = ConfigCreateRequest(**body)
logger.info(f"V1 create config - workspace: {api_key_auth.workspace_id}, config_name: {payload.config_name}")
# 构造管理端 Schemaworkspace_id 从 API Key 注入
current_user = _get_current_user(api_key_auth, db)
mgmt_payload = ConfigParamsCreate(
config_name=payload.config_name,
config_desc=payload.config_desc or "",
scene_id=payload.scene_id,
llm_id=payload.llm_id,
embedding_id=payload.embedding_id,
rerank_id=payload.rerank_id,
reflection_model_id=payload.reflection_model_id,
emotion_model_id=payload.emotion_model_id,
)
#将返回数据中UUID序列化处理
result =memory_storage_controller.create_config(
payload=mgmt_payload,
current_user=current_user,
db=db,
x_language_type=x_language_type,
)
return jsonable_encoder(result)
@router.put("/update_config")
@require_api_key(scopes=["memory"])
async def update_memory_config(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
):
"""
Update memory config basic info (name, description, scene).
Requires API Key with 'memory' scope
Only configs belonging to the authorized workspace can be updated.
"""
body = await request.json()
payload = ConfigUpdateRequest(**body)
logger.info(f"V1 update config - config_id: {payload.config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(payload.config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
mgmt_payload = ConfigUpdate(
config_id = payload.config_id,
config_name = payload.config_name,
config_desc = payload.config_desc,
scene_id = payload.scene_id,
)
return memory_storage_controller.update_config(
payload = mgmt_payload,
current_user = current_user,
db = db,
)
@router.put("/update_config_extracted")
@require_api_key(scopes=["memory"])
async def update_memory_config_extracted(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
):
"""
update memory config extraction engine config (models, thresholds, chunking, pruning, etc.).
Requires API Key with 'memory' scope.
Only configs belonging to the authorized workspace can be updated.
"""
body = await request.json()
payload = ConfigUpdateExtractedRequest(**body)
logger.info(f"V1 update extracted config - config_id: {payload.config_id}, workspace: {api_key_auth.workspace_id}")
#校验权限
_verify_config_ownership(payload.config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
update_fields = payload.model_dump(exclude_unset=True)
mgmt_payload = ConfigUpdateExtracted(**update_fields)
return memory_storage_controller.update_config_extracted(
payload = mgmt_payload,
current_user = current_user,
db = db,
)
@router.put("/update_config_forgetting")
@require_api_key(scopes=["memory"])
async def update_memory_config_forgetting(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
):
"""
update memory config forgetting settings (forgetting strategy, parameters, etc.).
Requires API Key with 'memory' scope.
Only configs belonging to the authorized workspace can be updated.
"""
body = await request.json()
payload = ConfigUpdateForgettingRequest(**body)
logger.info(f"V1 update forgetting config - config_id: {payload.config_id}, workspace: {api_key_auth.workspace_id}")
#校验权限
_verify_config_ownership(payload.config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
update_fields = payload.model_dump(exclude_unset=True)
mgmt_payload = ForgettingConfigUpdateRequest(**update_fields)
#将返回数据中UUID序列化处理
result = await memory_forget_controller.update_forgetting_config(
payload = mgmt_payload,
current_user = current_user,
db = db,
)
return jsonable_encoder(result)
@router.put("/update_config_emotion")
@require_api_key(scopes=["memory"])
async def update_config_emotion(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
):
"""
Update emotion engine config (full update).
All fields except emotion_model_id are required.
Only configs belonging to the authorized workspace can be updated.
"""
body = await request.json()
payload = EmotionConfigUpdateRequest(**body)
logger.info(f"V1 update emotion config - config_id: {payload.config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(payload.config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
update_fields = payload.model_dump(exclude_unset=True)
mgmt_payload = EmotionConfigUpdate(**update_fields)
return jsonable_encoder(emotion_config_controller.update_emotion_config(
config=mgmt_payload,
db=db,
current_user=current_user,
))
@router.put("/update_config_reflection")
@require_api_key(scopes=["memory"])
async def update_config_reflection(
request: Request,
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
message: str = Body(None, description="Request body"),
):
"""
Update reflection engine config (full update).
All fields are required.
Only configs belonging to the authorized workspace can be updated.
"""
body = await request.json()
payload = ReflectionConfigUpdateRequest(**body)
logger.info(f"V1 update reflection config - config_id: {payload.config_id}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(payload.config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
update_fields = payload.model_dump(exclude_unset=True)
mgmt_payload = Memory_Reflection(**update_fields)
return jsonable_encoder(await memory_reflection_controller.save_reflection_config(
request=mgmt_payload,
current_user=current_user,
db=db,
))
@router.delete("/delete_config")
@require_api_key(scopes=["memory"])
async def delete_memory_config(
config_id: str,
request: Request,
force: bool = Query(False, description="是否强制删除(即使有终端用户正在使用)"),
api_key_auth: ApiKeyAuth = None,
db: Session = Depends(get_db),
):
"""
Delete a memory config.
- Default configs cannot be deleted.
- If end users are connected and force=False, returns a warning.
- If force=True, clears end user references and deletes the config.
Only configs belonging to the authorized workspace can be deleted.
"""
logger.info(f"V1 delete config - config_id: {config_id}, force: {force}, workspace: {api_key_auth.workspace_id}")
_verify_config_ownership(config_id, api_key_auth.workspace_id, db)
current_user = _get_current_user(api_key_auth, db)
return memory_storage_controller.delete_config(
config_id=config_id,
force=force,
current_user=current_user,
db=db,
)