Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions backend/agents/create_agent_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
from database.agent_db import search_agent_info_by_agent_id, query_sub_agents_id_list
from database.tool_db import search_tools_for_sub_agent
from utils.prompt_template_utils import get_agent_prompt_template
from utils.config_utils import config_manager, tenant_config_manager, get_model_name_from_config
from utils.config_utils import tenant_config_manager, get_model_name_from_config
from utils.auth_utils import get_current_user_id
from consts.const import LOCAL_MCP_SERVER

logger = logging.getLogger("create_agent_info")
logger.setLevel(logging.DEBUG)
Expand Down Expand Up @@ -311,8 +312,7 @@ async def create_agent_run_info(agent_id, minio_files, query, history, authoriza
)

remote_mcp_list = await get_remote_mcp_server_list(tenant_id=tenant_id)
default_mcp_url = urljoin(
config_manager.get_config("NEXENT_MCP_SERVER"), "sse")
default_mcp_url = urljoin(LOCAL_MCP_SERVER, "sse")
remote_mcp_list.append({
"remote_mcp_server_name": "nexent",
"remote_mcp_server": default_mcp_url,
Expand Down
5 changes: 0 additions & 5 deletions backend/apps/config_sync_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from database.model_management_db import get_model_id_by_display_name
from utils.auth_utils import get_current_user_id, get_current_user_info
from utils.config_utils import (
config_manager,
get_env_key,
safe_value,
tenant_config_manager,
Expand Down Expand Up @@ -120,10 +119,6 @@ async def save_config(config: GlobalConfig, authorization: Optional[str] = Heade
env_config[f"{model_prefix}_API_KEY"] = safe_value(
embedding_api_config.get("apiKey"))

# Batch update environment variables
for key, value in env_config.items():
config_manager.set_config(key, value)

logger.info("Configuration saved successfully")
return JSONResponse(
status_code=200,
Expand Down
36 changes: 11 additions & 25 deletions backend/apps/user_management_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,20 @@
import requests
from dotenv import load_dotenv
from fastapi import APIRouter, Header, HTTPException, Request
from supabase import Client, create_client
from supabase import Client

from consts.const import SUPABASE_KEY, SUPABASE_URL
from consts.model import ServiceResponse, STATUS_CODES, UserSignInRequest, UserSignUpRequest
from database.model_management_db import create_model_record
from database.user_tenant_db import insert_user_tenant
from utils.auth_utils import calculate_expires_at, get_current_user_id, get_jwt_expiry_seconds
from utils.config_utils import config_manager
from utils.auth_utils import calculate_expires_at, get_current_user_id, get_jwt_expiry_seconds, get_supabase_client
from consts.const import INVITE_CODE

load_dotenv()
logging.getLogger("httpx").setLevel(logging.WARNING)
router = APIRouter(prefix="/user", tags=["user"])


def get_supabase_client() -> Client:
"""Create base supabase client"""
return create_client(SUPABASE_URL, SUPABASE_KEY)


# Set token to client
def set_auth_token_to_client(client: Client, token: str) -> None:
"""Set token to client"""
jwt_token = token.replace(
Expand Down Expand Up @@ -149,22 +144,13 @@ async def signup(request: UserSignUpRequest):
if request.is_admin:
logging.info("检测到管理员注册请求,开始验证邀请码")

# Try to get the invite code configuration from different sources
invite_code = config_manager.get_config("INVITE_CODE")
logging.info(f"从config_manager获取的INVITE_CODE: {invite_code}")

# If config_manager does not get the invite code, try to get it directly from the environment variable
if not invite_code:
invite_code = os.getenv("INVITE_CODE")
logging.info(
f"INVITE_CODE from environment variable: {invite_code}")
# Get the invite code from consts.const (which reads from environment variable)
logging.info(f"The INVITE_CODE obtained from consts.const: {INVITE_CODE}")

if not invite_code:
if not INVITE_CODE:
logging.error(
"Admin invite code not found in any configuration source")
logging.error("Please check the following configuration sources:")
logging.error("1. INVITE_CODE configuration in config_manager")
logging.error("2. INVITE_CODE environment variable")
"Admin invite code not found in configuration")
logging.error("Please check the INVITE_CODE environment variable")
return ServiceResponse(
code=STATUS_CODES["SERVER_ERROR"],
message="Admin registration feature is not available, please contact the system administrator to configure the invite code",
Expand All @@ -187,9 +173,9 @@ async def signup(request: UserSignUpRequest):
}
)

if request.invite_code != invite_code:
if request.invite_code != INVITE_CODE:
logging.warning(
f"Admin invite code verification failed: user provided='{request.invite_code}', system configured='{invite_code}'")
f"Admin invite code verification failed: user provided='{request.invite_code}', system configured='{INVITE_CODE}'")
return ServiceResponse(
code=STATUS_CODES["INVALID_INPUT"],
message="Admin invite code error, please check and re-enter",
Expand Down
10 changes: 9 additions & 1 deletion backend/consts/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,12 @@
DEFAULT_MEMORY_AGENT_SHARE_KEY = "always"


DEFAULT_LLM_MAX_TOKENS = 4096
DEFAULT_LLM_MAX_TOKENS = 4096


# MCP Server
LOCAL_MCP_SERVER = os.getenv("NEXENT_MCP_SERVER")


# Invite code
INVITE_CODE = os.getenv("INVITE_CODE")
60 changes: 36 additions & 24 deletions backend/services/tool_configuration_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
from database.tool_db import create_or_update_tool_by_tool_info, query_tool_instances_by_id, \
update_tool_table_from_scan_tool_list
from consts.model import ToolInstanceInfoRequest, ToolInfo, ToolSourceEnum
from consts.const import LOCAL_MCP_SERVER
from database.remote_mcp_db import get_mcp_records_by_tenant
from utils.auth_utils import get_current_user_id
from fastapi import Header

from utils.config_utils import config_manager

logger = logging.getLogger("tool_configuration_service")


def python_type_to_json_schema(annotation: Any) -> str:
"""
Convert Python type annotations to JSON Schema types
Expand Down Expand Up @@ -56,6 +56,7 @@ def python_type_to_json_schema(annotation: Any) -> str:
# Return mapped type, or original type name if no mapping exists
return type_mapping.get(type_name, type_name)


def get_local_tools() -> List[ToolInfo]:
"""
Get metadata for all locally available tools
Expand Down Expand Up @@ -91,14 +92,16 @@ def get_local_tools() -> List[ToolInfo]:
description=getattr(tool_class, 'description'),
params=init_params_list,
source=ToolSourceEnum.LOCAL.value,
inputs=json.dumps(getattr(tool_class, 'inputs'), ensure_ascii=False),
inputs=json.dumps(getattr(tool_class, 'inputs'),
ensure_ascii=False),
output_type=getattr(tool_class, 'output_type'),
class_name=tool_class.__name__,
usage=None
)
tools_info.append(tool_info)
return tools_info


def get_local_tools_classes() -> List[type]:
"""
Get all tool classes from the nexent.core.tools package
Expand Down Expand Up @@ -131,7 +134,7 @@ def _build_tool_info_from_langchain(obj) -> ToolInfo:
inputs = getattr(obj, "args", {})

if inputs:
for key,value in inputs.items():
for key, value in inputs.items():
if "description" not in value:
value["description"] = "see the description"

Expand All @@ -147,7 +150,7 @@ def _build_tool_info_from_langchain(obj) -> ToolInfo:
description=getattr(obj, "description", ""),
params=[],
source=ToolSourceEnum.LANGCHAIN.value,
inputs=json.dumps(inputs,ensure_ascii=False),
inputs=json.dumps(inputs, ensure_ascii=False),
output_type=output_type,
class_name=getattr(obj, "name", target_callable.__name__),
usage=None,
Expand All @@ -167,17 +170,19 @@ def get_langchain_tools() -> List[ToolInfo]:
tools_info: List[ToolInfo] = []
# Discover all objects that look like LangChain tools
discovered_tools = discover_langchain_modules()

# Process discovered tools
for obj, filename in discovered_tools:
try:
tool_info = _build_tool_info_from_langchain(obj)
tools_info.append(tool_info)
except Exception as e:
logger.warning(f"Error processing LangChain tool in {filename}: {e}")

logger.warning(
f"Error processing LangChain tool in {filename}: {e}")

return tools_info


async def get_all_mcp_tools(tenant_id: str) -> List[ToolInfo]:
"""
Get metadata for all tools available from the MCP service
Expand All @@ -192,15 +197,16 @@ async def get_all_mcp_tools(tenant_id: str) -> List[ToolInfo]:
if record["status"]:
try:
tools_info.extend(await get_tool_from_remote_mcp_server(mcp_server_name=record["mcp_name"],
remote_mcp_server=record["mcp_server"]))
remote_mcp_server=record["mcp_server"]))
except Exception as e:
logger.error(f"mcp connection error: {str(e)}")

default_mcp_url = urljoin(config_manager.get_config("NEXENT_MCP_SERVER"), "sse")
default_mcp_url = urljoin(LOCAL_MCP_SERVER, "sse")
tools_info.extend(await get_tool_from_remote_mcp_server(mcp_server_name="nexent",
remote_mcp_server=default_mcp_url))
return tools_info


def search_tool_info_impl(agent_id: int, tool_id: int, authorization: str = Header(None)):
"""
Search for tool configuration information by agent ID and tool ID
Expand All @@ -219,10 +225,13 @@ def search_tool_info_impl(agent_id: int, tool_id: int, authorization: str = Head
_, tenant_id = get_current_user_id(authorization)
try:
# now only admin can modify the tool, user_id is not used
tool_instance = query_tool_instances_by_id(agent_id, tool_id, tenant_id)
tool_instance = query_tool_instances_by_id(
agent_id, tool_id, tenant_id)
except Exception as e:
logger.error(f"search_tool_info_impl error in query_tool_instances_by_id, detail: {e}")
raise ValueError(f"search_tool_info_impl error in query_tool_instances_by_id, detail: {e}")
logger.error(
f"search_tool_info_impl error in query_tool_instances_by_id, detail: {e}")
raise ValueError(
f"search_tool_info_impl error in query_tool_instances_by_id, detail: {e}")

if tool_instance:
return {
Expand Down Expand Up @@ -251,10 +260,13 @@ def update_tool_info_impl(request: ToolInstanceInfoRequest, authorization: str =
"""
user_id, tenant_id = get_current_user_id(authorization)
try:
tool_instance = create_or_update_tool_by_tool_info(request, tenant_id, user_id)
tool_instance = create_or_update_tool_by_tool_info(
request, tenant_id, user_id)
except Exception as e:
logger.error(f"update_tool_info_impl error in create_or_update_tool, detail: {e}")
raise ValueError(f"update_tool_info_impl error in create_or_update_tool, detail: {e}")
logger.error(
f"update_tool_info_impl error in create_or_update_tool, detail: {e}")
raise ValueError(
f"update_tool_info_impl error in create_or_update_tool, detail: {e}")

return {
"tool_instance": tool_instance
Expand Down Expand Up @@ -284,16 +296,17 @@ async def get_tool_from_remote_mcp_server(mcp_server_name: str, remote_mcp_serve

sanitized_tool_name = _sanitize_function_name(tool.name)
tool_info = ToolInfo(name=sanitized_tool_name,
description=tool.description,
params=[],
source=ToolSourceEnum.MCP.value,
inputs=str(input_schema["properties"]),
output_type="string",
class_name=sanitized_tool_name,
usage=mcp_server_name)
description=tool.description,
params=[],
source=ToolSourceEnum.MCP.value,
inputs=str(input_schema["properties"]),
output_type="string",
class_name=sanitized_tool_name,
usage=mcp_server_name)
tools_info.append(tool_info)
return tools_info


async def update_tool_list(tenant_id: str, user_id: str):
"""
Scan and gather all available tools from both local and MCP sources
Expand All @@ -311,7 +324,6 @@ async def update_tool_list(tenant_id: str, user_id: str):
# unified tool list.
langchain_tools = get_langchain_tools()


try:
mcp_tools = await get_all_mcp_tools(tenant_id)
except Exception as e:
Expand Down
1 change: 0 additions & 1 deletion backend/utils/attachment_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import yaml
from typing import Union, BinaryIO

from utils.config_utils import tenant_config_manager, get_model_name_from_config
Expand Down
Loading