11import threading
22import logging
33from urllib .parse import urljoin
4+ from datetime import datetime
5+
6+ from jinja2 import Template , StrictUndefined
7+ from smolagents .utils import BASE_BUILTIN_MODULES
48from nexent .core .utils .observer import MessageObserver
59from nexent .core .agents .agent_model import AgentRunInfo , ModelConfig , AgentConfig , ToolConfig
6- from services .remote_mcp_service import get_remote_mcp_server_list
7- from utils .auth_utils import get_current_user_id
10+ from nexent .memory .memory_service import search_memory_in_levels
811
9- from database .agent_db import search_agent_info_by_agent_id , query_sub_agents_id_list
10- from database .tool_db import search_tools_for_sub_agent
1112from services .elasticsearch_service import ElasticSearchService , elastic_core , get_embedding_model
1213from services .tenant_config_service import get_selected_knowledge_list
14+ from services .remote_mcp_service import get_remote_mcp_server_list
15+ from services .memory_config_service import build_memory_context
16+ from database .agent_db import search_agent_info_by_agent_id , query_sub_agents_id_list
17+ from database .tool_db import search_tools_for_sub_agent
1318from utils .prompt_template_utils import get_agent_prompt_template
1419from utils .config_utils import config_manager , tenant_config_manager , get_model_name_from_config
15- from smolagents .utils import BASE_BUILTIN_MODULES
16- from services .memory_config_service import build_memory_context
17- from jinja2 import Template , StrictUndefined
18- from datetime import datetime
19-
20- from nexent .memory .memory_service import search_memory_in_levels
21-
20+ from utils .auth_utils import get_current_user_id
2221
2322logger = logging .getLogger ("create_agent_info" )
2423logger .setLevel (logging .DEBUG )
2524
25+
2626async def create_model_config_list (tenant_id ):
27- main_model_config = tenant_config_manager .get_model_config (key = "LLM_ID" , tenant_id = tenant_id )
28- sub_model_config = tenant_config_manager .get_model_config (key = "LLM_SECONDARY_ID" , tenant_id = tenant_id )
27+ main_model_config = tenant_config_manager .get_model_config (
28+ key = "LLM_ID" , tenant_id = tenant_id )
29+ sub_model_config = tenant_config_manager .get_model_config (
30+ key = "LLM_SECONDARY_ID" , tenant_id = tenant_id )
2931
3032 return [ModelConfig (cite_name = "main_model" ,
3133 api_key = main_model_config .get ("api_key" , "" ),
@@ -40,10 +42,12 @@ async def create_model_config_list(tenant_id):
4042
4143
4244async def create_agent_config (agent_id , tenant_id , user_id , language : str = 'zh' , last_user_query : str = None ):
43- agent_info = search_agent_info_by_agent_id (agent_id = agent_id , tenant_id = tenant_id )
45+ agent_info = search_agent_info_by_agent_id (
46+ agent_id = agent_id , tenant_id = tenant_id )
4447
4548 # create sub agent
46- sub_agent_id_list = query_sub_agents_id_list (main_agent_id = agent_id , tenant_id = tenant_id )
49+ sub_agent_id_list = query_sub_agents_id_list (
50+ main_agent_id = agent_id , tenant_id = tenant_id )
4751 managed_agents = []
4852 for sub_agent_id in sub_agent_id_list :
4953 sub_agent_config = await create_agent_config (
@@ -55,19 +59,22 @@ async def create_agent_config(agent_id, tenant_id, user_id, language: str = 'zh'
5559 managed_agents .append (sub_agent_config )
5660
5761 tool_list = await create_tool_config_list (agent_id , tenant_id , user_id )
58-
62+
5963 # Build system prompt: prioritize segmented fields, fallback to original prompt field if not available
6064 duty_prompt = agent_info .get ("duty_prompt" , "" )
6165 constraint_prompt = agent_info .get ("constraint_prompt" , "" )
6266 few_shots_prompt = agent_info .get ("few_shots_prompt" , "" )
63-
67+
6468 # Get template content
65- prompt_template = get_agent_prompt_template (is_manager = len (managed_agents ) > 0 , language = language )
69+ prompt_template = get_agent_prompt_template (
70+ is_manager = len (managed_agents ) > 0 , language = language )
6671
6772 # Get app information
6873 default_app_description = 'Nexent 是一个开源智能体SDK和平台' if language == 'zh' else 'Nexent is an open-source agent SDK and platform'
69- app_name = tenant_config_manager .get_app_config ('APP_NAME' , tenant_id = tenant_id ) or "Nexent"
70- app_description = tenant_config_manager .get_app_config ('APP_DESCRIPTION' , tenant_id = tenant_id ) or default_app_description
74+ app_name = tenant_config_manager .get_app_config (
75+ 'APP_NAME' , tenant_id = tenant_id ) or "Nexent"
76+ app_description = tenant_config_manager .get_app_config (
77+ 'APP_DESCRIPTION' , tenant_id = tenant_id ) or default_app_description
7178
7279 # Get memory list
7380 memory_context = build_memory_context (user_id , tenant_id , agent_id )
@@ -84,7 +91,8 @@ async def create_agent_config(agent_id, tenant_id, user_id, language: str = 'zh'
8491 memory_levels .remove ("user_agent" )
8592
8693 search_res = await search_memory_in_levels (
87- query_text = last_user_query if last_user_query else agent_info .get ("name" ),
94+ query_text = last_user_query if last_user_query else agent_info .get (
95+ "name" ),
8896 memory_config = memory_context .memory_config ,
8997 tenant_id = memory_context .tenant_id ,
9098 user_id = memory_context .user_id ,
@@ -100,7 +108,8 @@ async def create_agent_config(agent_id, tenant_id, user_id, language: str = 'zh'
100108 try :
101109 for tool in tool_list :
102110 if "KnowledgeBaseSearchTool" == tool .class_name :
103- knowledge_info_list = get_selected_knowledge_list (tenant_id = tenant_id , user_id = user_id )
111+ knowledge_info_list = get_selected_knowledge_list (
112+ tenant_id = tenant_id , user_id = user_id )
104113 if knowledge_info_list :
105114 for knowledge_info in knowledge_info_list :
106115 knowledge_name = knowledge_info .get ("index_name" )
@@ -109,15 +118,16 @@ async def create_agent_config(agent_id, tenant_id, user_id, language: str = 'zh'
109118 summary = message .get ("summary" , "" )
110119 knowledge_base_summary += f"**{ knowledge_name } **: { summary } \n \n "
111120 except Exception as e :
112- logger .warning (f"Failed to get summary for knowledge base { knowledge_name } : { e } " )
121+ logger .warning (
122+ f"Failed to get summary for knowledge base { knowledge_name } : { e } " )
113123 else :
114124 knowledge_base_summary = "当前没有可用的知识库索引。\n " if language == 'zh' else "No knowledge base indexes are currently available.\n "
115125 break # Only process the first KnowledgeBaseSearchTool found
116126 except Exception as e :
117127 logger .error (f"Failed to build knowledge base summary: { e } " )
118-
128+
119129 # Assemble system_prompt
120- if ( duty_prompt or constraint_prompt or few_shots_prompt ) :
130+ if duty_prompt or constraint_prompt or few_shots_prompt :
121131 system_prompt = Template (prompt_template ["system_prompt" ], undefined = StrictUndefined ).render ({
122132 "duty" : duty_prompt ,
123133 "constraint" : constraint_prompt ,
@@ -129,15 +139,19 @@ async def create_agent_config(agent_id, tenant_id, user_id, language: str = 'zh'
129139 "APP_DESCRIPTION" : app_description ,
130140 "memory_list" : memory_list ,
131141 "knowledge_base_summary" : knowledge_base_summary ,
132- "time" : datetime .now ().strftime ("%Y-%m-%d %H:%M:%S" )
142+ "time" : datetime .now ().strftime ("%Y-%m-%d %H:%M:%S" )
133143 })
134144 else :
135145 system_prompt = agent_info .get ("prompt" , "" )
136-
146+
137147 agent_config = AgentConfig (
138148 name = "undefined" if agent_info ["name" ] is None else agent_info ["name" ],
139149 description = "undefined" if agent_info ["description" ] is None else agent_info ["description" ],
140- prompt_templates = await prepare_prompt_templates (is_manager = len (managed_agents )> 0 , system_prompt = system_prompt , language = language ),
150+ prompt_templates = await prepare_prompt_templates (
151+ is_manager = len (managed_agents ) > 0 ,
152+ system_prompt = system_prompt ,
153+ language = language
154+ ),
141155 tools = tool_list ,
142156 max_steps = agent_info .get ("max_steps" , 10 ),
143157 model_name = agent_info .get ("model_name" ),
@@ -178,25 +192,27 @@ async def create_tool_config_list(agent_id, tenant_id, user_id):
178192
179193 # special logic for knowledge base search tool
180194 if tool_config .class_name == "KnowledgeBaseSearchTool" :
181- knowledge_info_list = get_selected_knowledge_list (tenant_id = tenant_id , user_id = user_id )
182- index_names = [knowledge_info .get ("index_name" ) for knowledge_info in knowledge_info_list ]
195+ knowledge_info_list = get_selected_knowledge_list (
196+ tenant_id = tenant_id , user_id = user_id )
197+ index_names = [knowledge_info .get (
198+ "index_name" ) for knowledge_info in knowledge_info_list ]
183199 tool_config .metadata = {"index_names" : index_names ,
184200 "es_core" : elastic_core ,
185201 "embedding_model" : get_embedding_model (tenant_id = tenant_id )}
186202 tool_config_list .append (tool_config )
187-
203+
188204 return tool_config_list
189205
190206
191207async def discover_langchain_tools ():
192208 """
193209 Discover LangChain tools implemented with the `@tool` decorator.
194-
210+
195211 Returns:
196212 list: List of discovered LangChain tool instances
197213 """
198214 from utils .langchain_utils import discover_langchain_modules
199-
215+
200216 langchain_tools = []
201217
202218 # ----------------------------------------------
@@ -206,18 +222,21 @@ async def discover_langchain_tools():
206222 try :
207223 # Use the utility function to discover all BaseTool objects
208224 discovered_tools = discover_langchain_modules ()
209-
225+
210226 for obj , filename in discovered_tools :
211227 try :
212228 # Log successful tool discovery
213- logger .info (f"Loaded LangChain tool '{ obj .name } ' from { filename } " )
229+ logger .info (
230+ f"Loaded LangChain tool '{ obj .name } ' from { filename } " )
214231 langchain_tools .append (obj )
215232 except Exception as e :
216- logger .error (f"Error processing LangChain tool from { filename } : { e } " )
217-
233+ logger .error (
234+ f"Error processing LangChain tool from { filename } : { e } " )
235+
218236 except Exception as e :
219- logger .error (f"Unexpected error scanning LangChain tools directory: { e } " )
220-
237+ logger .error (
238+ f"Unexpected error scanning LangChain tools directory: { e } " )
239+
221240 return langchain_tools
222241
223242
@@ -253,7 +272,7 @@ async def join_minio_file_description_to_query(minio_files, query):
253272 return final_query
254273
255274
256- def filter_mcp_servers_and_tools (input_agent_config : AgentConfig , mcp_info_dict )-> list :
275+ def filter_mcp_servers_and_tools (input_agent_config : AgentConfig , mcp_info_dict ) -> list :
257276 """
258277 Filter mcp servers and tools, only keep the actual used mcp servers
259278 Support multi-level agent, recursively check all sub-agent tools
@@ -265,7 +284,8 @@ def check_agent_tools(agent_config: AgentConfig):
265284 # Check current agent tools
266285 for tool in agent_config .tools :
267286 if tool .source == "mcp" and tool .usage in mcp_info_dict :
268- used_mcp_urls .add (mcp_info_dict [tool .usage ]["remote_mcp_server" ])
287+ used_mcp_urls .add (
288+ mcp_info_dict [tool .usage ]["remote_mcp_server" ])
269289
270290 # Recursively check sub-agent
271291 for sub_agent_config in agent_config .managed_agents :
@@ -282,22 +302,28 @@ async def create_agent_run_info(agent_id, minio_files, query, history, authoriza
282302
283303 final_query = await join_minio_file_description_to_query (minio_files = minio_files , query = query )
284304 model_list = await create_model_config_list (tenant_id )
285- agent_config = await create_agent_config (agent_id = agent_id , tenant_id = tenant_id , user_id = user_id ,
286- language = language , last_user_query = final_query )
305+ agent_config = await create_agent_config (
306+ agent_id = agent_id ,
307+ tenant_id = tenant_id ,
308+ user_id = user_id ,
309+ language = language ,
310+ last_user_query = final_query
311+ )
287312
288313 remote_mcp_list = await get_remote_mcp_server_list (tenant_id = tenant_id )
289- default_mcp_url = urljoin (config_manager .get_config ("NEXENT_MCP_SERVER" ), "sse" )
314+ default_mcp_url = urljoin (
315+ config_manager .get_config ("NEXENT_MCP_SERVER" ), "sse" )
290316 remote_mcp_list .append ({
291317 "remote_mcp_server_name" : "nexent" ,
292318 "remote_mcp_server" : default_mcp_url ,
293319 "status" : True
294320 })
295- remote_mcp_dict = {record ["remote_mcp_server_name" ]: record for record in remote_mcp_list if record ["status" ]}
321+ remote_mcp_dict = {record ["remote_mcp_server_name" ]
322+ : record for record in remote_mcp_list if record ["status" ]}
296323
297324 # Filter MCP servers and tools
298325 mcp_host = filter_mcp_servers_and_tools (agent_config , remote_mcp_dict )
299326
300-
301327 agent_run_info = AgentRunInfo (
302328 query = final_query ,
303329 model_config_list = model_list ,
0 commit comments