Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
bf930ce
Update opensource-memorial-wall.md
qianmoyaq Nov 11, 2025
42d5cc6
Include testimonials for agent features and open-source journey
muxinmoment Nov 11, 2025
711d3fe
Add user feedback on automatic agent creation feature
JQTXZS2 Nov 11, 2025
20ea018
Update opensource-memorial-wall.md from qianmoyaq/patch-1
WMC001 Nov 12, 2025
c5e9fbd
Merge branch 'develop' into patch-1
WMC001 Nov 12, 2025
d2ccba4
Include testimonials for agent features and open-source journey from …
WMC001 Nov 12, 2025
cfdcad1
🚚 Unify main and develop branch (opensource-memorial-wall and other …
Phinease Nov 12, 2025
a45e57e
🐛 delete codeql workflow #1476
WMC001 Nov 12, 2025
3e07543
Update opensource-memorial-wall.md
yifeiqiao Nov 12, 2025
6b0fc12
Revise Nexent acknowledgment in memorial wall
andznrule Nov 12, 2025
3029553
✨ Now user can save or discard changes in agent config page
Jasonxia007 Nov 12, 2025
576410e
✨ Now user can save or discard changes in agent config page
Jasonxia007 Nov 12, 2025
1875cc2
Add tip section for new open source contributors
0501-maomao Nov 12, 2025
98c532f
Add tip from jeery1 about Huawei ICT event
Jeery1 Nov 12, 2025
95685cf
Update opensource-memorial-wall.md
Ren-chao02 Nov 12, 2025
1b78128
Update opensource-memorial-wall.md
hly7774 Nov 12, 2025
ef94d09
Update opensource-memorial-wall.md
wilson-hash Nov 12, 2025
3bef4a3
📝 Update upgrade guide doc
WMC001 Nov 13, 2025
00c80e7
✨[Request] Abstract Storage SDK
Zhi-a Nov 11, 2025
df29776
Add user contributions to memorial wall
KevinLeeNJ Nov 13, 2025
8faee38
✨[Request] Abstract Storage SDK
Zhi-a Nov 13, 2025
9a45259
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
910a6df
Add user feedback on automatic agent creation feature from JQTXZS2/pa…
WMC001 Nov 13, 2025
0eda532
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
bd164d1
Update opensource-memorial-wall.md from yifeiqiao/patch-1
WMC001 Nov 13, 2025
1de1d47
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
a42c614
Revise Nexent acknowledgment in memorial wall from andznrule/patch-1
WMC001 Nov 13, 2025
6800848
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
63478aa
✨ Now user can save or discard changes in agent config page
Phinease Nov 13, 2025
24a0312
✨[Request] Abstract Storage SDK
Zhi-a Nov 13, 2025
1cad13b
📝 Update upgrade guide doc 2
WMC001 Nov 13, 2025
2cf6f04
✨[Request] Abstract Storage SDK
Zhi-a Nov 13, 2025
77402ec
📝 Update upgrade guide doc 3
WMC001 Nov 13, 2025
ce2e407
first commit message
chengliuxiang2002 Nov 13, 2025
bd5588a
🐛 Even when there is no historical login token, the login prompt need…
Phinease Nov 13, 2025
2954132
Add tip section for new open source contributors from 0501-maomao/pat…
WMC001 Nov 13, 2025
397e79e
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
73db097
Add tip from Jeery1/patch-1
WMC001 Nov 13, 2025
998c1ed
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
0127c8a
Update opensource-memorial-wall.md from Ren-chao02/patch-1
WMC001 Nov 13, 2025
bed82f8
Merge branch 'develop' into patch-1
WMC001 Nov 13, 2025
ccf5f1b
Update opensource-memorial-wall.md from hly7774/patch-1
WMC001 Nov 13, 2025
a4dfd2a
Merge branch 'develop' into patch-2
WMC001 Nov 13, 2025
75fee64
Update opensource-memorial-wall.md from wilson-hash/patch-2
WMC001 Nov 13, 2025
5db8505
Add user contributions to memorial wall from KevinLeeNJ/patch-1
WMC001 Nov 13, 2025
076e88e
Merge branch 'develop' into patch-2
WMC001 Nov 13, 2025
b33d19b
first commit message from chengliuxiang2002/patch-2
WMC001 Nov 13, 2025
efa7c28
📝 Update app version
WMC001 Nov 13, 2025
f0dc54b
📝 Update app version
Phinease Nov 14, 2025
57da5f4
✨ Abstract Storage SDK #1219
Phinease Nov 14, 2025
7c35585
🐛 Bugfix: login window cannot be closed #1476
WMC001 Nov 14, 2025
75b6a0a
🐛 login window cannot be closed #1476
Phinease Nov 14, 2025
1a6c084
🐛 Agents with abnormal status should also be allowed to operate #1683
WMC001 Nov 14, 2025
41cc466
🐛 Bugfix: generate button in Agent config page returns error: Empty A…
Jasonxia007 Nov 14, 2025
0e04b30
🐛 Fix auth header didn't passed after relogin
WMC001 Nov 14, 2025
5bb9ff7
🐛 Agents with abnormal status should also be allowed to operate #1683
Phinease Nov 14, 2025
e02da79
🐛 generate button in Agent config page returns error: Empty agent ID …
Phinease Nov 14, 2025
d90b04b
♻️ Imporvement: nexent-data-process now takes less memory (down to ~1…
Jasonxia007 Nov 14, 2025
d56ed70
♻️ nexent-data-process now takes less memory, elasticsearch takes mor…
Phinease Nov 14, 2025
d053fe1
add codeql.yml
WMC001 Nov 14, 2025
ac56e1d
🐛 Bugfix: generate button in Agent config page returns error: Empty A…
Jasonxia007 Nov 14, 2025
0b10478
♻️ Imporvement: nexent-data-process now takes less memory (down to ~1…
Jasonxia007 Nov 14, 2025
b2419ac
Merge remote-tracking branch 'origin/release/v1.7.5.3' into release/v…
WMC001 Nov 14, 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
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@ jobs:
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
category: "/language:${{matrix.language}}"
45 changes: 3 additions & 42 deletions backend/apps/agent_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing import Optional

from fastapi import APIRouter, Body, Header, HTTPException, Request
from fastapi.responses import JSONResponse

from consts.model import AgentRequest, AgentInfoRequest, AgentIDRequest, ConversationResponse, AgentImportRequest
from services.agent_service import (
Expand All @@ -14,11 +13,9 @@
export_agent_impl,
import_agent_impl,
list_all_agent_info_impl,
insert_related_agent_impl,
run_agent_stream,
stop_agent_tasks,
get_agent_call_relationship_impl,
delete_related_agent_impl
get_agent_call_relationship_impl
)
from utils.auth_utils import get_current_user_info, get_current_user_id

Expand Down Expand Up @@ -94,8 +91,8 @@ async def update_agent_info_api(request: AgentInfoRequest, authorization: Option
Update an existing agent
"""
try:
await update_agent_info_impl(request, authorization)
return {}
result = await update_agent_info_impl(request, authorization)
return result or {}
except Exception as e:
logger.error(f"Agent update error: {str(e)}")
raise HTTPException(
Expand Down Expand Up @@ -158,42 +155,6 @@ async def list_all_agent_info_api(authorization: Optional[str] = Header(None), r
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Agent list error.")


@router.post("/related_agent")
async def related_agent_api(parent_agent_id: int = Body(...),
child_agent_id: int = Body(...),
authorization: Optional[str] = Header(None)):
"""
get related agent info
"""
try:
_, tenant_id = get_current_user_id(authorization)
return insert_related_agent_impl(parent_agent_id=parent_agent_id,
child_agent_id=child_agent_id,
tenant_id=tenant_id)
except Exception as e:
logger.error(f"Agent related info error: {str(e)}")
return JSONResponse(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
content={"message": "Failed to insert relation", "status": "error"}
)


@router.post("/delete_related_agent")
async def delete_related_agent_api(parent_agent_id: int = Body(...),
child_agent_id: int = Body(...),
authorization: Optional[str] = Header(None)):
"""
delete related agent info
"""
try:
_, tenant_id = get_current_user_id(authorization)
return delete_related_agent_impl(parent_agent_id, child_agent_id, tenant_id)
except Exception as e:
logger.error(f"Agent related info error: {str(e)}")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Agent related info error.")


@router.get("/call_relationship/{agent_id}")
async def get_agent_call_relationship_api(agent_id: int, authorization: Optional[str] = Header(None)):
"""
Expand Down
9 changes: 6 additions & 3 deletions backend/consts/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,14 @@
RAY_DASHBOARD_PORT = int(os.getenv("RAY_DASHBOARD_PORT", "8265"))
RAY_DASHBOARD_HOST = os.getenv("RAY_DASHBOARD_HOST", "0.0.0.0")
RAY_NUM_CPUS = os.getenv("RAY_NUM_CPUS")
RAY_PLASMA_DIRECTORY = os.getenv("RAY_PLASMA_DIRECTORY", "/tmp")
RAY_OBJECT_STORE_MEMORY_GB = float(
os.getenv("RAY_OBJECT_STORE_MEMORY_GB", "2.0"))
os.getenv("RAY_OBJECT_STORE_MEMORY_GB", "0.25"))
RAY_TEMP_DIR = os.getenv("RAY_TEMP_DIR", "/tmp/ray")
RAY_LOG_LEVEL = os.getenv("RAY_LOG_LEVEL", "INFO").upper()
# Disable plasma preallocation to reduce idle memory usage
# When set to false, Ray will allocate object store memory on-demand instead of preallocating
RAY_preallocate_plasma = os.getenv(
"RAY_preallocate_plasma", "false").lower() == "true"


# Service Control Flags
Expand Down Expand Up @@ -270,7 +273,7 @@
os.getenv("LLM_SLOW_TOKEN_RATE_THRESHOLD", "10.0")) # tokens per second

# APP Version
APP_VERSION = "v1.7.5.2"
APP_VERSION = "v1.7.5.3"

DEFAULT_ZH_TITLE = "新对话"
DEFAULT_EN_TITLE = "New Conversation"
4 changes: 3 additions & 1 deletion backend/consts/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class GenerateTitleRequest(BaseModel):

# used in agent/search agent/update for save agent info
class AgentInfoRequest(BaseModel):
agent_id: int
agent_id: Optional[int] = None
name: Optional[str] = None
display_name: Optional[str] = None
description: Optional[str] = None
Expand All @@ -217,6 +217,8 @@ class AgentInfoRequest(BaseModel):
enabled: Optional[bool] = None
business_logic_model_name: Optional[str] = None
business_logic_model_id: Optional[int] = None
enabled_tool_ids: Optional[List[int]] = None
related_agent_ids: Optional[List[int]] = None


class AgentIDRequest(BaseModel):
Expand Down
57 changes: 45 additions & 12 deletions backend/data_process/ray_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
import ray

from consts.const import (
RAY_NUM_CPUS,
RAY_OBJECT_STORE_MEMORY_GB,
RAY_PLASMA_DIRECTORY,
RAY_TEMP_DIR,
RAY_preallocate_plasma,
)

logger = logging.getLogger("data_process.ray_config")
Expand All @@ -25,9 +24,9 @@ class RayConfig:
"""Ray configuration manager"""

def __init__(self):
self.plasma_directory = RAY_PLASMA_DIRECTORY
self.object_store_memory_gb = RAY_OBJECT_STORE_MEMORY_GB
self.temp_dir = RAY_TEMP_DIR
self.preallocate_plasma = RAY_preallocate_plasma

def get_init_params(
self,
Expand All @@ -52,7 +51,6 @@ def get_init_params(
"""
params = {
"ignore_reinit_error": True,
"_plasma_directory": self.plasma_directory,
}

if address:
Expand All @@ -70,9 +68,16 @@ def get_init_params(
# Temp directory configuration
params["_temp_dir"] = self.temp_dir

# Object spilling directory (stable API)
# This allows Ray to spill objects to disk when memory is full
params["object_spilling_directory"] = self.temp_dir

# Dashboard configuration
# Always pass include_dashboard explicitly because Ray's default is True.
# If we omit this parameter when include_dashboard is False,
# Ray will still start the dashboard by default.
params["include_dashboard"] = include_dashboard
if include_dashboard:
params["include_dashboard"] = True
params["dashboard_host"] = dashboard_host
params["dashboard_port"] = dashboard_port

Expand All @@ -93,30 +98,49 @@ def init_ray(self, **kwargs) -> bool:
logger.info("Ray already initialized, skipping...")
return True

# Set RAY_preallocate_plasma environment variable before initialization
# Ray reads this environment variable during initialization
os.environ["RAY_preallocate_plasma"] = str(
self.preallocate_plasma).lower()

params = self.get_init_params(**kwargs)

# Log the attempt to initialize
logger.debug("Initializing Ray cluster...")
logger.debug("Ray configuration parameters:")
logger.info("Initializing Ray cluster...")
logger.info("Ray memory optimization configuration:")
logger.info(
f" RAY_preallocate_plasma: {self.preallocate_plasma}")
logger.info(
f" Object store memory: {self.object_store_memory_gb} GB")
for key, value in params.items():
if key.startswith('_'):
logger.debug(f" {key}: {value}")
elif key == 'object_store_memory':
logger.debug(f" {key}: {value / (1024 ** 3):.1f} GB")
logger.info(f" {key}: {value / (1024 ** 3):.2f} GB")
elif key == 'object_spilling_directory':
logger.info(f" {key}: {value}")
else:
logger.debug(f" {key}: {value}")

ray.init(**params)
logger.info("✅ Ray initialization successful")

# Display cluster information
# Display cluster information and verify memory configuration
try:
if hasattr(ray, 'cluster_resources'):
resources = ray.cluster_resources()
logger.debug(f"Ray cluster resources: {resources}")
logger.info(f"Ray cluster resources: {resources}")

# Log memory-related resources
if 'memory' in resources:
logger.info(
f" Total cluster memory: {resources['memory'] / (1024**3):.2f} GB")
if 'object_store_memory' in resources:
logger.info(
f" Object store memory: {resources['object_store_memory'] / (1024**3):.2f} GB")
except Exception as e:
logger.error(
f"Failed to get cluster resources information: {e}")
logger.warning(
f"Could not retrieve cluster resources information: {e}")

return True

Expand All @@ -139,9 +163,17 @@ def connect_to_cluster(self, address: str = "auto") -> bool:
logger.debug("Ray already initialized, skipping...")
return True

# Set RAY_preallocate_plasma environment variable before initialization
# Note: When connecting to existing cluster, this setting may not take effect
# as the cluster was already initialized with its own settings
os.environ["RAY_preallocate_plasma"] = str(
self.preallocate_plasma).lower()

params = self.get_init_params(address=address)

logger.debug(f"Connecting to Ray cluster: {address}")
logger.debug(
f" RAY_preallocate_plasma: {self.preallocate_plasma}")
ray.init(**params)
logger.info("✅ Successfully connected to Ray cluster")

Expand Down Expand Up @@ -183,6 +215,7 @@ def log_configuration(self):
logger.debug(f" Plasma directory: {self.plasma_directory}")
logger.debug(f" ObjectStore memory: {self.object_store_memory_gb} GB")
logger.debug(f" Temp directory: {self.temp_dir}")
logger.debug(f" Preallocate plasma: {self.preallocate_plasma}")

@classmethod
def init_ray_for_worker(cls, address: str = "auto") -> bool:
Expand Down
39 changes: 22 additions & 17 deletions backend/data_process/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
REDIS_BACKEND_URL,
FORWARD_REDIS_RETRY_DELAY_S,
FORWARD_REDIS_RETRY_MAX,
DISABLE_RAY_DASHBOARD,
)


Expand All @@ -36,24 +37,28 @@ def init_ray_in_worker():
Initializes Ray within a Celery worker, ensuring it is done only once.
This function is designed to be called from within a task.
"""
if not ray.is_initialized():
logger.info(
"Ray not initialized. Initializing Ray for Celery worker...")
try:
# `configure_logging=False` prevents Ray from setting up its own loggers,
# which can interfere with Celery's logging.
# `faulthandler=False` is critical to prevent the `AttributeError: 'LoggingProxy' object has no attribute 'fileno'`
# error when running inside a Celery worker.
ray.init(
configure_logging=False,
faulthandler=False
)
logger.info("Ray initialized successfully for Celery worker.")
except Exception as e:
logger.error(f"Failed to initialize Ray for Celery worker: {e}")
raise
else:
if ray.is_initialized():
logger.debug("Ray is already initialized.")
return

logger.info("Ray not initialized. Initializing Ray for Celery worker...")
try:
# `configure_logging=False` prevents Ray from setting up its own loggers,
# which can interfere with Celery's logging.
# `faulthandler=False` is critical to prevent the
# `AttributeError: 'LoggingProxy' object has no attribute 'fileno'`
# error when running inside a Celery worker.
# We also explicitly control the Ray dashboard behavior here to ensure
# that Celery workers respect the global DISABLE_RAY_DASHBOARD setting.
ray.init(
configure_logging=False,
faulthandler=False,
include_dashboard=not DISABLE_RAY_DASHBOARD,
)
logger.info("Ray initialized successfully for Celery worker.")
except Exception as e:
logger.error(f"Failed to initialize Ray for Celery worker: {e}")
raise


def run_async(coro):
Expand Down
7 changes: 5 additions & 2 deletions backend/data_process/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
ELASTICSEARCH_SERVICE,
QUEUES,
RAY_ADDRESS,
RAY_PLASMA_DIRECTORY,
RAY_preallocate_plasma,
REDIS_URL,
WORKER_CONCURRENCY,
WORKER_NAME,
Expand Down Expand Up @@ -94,13 +94,16 @@ def setup_worker_environment(**kwargs):
ray_address = RAY_ADDRESS

try:
os.environ["RAY_preallocate_plasma"] = str(
RAY_preallocate_plasma).lower()

# Initialize Ray using the centralized RayConfig helper
if not RayConfig.init_ray_for_worker(ray_address):
logger.warning("Warning: fallback to direct ray.init")
# Fallback to direct ray.init if helper fails
ray.init(
address=ray_address,
ignore_reinit_error=True,
_plasma_directory=RAY_PLASMA_DIRECTORY
)

logger.info(
Expand Down
20 changes: 17 additions & 3 deletions backend/data_process_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from consts.const import (
REDIS_URL, REDIS_PORT, FLOWER_PORT, RAY_DASHBOARD_PORT, RAY_DASHBOARD_HOST,
RAY_ACTOR_NUM_CPUS, RAY_NUM_CPUS, DISABLE_RAY_DASHBOARD, DISABLE_CELERY_FLOWER,
DOCKER_ENVIRONMENT
DOCKER_ENVIRONMENT, RAY_OBJECT_STORE_MEMORY_GB, RAY_preallocate_plasma, RAY_TEMP_DIR
)

# Load environment variables
Expand Down Expand Up @@ -111,16 +111,30 @@ def start_ray_cluster(self):
if not success:
# Fallback to direct Ray initialization
try:
# Set RAY_preallocate_plasma environment variable before initialization
os.environ["RAY_preallocate_plasma"] = str(
RAY_preallocate_plasma).lower()

# Calculate object store memory in bytes
object_store_memory = int(
RAY_OBJECT_STORE_MEMORY_GB * 1024 * 1024 * 1024)

logger.info(
f"Fallback: Initializing Ray with object_store_memory={RAY_OBJECT_STORE_MEMORY_GB}GB, preallocate_plasma={RAY_preallocate_plasma}")

ray.init(
num_cpus=num_cpus,
_plasma_directory="/tmp",
object_store_memory=object_store_memory,
_temp_dir=RAY_TEMP_DIR,
object_spilling_directory=RAY_TEMP_DIR,
include_dashboard=include_dashboard,
dashboard_host=dashboard_host,
dashboard_port=self.ray_dashboard_port,
ignore_reinit_error=True
)
success = True
except Exception:
except Exception as e:
logger.error(f"Fallback Ray initialization failed: {e}")
success = False

if success:
Expand Down
Loading
Loading