Skip to content

Commit b99e36f

Browse files
authored
Release/v1.8.0.1
Release/v1.8.0.1
2 parents 3ed8134 + 6c3e4d2 commit b99e36f

File tree

185 files changed

+7553
-2403
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

185 files changed

+7553
-2403
lines changed

backend/agents/create_agent_info.py

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from services.memory_config_service import build_memory_context
2020
from services.image_service import get_vlm_model
2121
from database.agent_db import search_agent_info_by_agent_id, query_sub_agents_id_list
22+
from database.agent_version_db import query_current_version_no
2223
from database.tool_db import search_tools_for_sub_agent
2324
from database.model_management_db import get_model_records, get_model_by_model_id
2425
from database.client import minio_client
@@ -75,26 +76,31 @@ async def create_agent_config(
7576
language: str = LANGUAGE["ZH"],
7677
last_user_query: str = None,
7778
allow_memory_search: bool = True,
79+
version_no: int = 0,
7880
):
7981
agent_info = search_agent_info_by_agent_id(
80-
agent_id=agent_id, tenant_id=tenant_id)
82+
agent_id=agent_id, tenant_id=tenant_id, version_no=version_no)
8183

8284
# create sub agent
8385
sub_agent_id_list = query_sub_agents_id_list(
84-
main_agent_id=agent_id, tenant_id=tenant_id)
86+
main_agent_id=agent_id, tenant_id=tenant_id, version_no=version_no)
8587
managed_agents = []
8688
for sub_agent_id in sub_agent_id_list:
89+
# Get the current published version for this sub-agent (from draft version 0)
90+
sub_agent_version_no = query_current_version_no(
91+
agent_id=sub_agent_id, tenant_id=tenant_id) or 0
8792
sub_agent_config = await create_agent_config(
8893
agent_id=sub_agent_id,
8994
tenant_id=tenant_id,
9095
user_id=user_id,
9196
language=language,
9297
last_user_query=last_user_query,
9398
allow_memory_search=allow_memory_search,
99+
version_no=sub_agent_version_no,
94100
)
95101
managed_agents.append(sub_agent_config)
96102

97-
tool_list = await create_tool_config_list(agent_id, tenant_id, user_id)
103+
tool_list = await create_tool_config_list(agent_id, tenant_id, user_id, version_no=version_no)
98104

99105
# Build system prompt: prioritize segmented fields, fallback to original prompt field if not available
100106
duty_prompt = agent_info.get("duty_prompt", "")
@@ -202,13 +208,13 @@ async def create_agent_config(
202208
return agent_config
203209

204210

205-
async def create_tool_config_list(agent_id, tenant_id, user_id):
211+
async def create_tool_config_list(agent_id, tenant_id, user_id, version_no: int = 0):
206212
# create tool
207213
tool_config_list = []
208214
langchain_tools = await discover_langchain_tools()
209215

210216
# now only admin can modify the agent, user_id is not used
211-
tools_list = search_tools_for_sub_agent(agent_id, tenant_id)
217+
tools_list = search_tools_for_sub_agent(agent_id, tenant_id, version_no=version_no)
212218
for tool in tools_list:
213219
param_dict = {}
214220
for param in tool.get("params", []):
@@ -355,7 +361,21 @@ async def create_agent_run_info(
355361
user_id: str,
356362
language: str = "zh",
357363
allow_memory_search: bool = True,
364+
is_debug: bool = False,
358365
):
366+
# Determine which version_no to use based on is_debug flag
367+
# If is_debug=false, use the current published version (current_version_no)
368+
# If is_debug=true, use version 0 (draft/editing state)
369+
if is_debug:
370+
version_no = 0
371+
else:
372+
# Get current published version number
373+
version_no = query_current_version_no(agent_id=agent_id, tenant_id=tenant_id)
374+
# Fallback to 0 if no published version exists
375+
if version_no is None:
376+
version_no = 0
377+
logger.info(f"Agent {agent_id} has no published version, using draft version 0")
378+
359379
final_query = await join_minio_file_description_to_query(minio_files=minio_files, query=query)
360380
model_list = await create_model_config_list(tenant_id)
361381
agent_config = await create_agent_config(
@@ -365,19 +385,45 @@ async def create_agent_run_info(
365385
language=language,
366386
last_user_query=final_query,
367387
allow_memory_search=allow_memory_search,
388+
version_no=version_no,
368389
)
369390

370-
remote_mcp_list = await get_remote_mcp_server_list(tenant_id=tenant_id)
391+
remote_mcp_list = await get_remote_mcp_server_list(tenant_id=tenant_id, is_need_auth=True)
371392
default_mcp_url = urljoin(LOCAL_MCP_SERVER, "sse")
372393
remote_mcp_list.append({
373394
"remote_mcp_server_name": "nexent",
374395
"remote_mcp_server": default_mcp_url,
375-
"status": True
396+
"status": True,
397+
"authorization_token": None
376398
})
377399
remote_mcp_dict = {record["remote_mcp_server_name"]: record for record in remote_mcp_list if record["status"]}
378400

379-
# Filter MCP servers and tools
380-
mcp_host = filter_mcp_servers_and_tools(agent_config, remote_mcp_dict)
401+
# Filter MCP servers and tools, and build mcp_host with authorization
402+
used_mcp_urls = filter_mcp_servers_and_tools(agent_config, remote_mcp_dict)
403+
404+
# Build mcp_host list with authorization tokens
405+
mcp_host = []
406+
for url in used_mcp_urls:
407+
# Find the MCP record for this URL
408+
mcp_record = None
409+
for record in remote_mcp_list:
410+
if record.get("remote_mcp_server") == url and record.get("status"):
411+
mcp_record = record
412+
break
413+
414+
if mcp_record:
415+
mcp_config = {
416+
"url": url,
417+
"transport": "sse" if url.endswith("/sse") else "streamable-http"
418+
}
419+
# Add authorization if present
420+
auth_token = mcp_record.get("authorization_token")
421+
if auth_token:
422+
mcp_config["authorization"] = auth_token
423+
mcp_host.append(mcp_config)
424+
else:
425+
# Fallback to string format if record not found
426+
mcp_host.append(url)
381427

382428
agent_run_info = AgentRunInfo(
383429
query=final_query,

backend/apps/agent_app.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from fastapi.encoders import jsonable_encoder
77
from starlette.responses import JSONResponse
88

9-
from consts.model import AgentRequest, AgentInfoRequest, AgentIDRequest, ConversationResponse, AgentImportRequest, AgentNameBatchCheckRequest, AgentNameBatchRegenerateRequest, VersionPublishRequest, VersionListResponse, VersionDetailResponse, VersionRollbackRequest, VersionStatusRequest, CurrentVersionResponse, VersionCompareRequest
9+
from consts.model import AgentRequest, AgentInfoRequest, AgentIDRequest, ConversationResponse, AgentImportRequest, AgentNameBatchCheckRequest, AgentNameBatchRegenerateRequest, VersionPublishRequest, VersionListResponse, VersionDetailResponse, VersionRollbackRequest, VersionStatusRequest, CurrentVersionResponse, VersionCompareRequest, VersionUpdateRequest
1010
from services.agent_service import (
1111
get_agent_info_impl,
1212
get_creating_sub_agent_info_impl,
@@ -29,6 +29,7 @@
2929
get_version_detail_impl,
3030
rollback_version_impl,
3131
update_version_status_impl,
32+
update_version_impl,
3233
delete_version_impl,
3334
get_current_version_impl,
3435
compare_versions_impl,
@@ -443,6 +444,34 @@ async def update_version_status_api(
443444
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Update version status error.")
444445

445446

447+
@agent_config_router.put("/{agent_id}/versions/{version_no}")
448+
async def update_version_api(
449+
agent_id: int,
450+
version_no: int,
451+
request: VersionUpdateRequest,
452+
authorization: str = Header(None),
453+
):
454+
"""
455+
Update version metadata (version_name and release_note)
456+
"""
457+
try:
458+
user_id, tenant_id = get_current_user_id(authorization)
459+
result = update_version_impl(
460+
agent_id=agent_id,
461+
tenant_id=tenant_id,
462+
user_id=user_id,
463+
version_no=version_no,
464+
version_name=request.version_name,
465+
release_note=request.release_note,
466+
)
467+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
468+
except ValueError as e:
469+
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
470+
except Exception as e:
471+
logger.error(f"Update version error: {str(e)}")
472+
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Update version error.")
473+
474+
446475
@agent_config_router.delete("/{agent_id}/versions/{version_no}")
447476
async def delete_version_api(
448477
agent_id: int,

backend/apps/conversation_management_app.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,15 @@ async def generate_conversation_title_endpoint(
175175
authorization: Optional[str] = Header(None)
176176
):
177177
"""
178-
Generate conversation title
178+
Generate conversation title from user question
179+
180+
This endpoint generates title immediately after user sends a message,
181+
using only the question content instead of waiting for full conversation.
179182
180183
Args:
181184
request: GenerateTitleRequest object containing:
182185
- conversation_id: Conversation ID
183-
- history: Conversation history list
186+
- question: User's question content
184187
http_request: http request containing language info
185188
authorization: Authorization header
186189
@@ -190,7 +193,8 @@ async def generate_conversation_title_endpoint(
190193
try:
191194
user_id, tenant_id, language = get_current_user_info(
192195
authorization=authorization, request=http_request)
193-
title = await generate_conversation_title_service(request.conversation_id, request.history, user_id, tenant_id=tenant_id, language=language)
196+
title = await generate_conversation_title_service(
197+
request.conversation_id, request.question, user_id, tenant_id=tenant_id, language=language)
194198
return ConversationResponse(code=0, message="success", data=title)
195199
except Exception as e:
196200
logging.error(f"Failed to generate conversation title: {str(e)}")

backend/apps/mock_user_management_app.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,24 @@ async def signup(request: UserSignUpRequest):
3333
Mock user registration endpoint
3434
"""
3535
try:
36-
logger.info(
37-
f"Mock signup request: email={request.email}, is_admin={request.is_admin}")
36+
logger.info(f"Mock signup request: email={request.email}")
3837

3938
# Mock success response matching user_management_app.py format
40-
if request.is_admin:
41-
success_message = "🎉 Admin account registered successfully! You now have system management permissions."
42-
else:
43-
success_message = "🎉 User account registered successfully! Please start experiencing the AI assistant service."
39+
success_message = "🎉 User account registered successfully! Please start experiencing the AI assistant service."
4440

4541
user_data = {
4642
"user": {
4743
"id": MOCK_USER["id"],
4844
"email": request.email,
49-
"role": "admin" if request.is_admin else "user"
45+
"role": "user"
5046
},
5147
"session": {
5248
"access_token": MOCK_SESSION["access_token"],
5349
"refresh_token": MOCK_SESSION["refresh_token"],
5450
"expires_at": int((datetime.now() + timedelta(days=3650)).timestamp()),
5551
"expires_in_seconds": MOCK_SESSION["expires_in_seconds"]
5652
},
57-
"registration_type": "admin" if request.is_admin else "user"
53+
"registration_type": "user"
5854
}
5955

6056
return JSONResponse(status_code=HTTPStatus.OK,

backend/apps/remote_mcp_app.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
upload_and_start_mcp_image,
1818
update_remote_mcp_server_list,
1919
attach_mcp_container_permissions,
20+
get_mcp_record_by_id,
2021
)
2122
from database.remote_mcp_db import check_mcp_name_exists
2223
from services.tool_configuration_service import get_tool_from_remote_mcp_server
@@ -30,11 +31,18 @@
3031
@router.post("/tools")
3132
async def get_tools_from_remote_mcp(
3233
service_name: str,
33-
mcp_url: str
34+
mcp_url: str,
35+
authorization: Optional[str] = Header(None),
36+
http_request: Request = None
3437
):
3538
""" Used to list tool information from the remote MCP server """
3639
try:
37-
tools_info = await get_tool_from_remote_mcp_server(mcp_server_name=service_name, remote_mcp_server=mcp_url)
40+
user_id, tenant_id, _ = get_current_user_info(authorization, http_request)
41+
tools_info = await get_tool_from_remote_mcp_server(
42+
mcp_server_name=service_name,
43+
remote_mcp_server=mcp_url,
44+
tenant_id=tenant_id
45+
)
3846
return JSONResponse(
3947
status_code=HTTPStatus.OK,
4048
content={
@@ -54,6 +62,8 @@ async def get_tools_from_remote_mcp(
5462
async def add_remote_proxies(
5563
mcp_url: str,
5664
service_name: str,
65+
authorization_token: Optional[str] = Query(
66+
None, description="Authorization token for MCP server authentication (e.g., Bearer token)"),
5767
tenant_id: Optional[str] = Query(
5868
None, description="Tenant ID for filtering (uses auth if not provided)"),
5969
authorization: Optional[str] = Header(None),
@@ -68,7 +78,8 @@ async def add_remote_proxies(
6878
user_id=user_id,
6979
remote_mcp_server=mcp_url,
7080
remote_mcp_server_name=service_name,
71-
container_id=None)
81+
container_id=None,
82+
authorization_token=authorization_token)
7283
return JSONResponse(
7384
status_code=HTTPStatus.OK,
7485
content={"message": "Successfully added remote MCP proxy",
@@ -170,6 +181,7 @@ async def get_remote_proxies(
170181
remote_mcp_server_list = await get_remote_mcp_server_list(
171182
tenant_id=effective_tenant_id,
172183
user_id=user_id,
184+
is_need_auth=False
173185
)
174186
return JSONResponse(
175187
status_code=HTTPStatus.OK,
@@ -183,6 +195,50 @@ async def get_remote_proxies(
183195
detail="Failed to get remote MCP proxy")
184196

185197

198+
@router.get("/record/{mcp_id}")
199+
async def get_mcp_record(
200+
mcp_id: int,
201+
tenant_id: Optional[str] = Query(
202+
None, description="Tenant ID for filtering (uses auth if not provided)"),
203+
authorization: Optional[str] = Header(None),
204+
http_request: Request = None
205+
):
206+
""" Get single MCP record by ID """
207+
try:
208+
user_id, auth_tenant_id, _ = get_current_user_info(authorization, http_request)
209+
# Use explicit tenant_id if provided, otherwise fall back to auth tenant_id
210+
effective_tenant_id = tenant_id or auth_tenant_id
211+
212+
mcp_record = await get_mcp_record_by_id(
213+
mcp_id=mcp_id,
214+
tenant_id=effective_tenant_id
215+
)
216+
217+
if not mcp_record:
218+
raise HTTPException(
219+
status_code=HTTPStatus.NOT_FOUND,
220+
detail="MCP record not found"
221+
)
222+
223+
return JSONResponse(
224+
status_code=HTTPStatus.OK,
225+
content={
226+
"mcp_name": mcp_record.get("mcp_name"),
227+
"mcp_server": mcp_record.get("mcp_server"),
228+
"authorization_token": mcp_record.get("authorization_token"),
229+
"status": "success"
230+
}
231+
)
232+
except HTTPException:
233+
raise
234+
except Exception as e:
235+
logger.error(f"Failed to get MCP record: {e}")
236+
raise HTTPException(
237+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
238+
detail="Failed to get MCP record"
239+
)
240+
241+
186242
@router.get("/healthcheck")
187243
async def check_mcp_health(
188244
mcp_url: str,

0 commit comments

Comments
 (0)