Skip to content

Commit 9c7838f

Browse files
authored
♻️ Refactor cleanup model_managment_app.py, memory_config_app.py
2 parents 6261e5b + b9d65d4 commit 9c7838f

24 files changed

+3049
-1660
lines changed

backend/apps/me_model_managment_app.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from http import HTTPStatus
33

4-
from fastapi import APIRouter, Query
4+
from fastapi import APIRouter, Query, HTTPException
55
from fastapi.responses import JSONResponse
66

77
from consts.exceptions import TimeoutException, NotFoundException, MEConnectionException
@@ -44,9 +44,9 @@ async def get_me_models(
4444
"data": []
4545
})
4646
except Exception as e:
47-
logging.error(f"Failed to get model list: {str(e)}")
47+
logging.error(f"Failed to get me model list: {str(e)}")
4848
return JSONResponse(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, content={
49-
"message": f"Failed to get model list: {str(e)}",
49+
"message": f"Failed to get me model list: {str(e)}",
5050
"data": []
5151
})
5252

@@ -61,23 +61,16 @@ async def check_me_connectivity(timeout: int = Query(default=2, description="Tim
6161
return JSONResponse(
6262
status_code=HTTPStatus.OK,
6363
content={
64-
"status": "Connected",
65-
"desc": "Connection successful.",
66-
"connect_status": ModelConnectStatusEnum.AVAILABLE.value
64+
"connectivity": True,
65+
"message": "ModelEngine model connect successfully.",
6766
}
6867
)
6968
except MEConnectionException as e:
70-
logging.error(f"Request me model connectivity failed: {str(e)}")
71-
return JSONResponse(status_code=HTTPStatus.SERVICE_UNAVAILABLE, content={"status": "Disconnected",
72-
"desc": f"Connection failed.",
73-
"connect_status": ModelConnectStatusEnum.UNAVAILABLE.value})
69+
logging.error(f"ModelEngine model healthcheck failed: {str(e)}")
70+
raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail="ModelEngine model connect failed.")
7471
except TimeoutException as e:
75-
logging.error(f"Request me model connectivity timeout: {str(e)}")
76-
return JSONResponse(status_code=HTTPStatus.REQUEST_TIMEOUT, content={"status": "Disconnected",
77-
"desc": "Connection timeout.",
78-
"connect_status": ModelConnectStatusEnum.UNAVAILABLE.value})
72+
logging.error(f"ModelEngine model healthcheck timeout: {str(e)}")
73+
raise HTTPException(status_code=HTTPStatus.REQUEST_TIMEOUT, detail="ModelEngine model connect timeout.")
7974
except Exception as e:
80-
logging.error(f"Unknown error occurred: {str(e)}.")
81-
return JSONResponse(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, content={"status": "Disconnected",
82-
"desc": f"Unknown error occurred: {str(e)}",
83-
"connect_status": ModelConnectStatusEnum.UNAVAILABLE.value})
75+
logging.error(f"ModelEngine model healthcheck failed with unknown error: {str(e)}.")
76+
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="ModelEngine model connect failed.")

backend/apps/memory_config_app.py

Lines changed: 142 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,45 @@
1+
"""Memory configuration and CRUD API endpoints for the app layer.
2+
3+
This module exposes HTTP endpoints under the `/memory` prefix. It follows the
4+
app-layer responsibilities:
5+
- Parse and validate HTTP inputs
6+
- Delegate business logic to the service layer
7+
- Convert unexpected exceptions to error JSON responses
8+
9+
Routes:
10+
- GET `/memory/config/load`: Load memory-related configuration for current user
11+
- POST `/memory/config/set`: Set a single configuration entry
12+
- POST `/memory/config/disable_agent`: Add a disabled agent id
13+
- DELETE `/memory/config/disable_agent/{agent_id}`: Remove a disabled agent id
14+
- POST `/memory/config/disable_useragent`: Add a disabled user-agent id
15+
- DELETE `/memory/config/disable_useragent/{agent_id}`: Remove a disabled user-agent id
16+
- POST `/memory/add`: Add memory items (optionally with LLM inference)
17+
- POST `/memory/search`: Semantic search memory items
18+
- GET `/memory/list`: List memory items
19+
- DELETE `/memory/delete/{memory_id}`: Delete a single memory item
20+
- DELETE `/memory/clear`: Clear memory items by scope
21+
"""
122
import asyncio
223
import logging
324
from typing import Any, Dict, List, Optional
425

5-
from fastapi import APIRouter, Body, Header, Path, Query
26+
from http import HTTPStatus
27+
from fastapi import APIRouter, Body, Header, Path, Query, HTTPException
628
from fastapi.responses import JSONResponse
29+
730
from nexent.memory.memory_service import (
831
add_memory as svc_add_memory,
932
clear_memory as svc_clear_memory,
1033
delete_memory as svc_delete_memory,
1134
list_memory as svc_list_memory,
1235
search_memory as svc_search_memory,
1336
)
14-
1537
from consts.const import (
1638
MEMORY_AGENT_SHARE_KEY,
1739
MEMORY_SWITCH_KEY,
1840
)
1941
from consts.model import MemoryAgentShareMode
42+
from consts.exceptions import UnauthorizedError
2043
from services.memory_config_service import (
2144
add_disabled_agent_id,
2245
add_disabled_useragent_id,
@@ -34,35 +57,26 @@
3457
router = APIRouter(prefix="/memory")
3558

3659

37-
# ---------------------------------------------------------------------------
38-
# Generic helpers
39-
# ---------------------------------------------------------------------------
40-
def _success(message: str = "success", content: Optional[Any] = None):
41-
return JSONResponse(status_code=200, content={"message": message, "status": "success", "content": content})
42-
43-
44-
def _error(message: str = "error"):
45-
return JSONResponse(status_code=400, content={"message": message, "status": "error"})
46-
47-
48-
# ---------------------------------------------------------------------------
49-
# Helper function
50-
# ---------------------------------------------------------------------------
51-
52-
5360
# ---------------------------------------------------------------------------
5461
# Configuration Endpoints
5562
# ---------------------------------------------------------------------------
5663
@router.get("/config/load")
5764
def load_configs(authorization: Optional[str] = Header(None)):
58-
"""Load all memory-related configuration for current user."""
65+
"""Load all memory-related configuration for the current user.
66+
67+
Args:
68+
authorization: Optional authorization header used to identify the user.
69+
"""
5970
try:
6071
user_id, _ = get_current_user_id(authorization)
6172
configs = get_user_configs(user_id)
62-
return _success(content=configs)
73+
return JSONResponse(status_code=HTTPStatus.OK, content=configs)
74+
except UnauthorizedError as e:
75+
raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail=str(e))
6376
except Exception as e:
6477
logger.error("load_configs failed: %s", e)
65-
return _error("Failed to load configuration")
78+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
79+
detail="Failed to load configuration")
6680

6781

6882
@router.post("/config/set")
@@ -71,7 +85,17 @@ def set_single_config(
7185
value: Any = Body(..., embed=True, description="Configuration value"),
7286
authorization: Optional[str] = Header(None),
7387
):
74-
"""Unified endpoint to set single-value configuration items."""
88+
"""Set a single-value configuration item for the current user.
89+
90+
Supported keys:
91+
- `MEMORY_SWITCH_KEY`: Toggle memory system on/off (boolean-like values accepted)
92+
- `MEMORY_AGENT_SHARE_KEY`: Set agent share mode (`always`/`ask`/`never`)
93+
94+
Args:
95+
key: Configuration key to update.
96+
value: New value for the configuration key.
97+
authorization: Optional authorization header used to identify the user.
98+
"""
7599
user_id, _ = get_current_user_id(authorization)
76100

77101
if key == MEMORY_SWITCH_KEY:
@@ -82,52 +106,93 @@ def set_single_config(
82106
try:
83107
mode = MemoryAgentShareMode(str(value))
84108
except ValueError:
85-
return _error("Invalid value for MEMORY_AGENT_SHARE (expected always/ask/never)")
109+
raise HTTPException(status_code=HTTPStatus.NOT_ACCEPTABLE,
110+
detail="Invalid value for MEMORY_AGENT_SHARE (expected always/ask/never)")
86111
ok = set_agent_share(user_id, mode)
87112
else:
88-
return _error("Unsupported configuration key")
113+
raise HTTPException(status_code=HTTPStatus.NOT_ACCEPTABLE,
114+
detail="Unsupported configuration key")
89115

90-
return _success() if ok else _error("Failed to update configuration")
116+
if ok:
117+
return JSONResponse(status_code=HTTPStatus.OK, content={"success": True})
118+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
119+
detail="Failed to update configuration")
91120

92121

93122
@router.post("/config/disable_agent")
94123
def add_disable_agent(
95124
agent_id: str = Body(..., embed=True),
96125
authorization: Optional[str] = Header(None),
97126
):
127+
"""Add an agent id to the user's disabled agent list.
128+
129+
Args:
130+
agent_id: Identifier of the agent to disable.
131+
authorization: Optional authorization header used to identify the user.
132+
"""
98133
user_id, _ = get_current_user_id(authorization)
99134
ok = add_disabled_agent_id(user_id, agent_id)
100-
return _success() if ok else _error("Failed to add disable agent id")
135+
if ok:
136+
return JSONResponse(status_code=HTTPStatus.OK, content={"success": True})
137+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
138+
detail="Failed to add disable agent id")
101139

102140

103141
@router.delete("/config/disable_agent/{agent_id}")
104142
def remove_disable_agent(
105143
agent_id: str = Path(...),
106144
authorization: Optional[str] = Header(None),
107145
):
146+
"""Remove an agent id from the user's disabled agent list.
147+
148+
Args:
149+
agent_id: Identifier of the agent to remove from the disabled list.
150+
authorization: Optional authorization header used to identify the user.
151+
"""
108152
user_id, _ = get_current_user_id(authorization)
109153
ok = remove_disabled_agent_id(user_id, agent_id)
110-
return _success() if ok else _error("Failed to remove disable agent id")
154+
if ok:
155+
return JSONResponse(status_code=HTTPStatus.OK, content={"success": True})
156+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
157+
detail="Failed to remove disable agent id")
111158

112159

113160
@router.post("/config/disable_useragent")
114161
def add_disable_useragent(
115162
agent_id: str = Body(..., embed=True),
116163
authorization: Optional[str] = Header(None),
117164
):
165+
"""Add a user-agent id to the user's disabled user-agent list.
166+
167+
Args:
168+
agent_id: Identifier of the user-agent to disable.
169+
authorization: Optional authorization header used to identify the user.
170+
"""
118171
user_id, _ = get_current_user_id(authorization)
119172
ok = add_disabled_useragent_id(user_id, agent_id)
120-
return _success() if ok else _error("Failed to add disable user-agent id")
173+
if ok:
174+
return JSONResponse(status_code=HTTPStatus.OK, content={"success": True})
175+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
176+
detail="Failed to add disable user-agent id")
121177

122178

123179
@router.delete("/config/disable_useragent/{agent_id}")
124180
def remove_disable_useragent(
125181
agent_id: str = Path(...),
126182
authorization: Optional[str] = Header(None),
127183
):
184+
"""Remove a user-agent id from the user's disabled user-agent list.
185+
186+
Args:
187+
agent_id: Identifier of the user-agent to remove from the disabled list.
188+
authorization: Optional authorization header used to identify the user.
189+
"""
128190
user_id, _ = get_current_user_id(authorization)
129191
ok = remove_disabled_useragent_id(user_id, agent_id)
130-
return _success() if ok else _error("Failed to remove disable user-agent id")
192+
if ok:
193+
return JSONResponse(status_code=HTTPStatus.OK, content={"success": True})
194+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
195+
detail="Failed to remove disable user-agent id")
131196

132197

133198
# ---------------------------------------------------------------------------
@@ -144,6 +209,15 @@ def add_memory(
144209
True, embed=True, description="Whether to run LLM inference during add"),
145210
authorization: Optional[str] = Header(None),
146211
):
212+
"""Add memory records for the given scope.
213+
214+
Args:
215+
messages: List of chat messages as dictionaries.
216+
memory_level: Scope for the memory record (tenant/agent/user/user_agent).
217+
agent_id: Optional agent identifier when scope is agent-related.
218+
infer: Whether to run LLM inference during add.
219+
authorization: Optional authorization header used to identify the user.
220+
"""
147221
user_id, tenant_id = get_current_user_id(authorization)
148222
try:
149223
result = asyncio.run(svc_add_memory(
@@ -155,10 +229,10 @@ def add_memory(
155229
agent_id=agent_id,
156230
infer=infer,
157231
))
158-
return _success(content=result)
232+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
159233
except Exception as e:
160234
logger.error("add_memory error: %s", e, exc_info=True)
161-
return _error(str(e))
235+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
162236

163237

164238
@router.post("/search")
@@ -169,6 +243,15 @@ def search_memory(
169243
agent_id: Optional[str] = Body(None, embed=True),
170244
authorization: Optional[str] = Header(None),
171245
):
246+
"""Search memory semantically for the given scope.
247+
248+
Args:
249+
query_text: Natural language query to search memory.
250+
memory_level: Scope for search (tenant/agent/user/user_agent).
251+
top_k: Maximum number of results to return.
252+
agent_id: Optional agent identifier when scope is agent-related.
253+
authorization: Optional authorization header used to identify the user.
254+
"""
172255
user_id, tenant_id = get_current_user_id(authorization)
173256
try:
174257
results = asyncio.run(svc_search_memory(
@@ -180,10 +263,10 @@ def search_memory(
180263
top_k=top_k,
181264
agent_id=agent_id,
182265
))
183-
return _success(content=results)
266+
return JSONResponse(status_code=HTTPStatus.OK, content=results)
184267
except Exception as e:
185268
logger.error("search_memory error: %s", e, exc_info=True)
186-
return _error(str(e))
269+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
187270

188271

189272
@router.get("/list")
@@ -194,6 +277,13 @@ def list_memory(
194277
None, description="Filter by agent id if applicable"),
195278
authorization: Optional[str] = Header(None),
196279
):
280+
"""List memory for the given scope.
281+
282+
Args:
283+
memory_level: Scope for listing (tenant/agent/user/user_agent).
284+
agent_id: Optional agent filter when scope is agent-related.
285+
authorization: Optional authorization header used to identify the user.
286+
"""
197287
user_id, tenant_id = get_current_user_id(authorization)
198288
try:
199289
payload = asyncio.run(svc_list_memory(
@@ -203,25 +293,31 @@ def list_memory(
203293
user_id=user_id,
204294
agent_id=agent_id,
205295
))
206-
return _success(content=payload)
296+
return JSONResponse(status_code=HTTPStatus.OK, content=payload)
207297
except Exception as e:
208298
logger.error("list_memory error: %s", e, exc_info=True)
209-
return _error(str(e))
299+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
210300

211301

212302
@router.delete("/delete/{memory_id}")
213303
def delete_memory(
214304
memory_id: str = Path(..., description="ID of memory to delete"),
215305
authorization: Optional[str] = Header(None),
216306
):
307+
"""Delete a specific memory record by id.
308+
309+
Args:
310+
memory_id: Identifier of the memory record to delete.
311+
authorization: Optional authorization header used to identify the user.
312+
"""
217313
_user_id, tenant_id = get_current_user_id(authorization)
218314
try:
219315
result = asyncio.run(svc_delete_memory(
220316
memory_id=memory_id, memory_config=build_memory_config(tenant_id)))
221-
return _success(content=result)
317+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
222318
except Exception as e:
223319
logger.error("delete_memory error: %s", e, exc_info=True)
224-
return _error(str(e))
320+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
225321

226322

227323
@router.delete("/clear")
@@ -232,6 +328,13 @@ def clear_memory(
232328
None, description="Filter by agent id if applicable"),
233329
authorization: Optional[str] = Header(None),
234330
):
331+
"""Clear memory records for the given scope.
332+
333+
Args:
334+
memory_level: Scope for clearing (tenant/agent/user/user_agent).
335+
agent_id: Optional agent filter when scope is agent-related.
336+
authorization: Optional authorization header used to identify the user.
337+
"""
235338
user_id, tenant_id = get_current_user_id(authorization)
236339
try:
237340
result = asyncio.run(svc_clear_memory(
@@ -241,7 +344,7 @@ def clear_memory(
241344
user_id=user_id,
242345
agent_id=agent_id,
243346
))
244-
return _success(content=result)
347+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
245348
except Exception as e:
246349
logger.error("clear_memory error: %s", e, exc_info=True)
247-
return _error(str(e))
350+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))

0 commit comments

Comments
 (0)