Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
80b81f4
Modify conversation title generation logic to use question only
SimengBian Feb 10, 2026
eefdadc
♻️ Support starting MCP services using uvx #2241
YehongPan Feb 13, 2026
53cbacc
🐛 Bugfix: add empty tenant_id judging logic in user sync script
Jasonxia007 Feb 14, 2026
c2b4742
Update opensource-memorial-wall.md
feria-tu Feb 21, 2026
f9d6a5b
🐛 Bugfix: Tenant administrator account delete error #2522
WMC001 Feb 24, 2026
cb1f4d4
🐛 Enhance model configuration checks and tool management for VLM and …
Zhi-a Feb 24, 2026
9019501
🐛 Bugfix: permission error on super admin #2530
WMC001 Feb 24, 2026
bb38a3c
bugfix agent info tablebase definition
xuyaqist Feb 24, 2026
0ae6ed2
🐛 Enhance model configuration checks and tool management for VLM and …
Zhi-a Feb 24, 2026
54ed5c3
♻️ Support starting MCP services using uvx
WMC001 Feb 24, 2026
80ad615
♻️ Modify conversation title generation logic to use question only
WMC001 Feb 24, 2026
2a519f1
🐛 Bugfix: agent info tablebase definition error #2535
WMC001 Feb 24, 2026
d85a4ac
🐛 Bugfix: Tenant administrator account delete error
WMC001 Feb 24, 2026
36db108
Revert "🐛 Bugfix: agent info tablebase definition error #2535"
xuyaqist Feb 24, 2026
f62e1e6
add sql to fix v1.8.0 user cannot create agent
xuyaqist Feb 24, 2026
dae87d4
🐛 Bugfix: fix v1.8.0 init.sql cannot create new agent
WMC001 Feb 25, 2026
24cd3b4
🐛 Bugfix: add empty tenant_id judging logic in user sync script
WMC001 Feb 25, 2026
2b2fbe3
bugfix sql field cannot be both integer and serial
xuyaqist Feb 25, 2026
932eea0
🐛 Bugfix: sql field cannot be both integer and serial
WMC001 Feb 25, 2026
6bd4d9a
🐛 Bugfix: When deleting an Agent, the display name should be used #2067
WMC001 Feb 25, 2026
8b5dc03
Bugfix: fix default modal_id is 0 when enter create mode
xuyaqist Feb 25, 2026
b0e8331
delete log
xuyaqist Feb 25, 2026
233a5fa
🐛 Bugfix: the tenant list query interface need to be paginated #2521
WMC001 Feb 25, 2026
5317aee
🐛 Bugfix: Enhance model configuration checks and tool management for …
WMC001 Feb 25, 2026
0692b85
🐛 Bugfix: fix default modal_id is 0 when enter create mode
WMC001 Feb 25, 2026
ec9ad29
🐛 Bugfix: When deleting an Agent, the display name should be used
WMC001 Feb 25, 2026
bb4f454
#2182 #2183
xuyaqist Feb 25, 2026
1fbe064
add i18n
xuyaqist Feb 25, 2026
5fce864
add i18n
xuyaqist Feb 25, 2026
ecde51b
Remove useless code
SimengBian Feb 25, 2026
45b8067
remove useless code in test case
SimengBian Feb 25, 2026
03718f5
🐛 Bugfix: add empty tenant_id judging logic in user sync script
Jasonxia007 Feb 14, 2026
8cce5cb
✨ Now su can choose to create a new tenant admin when creating new te…
Jasonxia007 Feb 25, 2026
913cc7e
Merge branch 'develop' into xyc/v180_bugfix
Jasonxia007 Feb 25, 2026
d5debaf
✨ Now su can choose to create a new tenant admin when creating new te…
Jasonxia007 Feb 25, 2026
c7ffe37
✨ Now su can choose to create a new tenant admin when creating new te…
Jasonxia007 Feb 25, 2026
6aad945
✨ Now su can choose to create a new tenant admin when creating new te…
Jasonxia007 Feb 25, 2026
36b0337
Update opensource-memorial-wall.md from feria-tu/patch-1
WMC001 Feb 26, 2026
d248556
♻️ MCP services support authorization #2086
YehongPan Feb 26, 2026
6e9f7b0
🐛 Bugfix: Admin user can create admin invitations unauthorizedly
Jasonxia007 Feb 26, 2026
b67f047
🐛 Bugfix: Improve knowledge base selection handling and Dify config c…
Zhi-a Feb 26, 2026
21cdfdc
🐛 Bugfix: support version comparsion & agent version create time adju…
WMC001 Feb 26, 2026
9770546
🐛 Fix Agent list show nothing with dev account when agents not assign…
YehongPan Feb 26, 2026
2cab158
🐛 Fix Agent list show nothing with dev account when agents not assign…
YehongPan Feb 26, 2026
1de5223
✨ Now su can choose to create a new tenant admin when creating new te…
WMC001 Feb 26, 2026
b081858
agent version support update version info
xuyaqist Feb 26, 2026
65e9f25
agent version name duplicate detection
xuyaqist Feb 26, 2026
d1891ee
add ut
xuyaqist Feb 26, 2026
8f7daa5
Refresh version list using the proper invalidate function
xuyaqist Feb 26, 2026
2f01adb
🐛 Bugfix: Refactor knowledge base config change handling in ToolConfi…
Zhi-a Feb 26, 2026
7ee17bf
✨ Support delete tenant
WMC001 Feb 26, 2026
66f09c9
✨ Support delete tenant
WMC001 Feb 26, 2026
d3eeb8a
🐛 Bugfix: Improve knowledge base selection handling and Dify config c…
WMC001 Feb 26, 2026
e989d38
✨ Agent version support update version info & agent version name dupl…
WMC001 Feb 26, 2026
b57c63f
🐛 Fix Agent list show nothing with dev account when agents not assign…
WMC001 Feb 26, 2026
29b6fcf
♻️ MCP services support authorization #2086
YehongPan Feb 26, 2026
c9dda63
remove redundant space
SimengBian Feb 26, 2026
555128c
♻️ MCP services support authorization #2086
YehongPan Feb 26, 2026
86653f8
✨ Support delete tenant:comments fix
WMC001 Feb 26, 2026
154209c
✨ Support delete tenant:comments fix
WMC001 Feb 26, 2026
6444d6c
♻️ MCP services support authorization
WMC001 Feb 26, 2026
c54e61d
🐛Bugfix: knowledge base summary render error to avoid <p> </p>
WMC001 Feb 26, 2026
6f8d4f2
🐛 Bugfix: knowledgebase chunk filename lost when manually created
Jasonxia007 Feb 26, 2026
fc7c662
Merge remote-tracking branch 'origin/develop' into xyc/v180_bugfix
Jasonxia007 Feb 26, 2026
d82fe61
improve frontend build time, use dependencies caches
xuyaqist Feb 26, 2026
8bb7f29
🐛 Bugfix: knowledgebase chunk filename lost when manually created
Jasonxia007 Feb 26, 2026
9560422
🐛 Bugfix: knowledgebase chunk filename lost when manually created
Jasonxia007 Feb 26, 2026
1d215ba
Docker version lower than 23.0 needs to set environment variable to e…
xuyaqist Feb 26, 2026
3701eaa
♻️ Improve frontend build time, use dependencies caches
WMC001 Feb 27, 2026
502fe6c
✨ Support delete tenant:concurrently delete all users
WMC001 Feb 27, 2026
2c9f8b9
docs update
Feb 27, 2026
069f2d9
🐛 Bugfix: knowledgebase chunk filename lost when manually created
WMC001 Feb 27, 2026
be51109
✨ Support delete tenant:concurrently delete all users
WMC001 Feb 27, 2026
31a9cc5
docs update2
Feb 27, 2026
0ff0c9f
Bugfix: When generating an agent, the agent information page can be e…
xuyaqist Feb 27, 2026
a686fa6
🐛 Bugfix: When generating an agent, the agent information page cannot…
WMC001 Feb 27, 2026
82cc541
Bugfix: multiple agent version causing tool instance cannot be updated
xuyaqist Feb 27, 2026
cb37d7e
Bugfix: Agent cannot run based on the corresponding version
xuyaqist Feb 27, 2026
ee2f782
fix ut
xuyaqist Feb 27, 2026
749b6f8
add ut
xuyaqist Feb 27, 2026
94d5317
bugfix: subagent must be published
xuyaqist Feb 27, 2026
9489905
update image-en
Feb 27, 2026
66a00df
🐛 Bugfix: multiple agent version causing tool instance cannot be updated
WMC001 Feb 27, 2026
d024053
📝 User-guide docs update
WMC001 Feb 28, 2026
21d159d
Enhance Dockerfile: Pre-download tiktoken cl100k_base model to preven…
Zhi-a Feb 28, 2026
958335c
Pre-download tiktoken cl100k_base model
WMC001 Feb 28, 2026
6d6961b
🐛 Bugfix: The agent_run process cannot invoke the MCP service with au…
YehongPan Feb 28, 2026
6c3e4d2
🐛 Bugfix: The agent_run process cannot invoke the MCP service with au…
WMC001 Feb 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 55 additions & 9 deletions backend/agents/create_agent_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from services.memory_config_service import build_memory_context
from services.image_service import get_vlm_model
from database.agent_db import search_agent_info_by_agent_id, query_sub_agents_id_list
from database.agent_version_db import query_current_version_no
from database.tool_db import search_tools_for_sub_agent
from database.model_management_db import get_model_records, get_model_by_model_id
from database.client import minio_client
Expand Down Expand Up @@ -75,26 +76,31 @@ async def create_agent_config(
language: str = LANGUAGE["ZH"],
last_user_query: str = None,
allow_memory_search: bool = True,
version_no: int = 0,
):
agent_info = search_agent_info_by_agent_id(
agent_id=agent_id, tenant_id=tenant_id)
agent_id=agent_id, tenant_id=tenant_id, version_no=version_no)

# create sub agent
sub_agent_id_list = query_sub_agents_id_list(
main_agent_id=agent_id, tenant_id=tenant_id)
main_agent_id=agent_id, tenant_id=tenant_id, version_no=version_no)
managed_agents = []
for sub_agent_id in sub_agent_id_list:
# Get the current published version for this sub-agent (from draft version 0)
sub_agent_version_no = query_current_version_no(
agent_id=sub_agent_id, tenant_id=tenant_id) or 0
sub_agent_config = await create_agent_config(
agent_id=sub_agent_id,
tenant_id=tenant_id,
user_id=user_id,
language=language,
last_user_query=last_user_query,
allow_memory_search=allow_memory_search,
version_no=sub_agent_version_no,
)
managed_agents.append(sub_agent_config)

tool_list = await create_tool_config_list(agent_id, tenant_id, user_id)
tool_list = await create_tool_config_list(agent_id, tenant_id, user_id, version_no=version_no)

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


async def create_tool_config_list(agent_id, tenant_id, user_id):
async def create_tool_config_list(agent_id, tenant_id, user_id, version_no: int = 0):
# create tool
tool_config_list = []
langchain_tools = await discover_langchain_tools()

# now only admin can modify the agent, user_id is not used
tools_list = search_tools_for_sub_agent(agent_id, tenant_id)
tools_list = search_tools_for_sub_agent(agent_id, tenant_id, version_no=version_no)
for tool in tools_list:
param_dict = {}
for param in tool.get("params", []):
Expand Down Expand Up @@ -355,7 +361,21 @@ async def create_agent_run_info(
user_id: str,
language: str = "zh",
allow_memory_search: bool = True,
is_debug: bool = False,
):
# Determine which version_no to use based on is_debug flag
# If is_debug=false, use the current published version (current_version_no)
# If is_debug=true, use version 0 (draft/editing state)
if is_debug:
version_no = 0
else:
# Get current published version number
version_no = query_current_version_no(agent_id=agent_id, tenant_id=tenant_id)
# Fallback to 0 if no published version exists
if version_no is None:
version_no = 0
logger.info(f"Agent {agent_id} has no published version, using draft version 0")

final_query = await join_minio_file_description_to_query(minio_files=minio_files, query=query)
model_list = await create_model_config_list(tenant_id)
agent_config = await create_agent_config(
Expand All @@ -365,19 +385,45 @@ async def create_agent_run_info(
language=language,
last_user_query=final_query,
allow_memory_search=allow_memory_search,
version_no=version_no,
)

remote_mcp_list = await get_remote_mcp_server_list(tenant_id=tenant_id)
remote_mcp_list = await get_remote_mcp_server_list(tenant_id=tenant_id, is_need_auth=True)
default_mcp_url = urljoin(LOCAL_MCP_SERVER, "sse")
remote_mcp_list.append({
"remote_mcp_server_name": "nexent",
"remote_mcp_server": default_mcp_url,
"status": True
"status": True,
"authorization_token": None
})
remote_mcp_dict = {record["remote_mcp_server_name"]: record for record in remote_mcp_list if record["status"]}

# Filter MCP servers and tools
mcp_host = filter_mcp_servers_and_tools(agent_config, remote_mcp_dict)
# Filter MCP servers and tools, and build mcp_host with authorization
used_mcp_urls = filter_mcp_servers_and_tools(agent_config, remote_mcp_dict)

# Build mcp_host list with authorization tokens
mcp_host = []
for url in used_mcp_urls:
# Find the MCP record for this URL
mcp_record = None
for record in remote_mcp_list:
if record.get("remote_mcp_server") == url and record.get("status"):
mcp_record = record
break

if mcp_record:
mcp_config = {
"url": url,
"transport": "sse" if url.endswith("/sse") else "streamable-http"
}
# Add authorization if present
auth_token = mcp_record.get("authorization_token")
if auth_token:
mcp_config["authorization"] = auth_token
mcp_host.append(mcp_config)
else:
# Fallback to string format if record not found
mcp_host.append(url)

agent_run_info = AgentRunInfo(
query=final_query,
Expand Down
31 changes: 30 additions & 1 deletion backend/apps/agent_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from fastapi.encoders import jsonable_encoder
from starlette.responses import JSONResponse

from consts.model import AgentRequest, AgentInfoRequest, AgentIDRequest, ConversationResponse, AgentImportRequest, AgentNameBatchCheckRequest, AgentNameBatchRegenerateRequest, VersionPublishRequest, VersionListResponse, VersionDetailResponse, VersionRollbackRequest, VersionStatusRequest, CurrentVersionResponse, VersionCompareRequest
from consts.model import AgentRequest, AgentInfoRequest, AgentIDRequest, ConversationResponse, AgentImportRequest, AgentNameBatchCheckRequest, AgentNameBatchRegenerateRequest, VersionPublishRequest, VersionListResponse, VersionDetailResponse, VersionRollbackRequest, VersionStatusRequest, CurrentVersionResponse, VersionCompareRequest, VersionUpdateRequest
from services.agent_service import (
get_agent_info_impl,
get_creating_sub_agent_info_impl,
Expand All @@ -29,6 +29,7 @@
get_version_detail_impl,
rollback_version_impl,
update_version_status_impl,
update_version_impl,
delete_version_impl,
get_current_version_impl,
compare_versions_impl,
Expand Down Expand Up @@ -443,6 +444,34 @@ async def update_version_status_api(
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Update version status error.")


@agent_config_router.put("/{agent_id}/versions/{version_no}")
async def update_version_api(
agent_id: int,
version_no: int,
request: VersionUpdateRequest,
authorization: str = Header(None),
):
"""
Update version metadata (version_name and release_note)
"""
try:
user_id, tenant_id = get_current_user_id(authorization)
result = update_version_impl(
agent_id=agent_id,
tenant_id=tenant_id,
user_id=user_id,
version_no=version_no,
version_name=request.version_name,
release_note=request.release_note,
)
return JSONResponse(status_code=HTTPStatus.OK, content=result)
except ValueError as e:
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e))
except Exception as e:
logger.error(f"Update version error: {str(e)}")
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Update version error.")


@agent_config_router.delete("/{agent_id}/versions/{version_no}")
async def delete_version_api(
agent_id: int,
Expand Down
10 changes: 7 additions & 3 deletions backend/apps/conversation_management_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,15 @@ async def generate_conversation_title_endpoint(
authorization: Optional[str] = Header(None)
):
"""
Generate conversation title
Generate conversation title from user question

This endpoint generates title immediately after user sends a message,
using only the question content instead of waiting for full conversation.

Args:
request: GenerateTitleRequest object containing:
- conversation_id: Conversation ID
- history: Conversation history list
- question: User's question content
http_request: http request containing language info
authorization: Authorization header

Expand All @@ -190,7 +193,8 @@ async def generate_conversation_title_endpoint(
try:
user_id, tenant_id, language = get_current_user_info(
authorization=authorization, request=http_request)
title = await generate_conversation_title_service(request.conversation_id, request.history, user_id, tenant_id=tenant_id, language=language)
title = await generate_conversation_title_service(
request.conversation_id, request.question, user_id, tenant_id=tenant_id, language=language)
return ConversationResponse(code=0, message="success", data=title)
except Exception as e:
logging.error(f"Failed to generate conversation title: {str(e)}")
Expand Down
12 changes: 4 additions & 8 deletions backend/apps/mock_user_management_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,24 @@ async def signup(request: UserSignUpRequest):
Mock user registration endpoint
"""
try:
logger.info(
f"Mock signup request: email={request.email}, is_admin={request.is_admin}")
logger.info(f"Mock signup request: email={request.email}")

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

user_data = {
"user": {
"id": MOCK_USER["id"],
"email": request.email,
"role": "admin" if request.is_admin else "user"
"role": "user"
},
"session": {
"access_token": MOCK_SESSION["access_token"],
"refresh_token": MOCK_SESSION["refresh_token"],
"expires_at": int((datetime.now() + timedelta(days=3650)).timestamp()),
"expires_in_seconds": MOCK_SESSION["expires_in_seconds"]
},
"registration_type": "admin" if request.is_admin else "user"
"registration_type": "user"
}

return JSONResponse(status_code=HTTPStatus.OK,
Expand Down
62 changes: 59 additions & 3 deletions backend/apps/remote_mcp_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
upload_and_start_mcp_image,
update_remote_mcp_server_list,
attach_mcp_container_permissions,
get_mcp_record_by_id,
)
from database.remote_mcp_db import check_mcp_name_exists
from services.tool_configuration_service import get_tool_from_remote_mcp_server
Expand All @@ -30,11 +31,18 @@
@router.post("/tools")
async def get_tools_from_remote_mcp(
service_name: str,
mcp_url: str
mcp_url: str,
authorization: Optional[str] = Header(None),
http_request: Request = None
):
""" Used to list tool information from the remote MCP server """
try:
tools_info = await get_tool_from_remote_mcp_server(mcp_server_name=service_name, remote_mcp_server=mcp_url)
user_id, tenant_id, _ = get_current_user_info(authorization, http_request)
tools_info = await get_tool_from_remote_mcp_server(
mcp_server_name=service_name,
remote_mcp_server=mcp_url,
tenant_id=tenant_id
)
return JSONResponse(
status_code=HTTPStatus.OK,
content={
Expand All @@ -54,6 +62,8 @@ async def get_tools_from_remote_mcp(
async def add_remote_proxies(
mcp_url: str,
service_name: str,
authorization_token: Optional[str] = Query(
None, description="Authorization token for MCP server authentication (e.g., Bearer token)"),
tenant_id: Optional[str] = Query(
None, description="Tenant ID for filtering (uses auth if not provided)"),
authorization: Optional[str] = Header(None),
Expand All @@ -68,7 +78,8 @@ async def add_remote_proxies(
user_id=user_id,
remote_mcp_server=mcp_url,
remote_mcp_server_name=service_name,
container_id=None)
container_id=None,
authorization_token=authorization_token)
return JSONResponse(
status_code=HTTPStatus.OK,
content={"message": "Successfully added remote MCP proxy",
Expand Down Expand Up @@ -170,6 +181,7 @@ async def get_remote_proxies(
remote_mcp_server_list = await get_remote_mcp_server_list(
tenant_id=effective_tenant_id,
user_id=user_id,
is_need_auth=False
)
return JSONResponse(
status_code=HTTPStatus.OK,
Expand All @@ -183,6 +195,50 @@ async def get_remote_proxies(
detail="Failed to get remote MCP proxy")


@router.get("/record/{mcp_id}")
async def get_mcp_record(
mcp_id: int,
tenant_id: Optional[str] = Query(
None, description="Tenant ID for filtering (uses auth if not provided)"),
authorization: Optional[str] = Header(None),
http_request: Request = None
):
""" Get single MCP record by ID """
try:
user_id, auth_tenant_id, _ = get_current_user_info(authorization, http_request)
# Use explicit tenant_id if provided, otherwise fall back to auth tenant_id
effective_tenant_id = tenant_id or auth_tenant_id

mcp_record = await get_mcp_record_by_id(
mcp_id=mcp_id,
tenant_id=effective_tenant_id
)

if not mcp_record:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND,
detail="MCP record not found"
)

return JSONResponse(
status_code=HTTPStatus.OK,
content={
"mcp_name": mcp_record.get("mcp_name"),
"mcp_server": mcp_record.get("mcp_server"),
"authorization_token": mcp_record.get("authorization_token"),
"status": "success"
}
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to get MCP record: {e}")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Failed to get MCP record"
)


@router.get("/healthcheck")
async def check_mcp_health(
mcp_url: str,
Expand Down
Loading