Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ad81d60
Add user testimonials to memorial wall documentation
Decksweeper20 Dec 10, 2025
1331726
refactoring TopNavbar & SideNavigation by using antd default style
xuyaqist Dec 12, 2025
aebf020
🐛 The prompt includes the thought process #2038
YehongPan Dec 13, 2025
d55cbf1
Add new tip for 开源新手 on Nexent platform
Magic026 Dec 14, 2025
fa2cbe1
Add new tip for 开源新手 on Nexent platform from Magic026/patch-1
WMC001 Dec 15, 2025
a76cd17
Merge branch 'develop' into patch-1
WMC001 Dec 15, 2025
108c1aa
Add user testimonials to memorial wall documentation from Decksweeper…
WMC001 Dec 15, 2025
53bab91
Bugfix workspace root detection for multiple lockfiles
xuyaqist Dec 15, 2025
cbc12a2
Unify global modals:
xuyaqist Dec 15, 2025
4719c4b
♻️ The agent import performance improvement: add existing tool check
WMC001 Dec 15, 2025
80ebe27
♻️ The agent import performance improvement: add doc about importing …
WMC001 Dec 16, 2025
e220b5b
Revert "Unify global modals:"
xuyaqist Dec 16, 2025
24d12df
user-guide change
Dec 16, 2025
89d832d
Unify global modals:
xuyaqist Dec 15, 2025
5bf8b1f
Unify global modals:
xuyaqist Dec 16, 2025
b683865
Unify code style
xuyaqist Dec 16, 2025
f0c70ec
Unify code style
xuyaqist Dec 16, 2025
6cdaba3
uersguide docs change
Dec 16, 2025
478d775
Revert "Unify code style"
xuyaqist Dec 16, 2025
cdd75de
Delete radix-ui/react-dialog, replace it with ant design modal
xuyaqist Dec 16, 2025
94a8097
♻️ The tool status is not synchronized when the service starts
WMC001 Dec 16, 2025
4a70506
Unify global modals:
xuyaqist Dec 16, 2025
b18673a
♻️ Unify frontend code style
Phinease Dec 16, 2025
d78a6f0
♻️ Unify dialog&modal
Phinease Dec 16, 2025
43af69b
♻️ Refactoring TopNavbar & SideNavigation by using antd default style
Phinease Dec 16, 2025
9af761c
📝 User-Guide Updates
Phinease Dec 16, 2025
12f0f35
🐛 The prompt includes the thought process #2038
Phinease Dec 16, 2025
f8b73bd
♻️ The tool status is not synchronized when the service starts
WMC001 Dec 16, 2025
f1d6b17
♻️ The agent import performance improvement: add existing tool check
Phinease Dec 16, 2025
83a25f9
Unify global dialog&modal, delete unused code
xuyaqist Dec 17, 2025
91508cb
♻️ Unify global dialog&modal, delete unused code
Phinease Dec 17, 2025
15cf7a3
🐛 Bugfix: the deployment pipeline deploy.sh failed to execute #2096
WMC001 Dec 17, 2025
3eb3e8a
🐛 Bugfix: Skip MCP tools as they will be handled in the MCP server in…
WMC001 Dec 17, 2025
bec3558
Unify global modal, delete unused code
xuyaqist Dec 17, 2025
85f347f
Delete unused modals
xuyaqist Dec 17, 2025
f167937
Delete unused navbar
xuyaqist Dec 17, 2025
705fdd1
Fix typeScript type check
xuyaqist Dec 17, 2025
7766c06
Revert "Delete unused modals"
xuyaqist Dec 17, 2025
3708754
Delete modals that will never be opened
xuyaqist Dec 17, 2025
f292eb5
🎨 Standardize frontend icons into lucide icon and antd icons
Jasonxia007 Dec 17, 2025
601c786
🐛 Fix the deployment pipeline deploy.sh failed to execute
Phinease Dec 17, 2025
e6297c1
♻️ Unify global modal, delete unused code
Phinease Dec 17, 2025
4d848f4
♻️ Delete unused navbar
Phinease Dec 17, 2025
c2e3dbf
Merge remote-tracking branch 'origin/develop' into xyc/frontend_ui
Jasonxia007 Dec 17, 2025
c08e0dc
🎨 Standardize frontend icons into lucide icon and antd icons
Jasonxia007 Dec 18, 2025
97e8999
Merge pull request #2103 from ModelEngine-Group/xyc/frontend_ui
Phinease Dec 18, 2025
b16f889
Bugfix: when clearing modal, modal popup twice
xuyaqist Dec 18, 2025
60b01a6
delete declare
xuyaqist Dec 18, 2025
08a0aba
🎨 Change some modal button style from danger to normal
Jasonxia007 Dec 18, 2025
db885b8
Merge pull request #2109 from ModelEngine-Group/xyc/frontend_ui
Phinease Dec 19, 2025
a836a8d
Merge pull request #2108 from ModelEngine-Group/xyq/unify_dialog&modal
Phinease Dec 19, 2025
34f351e
Revert "delete declare"
xuyaqist Dec 19, 2025
1313e88
♻️ Revert package declare from ModelEngine-Group/xyq/unify_dialog&modal
WMC001 Dec 19, 2025
2cbcf9d
📝 Updates app version
WMC001 Dec 19, 2025
7bcc859
📝 Updates app version from ModelEngine-Group/wmc/bugfix_1117
WMC001 Dec 19, 2025
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
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,jsx,ts,tsx,json}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
16 changes: 12 additions & 4 deletions .github/workflows/docker-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ on:
description: 'runner array in json format (e.g. ["ubuntu-latest"] or ["self-hosted"])'
required: true
default: '[]'
app_version:
description: 'Docker image tag to build and deploy (e.g. v1.7.1)'
required: true
default: 'latest'
type: string

jobs:
build-main:
Expand All @@ -23,7 +28,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Build main application image
run: docker build --build-arg MIRROR=https://pypi.tuna.tsinghua.edu.cn/simple --build-arg APT_MIRROR=tsinghua -t nexent/nexent -f make/main/Dockerfile .
run: docker build --build-arg MIRROR=https://pypi.tuna.tsinghua.edu.cn/simple --build-arg APT_MIRROR=tsinghua -t nexent/nexent:${{ github.event.inputs.app_version }} -t nexent/nexent -f make/main/Dockerfile .

build-data-process:
runs-on: ${{ fromJson(inputs.runner_label_json) }}
Expand All @@ -47,23 +52,23 @@ jobs:
GIT_TRACE=1 GIT_CURL_VERBOSE=1 GIT_LFS_LOG=debug git lfs pull
rm -rf .git .gitattributes
- name: Build data process image
run: docker build --build-arg MIRROR=https://pypi.tuna.tsinghua.edu.cn/simple --build-arg APT_MIRROR=tsinghua -t nexent/nexent-data-process -f make/data_process/Dockerfile .
run: docker build --build-arg MIRROR=https://pypi.tuna.tsinghua.edu.cn/simple --build-arg APT_MIRROR=tsinghua -t nexent/nexent-data-process:${{ github.event.inputs.app_version }} -t nexent/nexent-data-process -f make/data_process/Dockerfile .

build-web:
runs-on: ${{ fromJson(inputs.runner_label_json) }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build web frontend image
run: docker build --build-arg MIRROR=https://registry.npmmirror.com --build-arg APK_MIRROR=tsinghua -t nexent/nexent-web -f make/web/Dockerfile .
run: docker build --build-arg MIRROR=https://registry.npmmirror.com --build-arg APK_MIRROR=tsinghua -t nexent/nexent-web:${{ github.event.inputs.app_version }} -t nexent/nexent-web -f make/web/Dockerfile .

build-docs:
runs-on: ${{ fromJson(inputs.runner_label_json) }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build docs image
run: docker build --progress=plain -t nexent/nexent-docs -f make/docs/Dockerfile .
run: docker build --progress=plain -t nexent/nexent-docs:${{ github.event.inputs.app_version }} -t nexent/nexent-docs -f make/docs/Dockerfile .

deploy:
runs-on: ${{ fromJson(inputs.runner_label_json) }}
Expand All @@ -76,6 +81,9 @@ jobs:
rm -rf $HOME/nexent
mkdir -p $HOME/nexent
cp -r $GITHUB_WORKSPACE/* $HOME/nexent/
- name: Force APP_VERSION to latest in deploy.sh (CI only)
run: |
sed -i 's/APP_VERSION="$(get_app_version)"/APP_VERSION="${{ github.event.inputs.app_version }}"/' $HOME/nexent/docker/deploy.sh
- name: Start docs container
run: |
docker stop nexent-docs 2>/dev/null || true
Expand Down
21 changes: 2 additions & 19 deletions backend/config_service.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import uvicorn
import logging
import warnings
import asyncio

from consts.const import APP_VERSION

Expand All @@ -12,30 +11,14 @@

from apps.config_app import app
from utils.logging_utils import configure_logging, configure_elasticsearch_logging
from services.tool_configuration_service import initialize_tools_on_startup


configure_logging(logging.INFO)
configure_elasticsearch_logging()
logger = logging.getLogger("config_service")


async def startup_initialization():
"""
Perform initialization tasks during server startup
"""
if __name__ == "__main__":
logger.info("Starting server initialization...")
logger.info(f"APP version is: {APP_VERSION}")
try:
# Initialize tools on startup - service layer handles detailed logging
await initialize_tools_on_startup()
logger.info("Server initialization completed successfully!")

except Exception as e:
logger.error(f"Server initialization failed: {str(e)}")
# Don't raise the exception to allow server to start even if initialization fails
logger.warning("Server will continue to start despite initialization issues")


if __name__ == "__main__":
asyncio.run(startup_initialization())
uvicorn.run(app, host="0.0.0.0", port=5010, log_level="info")
2 changes: 1 addition & 1 deletion backend/consts/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,4 +285,4 @@ class VectorDatabaseType(str, Enum):


# APP Version
APP_VERSION = "v1.7.8"
APP_VERSION = "v1.7.8.1"
20 changes: 2 additions & 18 deletions backend/runtime_service.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import uvicorn
import logging
import warnings
import asyncio

from consts.const import APP_VERSION

Expand All @@ -12,31 +11,16 @@

from apps.runtime_app import app
from utils.logging_utils import configure_logging, configure_elasticsearch_logging
from services.tool_configuration_service import initialize_tools_on_startup


configure_logging(logging.INFO)
configure_elasticsearch_logging()
logger = logging.getLogger("runtime_service")


async def startup_initialization():
"""
Perform initialization tasks during server startup
"""
if __name__ == "__main__":
logger.info("Starting server initialization...")
logger.info(f"APP version is: {APP_VERSION}")
try:
# Initialize tools on startup - service layer handles detailed logging
await initialize_tools_on_startup()
logger.info("Server initialization completed successfully!")
except Exception as e:
logger.error(f"Server initialization failed: {str(e)}")
# Don't raise the exception to allow server to start even if initialization fails
logger.warning("Server will continue to start despite initialization issues")


if __name__ == "__main__":
asyncio.run(startup_initialization())
uvicorn.run(app, host="0.0.0.0", port=5014, log_level="info")


68 changes: 1 addition & 67 deletions backend/services/tool_configuration_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import jsonref
from mcpadapt.smolagents_adapter import _sanitize_function_name

from consts.const import DEFAULT_USER_ID, LOCAL_MCP_SERVER, DATA_PROCESS_SERVICE
from consts.const import LOCAL_MCP_SERVER, DATA_PROCESS_SERVICE
from consts.exceptions import MCPConnectionError, ToolExecutionException, NotFoundException
from consts.model import ToolInstanceInfoRequest, ToolInfo, ToolSourceEnum, ToolValidateRequest
from database.remote_mcp_db import get_mcp_records_by_tenant, get_mcp_server_by_name_and_tenant
Expand All @@ -22,7 +22,6 @@
update_tool_table_from_scan_tool_list,
search_last_tool_instance_by_tool_id,
)
from database.user_tenant_db import get_all_tenant_ids
from services.file_management_service import get_llm_model
from services.vectordatabase_service import get_embedding_model, get_vector_db_core
from services.tenant_config_service import get_selected_knowledge_list, build_knowledge_name_mapping
Expand Down Expand Up @@ -367,71 +366,6 @@ async def list_all_tools(tenant_id: str):
return formatted_tools


async def initialize_tools_on_startup():
"""
Initialize and scan all tools during server startup for all tenants

This function scans all available tools (local, LangChain, and MCP)
and updates the database with the latest tool information for all tenants.
"""

logger.info("Starting tool initialization on server startup...")

try:
# Get all tenant IDs from the database
tenant_ids = get_all_tenant_ids()

if not tenant_ids:
logger.warning("No tenants found in database, skipping tool initialization")
return

logger.info(f"Found {len(tenant_ids)} tenants: {tenant_ids}")

total_tools = 0
successful_tenants = 0
failed_tenants = []

# Process each tenant
for tenant_id in tenant_ids:
try:
logger.info(f"Initializing tools for tenant: {tenant_id}")

# Add timeout to prevent hanging during startup
try:
await asyncio.wait_for(
update_tool_list(tenant_id=tenant_id, user_id=DEFAULT_USER_ID),
timeout=60.0 # 60 seconds timeout per tenant
)

# Get the count of tools for this tenant
tools_info = query_all_tools(tenant_id)
tenant_tool_count = len(tools_info)
total_tools += tenant_tool_count
successful_tenants += 1

logger.info(f"Tenant {tenant_id}: {tenant_tool_count} tools initialized")

except asyncio.TimeoutError:
logger.error(f"Tool initialization timed out for tenant {tenant_id}")
failed_tenants.append(f"{tenant_id} (timeout)")

except Exception as e:
logger.error(f"Tool initialization failed for tenant {tenant_id}: {str(e)}")
failed_tenants.append(f"{tenant_id} (error: {str(e)})")

# Log final results
logger.info("Tool initialization completed!")
logger.info(f"Total tools available across all tenants: {total_tools}")
logger.info(f"Successfully processed: {successful_tenants}/{len(tenant_ids)} tenants")

if failed_tenants:
logger.warning(f"Failed tenants: {', '.join(failed_tenants)}")

except Exception as e:
logger.error(f"❌ Tool initialization failed: {str(e)}")
raise


def load_last_tool_config_impl(tool_id: int, tenant_id: str, user_id: str):
"""
Load the last tool configuration for a given tool ID
Expand Down
61 changes: 52 additions & 9 deletions backend/utils/llm_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,37 @@ def _process_thinking_tokens(
) -> bool:
"""
Process tokens to filter out thinking content between <think> and </think> tags.
Handles cases where providers only send a closing tag or mix reasoning_content.
"""
if is_thinking:
return THINK_END_PATTERN not in new_token
# Check for end tag first, as it might appear in the same token as start tag
if THINK_END_PATTERN in new_token:
# If we were never in think mode, treat everything accumulated so far as reasoning and clear it
if not is_thinking:
token_join.clear()
if callback:
callback("") # clear any previously streamed reasoning content

# Exit thinking mode and only keep content after </think>
_, _, after_end = new_token.partition(THINK_END_PATTERN)
is_thinking = False
new_token = after_end
# Continue processing the remaining content in this token

# Check for start tag (after processing end tag, in case both are in the same token)
if THINK_START_PATTERN in new_token:
# Drop any content before <think> and switch to thinking mode
_, _, after_start = new_token.partition(THINK_START_PATTERN)
new_token = after_start
is_thinking = True

if is_thinking:
# Still inside thinking content; ignore until we exit
return True

token_join.append(new_token)
if callback:
callback("".join(token_join))
if new_token:
token_join.append(new_token)
if callback:
callback("".join(token_join))

return False

Expand All @@ -46,8 +67,8 @@ def call_llm_for_system_prompt(

llm = OpenAIModel(
model_id=get_model_name_from_config(llm_model_config) if llm_model_config else "",
api_base=llm_model_config.get("base_url", ""),
api_key=llm_model_config.get("api_key", ""),
api_base=llm_model_config.get("base_url", "") if llm_model_config else "",
api_key=llm_model_config.get("api_key", "") if llm_model_config else "",
temperature=0.3,
top_p=0.95,
)
Expand All @@ -65,16 +86,38 @@ def call_llm_for_system_prompt(
current_request = llm.client.chat.completions.create(stream=True, **completion_kwargs)
token_join: List[str] = []
is_thinking = False
reasoning_content_seen = False
content_tokens_seen = 0
for chunk in current_request:
new_token = chunk.choices[0].delta.content
delta = chunk.choices[0].delta
reasoning_content = getattr(delta, "reasoning_content", None)
new_token = delta.content

# Note: reasoning_content is separate metadata and doesn't affect content filtering
# We only filter content based on <think> tags in delta.content
if reasoning_content:
reasoning_content_seen = True
logger.debug("Received reasoning_content (metadata only, not filtering content)")

# Process content token if it exists
if new_token is not None:
content_tokens_seen += 1
is_thinking = _process_thinking_tokens(
new_token,
is_thinking,
token_join,
callback,
)
return "".join(token_join)

result = "".join(token_join)
if not result and content_tokens_seen > 0:
logger.warning(
"Generated prompt is empty but %d content tokens were processed. "
"This suggests all content was filtered out.",
content_tokens_seen
)

return result
except Exception as exc:
logger.error("Failed to generate prompt from LLM: %s", str(exc))
raise
Expand Down
8 changes: 6 additions & 2 deletions doc/docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// https://vitepress.dev/reference/site-config
// https://vitepress.dev/reference/site-config
import { defineConfig } from "vitepress";

export default defineConfig({
Expand Down Expand Up @@ -89,6 +89,8 @@ export default defineConfig({
text: "Knowledge Base",
link: "/en/user-guide/knowledge-base",
},
{ text: "MCP Tools", link: "/en/user-guide/mcp-tools" },
{ text: "Monitoring & Ops", link: "/en/user-guide/monitor" },
{
text: "Model Management",
link: "/en/user-guide/model-management",
Expand Down Expand Up @@ -267,7 +269,7 @@ export default defineConfig({
items: [
{ text: "首页", link: "/zh/user-guide/home-page" },
{ text: "开始问答", link: "/zh/user-guide/start-chat" },
{ text: "快速设置", link: "/zh/user-guide/quick-setup" },
{ text: "快速配置", link: "/zh/user-guide/quick-setup" },
{ text: "智能体空间", link: "/zh/user-guide/agent-space" },
{ text: "智能体市场", link: "/zh/user-guide/agent-market" },
{
Expand All @@ -278,6 +280,8 @@ export default defineConfig({
text: "知识库",
link: "/zh/user-guide/knowledge-base",
},
{ text: "MCP工具", link: "/zh/user-guide/mcp-tools" },
{ text: "监控与运维", link: "/zh/user-guide/monitor" },
{ text: "模型管理", link: "/zh/user-guide/model-management" },
{ text: "记忆管理", link: "/zh/user-guide/memory-management" },
{ text: "用户管理", link: "/zh/user-guide/user-management" },
Expand Down
Loading
Loading