Skip to content

Commit 4cd6eda

Browse files
authored
Merge branch 'develop' into prompt_template
2 parents 3bc3579 + e395bcd commit 4cd6eda

290 files changed

Lines changed: 40264 additions & 3930 deletions

File tree

Some content is hidden

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

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ docker/volumes/db/data
2121
docker/.env
2222
docker/.run
2323
docker/deploy.options
24+
k8s/helm/.deploy.options
2425

2526
frontend_standalone/
2627
.pnpm-store/
@@ -32,4 +33,4 @@ model-assets/
3233
*coverage_html
3334
*.pytest_cache
3435
*.coverage
35-
*coverage.xml
36+
*coverage.xml

LICENSE

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
# Nexent Open Source License
2-
3-
Nexent is licensed under the MIT License, with the following additional conditions:
4-
5-
Nexent is permitted to be used commercially, including as a backend service for other applications or as an application development platform for enterprises. However, when the following conditions are met, you must contact the producer to obtain a commercial license:
6-
7-
a. Multi-tenant SaaS service: Unless explicitly authorized by Nexent in writing, you may not use the Nexent source code to operate a multi-tenant SaaS service.
8-
b. LOGO and copyright information: In the process of using Nexent's frontend, you may not remove or modify the LOGO or copyright information in the Nexent console or applications. This restriction is inapplicable to uses of Nexent that do not involve its frontend.
9-
10-
Please contact zhenggaoqi@huawei.com by email to inquire about licensing matters.
11-
12-
As a contributor, you should agree that:
13-
14-
a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
15-
b. Your contributed code may be used for commercial purposes, such as Nexent's cloud business.
16-
17-
Apart from the specific conditions mentioned above, all other rights and restrictions follow the MIT License.
18-
Detailed information about the MIT License can be found at: https://opensource.org/licenses/MIT
19-
20-
Copyright © 2025 Huawei Technologies Co., Ltd.
1+
MIT License
2+
3+
Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![Docker Pulls](https://img.shields.io/docker/pulls/nexent/nexent?logo=docker&label=DockerPull)](https://hub.docker.com/repositories/nexent)
88
[![Codecov (with branch)](https://img.shields.io/codecov/c/github/ModelEngine-Group/nexent/develop?logo=codecov&color=green)](https://codecov.io/gh/ModelEngine-Group/nexent)
99

10-
Nexent is a zero-code platform for auto-generating agents — no orchestration, no complex drag-and-drop required, using pure language to develop any agent you want. Built on the MCP ecosystem with rich tool integration, Nexent also provides various built-in agents to meet your intelligent service needs in different scenarios such as work, travel, and daily life. Nexent offers powerful capabilities for agent running control, multi-agent collaboration, data processing and knowledge tracing, multimodal dialogue, and batch scaling.
10+
Nexent is a zero-code platform for auto-generating production-grade AI agents, built on **Harness Engineering** principles. It provides unified tools, skills, memory, and orchestration with built-in constraints, feedback loops, and control planes — no orchestration, no complex drag-and-drop required, using pure language to develop any agent you want.
1111

1212
> One prompt. Endless reach.
1313
@@ -58,7 +58,7 @@ Most of all, we need visibility. Star ⭐ and watch the repo, share it with frie
5858

5959
## 💬 Community & contact
6060

61-
- Browse the [Documentation](https://modelengine-group.github.io/nexent) for more information.
61+
- Browse the [Documentation](https://modelengine-group.github.io/nexent) for more information.
6262
- Join our [Discord community](https://discord.gg/tb5H3S3wyv) to chat with other developers and get help!
6363
- Conntact us by Wechat, find our QR Code in our [website](https://nexent.tech/en/contact)
6464

@@ -119,5 +119,4 @@ Prefer to run Nexent from source code? Follow our [Developer Guide](https://mode
119119

120120
# 📄 License
121121

122-
Nexent is licensed under the [MIT](LICENSE) with additional conditions. Please read the [LICENSE](LICENSE) file for details.
123-
122+
Nexent is licensed under the [MIT License](LICENSE).

README_CN.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![Docker Pulls](https://img.shields.io/docker/pulls/nexent/nexent?logo=docker&label=DockerPull)](https://hub.docker.com/repositories/nexent)
88
[![Codecov (with branch)](https://img.shields.io/codecov/c/github/ModelEngine-Group/nexent/develop?logo=codecov&color=green)](https://codecov.io/gh/ModelEngine-Group/nexent)
99

10-
Nexent 是一个零代码智能体自动生成平台 —— 无需编排,无需复杂的拖拉拽操作,使用纯语言开发你想要的任何智能体。基于MCP生态,具备丰富的工具集成,同时提供多种自带智能体,满足你的工作、旅行、生活等不同场景的智能服务需要。Nexent 还提供强大的智能体运行控制、多智能体协作、数据处理和知识溯源、多模态对话、批量扩展能力
10+
Nexent 是一个基于 **Harness Engineering** 原则打造的零代码智能体自动生成平台。集统一工具、技能、记忆和编排能力于一体,内置约束机制、反馈循环和控制平面。无需编排,无需复杂的拖拉拽操作,使用纯语言开发你想要的任何智能体。
1111

1212
> 一个提示词,无限种可能。
1313
@@ -58,7 +58,7 @@ bash deploy.sh
5858

5959
## 💬 社区与联系方式
6060

61-
- 浏览 [文档](https://modelengine-group.github.io/nexent) 了解更多信息。
61+
- 浏览 [文档](https://modelengine-group.github.io/nexent) 了解更多信息。
6262
- 加入我们的 [Discord 社区](https://discord.gg/tb5H3S3wyv) 与其他开发者交流并获取帮助!
6363
- 通过微信联系我们,在我们的[网站](https://nexent.tech/zh/contact)找到二维码
6464

@@ -119,4 +119,4 @@ bash deploy.sh
119119

120120
# 📄 许可证
121121

122-
Nexent 采用 [MIT](LICENSE) 许可证,并附有额外条件。请阅读 [LICENSE](LICENSE) 文件了解详情
122+
Nexent 采用 [MIT 许可证](LICENSE)

backend/agents/create_agent_info.py

Lines changed: 162 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import threading
22
import logging
3+
from typing import List
34
from urllib.parse import urljoin
45
from datetime import datetime
56

67
from jinja2 import Template, StrictUndefined
7-
from smolagents.utils import BASE_BUILTIN_MODULES
88
from nexent.core.utils.observer import MessageObserver
99
from nexent.core.agents.agent_model import AgentRunInfo, ModelConfig, AgentConfig, ToolConfig
1010
from nexent.memory.memory_service import search_memory_in_levels
@@ -14,6 +14,7 @@
1414
ElasticSearchService,
1515
get_vector_db_core,
1616
get_embedding_model,
17+
get_rerank_model,
1718
)
1819
from services.remote_mcp_service import get_remote_mcp_server_list
1920
from services.memory_config_service import build_memory_context
@@ -27,11 +28,119 @@
2728
from utils.prompt_template_utils import get_agent_prompt_template
2829
from utils.config_utils import tenant_config_manager, get_model_name_from_config
2930
from consts.const import LOCAL_MCP_SERVER, MODEL_CONFIG_MAPPING, LANGUAGE, DATA_PROCESS_SERVICE
31+
import re
3032

3133
logger = logging.getLogger("create_agent_info")
3234
logger.setLevel(logging.DEBUG)
3335

3436

37+
def _get_skills_for_template(
38+
agent_id: int,
39+
tenant_id: str,
40+
version_no: int = 0
41+
) -> List[dict]:
42+
"""Get skills list for prompt template injection.
43+
44+
Args:
45+
agent_id: Agent ID
46+
tenant_id: Tenant ID
47+
version_no: Version number
48+
49+
Returns:
50+
List of skill dicts with name and description
51+
"""
52+
try:
53+
from services.skill_service import SkillService
54+
skill_service = SkillService()
55+
enabled_skills = skill_service.get_enabled_skills_for_agent(
56+
agent_id=agent_id,
57+
tenant_id=tenant_id,
58+
version_no=version_no
59+
)
60+
return [
61+
{"name": s.get("name", ""), "description": s.get("description", "")}
62+
for s in enabled_skills
63+
]
64+
except Exception as e:
65+
logger.warning(f"Failed to get skills for template: {e}")
66+
return []
67+
68+
69+
def _get_skill_script_tools(
70+
agent_id: int,
71+
tenant_id: str,
72+
version_no: int = 0
73+
) -> List[ToolConfig]:
74+
"""Get tool config for skill script execution and skill reading.
75+
76+
Args:
77+
agent_id: Agent ID for filtering available skills in error messages.
78+
tenant_id: Tenant ID for filtering available skills in error messages.
79+
version_no: Version number for filtering available skills.
80+
81+
Returns:
82+
List of ToolConfig for skill execution and reading tools
83+
"""
84+
from consts.const import CONTAINER_SKILLS_PATH
85+
86+
skill_context = {
87+
"agent_id": agent_id,
88+
"tenant_id": tenant_id,
89+
"version_no": version_no,
90+
}
91+
92+
try:
93+
return [
94+
ToolConfig(
95+
class_name="RunSkillScriptTool",
96+
name="run_skill_script",
97+
description="Execute a skill script with given parameters. Use this to run Python or shell scripts that are part of a skill.",
98+
inputs='{"skill_name": "str", "script_path": "str", "params": "dict"}',
99+
output_type="string",
100+
params={"local_skills_dir": CONTAINER_SKILLS_PATH},
101+
source="builtin",
102+
usage="builtin",
103+
metadata=skill_context,
104+
),
105+
ToolConfig(
106+
class_name="ReadSkillMdTool",
107+
name="read_skill_md",
108+
description="Read skill execution guide and optional additional files. Always reads SKILL.md first, then optionally reads additional files.",
109+
inputs='{"skill_name": "str", "additional_files": "list[str]"}',
110+
output_type="string",
111+
params={"local_skills_dir": CONTAINER_SKILLS_PATH},
112+
source="builtin",
113+
usage="builtin",
114+
metadata=skill_context,
115+
),
116+
ToolConfig(
117+
class_name="ReadSkillConfigTool",
118+
name="read_skill_config",
119+
description="Read the config.yaml file from a skill directory. Returns JSON containing configuration variables needed for skill workflows.",
120+
inputs='{"skill_name": "str"}',
121+
output_type="string",
122+
params={"local_skills_dir": CONTAINER_SKILLS_PATH},
123+
source="builtin",
124+
usage="builtin",
125+
metadata=skill_context,
126+
),
127+
ToolConfig(
128+
class_name="WriteSkillFileTool",
129+
name="write_skill_file",
130+
description="Write content to a file within a skill directory. Creates parent directories if they do not exist.",
131+
inputs='{"skill_name": "str", "file_path": "str", "content": "str"}',
132+
output_type="string",
133+
params={"local_skills_dir": CONTAINER_SKILLS_PATH},
134+
source="builtin",
135+
usage="builtin",
136+
metadata=skill_context,
137+
)
138+
]
139+
except Exception as e:
140+
logger.warning(f"Failed to load skill script tool: {e}")
141+
return []
142+
143+
35144
async def create_model_config_list(tenant_id):
36145
records = get_model_records({"model_type": "llm"}, tenant_id)
37146
model_list = []
@@ -171,22 +280,24 @@ async def create_agent_config(
171280
logger.error(f"Failed to build knowledge base summary: {e}")
172281

173282
# Assemble system_prompt
174-
if duty_prompt or constraint_prompt or few_shots_prompt:
175-
system_prompt = Template(prompt_template["system_prompt"], undefined=StrictUndefined).render({
176-
"duty": duty_prompt,
177-
"constraint": constraint_prompt,
178-
"few_shots": few_shots_prompt,
179-
"tools": {tool.name: tool for tool in tool_list},
180-
"managed_agents": {agent.name: agent for agent in managed_agents},
181-
"authorized_imports": str(BASE_BUILTIN_MODULES),
182-
"APP_NAME": app_name,
183-
"APP_DESCRIPTION": app_description,
184-
"memory_list": memory_list,
185-
"knowledge_base_summary": knowledge_base_summary,
186-
"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
187-
})
188-
else:
189-
system_prompt = agent_info.get("prompt", "")
283+
# Get skills list for prompt template
284+
skills = _get_skills_for_template(agent_id, tenant_id, version_no)
285+
286+
render_kwargs = {
287+
"duty": duty_prompt,
288+
"constraint": constraint_prompt,
289+
"few_shots": few_shots_prompt,
290+
"tools": {tool.name: tool for tool in tool_list},
291+
"skills": skills,
292+
"managed_agents": {agent.name: agent for agent in managed_agents},
293+
"APP_NAME": app_name,
294+
"APP_DESCRIPTION": app_description,
295+
"memory_list": memory_list,
296+
"knowledge_base_summary": knowledge_base_summary,
297+
"time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
298+
"user_id": user_id,
299+
}
300+
system_prompt = Template(prompt_template["system_prompt"], undefined=StrictUndefined).render(render_kwargs)
190301

191302
model_id_to_use = override_model_id if override_model_id else agent_info.get("model_id")
192303
if model_id_to_use is not None:
@@ -200,9 +311,10 @@ async def create_agent_config(
200311
prompt_templates=await prepare_prompt_templates(
201312
is_manager=len(managed_agents) > 0,
202313
system_prompt=system_prompt,
203-
language=language
314+
language=language,
315+
agent_id=agent_id
204316
),
205-
tools=tool_list,
317+
tools=tool_list + _get_skill_script_tools(agent_id, tenant_id, version_no),
206318
max_steps=agent_info.get("max_steps", 10),
207319
model_name=model_name,
208320
provide_run_summary=agent_info.get("provide_run_summary", False),
@@ -240,11 +352,32 @@ async def create_tool_config_list(agent_id, tenant_id, user_id, version_no: int
240352
tool_config.metadata = langchain_tool
241353
break
242354

243-
# special logic for knowledge base search tool
355+
# special logic for search tools that may use reranking models
244356
if tool_config.class_name == "KnowledgeBaseSearchTool":
245-
tool_config.metadata = {
357+
rerank = param_dict.get("rerank", False)
358+
rerank_model_name = param_dict.get("rerank_model_name", "")
359+
rerank_model = None
360+
if rerank and rerank_model_name:
361+
rerank_model = get_rerank_model(
362+
tenant_id=tenant_id, model_name=rerank_model_name
363+
)
364+
365+
tool_config.metadata = {
246366
"vdb_core": get_vector_db_core(),
247367
"embedding_model": get_embedding_model(tenant_id=tenant_id),
368+
"rerank_model": rerank_model,
369+
}
370+
elif tool_config.class_name in ["DifySearchTool", "DataMateSearchTool"]:
371+
rerank = param_dict.get("rerank", False)
372+
rerank_model_name = param_dict.get("rerank_model_name", "")
373+
rerank_model = None
374+
if rerank and rerank_model_name:
375+
rerank_model = get_rerank_model(
376+
tenant_id=tenant_id, model_name=rerank_model_name
377+
)
378+
379+
tool_config.metadata = {
380+
"rerank_model": rerank_model,
248381
}
249382
elif tool_config.class_name == "AnalyzeTextFileTool":
250383
tool_config.metadata = {
@@ -299,20 +432,27 @@ async def discover_langchain_tools():
299432
return langchain_tools
300433

301434

302-
async def prepare_prompt_templates(is_manager: bool, system_prompt: str, language: str = 'zh'):
435+
async def prepare_prompt_templates(
436+
is_manager: bool,
437+
system_prompt: str,
438+
language: str = 'zh',
439+
agent_id: int = None,
440+
):
303441
"""
304442
Prepare prompt templates, support multiple languages
305443
306444
Args:
307445
is_manager: Whether it is a manager mode
308446
system_prompt: System prompt content
309447
language: Language code ('zh' or 'en')
448+
agent_id: Agent ID for fetching skill instances
310449
311450
Returns:
312451
dict: Prompt template configuration
313452
"""
314453
prompt_templates = get_agent_prompt_template(is_manager, language)
315454
prompt_templates["system_prompt"] = system_prompt
455+
316456
return prompt_templates
317457

318458

0 commit comments

Comments
 (0)