Skip to content

Commit d6c0f1f

Browse files
author
jiangpeiling
committed
Merge branch 'develop' of github.com:ModelEngine-Group/nexent into jpl/jpl_0813
2 parents e9c9372 + 6ae6067 commit d6c0f1f

Some content is hidden

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

54 files changed

+1972
-1293
lines changed

backend/agents/agent_run_manager.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import logging
22
import threading
33
from typing import Dict
4+
45
from nexent.core.agents.agent_model import AgentRunInfo
56

67
logger = logging.getLogger("agent_run_manager")
78

9+
810
class AgentRunManager:
911
_instance = None
1012
_lock = threading.Lock()
@@ -19,23 +21,27 @@ def __new__(cls):
1921

2022
def __init__(self):
2123
if not self._initialized:
22-
self.agent_runs: Dict[int, AgentRunInfo] = {} # conversation_id -> agent_run_info
24+
# conversation_id -> agent_run_info
25+
self.agent_runs: Dict[int, AgentRunInfo] = {}
2326
self._initialized = True
2427

2528
def register_agent_run(self, conversation_id: int, agent_run_info):
2629
"""register agent run instance"""
2730
with self._lock:
2831
self.agent_runs[conversation_id] = agent_run_info
29-
logger.info(f"register agent run instance, conversation_id: {conversation_id}")
32+
logger.info(
33+
f"register agent run instance, conversation_id: {conversation_id}")
3034

3135
def unregister_agent_run(self, conversation_id: int):
3236
"""unregister agent run instance"""
3337
with self._lock:
3438
if conversation_id in self.agent_runs:
3539
del self.agent_runs[conversation_id]
36-
logger.info(f"unregister agent run instance, conversation_id: {conversation_id}")
40+
logger.info(
41+
f"unregister agent run instance, conversation_id: {conversation_id}")
3742
else:
38-
logger.info(f"no agent run instance found for conversation_id: {conversation_id}")
43+
logger.info(
44+
f"no agent run instance found for conversation_id: {conversation_id}")
3945

4046
def get_agent_run_info(self, conversation_id: int):
4147
"""get agent run instance"""
@@ -46,10 +52,11 @@ def stop_agent_run(self, conversation_id: int) -> bool:
4652
agent_run_info = self.get_agent_run_info(conversation_id)
4753
if agent_run_info is not None:
4854
agent_run_info.stop_event.set()
49-
logger.info(f"agent run stopped, conversation_id: {conversation_id}")
55+
logger.info(
56+
f"agent run stopped, conversation_id: {conversation_id}")
5057
return True
5158
return False
5259

5360

5461
# create singleton instance
55-
agent_run_manager = AgentRunManager()
62+
agent_run_manager = AgentRunManager()

backend/agents/create_agent_info.py

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,33 @@
11
import threading
22
import logging
33
from urllib.parse import urljoin
4+
from datetime import datetime
5+
6+
from jinja2 import Template, StrictUndefined
7+
from smolagents.utils import BASE_BUILTIN_MODULES
48
from nexent.core.utils.observer import MessageObserver
59
from 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
1112
from services.elasticsearch_service import ElasticSearchService, elastic_core, get_embedding_model
1213
from 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
1318
from utils.prompt_template_utils import get_agent_prompt_template
1419
from 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

2322
logger = logging.getLogger("create_agent_info")
2423
logger.setLevel(logging.DEBUG)
2524

25+
2626
async 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

4244
async 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

191207
async 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

Comments
 (0)