Skip to content

Commit 38a80bf

Browse files
authored
Merge branch 'develop' into patch-2
2 parents c5a61eb + 26b40e6 commit 38a80bf

File tree

128 files changed

+4676
-731
lines changed

Some content is hidden

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

128 files changed

+4676
-731
lines changed

backend/apps/agent_app.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,11 @@ async def import_agent_api(request: AgentImportRequest, authorization: Optional[
134134
import an agent
135135
"""
136136
try:
137-
await import_agent_impl(request.agent_info, authorization)
137+
await import_agent_impl(
138+
request.agent_info,
139+
authorization,
140+
force_import=request.force_import
141+
)
138142
return {}
139143
except Exception as e:
140144
logger.error(f"Agent import error: {str(e)}")

backend/apps/vectordatabase_app.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Path, Query
66
from fastapi.responses import JSONResponse
77

8-
from consts.model import HybridSearchRequest, IndexingResponse
8+
from consts.model import ChunkCreateRequest, ChunkUpdateRequest, HybridSearchRequest, IndexingResponse
99
from nexent.vector_database.base import VectorDatabaseCore
1010
from services.vectordatabase_service import (
1111
ElasticSearchService,
@@ -228,6 +228,99 @@ def get_index_chunks(
228228
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=f"Error getting chunks: {error_msg}")
229229

230230

231+
@router.post("/{index_name}/chunk")
232+
def create_chunk(
233+
index_name: str = Path(..., description="Name of the index"),
234+
payload: ChunkCreateRequest = Body(..., description="Chunk data"),
235+
vdb_core: VectorDatabaseCore = Depends(get_vector_db_core),
236+
authorization: Optional[str] = Header(None),
237+
):
238+
"""Create a manual chunk."""
239+
try:
240+
user_id, _ = get_current_user_id(authorization)
241+
result = ElasticSearchService.create_chunk(
242+
index_name=index_name,
243+
chunk_request=payload,
244+
vdb_core=vdb_core,
245+
user_id=user_id,
246+
)
247+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
248+
except Exception as exc:
249+
logger.error(
250+
"Error creating chunk for index %s: %s", index_name, exc, exc_info=True
251+
)
252+
raise HTTPException(
253+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
254+
)
255+
256+
257+
@router.put("/{index_name}/chunk/{chunk_id}")
258+
def update_chunk(
259+
index_name: str = Path(..., description="Name of the index"),
260+
chunk_id: str = Path(..., description="Chunk identifier"),
261+
payload: ChunkUpdateRequest = Body(...,
262+
description="Chunk update payload"),
263+
vdb_core: VectorDatabaseCore = Depends(get_vector_db_core),
264+
authorization: Optional[str] = Header(None),
265+
):
266+
"""Update an existing chunk."""
267+
try:
268+
user_id, _ = get_current_user_id(authorization)
269+
result = ElasticSearchService.update_chunk(
270+
index_name=index_name,
271+
chunk_id=chunk_id,
272+
chunk_request=payload,
273+
vdb_core=vdb_core,
274+
user_id=user_id,
275+
)
276+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
277+
except ValueError as exc:
278+
raise HTTPException(
279+
status_code=HTTPStatus.BAD_REQUEST, detail=str(exc))
280+
except Exception as exc:
281+
logger.error(
282+
"Error updating chunk %s for index %s: %s",
283+
chunk_id,
284+
index_name,
285+
exc,
286+
exc_info=True,
287+
)
288+
raise HTTPException(
289+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
290+
)
291+
292+
293+
@router.delete("/{index_name}/chunk/{chunk_id}")
294+
def delete_chunk(
295+
index_name: str = Path(..., description="Name of the index"),
296+
chunk_id: str = Path(..., description="Chunk identifier"),
297+
vdb_core: VectorDatabaseCore = Depends(get_vector_db_core),
298+
authorization: Optional[str] = Header(None),
299+
):
300+
"""Delete a chunk."""
301+
try:
302+
get_current_user_id(authorization)
303+
result = ElasticSearchService.delete_chunk(
304+
index_name=index_name,
305+
chunk_id=chunk_id,
306+
vdb_core=vdb_core,
307+
)
308+
return JSONResponse(status_code=HTTPStatus.OK, content=result)
309+
except ValueError as exc:
310+
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail=str(exc))
311+
except Exception as exc:
312+
logger.error(
313+
"Error deleting chunk %s for index %s: %s",
314+
chunk_id,
315+
index_name,
316+
exc,
317+
exc_info=True,
318+
)
319+
raise HTTPException(
320+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc)
321+
)
322+
323+
231324
@router.post("/search/hybrid")
232325
async def hybrid_search(
233326
payload: HybridSearchRequest,

backend/consts/model.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,31 @@ class IndexingResponse(BaseModel):
175175
total_submitted: int
176176

177177

178+
class ChunkCreateRequest(BaseModel):
179+
"""Request payload for manual chunk creation."""
180+
181+
content: str = Field(..., min_length=1, description="Chunk content")
182+
title: Optional[str] = Field(None, description="Optional chunk title")
183+
filename: Optional[str] = Field(None, description="Associated file name")
184+
path_or_url: Optional[str] = Field(None, description="Source path or URL")
185+
chunk_id: Optional[str] = Field(
186+
None, description="Explicit chunk identifier")
187+
metadata: Dict[str, Any] = Field(
188+
default_factory=dict, description="Additional chunk metadata")
189+
190+
191+
class ChunkUpdateRequest(BaseModel):
192+
"""Request payload for chunk updates."""
193+
194+
content: Optional[str] = Field(None, description="Updated chunk content")
195+
title: Optional[str] = Field(None, description="Updated chunk title")
196+
filename: Optional[str] = Field(None, description="Updated file name")
197+
path_or_url: Optional[str] = Field(
198+
None, description="Updated source path or URL")
199+
metadata: Dict[str, Any] = Field(
200+
default_factory=dict, description="Additional metadata updates")
201+
202+
178203
class HybridSearchRequest(BaseModel):
179204
"""Request payload for hybrid knowledge-base searches."""
180205
query: str = Field(..., min_length=1,
@@ -316,6 +341,7 @@ class ExportAndImportDataFormat(BaseModel):
316341

317342
class AgentImportRequest(BaseModel):
318343
agent_info: ExportAndImportDataFormat
344+
force_import: bool = False
319345

320346

321347
class ConvertStateRequest(BaseModel):

backend/prompts/utils/prompt_generate.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,49 @@ USER_PROMPT: |-
249249
{% else %}
250250
你没有可用的助手
251251
{% endif %}
252+
253+
254+
AGENT_NAME_REGENERATE_SYSTEM_PROMPT: |-
255+
### 你是【Agent变量名调整专家】
256+
你的工作是根据任务描述以及已有变量名,生成一个语义一致但不重复的 Python 变量名。
257+
258+
#### 约束
259+
1. 变量名只能包含字母、数字和下划线,并且以字母或下划线开头,以“_assistant”结尾,长度不超过 30 个字符。
260+
2. 避免与已有变量名重复,同时保持与原始名称相近的语义。
261+
3. 仅输出变量名本身,不要附加额外解释或标点。
262+
263+
264+
AGENT_NAME_REGENERATE_USER_PROMPT: |-
265+
### 任务描述
266+
{{ task_description }}
267+
268+
### 原始变量名
269+
{{ original_value }}
270+
271+
### 已有变量名
272+
{{ existing_values }}
273+
274+
请在满足约束的前提下,生成一个新的变量名,使其语义接近原始变量名但不与已有变量名重复。只输出变量名本身。
275+
276+
277+
AGENT_DISPLAY_NAME_REGENERATE_SYSTEM_PROMPT: |-
278+
### 你是【Agent展示名称调整专家】
279+
你的任务是结合业务背景和已有展示名称,生成一个语义一致但不重复的 Agent 展示名称。
280+
281+
#### 约束
282+
1. 展示名称需自然、易读,能够概括 Agent 的核心能力,以“助手”结尾,长度不超过 30 个字符。
283+
2. 不得包含具体工具名称或多余符号。
284+
3. 仅输出展示名称本身。
285+
286+
287+
AGENT_DISPLAY_NAME_REGENERATE_USER_PROMPT: |-
288+
### 任务描述
289+
{{ task_description }}
290+
291+
### 原始展示名称
292+
{{ original_value }}
293+
294+
### 已有展示名称
295+
{{ existing_values }}
296+
297+
请输出一个新的展示名称,语义接近原始名称但不与已存在的展示名称重复,并满足上述约束。只输出展示名称本身。

backend/prompts/utils/prompt_generate_en.yaml

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,50 @@ USER_PROMPT: |-
251251
{{assistant_description}}
252252
{% else %}
253253
You have no available assistants
254-
{% endif %}
254+
{% endif %}
255+
256+
257+
AGENT_NAME_REGENERATE_SYSTEM_PROMPT: |-
258+
### You are an [Agent Variable Name Refinement Expert]
259+
Your job is to generate a Python-friendly variable name that keeps the same intent while avoiding duplicates.
260+
261+
#### Constraints
262+
1. The name may contain only letters, numbers, and underscores, must start with a letter or underscore, ending with "_assistant", and stay within 30 characters.
263+
2. Keep the new name semantically close to the original one while ensuring it does not duplicate existing names.
264+
3. Return the variable name only—no explanations or extra symbols.
265+
266+
267+
AGENT_NAME_REGENERATE_USER_PROMPT: |-
268+
### Task Description
269+
{{ task_description }}
270+
271+
### Original Variable Name
272+
{{ original_value }}
273+
274+
### Existing Variable Names
275+
{{ existing_values }}
276+
277+
Generate a new variable name that satisfies the constraints, keeps the original meaning, and does not duplicate any existing names. Output only the variable name.
278+
279+
280+
AGENT_DISPLAY_NAME_REGENERATE_SYSTEM_PROMPT: |-
281+
### You are an [Agent Display Name Refinement Expert]
282+
You summarize the agent's capability and generate a readable display name that remains unique within the workspace.
283+
284+
#### Constraints
285+
1. The name must be concise, easy to read, summarize the agent's responsibility, ending with "Assistant", and stay within 30 characters.
286+
2. Avoid mentioning specific tool names or adding extra punctuation.
287+
3. Return only the display name.
288+
289+
290+
AGENT_DISPLAY_NAME_REGENERATE_USER_PROMPT: |-
291+
### Task Description
292+
{{ task_description }}
293+
294+
### Original Display Name
295+
{{ original_value }}
296+
297+
### Existing Display Names
298+
{{ existing_values }}
299+
300+
Output a new display name that is semantically aligned with the original while remaining unique and honoring the constraints. Return only the display name.

0 commit comments

Comments
 (0)