Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
15 changes: 5 additions & 10 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 @@ -150,7 +145,7 @@ async def signup(request: UserSignUpRequest):
logging.info("检测到管理员注册请求,开始验证邀请码")

# Try to get the invite code configuration from different sources
invite_code = config_manager.get_config("INVITE_CODE")
invite_code = 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
Expand Down
8 changes: 8 additions & 0 deletions backend/consts/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,11 @@
DISABLE_USERAGENT_ID_KEY = "DISABLE_USERAGENT_ID"
DEFAULT_MEMORY_SWITCH_KEY = "Y"
DEFAULT_MEMORY_AGENT_SHARE_KEY = "always"


# MCP Server
LOCAL_MCP_SERVER = os.getenv("NEXENT_MCP_SERVER", "http://localhost:5011")


# 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
Loading